4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
51 allowDomMove : false, // to stop relocations in parent onRender...
61 * Initialize Events for the element
63 initEvents : function() { },
69 can_build_overlaid : true,
71 container_method : false,
78 // returns the parent component..
79 return Roo.ComponentMgr.get(this.parentId)
85 onRender : function(ct, position)
87 // Roo.log("Call onRender: " + this.xtype);
89 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92 if (this.el.attr('xtype')) {
93 this.el.attr('xtypex', this.el.attr('xtype'));
94 this.el.dom.removeAttribute('xtype');
104 var cfg = Roo.apply({}, this.getAutoCreate());
106 cfg.id = this.id || Roo.id();
108 // fill in the extra attributes
109 if (this.xattr && typeof(this.xattr) =='object') {
110 for (var i in this.xattr) {
111 cfg[i] = this.xattr[i];
116 cfg.dataId = this.dataId;
120 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
123 if (this.style) { // fixme needs to support more complex style data.
124 cfg.style = this.style;
128 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
166 //Roo.log(['addxtype', cn]);
168 cn.parentType = this.xtype; //??
169 cn.parentId = this.id;
171 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 if (typeof(cn.container_method) == 'string') {
173 cntr = cn.container_method;
177 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
179 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
181 var build_from_html = Roo.XComponent.build_from_html;
183 var is_body = (tree.xtype == 'Body') ;
185 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
187 var self_cntr_el = Roo.get(this[cntr](false));
189 // do not try and build conditional elements
190 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
194 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196 return this.addxtypeChild(tree,cntr, is_body);
199 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
202 return this.addxtypeChild(Roo.apply({}, tree),cntr);
205 Roo.log('skipping render');
211 if (!build_from_html) {
215 // this i think handles overlaying multiple children of the same type
216 // with the sam eelement.. - which might be buggy..
218 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
224 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
228 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
235 addxtypeChild : function (tree, cntr, is_body)
237 Roo.debug && Roo.log('addxtypeChild:' + cntr);
239 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243 (typeof(tree['flexy:foreach']) != 'undefined');
247 skip_children = false;
248 // render the element if it's not BODY.
251 // if parent was disabled, then do not try and create the children..
252 if(!this[cntr](true)){
257 cn = Roo.factory(tree);
259 cn.parentType = this.xtype; //??
260 cn.parentId = this.id;
262 var build_from_html = Roo.XComponent.build_from_html;
265 // does the container contain child eleemnts with 'xtype' attributes.
266 // that match this xtype..
267 // note - when we render we create these as well..
268 // so we should check to see if body has xtype set.
269 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
271 var self_cntr_el = Roo.get(this[cntr](false));
272 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
274 //Roo.log(Roo.XComponent.build_from_html);
275 //Roo.log("got echild:");
278 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279 // and are not displayed -this causes this to use up the wrong element when matching.
280 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
283 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
290 //echild.dom.removeAttribute('xtype');
292 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293 Roo.debug && Roo.log(self_cntr_el);
294 Roo.debug && Roo.log(echild);
295 Roo.debug && Roo.log(cn);
301 // if object has flexy:if - then it may or may not be rendered.
302 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
303 // skip a flexy if element.
304 Roo.debug && Roo.log('skipping render');
305 Roo.debug && Roo.log(tree);
307 Roo.debug && Roo.log('skipping all children');
308 skip_children = true;
313 // actually if flexy:foreach is found, we really want to create
314 // multiple copies here...
316 //Roo.log(this[cntr]());
317 // some elements do not have render methods.. like the layouts...
319 if(this[cntr](true) === false){
324 cn.render && cn.render(this[cntr](true));
327 // then add the element..
334 if (typeof (tree.menu) != 'undefined') {
335 tree.menu.parentType = cn.xtype;
336 tree.menu.triggerEl = cn.el;
337 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
341 if (!tree.items || !tree.items.length) {
343 //Roo.log(["no children", this]);
348 var items = tree.items;
351 //Roo.log(items.length);
353 if (!skip_children) {
354 for(var i =0;i < items.length;i++) {
355 // Roo.log(['add child', items[i]]);
356 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
362 //Roo.log("fire childrenrendered");
364 cn.fireEvent('childrenrendered', this);
370 * Set the element that will be used to show or hide
372 setVisibilityEl : function(el)
374 this.visibilityEl = el;
378 * Get the element that will be used to show or hide
380 getVisibilityEl : function()
382 if (typeof(this.visibilityEl) == 'object') {
383 return this.visibilityEl;
386 if (typeof(this.visibilityEl) == 'string') {
387 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
394 * Show a component - removes 'hidden' class
398 if(!this.getVisibilityEl()){
402 this.getVisibilityEl().removeClass('hidden');
407 * Hide a component - adds 'hidden' class
411 if(!this.getVisibilityEl()){
415 this.getVisibilityEl().addClass('hidden');
428 * @class Roo.bootstrap.Body
429 * @extends Roo.bootstrap.Component
430 * Bootstrap Body class
434 * @param {Object} config The config object
437 Roo.bootstrap.Body = function(config){
439 config = config || {};
441 Roo.bootstrap.Body.superclass.constructor.call(this, config);
442 this.el = Roo.get(config.el ? config.el : document.body );
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
450 is_body : true,// just to make sure it's constructed?
455 onRender : function(ct, position)
457 /* Roo.log("Roo.bootstrap.Body - onRender");
458 if (this.cls && this.cls.length) {
459 Roo.get(document.body).addClass(this.cls);
478 * @class Roo.bootstrap.ButtonGroup
479 * @extends Roo.bootstrap.Component
480 * Bootstrap ButtonGroup class
481 * @cfg {String} size lg | sm | xs (default empty normal)
482 * @cfg {String} align vertical | justified (default none)
483 * @cfg {String} direction up | down (default down)
484 * @cfg {Boolean} toolbar false | true
485 * @cfg {Boolean} btn true | false
490 * @param {Object} config The config object
493 Roo.bootstrap.ButtonGroup = function(config){
494 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
505 getAutoCreate : function(){
511 cfg.html = this.html || cfg.html;
522 if (['vertical','justified'].indexOf(this.align)!==-1) {
523 cfg.cls = 'btn-group-' + this.align;
525 if (this.align == 'justified') {
526 console.log(this.items);
530 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531 cfg.cls += ' btn-group-' + this.size;
534 if (this.direction == 'up') {
535 cfg.cls += ' dropup' ;
551 * @class Roo.bootstrap.Button
552 * @extends Roo.bootstrap.Component
553 * Bootstrap Button class
554 * @cfg {String} html The button content
555 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
556 * @cfg {String} size ( lg | sm | xs)
557 * @cfg {String} tag ( a | input | submit)
558 * @cfg {String} href empty or href
559 * @cfg {Boolean} disabled default false;
560 * @cfg {Boolean} isClose default false;
561 * @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)
562 * @cfg {String} badge text for badge
563 * @cfg {String} theme (default|glow)
564 * @cfg {Boolean} inverse dark themed version
565 * @cfg {Boolean} toggle is it a slidy toggle button
566 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567 * @cfg {String} ontext text for on slidy toggle state
568 * @cfg {String} offtext text for off slidy toggle state
569 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
570 * @cfg {Boolean} removeClass remove the standard class..
571 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
574 * Create a new button
575 * @param {Object} config The config object
579 Roo.bootstrap.Button = function(config){
580 Roo.bootstrap.Button.superclass.constructor.call(this, config);
581 this.weightClass = ["btn-default",
593 * When a butotn is pressed
594 * @param {Roo.bootstrap.Button} btn
595 * @param {Roo.EventObject} e
600 * After the button has been toggles
601 * @param {Roo.bootstrap.Button} btn
602 * @param {Roo.EventObject} e
603 * @param {boolean} pressed (also available as button.pressed)
609 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
627 preventDefault: true,
635 getAutoCreate : function(){
643 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
644 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
651 if (this.toggle == true) {
654 cls: 'slider-frame roo-button',
659 'data-off-text':'OFF',
660 cls: 'slider-button',
666 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667 cfg.cls += ' '+this.weight;
676 cfg["aria-hidden"] = true;
678 cfg.html = "×";
684 if (this.theme==='default') {
685 cfg.cls = 'btn roo-button';
687 //if (this.parentType != 'Navbar') {
688 this.weight = this.weight.length ? this.weight : 'default';
690 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
692 cfg.cls += ' btn-' + this.weight;
694 } else if (this.theme==='glow') {
697 cfg.cls = 'btn-glow roo-button';
699 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
701 cfg.cls += ' ' + this.weight;
707 this.cls += ' inverse';
711 if (this.active || this.pressed === true) {
712 cfg.cls += ' active';
716 cfg.disabled = 'disabled';
720 Roo.log('changing to ul' );
722 this.glyphicon = 'caret';
725 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
727 //gsRoo.log(this.parentType);
728 if (this.parentType === 'Navbar' && !this.parent().bar) {
729 Roo.log('changing to li?');
738 href : this.href || '#'
741 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
742 cfg.cls += ' dropdown';
749 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
751 if (this.glyphicon) {
752 cfg.html = ' ' + cfg.html;
757 cls: 'glyphicon glyphicon-' + this.glyphicon
767 // cfg.cls='btn roo-button';
771 var value = cfg.html;
776 cls: 'glyphicon glyphicon-' + this.glyphicon,
795 cfg.cls += ' dropdown';
796 cfg.html = typeof(cfg.html) != 'undefined' ?
797 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
800 if (cfg.tag !== 'a' && this.href !== '') {
801 throw "Tag must be a to set href.";
802 } else if (this.href.length > 0) {
803 cfg.href = this.href;
806 if(this.removeClass){
811 cfg.target = this.target;
816 initEvents: function() {
817 // Roo.log('init events?');
818 // Roo.log(this.el.dom);
821 if (typeof (this.menu) != 'undefined') {
822 this.menu.parentType = this.xtype;
823 this.menu.triggerEl = this.el;
824 this.addxtype(Roo.apply({}, this.menu));
828 if (this.el.hasClass('roo-button')) {
829 this.el.on('click', this.onClick, this);
831 this.el.select('.roo-button').on('click', this.onClick, this);
834 if(this.removeClass){
835 this.el.on('click', this.onClick, this);
838 this.el.enableDisplayMode();
841 onClick : function(e)
847 Roo.log('button on click ');
848 if(this.preventDefault){
852 if (this.pressed === true || this.pressed === false) {
853 this.toggleActive(e);
857 this.fireEvent('click', this, e);
861 * Enables this button
865 this.disabled = false;
866 this.el.removeClass('disabled');
870 * Disable this button
874 this.disabled = true;
875 this.el.addClass('disabled');
878 * sets the active state on/off,
879 * @param {Boolean} state (optional) Force a particular state
881 setActive : function(v) {
883 this.el[v ? 'addClass' : 'removeClass']('active');
887 * toggles the current active state
889 toggleActive : function(e)
891 this.setActive(!this.pressed);
892 this.fireEvent('toggle', this, e, !this.pressed);
895 * get the current active state
896 * @return {boolean} true if it's active
898 isActive : function()
900 return this.el.hasClass('active');
903 * set the text of the first selected button
905 setText : function(str)
907 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
910 * get the text of the first selected button
914 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
925 setWeight : function(str)
927 this.el.removeClass(this.weightClass);
928 this.el.addClass('btn-' + str);
942 * @class Roo.bootstrap.Column
943 * @extends Roo.bootstrap.Component
944 * Bootstrap Column class
945 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
946 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
947 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
948 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
949 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
950 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
951 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
952 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
955 * @cfg {Boolean} hidden (true|false) hide the element
956 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
957 * @cfg {String} fa (ban|check|...) font awesome icon
958 * @cfg {Number} fasize (1|2|....) font awsome size
960 * @cfg {String} icon (info-sign|check|...) glyphicon name
962 * @cfg {String} html content of column.
965 * Create a new Column
966 * @param {Object} config The config object
969 Roo.bootstrap.Column = function(config){
970 Roo.bootstrap.Column.superclass.constructor.call(this, config);
973 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
991 getAutoCreate : function(){
992 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1000 ['xs','sm','md','lg'].map(function(size){
1001 //Roo.log( size + ':' + settings[size]);
1003 if (settings[size+'off'] !== false) {
1004 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1007 if (settings[size] === false) {
1011 if (!settings[size]) { // 0 = hidden
1012 cfg.cls += ' hidden-' + size;
1015 cfg.cls += ' col-' + size + '-' + settings[size];
1020 cfg.cls += ' hidden';
1023 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1024 cfg.cls +=' alert alert-' + this.alert;
1028 if (this.html.length) {
1029 cfg.html = this.html;
1033 if (this.fasize > 1) {
1034 fasize = ' fa-' + this.fasize + 'x';
1036 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1041 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1060 * @class Roo.bootstrap.Container
1061 * @extends Roo.bootstrap.Component
1062 * Bootstrap Container class
1063 * @cfg {Boolean} jumbotron is it a jumbotron element
1064 * @cfg {String} html content of element
1065 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1066 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1067 * @cfg {String} header content of header (for panel)
1068 * @cfg {String} footer content of footer (for panel)
1069 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1070 * @cfg {String} tag (header|aside|section) type of HTML tag.
1071 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1072 * @cfg {String} fa font awesome icon
1073 * @cfg {String} icon (info-sign|check|...) glyphicon name
1074 * @cfg {Boolean} hidden (true|false) hide the element
1075 * @cfg {Boolean} expandable (true|false) default false
1076 * @cfg {Boolean} expanded (true|false) default true
1077 * @cfg {String} rheader contet on the right of header
1078 * @cfg {Boolean} clickable (true|false) default false
1082 * Create a new Container
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Container = function(config){
1087 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1093 * After the panel has been expand
1095 * @param {Roo.bootstrap.Container} this
1100 * After the panel has been collapsed
1102 * @param {Roo.bootstrap.Container} this
1107 * When a element is chick
1108 * @param {Roo.bootstrap.Container} this
1109 * @param {Roo.EventObject} e
1115 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1133 getChildContainer : function() {
1139 if (this.panel.length) {
1140 return this.el.select('.panel-body',true).first();
1147 getAutoCreate : function(){
1150 tag : this.tag || 'div',
1154 if (this.jumbotron) {
1155 cfg.cls = 'jumbotron';
1160 // - this is applied by the parent..
1162 // cfg.cls = this.cls + '';
1165 if (this.sticky.length) {
1167 var bd = Roo.get(document.body);
1168 if (!bd.hasClass('bootstrap-sticky')) {
1169 bd.addClass('bootstrap-sticky');
1170 Roo.select('html',true).setStyle('height', '100%');
1173 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1177 if (this.well.length) {
1178 switch (this.well) {
1181 cfg.cls +=' well well-' +this.well;
1190 cfg.cls += ' hidden';
1194 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1195 cfg.cls +=' alert alert-' + this.alert;
1200 if (this.panel.length) {
1201 cfg.cls += ' panel panel-' + this.panel;
1203 if (this.header.length) {
1207 if(this.expandable){
1209 cfg.cls = cfg.cls + ' expandable';
1213 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1221 cls : 'panel-title',
1222 html : (this.expandable ? ' ' : '') + this.header
1226 cls: 'panel-header-right',
1232 cls : 'panel-heading',
1233 style : this.expandable ? 'cursor: pointer' : '',
1241 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1246 if (this.footer.length) {
1248 cls : 'panel-footer',
1257 body.html = this.html || cfg.html;
1258 // prefix with the icons..
1260 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1263 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1268 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1269 cfg.cls = 'container';
1275 initEvents: function()
1277 if(this.expandable){
1278 var headerEl = this.headerEl();
1281 headerEl.on('click', this.onToggleClick, this);
1286 this.el.on('click', this.onClick, this);
1291 onToggleClick : function()
1293 var headerEl = this.headerEl();
1309 if(this.fireEvent('expand', this)) {
1311 this.expanded = true;
1313 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1315 this.el.select('.panel-body',true).first().removeClass('hide');
1317 var toggleEl = this.toggleEl();
1323 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1328 collapse : function()
1330 if(this.fireEvent('collapse', this)) {
1332 this.expanded = false;
1334 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1335 this.el.select('.panel-body',true).first().addClass('hide');
1337 var toggleEl = this.toggleEl();
1343 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1347 toggleEl : function()
1349 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1353 return this.el.select('.panel-heading .fa',true).first();
1356 headerEl : function()
1358 if(!this.el || !this.panel.length || !this.header.length){
1362 return this.el.select('.panel-heading',true).first()
1367 if(!this.el || !this.panel.length){
1371 return this.el.select('.panel-body',true).first()
1374 titleEl : function()
1376 if(!this.el || !this.panel.length || !this.header.length){
1380 return this.el.select('.panel-title',true).first();
1383 setTitle : function(v)
1385 var titleEl = this.titleEl();
1391 titleEl.dom.innerHTML = v;
1394 getTitle : function()
1397 var titleEl = this.titleEl();
1403 return titleEl.dom.innerHTML;
1406 setRightTitle : function(v)
1408 var t = this.el.select('.panel-header-right',true).first();
1414 t.dom.innerHTML = v;
1417 onClick : function(e)
1421 this.fireEvent('click', this, e);
1434 * @class Roo.bootstrap.Img
1435 * @extends Roo.bootstrap.Component
1436 * Bootstrap Img class
1437 * @cfg {Boolean} imgResponsive false | true
1438 * @cfg {String} border rounded | circle | thumbnail
1439 * @cfg {String} src image source
1440 * @cfg {String} alt image alternative text
1441 * @cfg {String} href a tag href
1442 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1443 * @cfg {String} xsUrl xs image source
1444 * @cfg {String} smUrl sm image source
1445 * @cfg {String} mdUrl md image source
1446 * @cfg {String} lgUrl lg image source
1449 * Create a new Input
1450 * @param {Object} config The config object
1453 Roo.bootstrap.Img = function(config){
1454 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1460 * The img click event for the img.
1461 * @param {Roo.EventObject} e
1467 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1469 imgResponsive: true,
1479 getAutoCreate : function()
1481 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1482 return this.createSingleImg();
1487 cls: 'roo-image-responsive-group',
1492 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1494 if(!_this[size + 'Url']){
1500 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1501 html: _this.html || cfg.html,
1502 src: _this[size + 'Url']
1505 img.cls += ' roo-image-responsive-' + size;
1507 var s = ['xs', 'sm', 'md', 'lg'];
1509 s.splice(s.indexOf(size), 1);
1511 Roo.each(s, function(ss){
1512 img.cls += ' hidden-' + ss;
1515 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1516 cfg.cls += ' img-' + _this.border;
1520 cfg.alt = _this.alt;
1533 a.target = _this.target;
1537 cfg.cn.push((_this.href) ? a : img);
1544 createSingleImg : function()
1548 cls: (this.imgResponsive) ? 'img-responsive' : '',
1550 src : 'about:blank' // just incase src get's set to undefined?!?
1553 cfg.html = this.html || cfg.html;
1555 cfg.src = this.src || cfg.src;
1557 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1558 cfg.cls += ' img-' + this.border;
1575 a.target = this.target;
1580 return (this.href) ? a : cfg;
1583 initEvents: function()
1586 this.el.on('click', this.onClick, this);
1591 onClick : function(e)
1593 Roo.log('img onclick');
1594 this.fireEvent('click', this, e);
1597 * Sets the url of the image - used to update it
1598 * @param {String} url the url of the image
1601 setSrc : function(url)
1605 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1606 this.el.dom.src = url;
1610 this.el.select('img', true).first().dom.src = url;
1626 * @class Roo.bootstrap.Link
1627 * @extends Roo.bootstrap.Component
1628 * Bootstrap Link Class
1629 * @cfg {String} alt image alternative text
1630 * @cfg {String} href a tag href
1631 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1632 * @cfg {String} html the content of the link.
1633 * @cfg {String} anchor name for the anchor link
1634 * @cfg {String} fa - favicon
1636 * @cfg {Boolean} preventDefault (true | false) default false
1640 * Create a new Input
1641 * @param {Object} config The config object
1644 Roo.bootstrap.Link = function(config){
1645 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1651 * The img click event for the img.
1652 * @param {Roo.EventObject} e
1658 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1662 preventDefault: false,
1668 getAutoCreate : function()
1670 var html = this.html || '';
1672 if (this.fa !== false) {
1673 html = '<i class="fa fa-' + this.fa + '"></i>';
1678 // anchor's do not require html/href...
1679 if (this.anchor === false) {
1681 cfg.href = this.href || '#';
1683 cfg.name = this.anchor;
1684 if (this.html !== false || this.fa !== false) {
1687 if (this.href !== false) {
1688 cfg.href = this.href;
1692 if(this.alt !== false){
1697 if(this.target !== false) {
1698 cfg.target = this.target;
1704 initEvents: function() {
1706 if(!this.href || this.preventDefault){
1707 this.el.on('click', this.onClick, this);
1711 onClick : function(e)
1713 if(this.preventDefault){
1716 //Roo.log('img onclick');
1717 this.fireEvent('click', this, e);
1730 * @class Roo.bootstrap.Header
1731 * @extends Roo.bootstrap.Component
1732 * Bootstrap Header class
1733 * @cfg {String} html content of header
1734 * @cfg {Number} level (1|2|3|4|5|6) default 1
1737 * Create a new Header
1738 * @param {Object} config The config object
1742 Roo.bootstrap.Header = function(config){
1743 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1746 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1754 getAutoCreate : function(){
1759 tag: 'h' + (1 *this.level),
1760 html: this.html || ''
1772 * Ext JS Library 1.1.1
1773 * Copyright(c) 2006-2007, Ext JS, LLC.
1775 * Originally Released Under LGPL - original licence link has changed is not relivant.
1778 * <script type="text/javascript">
1782 * @class Roo.bootstrap.MenuMgr
1783 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1786 Roo.bootstrap.MenuMgr = function(){
1787 var menus, active, groups = {}, attached = false, lastShow = new Date();
1789 // private - called when first menu is created
1792 active = new Roo.util.MixedCollection();
1793 Roo.get(document).addKeyListener(27, function(){
1794 if(active.length > 0){
1802 if(active && active.length > 0){
1803 var c = active.clone();
1813 if(active.length < 1){
1814 Roo.get(document).un("mouseup", onMouseDown);
1822 var last = active.last();
1823 lastShow = new Date();
1826 Roo.get(document).on("mouseup", onMouseDown);
1831 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1832 m.parentMenu.activeChild = m;
1833 }else if(last && last.isVisible()){
1834 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1839 function onBeforeHide(m){
1841 m.activeChild.hide();
1843 if(m.autoHideTimer){
1844 clearTimeout(m.autoHideTimer);
1845 delete m.autoHideTimer;
1850 function onBeforeShow(m){
1851 var pm = m.parentMenu;
1852 if(!pm && !m.allowOtherMenus){
1854 }else if(pm && pm.activeChild && active != m){
1855 pm.activeChild.hide();
1859 // private this should really trigger on mouseup..
1860 function onMouseDown(e){
1861 Roo.log("on Mouse Up");
1863 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1864 Roo.log("MenuManager hideAll");
1873 function onBeforeCheck(mi, state){
1875 var g = groups[mi.group];
1876 for(var i = 0, l = g.length; i < l; i++){
1878 g[i].setChecked(false);
1887 * Hides all menus that are currently visible
1889 hideAll : function(){
1894 register : function(menu){
1898 menus[menu.id] = menu;
1899 menu.on("beforehide", onBeforeHide);
1900 menu.on("hide", onHide);
1901 menu.on("beforeshow", onBeforeShow);
1902 menu.on("show", onShow);
1904 if(g && menu.events["checkchange"]){
1908 groups[g].push(menu);
1909 menu.on("checkchange", onCheck);
1914 * Returns a {@link Roo.menu.Menu} object
1915 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1916 * be used to generate and return a new Menu instance.
1918 get : function(menu){
1919 if(typeof menu == "string"){ // menu id
1921 }else if(menu.events){ // menu instance
1924 /*else if(typeof menu.length == 'number'){ // array of menu items?
1925 return new Roo.bootstrap.Menu({items:menu});
1926 }else{ // otherwise, must be a config
1927 return new Roo.bootstrap.Menu(menu);
1934 unregister : function(menu){
1935 delete menus[menu.id];
1936 menu.un("beforehide", onBeforeHide);
1937 menu.un("hide", onHide);
1938 menu.un("beforeshow", onBeforeShow);
1939 menu.un("show", onShow);
1941 if(g && menu.events["checkchange"]){
1942 groups[g].remove(menu);
1943 menu.un("checkchange", onCheck);
1948 registerCheckable : function(menuItem){
1949 var g = menuItem.group;
1954 groups[g].push(menuItem);
1955 menuItem.on("beforecheckchange", onBeforeCheck);
1960 unregisterCheckable : function(menuItem){
1961 var g = menuItem.group;
1963 groups[g].remove(menuItem);
1964 menuItem.un("beforecheckchange", onBeforeCheck);
1976 * @class Roo.bootstrap.Menu
1977 * @extends Roo.bootstrap.Component
1978 * Bootstrap Menu class - container for MenuItems
1979 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1980 * @cfg {bool} hidden if the menu should be hidden when rendered.
1981 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1982 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1986 * @param {Object} config The config object
1990 Roo.bootstrap.Menu = function(config){
1991 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1992 if (this.registerMenu && this.type != 'treeview') {
1993 Roo.bootstrap.MenuMgr.register(this);
1998 * Fires before this menu is displayed
1999 * @param {Roo.menu.Menu} this
2004 * Fires before this menu is hidden
2005 * @param {Roo.menu.Menu} this
2010 * Fires after this menu is displayed
2011 * @param {Roo.menu.Menu} this
2016 * Fires after this menu is hidden
2017 * @param {Roo.menu.Menu} this
2022 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2023 * @param {Roo.menu.Menu} this
2024 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2025 * @param {Roo.EventObject} e
2030 * Fires when the mouse is hovering over this menu
2031 * @param {Roo.menu.Menu} this
2032 * @param {Roo.EventObject} e
2033 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2038 * Fires when the mouse exits this menu
2039 * @param {Roo.menu.Menu} this
2040 * @param {Roo.EventObject} e
2041 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2046 * Fires when a menu item contained in this menu is clicked
2047 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2048 * @param {Roo.EventObject} e
2052 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2055 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2059 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2062 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2064 registerMenu : true,
2066 menuItems :false, // stores the menu items..
2076 getChildContainer : function() {
2080 getAutoCreate : function(){
2082 //if (['right'].indexOf(this.align)!==-1) {
2083 // cfg.cn[1].cls += ' pull-right'
2089 cls : 'dropdown-menu' ,
2090 style : 'z-index:1000'
2094 if (this.type === 'submenu') {
2095 cfg.cls = 'submenu active';
2097 if (this.type === 'treeview') {
2098 cfg.cls = 'treeview-menu';
2103 initEvents : function() {
2105 // Roo.log("ADD event");
2106 // Roo.log(this.triggerEl.dom);
2108 this.triggerEl.on('click', this.onTriggerClick, this);
2110 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2112 this.triggerEl.addClass('dropdown-toggle');
2115 this.el.on('touchstart' , this.onTouch, this);
2117 this.el.on('click' , this.onClick, this);
2119 this.el.on("mouseover", this.onMouseOver, this);
2120 this.el.on("mouseout", this.onMouseOut, this);
2124 findTargetItem : function(e)
2126 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2130 //Roo.log(t); Roo.log(t.id);
2132 //Roo.log(this.menuitems);
2133 return this.menuitems.get(t.id);
2135 //return this.items.get(t.menuItemId);
2141 onTouch : function(e)
2143 Roo.log("menu.onTouch");
2144 //e.stopEvent(); this make the user popdown broken
2148 onClick : function(e)
2150 Roo.log("menu.onClick");
2152 var t = this.findTargetItem(e);
2153 if(!t || t.isContainer){
2158 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2159 if(t == this.activeItem && t.shouldDeactivate(e)){
2160 this.activeItem.deactivate();
2161 delete this.activeItem;
2165 this.setActiveItem(t, true);
2173 Roo.log('pass click event');
2177 this.fireEvent("click", this, t, e);
2181 if(!t.href.length || t.href == '#'){
2182 (function() { _this.hide(); }).defer(100);
2187 onMouseOver : function(e){
2188 var t = this.findTargetItem(e);
2191 // if(t.canActivate && !t.disabled){
2192 // this.setActiveItem(t, true);
2196 this.fireEvent("mouseover", this, e, t);
2198 isVisible : function(){
2199 return !this.hidden;
2201 onMouseOut : function(e){
2202 var t = this.findTargetItem(e);
2205 // if(t == this.activeItem && t.shouldDeactivate(e)){
2206 // this.activeItem.deactivate();
2207 // delete this.activeItem;
2210 this.fireEvent("mouseout", this, e, t);
2215 * Displays this menu relative to another element
2216 * @param {String/HTMLElement/Roo.Element} element The element to align to
2217 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2218 * the element (defaults to this.defaultAlign)
2219 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2221 show : function(el, pos, parentMenu){
2222 this.parentMenu = parentMenu;
2226 this.fireEvent("beforeshow", this);
2228 Roo.log('EL----------------');
2232 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2235 * Displays this menu at a specific xy position
2236 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2237 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2239 showAt : function(xy, parentMenu, /* private: */_e){
2240 this.parentMenu = parentMenu;
2245 this.fireEvent("beforeshow", this);
2246 //xy = this.el.adjustForConstraints(xy);
2250 this.hideMenuItems();
2251 this.hidden = false;
2252 this.triggerEl.addClass('open');
2254 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2255 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2258 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2263 this.fireEvent("show", this);
2269 this.doFocus.defer(50, this);
2273 doFocus : function(){
2275 this.focusEl.focus();
2280 * Hides this menu and optionally all parent menus
2281 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2283 hide : function(deep)
2286 this.hideMenuItems();
2287 if(this.el && this.isVisible()){
2288 this.fireEvent("beforehide", this);
2289 if(this.activeItem){
2290 this.activeItem.deactivate();
2291 this.activeItem = null;
2293 this.triggerEl.removeClass('open');;
2295 this.fireEvent("hide", this);
2297 if(deep === true && this.parentMenu){
2298 this.parentMenu.hide(true);
2302 onTriggerClick : function(e)
2304 Roo.log('trigger click');
2306 var target = e.getTarget();
2308 Roo.log(target.nodeName.toLowerCase());
2310 if(target.nodeName.toLowerCase() === 'i'){
2316 onTriggerPress : function(e)
2318 Roo.log('trigger press');
2319 //Roo.log(e.getTarget());
2320 // Roo.log(this.triggerEl.dom);
2322 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2323 var pel = Roo.get(e.getTarget());
2324 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2325 Roo.log('is treeview or dropdown?');
2329 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2333 if (this.isVisible()) {
2338 this.show(this.triggerEl, false, false);
2341 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2348 hideMenuItems : function()
2350 Roo.log("hide Menu Items");
2354 //$(backdrop).remove()
2355 this.el.select('.open',true).each(function(aa) {
2357 aa.removeClass('open');
2358 //var parent = getParent($(this))
2359 //var relatedTarget = { relatedTarget: this }
2361 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2362 //if (e.isDefaultPrevented()) return
2363 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2366 addxtypeChild : function (tree, cntr) {
2367 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2369 this.menuitems.add(comp);
2381 this.getEl().dom.innerHTML = '';
2382 this.menuitems.clear();
2396 * @class Roo.bootstrap.MenuItem
2397 * @extends Roo.bootstrap.Component
2398 * Bootstrap MenuItem class
2399 * @cfg {String} html the menu label
2400 * @cfg {String} href the link
2401 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2402 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2403 * @cfg {Boolean} active used on sidebars to highlight active itesm
2404 * @cfg {String} fa favicon to show on left of menu item.
2405 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2409 * Create a new MenuItem
2410 * @param {Object} config The config object
2414 Roo.bootstrap.MenuItem = function(config){
2415 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2420 * The raw click event for the entire grid.
2421 * @param {Roo.bootstrap.MenuItem} this
2422 * @param {Roo.EventObject} e
2428 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2432 preventDefault: false,
2433 isContainer : false,
2437 getAutoCreate : function(){
2439 if(this.isContainer){
2442 cls: 'dropdown-menu-item'
2456 if (this.fa !== false) {
2459 cls : 'fa fa-' + this.fa
2468 cls: 'dropdown-menu-item',
2471 if (this.parent().type == 'treeview') {
2472 cfg.cls = 'treeview-menu';
2475 cfg.cls += ' active';
2480 anc.href = this.href || cfg.cn[0].href ;
2481 ctag.html = this.html || cfg.cn[0].html ;
2485 initEvents: function()
2487 if (this.parent().type == 'treeview') {
2488 this.el.select('a').on('click', this.onClick, this);
2492 this.menu.parentType = this.xtype;
2493 this.menu.triggerEl = this.el;
2494 this.menu = this.addxtype(Roo.apply({}, this.menu));
2498 onClick : function(e)
2500 Roo.log('item on click ');
2502 if(this.preventDefault){
2505 //this.parent().hideMenuItems();
2507 this.fireEvent('click', this, e);
2526 * @class Roo.bootstrap.MenuSeparator
2527 * @extends Roo.bootstrap.Component
2528 * Bootstrap MenuSeparator class
2531 * Create a new MenuItem
2532 * @param {Object} config The config object
2536 Roo.bootstrap.MenuSeparator = function(config){
2537 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2540 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2542 getAutoCreate : function(){
2561 * @class Roo.bootstrap.Modal
2562 * @extends Roo.bootstrap.Component
2563 * Bootstrap Modal class
2564 * @cfg {String} title Title of dialog
2565 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2566 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2567 * @cfg {Boolean} specificTitle default false
2568 * @cfg {Array} buttons Array of buttons or standard button set..
2569 * @cfg {String} buttonPosition (left|right|center) default right
2570 * @cfg {Boolean} animate default true
2571 * @cfg {Boolean} allow_close default true
2572 * @cfg {Boolean} fitwindow default false
2573 * @cfg {String} size (sm|lg) default empty
2577 * Create a new Modal Dialog
2578 * @param {Object} config The config object
2581 Roo.bootstrap.Modal = function(config){
2582 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2587 * The raw btnclick event for the button
2588 * @param {Roo.EventObject} e
2593 * Fire when dialog resize
2594 * @param {Roo.bootstrap.Modal} this
2595 * @param {Roo.EventObject} e
2599 this.buttons = this.buttons || [];
2602 this.tmpl = Roo.factory(this.tmpl);
2607 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2609 title : 'test dialog',
2619 specificTitle: false,
2621 buttonPosition: 'right',
2640 onRender : function(ct, position)
2642 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2645 var cfg = Roo.apply({}, this.getAutoCreate());
2648 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2650 //if (!cfg.name.length) {
2654 cfg.cls += ' ' + this.cls;
2657 cfg.style = this.style;
2659 this.el = Roo.get(document.body).createChild(cfg, position);
2661 //var type = this.el.dom.type;
2664 if(this.tabIndex !== undefined){
2665 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2668 this.dialogEl = this.el.select('.modal-dialog',true).first();
2669 this.bodyEl = this.el.select('.modal-body',true).first();
2670 this.closeEl = this.el.select('.modal-header .close', true).first();
2671 this.headerEl = this.el.select('.modal-header',true).first();
2672 this.titleEl = this.el.select('.modal-title',true).first();
2673 this.footerEl = this.el.select('.modal-footer',true).first();
2675 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2677 //this.el.addClass("x-dlg-modal");
2679 if (this.buttons.length) {
2680 Roo.each(this.buttons, function(bb) {
2681 var b = Roo.apply({}, bb);
2682 b.xns = b.xns || Roo.bootstrap;
2683 b.xtype = b.xtype || 'Button';
2684 if (typeof(b.listeners) == 'undefined') {
2685 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2688 var btn = Roo.factory(b);
2690 btn.render(this.el.select('.modal-footer div').first());
2694 // render the children.
2697 if(typeof(this.items) != 'undefined'){
2698 var items = this.items;
2701 for(var i =0;i < items.length;i++) {
2702 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2706 this.items = nitems;
2708 // where are these used - they used to be body/close/footer
2712 //this.el.addClass([this.fieldClass, this.cls]);
2716 getAutoCreate : function(){
2721 html : this.html || ''
2726 cls : 'modal-title',
2730 if(this.specificTitle){
2736 if (this.allow_close) {
2748 if(this.size.length){
2749 size = 'modal-' + this.size;
2756 cls: "modal-dialog " + size,
2759 cls : "modal-content",
2762 cls : 'modal-header',
2767 cls : 'modal-footer',
2771 cls: 'btn-' + this.buttonPosition
2788 modal.cls += ' fade';
2794 getChildContainer : function() {
2799 getButtonContainer : function() {
2800 return this.el.select('.modal-footer div',true).first();
2803 initEvents : function()
2805 if (this.allow_close) {
2806 this.closeEl.on('click', this.hide, this);
2808 Roo.EventManager.onWindowResize(this.resize, this, true);
2815 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2816 if (this.fitwindow) {
2817 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2818 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2823 setSize : function(w,h)
2833 if (!this.rendered) {
2837 //this.el.setStyle('display', 'block');
2838 this.el.removeClass('hideing');
2839 this.el.addClass('show');
2841 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2844 this.el.addClass('in');
2847 this.el.addClass('in');
2851 // not sure how we can show data in here..
2853 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2856 Roo.get(document.body).addClass("x-body-masked");
2858 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2859 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2860 this.maskEl.addClass('show');
2864 this.fireEvent('show', this);
2866 // set zindex here - otherwise it appears to be ignored...
2867 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2870 this.items.forEach( function(e) {
2871 e.layout ? e.layout() : false;
2879 if(this.fireEvent("beforehide", this) !== false){
2880 this.maskEl.removeClass('show');
2881 Roo.get(document.body).removeClass("x-body-masked");
2882 this.el.removeClass('in');
2883 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2885 if(this.animate){ // why
2886 this.el.addClass('hideing');
2888 if (!this.el.hasClass('hideing')) {
2889 return; // it's been shown again...
2891 this.el.removeClass('show');
2892 this.el.removeClass('hideing');
2896 this.el.removeClass('show');
2898 this.fireEvent('hide', this);
2901 isVisible : function()
2904 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2908 addButton : function(str, cb)
2912 var b = Roo.apply({}, { html : str } );
2913 b.xns = b.xns || Roo.bootstrap;
2914 b.xtype = b.xtype || 'Button';
2915 if (typeof(b.listeners) == 'undefined') {
2916 b.listeners = { click : cb.createDelegate(this) };
2919 var btn = Roo.factory(b);
2921 btn.render(this.el.select('.modal-footer div').first());
2927 setDefaultButton : function(btn)
2929 //this.el.select('.modal-footer').()
2933 resizeTo: function(w,h)
2937 this.dialogEl.setWidth(w);
2938 if (this.diff === false) {
2939 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2942 this.bodyEl.setHeight(h-this.diff);
2944 this.fireEvent('resize', this);
2947 setContentSize : function(w, h)
2951 onButtonClick: function(btn,e)
2954 this.fireEvent('btnclick', btn.name, e);
2957 * Set the title of the Dialog
2958 * @param {String} str new Title
2960 setTitle: function(str) {
2961 this.titleEl.dom.innerHTML = str;
2964 * Set the body of the Dialog
2965 * @param {String} str new Title
2967 setBody: function(str) {
2968 this.bodyEl.dom.innerHTML = str;
2971 * Set the body of the Dialog using the template
2972 * @param {Obj} data - apply this data to the template and replace the body contents.
2974 applyBody: function(obj)
2977 Roo.log("Error - using apply Body without a template");
2980 this.tmpl.overwrite(this.bodyEl, obj);
2986 Roo.apply(Roo.bootstrap.Modal, {
2988 * Button config that displays a single OK button
2997 * Button config that displays Yes and No buttons
3013 * Button config that displays OK and Cancel buttons
3028 * Button config that displays Yes, No and Cancel buttons
3052 * messagebox - can be used as a replace
3056 * @class Roo.MessageBox
3057 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3061 Roo.Msg.alert('Status', 'Changes saved successfully.');
3063 // Prompt for user data:
3064 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3066 // process text value...
3070 // Show a dialog using config options:
3072 title:'Save Changes?',
3073 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3074 buttons: Roo.Msg.YESNOCANCEL,
3081 Roo.bootstrap.MessageBox = function(){
3082 var dlg, opt, mask, waitTimer;
3083 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3084 var buttons, activeTextEl, bwidth;
3088 var handleButton = function(button){
3090 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3094 var handleHide = function(){
3096 dlg.el.removeClass(opt.cls);
3099 // Roo.TaskMgr.stop(waitTimer);
3100 // waitTimer = null;
3105 var updateButtons = function(b){
3108 buttons["ok"].hide();
3109 buttons["cancel"].hide();
3110 buttons["yes"].hide();
3111 buttons["no"].hide();
3112 //dlg.footer.dom.style.display = 'none';
3115 dlg.footerEl.dom.style.display = '';
3116 for(var k in buttons){
3117 if(typeof buttons[k] != "function"){
3120 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3121 width += buttons[k].el.getWidth()+15;
3131 var handleEsc = function(d, k, e){
3132 if(opt && opt.closable !== false){
3142 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3143 * @return {Roo.BasicDialog} The BasicDialog element
3145 getDialog : function(){
3147 dlg = new Roo.bootstrap.Modal( {
3150 //constraintoviewport:false,
3152 //collapsible : false,
3157 //buttonAlign:"center",
3158 closeClick : function(){
3159 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3162 handleButton("cancel");
3167 dlg.on("hide", handleHide);
3169 //dlg.addKeyListener(27, handleEsc);
3171 this.buttons = buttons;
3172 var bt = this.buttonText;
3173 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3174 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3175 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3176 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3178 bodyEl = dlg.bodyEl.createChild({
3180 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3181 '<textarea class="roo-mb-textarea"></textarea>' +
3182 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3184 msgEl = bodyEl.dom.firstChild;
3185 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3186 textboxEl.enableDisplayMode();
3187 textboxEl.addKeyListener([10,13], function(){
3188 if(dlg.isVisible() && opt && opt.buttons){
3191 }else if(opt.buttons.yes){
3192 handleButton("yes");
3196 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3197 textareaEl.enableDisplayMode();
3198 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3199 progressEl.enableDisplayMode();
3201 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3202 var pf = progressEl.dom.firstChild;
3204 pp = Roo.get(pf.firstChild);
3205 pp.setHeight(pf.offsetHeight);
3213 * Updates the message box body text
3214 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3215 * the XHTML-compliant non-breaking space character '&#160;')
3216 * @return {Roo.MessageBox} This message box
3218 updateText : function(text)
3220 if(!dlg.isVisible() && !opt.width){
3221 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3222 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3224 msgEl.innerHTML = text || ' ';
3226 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3227 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3229 Math.min(opt.width || cw , this.maxWidth),
3230 Math.max(opt.minWidth || this.minWidth, bwidth)
3233 activeTextEl.setWidth(w);
3235 if(dlg.isVisible()){
3236 dlg.fixedcenter = false;
3238 // to big, make it scroll. = But as usual stupid IE does not support
3241 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3242 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3243 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3245 bodyEl.dom.style.height = '';
3246 bodyEl.dom.style.overflowY = '';
3249 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3251 bodyEl.dom.style.overflowX = '';
3254 dlg.setContentSize(w, bodyEl.getHeight());
3255 if(dlg.isVisible()){
3256 dlg.fixedcenter = true;
3262 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3263 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3264 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3265 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3266 * @return {Roo.MessageBox} This message box
3268 updateProgress : function(value, text){
3270 this.updateText(text);
3273 if (pp) { // weird bug on my firefox - for some reason this is not defined
3274 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3275 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3281 * Returns true if the message box is currently displayed
3282 * @return {Boolean} True if the message box is visible, else false
3284 isVisible : function(){
3285 return dlg && dlg.isVisible();
3289 * Hides the message box if it is displayed
3292 if(this.isVisible()){
3298 * Displays a new message box, or reinitializes an existing message box, based on the config options
3299 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3300 * The following config object properties are supported:
3302 Property Type Description
3303 ---------- --------------- ------------------------------------------------------------------------------------
3304 animEl String/Element An id or Element from which the message box should animate as it opens and
3305 closes (defaults to undefined)
3306 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3307 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3308 closable Boolean False to hide the top-right close button (defaults to true). Note that
3309 progress and wait dialogs will ignore this property and always hide the
3310 close button as they can only be closed programmatically.
3311 cls String A custom CSS class to apply to the message box element
3312 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3313 displayed (defaults to 75)
3314 fn Function A callback function to execute after closing the dialog. The arguments to the
3315 function will be btn (the name of the button that was clicked, if applicable,
3316 e.g. "ok"), and text (the value of the active text field, if applicable).
3317 Progress and wait dialogs will ignore this option since they do not respond to
3318 user actions and can only be closed programmatically, so any required function
3319 should be called by the same code after it closes the dialog.
3320 icon String A CSS class that provides a background image to be used as an icon for
3321 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3322 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3323 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3324 modal Boolean False to allow user interaction with the page while the message box is
3325 displayed (defaults to true)
3326 msg String A string that will replace the existing message box body text (defaults
3327 to the XHTML-compliant non-breaking space character ' ')
3328 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3329 progress Boolean True to display a progress bar (defaults to false)
3330 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3331 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3332 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3333 title String The title text
3334 value String The string value to set into the active textbox element if displayed
3335 wait Boolean True to display a progress bar (defaults to false)
3336 width Number The width of the dialog in pixels
3343 msg: 'Please enter your address:',
3345 buttons: Roo.MessageBox.OKCANCEL,
3348 animEl: 'addAddressBtn'
3351 * @param {Object} config Configuration options
3352 * @return {Roo.MessageBox} This message box
3354 show : function(options)
3357 // this causes nightmares if you show one dialog after another
3358 // especially on callbacks..
3360 if(this.isVisible()){
3363 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3364 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3365 Roo.log("New Dialog Message:" + options.msg )
3366 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3367 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3370 var d = this.getDialog();
3372 d.setTitle(opt.title || " ");
3373 d.closeEl.setDisplayed(opt.closable !== false);
3374 activeTextEl = textboxEl;
3375 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3380 textareaEl.setHeight(typeof opt.multiline == "number" ?
3381 opt.multiline : this.defaultTextHeight);
3382 activeTextEl = textareaEl;
3391 progressEl.setDisplayed(opt.progress === true);
3392 this.updateProgress(0);
3393 activeTextEl.dom.value = opt.value || "";
3395 dlg.setDefaultButton(activeTextEl);
3397 var bs = opt.buttons;
3401 }else if(bs && bs.yes){
3402 db = buttons["yes"];
3404 dlg.setDefaultButton(db);
3406 bwidth = updateButtons(opt.buttons);
3407 this.updateText(opt.msg);
3409 d.el.addClass(opt.cls);
3411 d.proxyDrag = opt.proxyDrag === true;
3412 d.modal = opt.modal !== false;
3413 d.mask = opt.modal !== false ? mask : false;
3415 // force it to the end of the z-index stack so it gets a cursor in FF
3416 document.body.appendChild(dlg.el.dom);
3417 d.animateTarget = null;
3418 d.show(options.animEl);
3424 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3425 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3426 * and closing the message box when the process is complete.
3427 * @param {String} title The title bar text
3428 * @param {String} msg The message box body text
3429 * @return {Roo.MessageBox} This message box
3431 progress : function(title, msg){
3438 minWidth: this.minProgressWidth,
3445 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3446 * If a callback function is passed it will be called after the user clicks the button, and the
3447 * id of the button that was clicked will be passed as the only parameter to the callback
3448 * (could also be the top-right close button).
3449 * @param {String} title The title bar text
3450 * @param {String} msg The message box body text
3451 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3452 * @param {Object} scope (optional) The scope of the callback function
3453 * @return {Roo.MessageBox} This message box
3455 alert : function(title, msg, fn, scope)
3470 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3471 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3472 * You are responsible for closing the message box when the process is complete.
3473 * @param {String} msg The message box body text
3474 * @param {String} title (optional) The title bar text
3475 * @return {Roo.MessageBox} This message box
3477 wait : function(msg, title){
3488 waitTimer = Roo.TaskMgr.start({
3490 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3498 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3499 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3500 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3501 * @param {String} title The title bar text
3502 * @param {String} msg The message box body text
3503 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3504 * @param {Object} scope (optional) The scope of the callback function
3505 * @return {Roo.MessageBox} This message box
3507 confirm : function(title, msg, fn, scope){
3511 buttons: this.YESNO,
3520 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3521 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3522 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3523 * (could also be the top-right close button) and the text that was entered will be passed as the two
3524 * parameters to the callback.
3525 * @param {String} title The title bar text
3526 * @param {String} msg The message box body text
3527 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3528 * @param {Object} scope (optional) The scope of the callback function
3529 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3530 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3531 * @return {Roo.MessageBox} This message box
3533 prompt : function(title, msg, fn, scope, multiline){
3537 buttons: this.OKCANCEL,
3542 multiline: multiline,
3549 * Button config that displays a single OK button
3554 * Button config that displays Yes and No buttons
3557 YESNO : {yes:true, no:true},
3559 * Button config that displays OK and Cancel buttons
3562 OKCANCEL : {ok:true, cancel:true},
3564 * Button config that displays Yes, No and Cancel buttons
3567 YESNOCANCEL : {yes:true, no:true, cancel:true},
3570 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3573 defaultTextHeight : 75,
3575 * The maximum width in pixels of the message box (defaults to 600)
3580 * The minimum width in pixels of the message box (defaults to 100)
3585 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3586 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3589 minProgressWidth : 250,
3591 * An object containing the default button text strings that can be overriden for localized language support.
3592 * Supported properties are: ok, cancel, yes and no.
3593 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3606 * Shorthand for {@link Roo.MessageBox}
3608 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3609 Roo.Msg = Roo.Msg || Roo.MessageBox;
3618 * @class Roo.bootstrap.Navbar
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Navbar class
3623 * Create a new Navbar
3624 * @param {Object} config The config object
3628 Roo.bootstrap.Navbar = function(config){
3629 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3633 * @event beforetoggle
3634 * Fire before toggle the menu
3635 * @param {Roo.EventObject} e
3637 "beforetoggle" : true
3641 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3650 getAutoCreate : function(){
3653 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3657 initEvents :function ()
3659 //Roo.log(this.el.select('.navbar-toggle',true));
3660 this.el.select('.navbar-toggle',true).on('click', function() {
3661 if(this.fireEvent('beforetoggle', this) !== false){
3662 this.el.select('.navbar-collapse',true).toggleClass('in');
3672 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3674 var size = this.el.getSize();
3675 this.maskEl.setSize(size.width, size.height);
3676 this.maskEl.enableDisplayMode("block");
3685 getChildContainer : function()
3687 if (this.el.select('.collapse').getCount()) {
3688 return this.el.select('.collapse',true).first();
3721 * @class Roo.bootstrap.NavSimplebar
3722 * @extends Roo.bootstrap.Navbar
3723 * Bootstrap Sidebar class
3725 * @cfg {Boolean} inverse is inverted color
3727 * @cfg {String} type (nav | pills | tabs)
3728 * @cfg {Boolean} arrangement stacked | justified
3729 * @cfg {String} align (left | right) alignment
3731 * @cfg {Boolean} main (true|false) main nav bar? default false
3732 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3734 * @cfg {String} tag (header|footer|nav|div) default is nav
3740 * Create a new Sidebar
3741 * @param {Object} config The config object
3745 Roo.bootstrap.NavSimplebar = function(config){
3746 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3749 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3765 getAutoCreate : function(){
3769 tag : this.tag || 'div',
3782 this.type = this.type || 'nav';
3783 if (['tabs','pills'].indexOf(this.type)!==-1) {
3784 cfg.cn[0].cls += ' nav-' + this.type
3788 if (this.type!=='nav') {
3789 Roo.log('nav type must be nav/tabs/pills')
3791 cfg.cn[0].cls += ' navbar-nav'
3797 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3798 cfg.cn[0].cls += ' nav-' + this.arrangement;
3802 if (this.align === 'right') {
3803 cfg.cn[0].cls += ' navbar-right';
3807 cfg.cls += ' navbar-inverse';
3834 * @class Roo.bootstrap.NavHeaderbar
3835 * @extends Roo.bootstrap.NavSimplebar
3836 * Bootstrap Sidebar class
3838 * @cfg {String} brand what is brand
3839 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3840 * @cfg {String} brand_href href of the brand
3841 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3842 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3843 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3844 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3847 * Create a new Sidebar
3848 * @param {Object} config The config object
3852 Roo.bootstrap.NavHeaderbar = function(config){
3853 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3857 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3864 desktopCenter : false,
3867 getAutoCreate : function(){
3870 tag: this.nav || 'nav',
3877 if (this.desktopCenter) {
3878 cn.push({cls : 'container', cn : []});
3885 cls: 'navbar-header',
3890 cls: 'navbar-toggle',
3891 'data-toggle': 'collapse',
3896 html: 'Toggle navigation'
3918 cls: 'collapse navbar-collapse',
3922 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3924 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3925 cfg.cls += ' navbar-' + this.position;
3927 // tag can override this..
3929 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3932 if (this.brand !== '') {
3935 href: this.brand_href ? this.brand_href : '#',
3936 cls: 'navbar-brand',
3944 cfg.cls += ' main-nav';
3952 getHeaderChildContainer : function()
3954 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3955 return this.el.select('.navbar-header',true).first();
3958 return this.getChildContainer();
3962 initEvents : function()
3964 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3966 if (this.autohide) {
3971 Roo.get(document).on('scroll',function(e) {
3972 var ns = Roo.get(document).getScroll().top;
3973 var os = prevScroll;
3977 ft.removeClass('slideDown');
3978 ft.addClass('slideUp');
3981 ft.removeClass('slideUp');
3982 ft.addClass('slideDown');
4003 * @class Roo.bootstrap.NavSidebar
4004 * @extends Roo.bootstrap.Navbar
4005 * Bootstrap Sidebar class
4008 * Create a new Sidebar
4009 * @param {Object} config The config object
4013 Roo.bootstrap.NavSidebar = function(config){
4014 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4017 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4019 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4021 getAutoCreate : function(){
4026 cls: 'sidebar sidebar-nav'
4048 * @class Roo.bootstrap.NavGroup
4049 * @extends Roo.bootstrap.Component
4050 * Bootstrap NavGroup class
4051 * @cfg {String} align (left|right)
4052 * @cfg {Boolean} inverse
4053 * @cfg {String} type (nav|pills|tab) default nav
4054 * @cfg {String} navId - reference Id for navbar.
4058 * Create a new nav group
4059 * @param {Object} config The config object
4062 Roo.bootstrap.NavGroup = function(config){
4063 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4066 Roo.bootstrap.NavGroup.register(this);
4070 * Fires when the active item changes
4071 * @param {Roo.bootstrap.NavGroup} this
4072 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4073 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4080 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4091 getAutoCreate : function()
4093 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4100 if (['tabs','pills'].indexOf(this.type)!==-1) {
4101 cfg.cls += ' nav-' + this.type
4103 if (this.type!=='nav') {
4104 Roo.log('nav type must be nav/tabs/pills')
4106 cfg.cls += ' navbar-nav'
4109 if (this.parent() && this.parent().sidebar) {
4112 cls: 'dashboard-menu sidebar-menu'
4118 if (this.form === true) {
4124 if (this.align === 'right') {
4125 cfg.cls += ' navbar-right';
4127 cfg.cls += ' navbar-left';
4131 if (this.align === 'right') {
4132 cfg.cls += ' navbar-right';
4136 cfg.cls += ' navbar-inverse';
4144 * sets the active Navigation item
4145 * @param {Roo.bootstrap.NavItem} the new current navitem
4147 setActiveItem : function(item)
4150 Roo.each(this.navItems, function(v){
4155 v.setActive(false, true);
4162 item.setActive(true, true);
4163 this.fireEvent('changed', this, item, prev);
4168 * gets the active Navigation item
4169 * @return {Roo.bootstrap.NavItem} the current navitem
4171 getActive : function()
4175 Roo.each(this.navItems, function(v){
4186 indexOfNav : function()
4190 Roo.each(this.navItems, function(v,i){
4201 * adds a Navigation item
4202 * @param {Roo.bootstrap.NavItem} the navitem to add
4204 addItem : function(cfg)
4206 var cn = new Roo.bootstrap.NavItem(cfg);
4208 cn.parentId = this.id;
4209 cn.onRender(this.el, null);
4213 * register a Navigation item
4214 * @param {Roo.bootstrap.NavItem} the navitem to add
4216 register : function(item)
4218 this.navItems.push( item);
4219 item.navId = this.navId;
4224 * clear all the Navigation item
4227 clearAll : function()
4230 this.el.dom.innerHTML = '';
4233 getNavItem: function(tabId)
4236 Roo.each(this.navItems, function(e) {
4237 if (e.tabId == tabId) {
4247 setActiveNext : function()
4249 var i = this.indexOfNav(this.getActive());
4250 if (i > this.navItems.length) {
4253 this.setActiveItem(this.navItems[i+1]);
4255 setActivePrev : function()
4257 var i = this.indexOfNav(this.getActive());
4261 this.setActiveItem(this.navItems[i-1]);
4263 clearWasActive : function(except) {
4264 Roo.each(this.navItems, function(e) {
4265 if (e.tabId != except.tabId && e.was_active) {
4266 e.was_active = false;
4273 getWasActive : function ()
4276 Roo.each(this.navItems, function(e) {
4291 Roo.apply(Roo.bootstrap.NavGroup, {
4295 * register a Navigation Group
4296 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4298 register : function(navgrp)
4300 this.groups[navgrp.navId] = navgrp;
4304 * fetch a Navigation Group based on the navigation ID
4305 * @param {string} the navgroup to add
4306 * @returns {Roo.bootstrap.NavGroup} the navgroup
4308 get: function(navId) {
4309 if (typeof(this.groups[navId]) == 'undefined') {
4311 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4313 return this.groups[navId] ;
4328 * @class Roo.bootstrap.NavItem
4329 * @extends Roo.bootstrap.Component
4330 * Bootstrap Navbar.NavItem class
4331 * @cfg {String} href link to
4332 * @cfg {String} html content of button
4333 * @cfg {String} badge text inside badge
4334 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4335 * @cfg {String} glyphicon name of glyphicon
4336 * @cfg {String} icon name of font awesome icon
4337 * @cfg {Boolean} active Is item active
4338 * @cfg {Boolean} disabled Is item disabled
4340 * @cfg {Boolean} preventDefault (true | false) default false
4341 * @cfg {String} tabId the tab that this item activates.
4342 * @cfg {String} tagtype (a|span) render as a href or span?
4343 * @cfg {Boolean} animateRef (true|false) link to element default false
4346 * Create a new Navbar Item
4347 * @param {Object} config The config object
4349 Roo.bootstrap.NavItem = function(config){
4350 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4355 * The raw click event for the entire grid.
4356 * @param {Roo.EventObject} e
4361 * Fires when the active item active state changes
4362 * @param {Roo.bootstrap.NavItem} this
4363 * @param {boolean} state the new state
4369 * Fires when scroll to element
4370 * @param {Roo.bootstrap.NavItem} this
4371 * @param {Object} options
4372 * @param {Roo.EventObject} e
4380 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4388 preventDefault : false,
4395 getAutoCreate : function(){
4404 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4406 if (this.disabled) {
4407 cfg.cls += ' disabled';
4410 if (this.href || this.html || this.glyphicon || this.icon) {
4414 href : this.href || "#",
4415 html: this.html || ''
4420 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4423 if(this.glyphicon) {
4424 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4429 cfg.cn[0].html += " <span class='caret'></span>";
4433 if (this.badge !== '') {
4435 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4443 initEvents: function()
4445 if (typeof (this.menu) != 'undefined') {
4446 this.menu.parentType = this.xtype;
4447 this.menu.triggerEl = this.el;
4448 this.menu = this.addxtype(Roo.apply({}, this.menu));
4451 this.el.select('a',true).on('click', this.onClick, this);
4453 if(this.tagtype == 'span'){
4454 this.el.select('span',true).on('click', this.onClick, this);
4457 // at this point parent should be available..
4458 this.parent().register(this);
4461 onClick : function(e)
4463 if (e.getTarget('.dropdown-menu-item')) {
4464 // did you click on a menu itemm.... - then don't trigger onclick..
4469 this.preventDefault ||
4472 Roo.log("NavItem - prevent Default?");
4476 if (this.disabled) {
4480 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4481 if (tg && tg.transition) {
4482 Roo.log("waiting for the transitionend");
4488 //Roo.log("fire event clicked");
4489 if(this.fireEvent('click', this, e) === false){
4493 if(this.tagtype == 'span'){
4497 //Roo.log(this.href);
4498 var ael = this.el.select('a',true).first();
4501 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4502 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4503 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4504 return; // ignore... - it's a 'hash' to another page.
4506 Roo.log("NavItem - prevent Default?");
4508 this.scrollToElement(e);
4512 var p = this.parent();
4514 if (['tabs','pills'].indexOf(p.type)!==-1) {
4515 if (typeof(p.setActiveItem) !== 'undefined') {
4516 p.setActiveItem(this);
4520 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4521 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4522 // remove the collapsed menu expand...
4523 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4527 isActive: function () {
4530 setActive : function(state, fire, is_was_active)
4532 if (this.active && !state && this.navId) {
4533 this.was_active = true;
4534 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4536 nv.clearWasActive(this);
4540 this.active = state;
4543 this.el.removeClass('active');
4544 } else if (!this.el.hasClass('active')) {
4545 this.el.addClass('active');
4548 this.fireEvent('changed', this, state);
4551 // show a panel if it's registered and related..
4553 if (!this.navId || !this.tabId || !state || is_was_active) {
4557 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4561 var pan = tg.getPanelByName(this.tabId);
4565 // if we can not flip to new panel - go back to old nav highlight..
4566 if (false == tg.showPanel(pan)) {
4567 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4569 var onav = nv.getWasActive();
4571 onav.setActive(true, false, true);
4580 // this should not be here...
4581 setDisabled : function(state)
4583 this.disabled = state;
4585 this.el.removeClass('disabled');
4586 } else if (!this.el.hasClass('disabled')) {
4587 this.el.addClass('disabled');
4593 * Fetch the element to display the tooltip on.
4594 * @return {Roo.Element} defaults to this.el
4596 tooltipEl : function()
4598 return this.el.select('' + this.tagtype + '', true).first();
4601 scrollToElement : function(e)
4603 var c = document.body;
4606 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4608 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4609 c = document.documentElement;
4612 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4618 var o = target.calcOffsetsTo(c);
4625 this.fireEvent('scrollto', this, options, e);
4627 Roo.get(c).scrollTo('top', options.value, true);
4640 * <span> icon </span>
4641 * <span> text </span>
4642 * <span>badge </span>
4646 * @class Roo.bootstrap.NavSidebarItem
4647 * @extends Roo.bootstrap.NavItem
4648 * Bootstrap Navbar.NavSidebarItem class
4649 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4650 * {Boolean} open is the menu open
4651 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4652 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4653 * {String} buttonSize (sm|md|lg)the extra classes for the button
4654 * {Boolean} showArrow show arrow next to the text (default true)
4656 * Create a new Navbar Button
4657 * @param {Object} config The config object
4659 Roo.bootstrap.NavSidebarItem = function(config){
4660 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4665 * The raw click event for the entire grid.
4666 * @param {Roo.EventObject} e
4671 * Fires when the active item active state changes
4672 * @param {Roo.bootstrap.NavSidebarItem} this
4673 * @param {boolean} state the new state
4681 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4683 badgeWeight : 'default',
4689 buttonWeight : 'default',
4695 getAutoCreate : function(){
4700 href : this.href || '#',
4706 if(this.buttonView){
4709 href : this.href || '#',
4710 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4723 cfg.cls += ' active';
4726 if (this.disabled) {
4727 cfg.cls += ' disabled';
4730 cfg.cls += ' open x-open';
4733 if (this.glyphicon || this.icon) {
4734 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4735 a.cn.push({ tag : 'i', cls : c }) ;
4738 if(!this.buttonView){
4741 html : this.html || ''
4748 if (this.badge !== '') {
4749 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4755 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4758 a.cls += ' dropdown-toggle treeview' ;
4764 initEvents : function()
4766 if (typeof (this.menu) != 'undefined') {
4767 this.menu.parentType = this.xtype;
4768 this.menu.triggerEl = this.el;
4769 this.menu = this.addxtype(Roo.apply({}, this.menu));
4772 this.el.on('click', this.onClick, this);
4774 if(this.badge !== ''){
4775 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4780 onClick : function(e)
4787 if(this.preventDefault){
4791 this.fireEvent('click', this);
4794 disable : function()
4796 this.setDisabled(true);
4801 this.setDisabled(false);
4804 setDisabled : function(state)
4806 if(this.disabled == state){
4810 this.disabled = state;
4813 this.el.addClass('disabled');
4817 this.el.removeClass('disabled');
4822 setActive : function(state)
4824 if(this.active == state){
4828 this.active = state;
4831 this.el.addClass('active');
4835 this.el.removeClass('active');
4840 isActive: function ()
4845 setBadge : function(str)
4851 this.badgeEl.dom.innerHTML = str;
4868 * @class Roo.bootstrap.Row
4869 * @extends Roo.bootstrap.Component
4870 * Bootstrap Row class (contains columns...)
4874 * @param {Object} config The config object
4877 Roo.bootstrap.Row = function(config){
4878 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4881 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4883 getAutoCreate : function(){
4902 * @class Roo.bootstrap.Element
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap Element class
4905 * @cfg {String} html contents of the element
4906 * @cfg {String} tag tag of the element
4907 * @cfg {String} cls class of the element
4908 * @cfg {Boolean} preventDefault (true|false) default false
4909 * @cfg {Boolean} clickable (true|false) default false
4912 * Create a new Element
4913 * @param {Object} config The config object
4916 Roo.bootstrap.Element = function(config){
4917 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4923 * When a element is chick
4924 * @param {Roo.bootstrap.Element} this
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4936 preventDefault: false,
4939 getAutoCreate : function(){
4943 // cls: this.cls, double assign in parent class Component.js :: onRender
4950 initEvents: function()
4952 Roo.bootstrap.Element.superclass.initEvents.call(this);
4955 this.el.on('click', this.onClick, this);
4960 onClick : function(e)
4962 if(this.preventDefault){
4966 this.fireEvent('click', this, e);
4969 getValue : function()
4971 return this.el.dom.innerHTML;
4974 setValue : function(value)
4976 this.el.dom.innerHTML = value;
4991 * @class Roo.bootstrap.Pagination
4992 * @extends Roo.bootstrap.Component
4993 * Bootstrap Pagination class
4994 * @cfg {String} size xs | sm | md | lg
4995 * @cfg {Boolean} inverse false | true
4998 * Create a new Pagination
4999 * @param {Object} config The config object
5002 Roo.bootstrap.Pagination = function(config){
5003 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5006 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5012 getAutoCreate : function(){
5018 cfg.cls += ' inverse';
5024 cfg.cls += " " + this.cls;
5042 * @class Roo.bootstrap.PaginationItem
5043 * @extends Roo.bootstrap.Component
5044 * Bootstrap PaginationItem class
5045 * @cfg {String} html text
5046 * @cfg {String} href the link
5047 * @cfg {Boolean} preventDefault (true | false) default true
5048 * @cfg {Boolean} active (true | false) default false
5049 * @cfg {Boolean} disabled default false
5053 * Create a new PaginationItem
5054 * @param {Object} config The config object
5058 Roo.bootstrap.PaginationItem = function(config){
5059 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5064 * The raw click event for the entire grid.
5065 * @param {Roo.EventObject} e
5071 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5075 preventDefault: true,
5080 getAutoCreate : function(){
5086 href : this.href ? this.href : '#',
5087 html : this.html ? this.html : ''
5097 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5101 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5107 initEvents: function() {
5109 this.el.on('click', this.onClick, this);
5112 onClick : function(e)
5114 Roo.log('PaginationItem on click ');
5115 if(this.preventDefault){
5123 this.fireEvent('click', this, e);
5139 * @class Roo.bootstrap.Slider
5140 * @extends Roo.bootstrap.Component
5141 * Bootstrap Slider class
5144 * Create a new Slider
5145 * @param {Object} config The config object
5148 Roo.bootstrap.Slider = function(config){
5149 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5152 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5154 getAutoCreate : function(){
5158 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5162 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5174 * Ext JS Library 1.1.1
5175 * Copyright(c) 2006-2007, Ext JS, LLC.
5177 * Originally Released Under LGPL - original licence link has changed is not relivant.
5180 * <script type="text/javascript">
5185 * @class Roo.grid.ColumnModel
5186 * @extends Roo.util.Observable
5187 * This is the default implementation of a ColumnModel used by the Grid. It defines
5188 * the columns in the grid.
5191 var colModel = new Roo.grid.ColumnModel([
5192 {header: "Ticker", width: 60, sortable: true, locked: true},
5193 {header: "Company Name", width: 150, sortable: true},
5194 {header: "Market Cap.", width: 100, sortable: true},
5195 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5196 {header: "Employees", width: 100, sortable: true, resizable: false}
5201 * The config options listed for this class are options which may appear in each
5202 * individual column definition.
5203 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5205 * @param {Object} config An Array of column config objects. See this class's
5206 * config objects for details.
5208 Roo.grid.ColumnModel = function(config){
5210 * The config passed into the constructor
5212 this.config = config;
5215 // if no id, create one
5216 // if the column does not have a dataIndex mapping,
5217 // map it to the order it is in the config
5218 for(var i = 0, len = config.length; i < len; i++){
5220 if(typeof c.dataIndex == "undefined"){
5223 if(typeof c.renderer == "string"){
5224 c.renderer = Roo.util.Format[c.renderer];
5226 if(typeof c.id == "undefined"){
5229 if(c.editor && c.editor.xtype){
5230 c.editor = Roo.factory(c.editor, Roo.grid);
5232 if(c.editor && c.editor.isFormField){
5233 c.editor = new Roo.grid.GridEditor(c.editor);
5235 this.lookup[c.id] = c;
5239 * The width of columns which have no width specified (defaults to 100)
5242 this.defaultWidth = 100;
5245 * Default sortable of columns which have no sortable specified (defaults to false)
5248 this.defaultSortable = false;
5252 * @event widthchange
5253 * Fires when the width of a column changes.
5254 * @param {ColumnModel} this
5255 * @param {Number} columnIndex The column index
5256 * @param {Number} newWidth The new width
5258 "widthchange": true,
5260 * @event headerchange
5261 * Fires when the text of a header changes.
5262 * @param {ColumnModel} this
5263 * @param {Number} columnIndex The column index
5264 * @param {Number} newText The new header text
5266 "headerchange": true,
5268 * @event hiddenchange
5269 * Fires when a column is hidden or "unhidden".
5270 * @param {ColumnModel} this
5271 * @param {Number} columnIndex The column index
5272 * @param {Boolean} hidden true if hidden, false otherwise
5274 "hiddenchange": true,
5276 * @event columnmoved
5277 * Fires when a column is moved.
5278 * @param {ColumnModel} this
5279 * @param {Number} oldIndex
5280 * @param {Number} newIndex
5282 "columnmoved" : true,
5284 * @event columlockchange
5285 * Fires when a column's locked state is changed
5286 * @param {ColumnModel} this
5287 * @param {Number} colIndex
5288 * @param {Boolean} locked true if locked
5290 "columnlockchange" : true
5292 Roo.grid.ColumnModel.superclass.constructor.call(this);
5294 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5296 * @cfg {String} header The header text to display in the Grid view.
5299 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5300 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5301 * specified, the column's index is used as an index into the Record's data Array.
5304 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5305 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5308 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5309 * Defaults to the value of the {@link #defaultSortable} property.
5310 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5313 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5316 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5319 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5322 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5325 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5326 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5327 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5328 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5331 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5334 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5337 * @cfg {String} cursor (Optional)
5340 * @cfg {String} tooltip (Optional)
5343 * @cfg {Number} xs (Optional)
5346 * @cfg {Number} sm (Optional)
5349 * @cfg {Number} md (Optional)
5352 * @cfg {Number} lg (Optional)
5355 * Returns the id of the column at the specified index.
5356 * @param {Number} index The column index
5357 * @return {String} the id
5359 getColumnId : function(index){
5360 return this.config[index].id;
5364 * Returns the column for a specified id.
5365 * @param {String} id The column id
5366 * @return {Object} the column
5368 getColumnById : function(id){
5369 return this.lookup[id];
5374 * Returns the column for a specified dataIndex.
5375 * @param {String} dataIndex The column dataIndex
5376 * @return {Object|Boolean} the column or false if not found
5378 getColumnByDataIndex: function(dataIndex){
5379 var index = this.findColumnIndex(dataIndex);
5380 return index > -1 ? this.config[index] : false;
5384 * Returns the index for a specified column id.
5385 * @param {String} id The column id
5386 * @return {Number} the index, or -1 if not found
5388 getIndexById : function(id){
5389 for(var i = 0, len = this.config.length; i < len; i++){
5390 if(this.config[i].id == id){
5398 * Returns the index for a specified column dataIndex.
5399 * @param {String} dataIndex The column dataIndex
5400 * @return {Number} the index, or -1 if not found
5403 findColumnIndex : function(dataIndex){
5404 for(var i = 0, len = this.config.length; i < len; i++){
5405 if(this.config[i].dataIndex == dataIndex){
5413 moveColumn : function(oldIndex, newIndex){
5414 var c = this.config[oldIndex];
5415 this.config.splice(oldIndex, 1);
5416 this.config.splice(newIndex, 0, c);
5417 this.dataMap = null;
5418 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5421 isLocked : function(colIndex){
5422 return this.config[colIndex].locked === true;
5425 setLocked : function(colIndex, value, suppressEvent){
5426 if(this.isLocked(colIndex) == value){
5429 this.config[colIndex].locked = value;
5431 this.fireEvent("columnlockchange", this, colIndex, value);
5435 getTotalLockedWidth : function(){
5437 for(var i = 0; i < this.config.length; i++){
5438 if(this.isLocked(i) && !this.isHidden(i)){
5439 this.totalWidth += this.getColumnWidth(i);
5445 getLockedCount : function(){
5446 for(var i = 0, len = this.config.length; i < len; i++){
5447 if(!this.isLocked(i)){
5452 return this.config.length;
5456 * Returns the number of columns.
5459 getColumnCount : function(visibleOnly){
5460 if(visibleOnly === true){
5462 for(var i = 0, len = this.config.length; i < len; i++){
5463 if(!this.isHidden(i)){
5469 return this.config.length;
5473 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5474 * @param {Function} fn
5475 * @param {Object} scope (optional)
5476 * @return {Array} result
5478 getColumnsBy : function(fn, scope){
5480 for(var i = 0, len = this.config.length; i < len; i++){
5481 var c = this.config[i];
5482 if(fn.call(scope||this, c, i) === true){
5490 * Returns true if the specified column is sortable.
5491 * @param {Number} col The column index
5494 isSortable : function(col){
5495 if(typeof this.config[col].sortable == "undefined"){
5496 return this.defaultSortable;
5498 return this.config[col].sortable;
5502 * Returns the rendering (formatting) function defined for the column.
5503 * @param {Number} col The column index.
5504 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5506 getRenderer : function(col){
5507 if(!this.config[col].renderer){
5508 return Roo.grid.ColumnModel.defaultRenderer;
5510 return this.config[col].renderer;
5514 * Sets the rendering (formatting) function for a column.
5515 * @param {Number} col The column index
5516 * @param {Function} fn The function to use to process the cell's raw data
5517 * to return HTML markup for the grid view. The render function is called with
5518 * the following parameters:<ul>
5519 * <li>Data value.</li>
5520 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5521 * <li>css A CSS style string to apply to the table cell.</li>
5522 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5523 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5524 * <li>Row index</li>
5525 * <li>Column index</li>
5526 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5528 setRenderer : function(col, fn){
5529 this.config[col].renderer = fn;
5533 * Returns the width for the specified column.
5534 * @param {Number} col The column index
5537 getColumnWidth : function(col){
5538 return this.config[col].width * 1 || this.defaultWidth;
5542 * Sets the width for a column.
5543 * @param {Number} col The column index
5544 * @param {Number} width The new width
5546 setColumnWidth : function(col, width, suppressEvent){
5547 this.config[col].width = width;
5548 this.totalWidth = null;
5550 this.fireEvent("widthchange", this, col, width);
5555 * Returns the total width of all columns.
5556 * @param {Boolean} includeHidden True to include hidden column widths
5559 getTotalWidth : function(includeHidden){
5560 if(!this.totalWidth){
5561 this.totalWidth = 0;
5562 for(var i = 0, len = this.config.length; i < len; i++){
5563 if(includeHidden || !this.isHidden(i)){
5564 this.totalWidth += this.getColumnWidth(i);
5568 return this.totalWidth;
5572 * Returns the header for the specified column.
5573 * @param {Number} col The column index
5576 getColumnHeader : function(col){
5577 return this.config[col].header;
5581 * Sets the header for a column.
5582 * @param {Number} col The column index
5583 * @param {String} header The new header
5585 setColumnHeader : function(col, header){
5586 this.config[col].header = header;
5587 this.fireEvent("headerchange", this, col, header);
5591 * Returns the tooltip for the specified column.
5592 * @param {Number} col The column index
5595 getColumnTooltip : function(col){
5596 return this.config[col].tooltip;
5599 * Sets the tooltip for a column.
5600 * @param {Number} col The column index
5601 * @param {String} tooltip The new tooltip
5603 setColumnTooltip : function(col, tooltip){
5604 this.config[col].tooltip = tooltip;
5608 * Returns the dataIndex for the specified column.
5609 * @param {Number} col The column index
5612 getDataIndex : function(col){
5613 return this.config[col].dataIndex;
5617 * Sets the dataIndex for a column.
5618 * @param {Number} col The column index
5619 * @param {Number} dataIndex The new dataIndex
5621 setDataIndex : function(col, dataIndex){
5622 this.config[col].dataIndex = dataIndex;
5628 * Returns true if the cell is editable.
5629 * @param {Number} colIndex The column index
5630 * @param {Number} rowIndex The row index - this is nto actually used..?
5633 isCellEditable : function(colIndex, rowIndex){
5634 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5638 * Returns the editor defined for the cell/column.
5639 * return false or null to disable editing.
5640 * @param {Number} colIndex The column index
5641 * @param {Number} rowIndex The row index
5644 getCellEditor : function(colIndex, rowIndex){
5645 return this.config[colIndex].editor;
5649 * Sets if a column is editable.
5650 * @param {Number} col The column index
5651 * @param {Boolean} editable True if the column is editable
5653 setEditable : function(col, editable){
5654 this.config[col].editable = editable;
5659 * Returns true if the column is hidden.
5660 * @param {Number} colIndex The column index
5663 isHidden : function(colIndex){
5664 return this.config[colIndex].hidden;
5669 * Returns true if the column width cannot be changed
5671 isFixed : function(colIndex){
5672 return this.config[colIndex].fixed;
5676 * Returns true if the column can be resized
5679 isResizable : function(colIndex){
5680 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5683 * Sets if a column is hidden.
5684 * @param {Number} colIndex The column index
5685 * @param {Boolean} hidden True if the column is hidden
5687 setHidden : function(colIndex, hidden){
5688 this.config[colIndex].hidden = hidden;
5689 this.totalWidth = null;
5690 this.fireEvent("hiddenchange", this, colIndex, hidden);
5694 * Sets the editor for a column.
5695 * @param {Number} col The column index
5696 * @param {Object} editor The editor object
5698 setEditor : function(col, editor){
5699 this.config[col].editor = editor;
5703 Roo.grid.ColumnModel.defaultRenderer = function(value)
5705 if(typeof value == "object") {
5708 if(typeof value == "string" && value.length < 1){
5712 return String.format("{0}", value);
5715 // Alias for backwards compatibility
5716 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5719 * Ext JS Library 1.1.1
5720 * Copyright(c) 2006-2007, Ext JS, LLC.
5722 * Originally Released Under LGPL - original licence link has changed is not relivant.
5725 * <script type="text/javascript">
5729 * @class Roo.LoadMask
5730 * A simple utility class for generically masking elements while loading data. If the element being masked has
5731 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5732 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5733 * element's UpdateManager load indicator and will be destroyed after the initial load.
5735 * Create a new LoadMask
5736 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5737 * @param {Object} config The config object
5739 Roo.LoadMask = function(el, config){
5740 this.el = Roo.get(el);
5741 Roo.apply(this, config);
5743 this.store.on('beforeload', this.onBeforeLoad, this);
5744 this.store.on('load', this.onLoad, this);
5745 this.store.on('loadexception', this.onLoadException, this);
5746 this.removeMask = false;
5748 var um = this.el.getUpdateManager();
5749 um.showLoadIndicator = false; // disable the default indicator
5750 um.on('beforeupdate', this.onBeforeLoad, this);
5751 um.on('update', this.onLoad, this);
5752 um.on('failure', this.onLoad, this);
5753 this.removeMask = true;
5757 Roo.LoadMask.prototype = {
5759 * @cfg {Boolean} removeMask
5760 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5761 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5765 * The text to display in a centered loading message box (defaults to 'Loading...')
5769 * @cfg {String} msgCls
5770 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5772 msgCls : 'x-mask-loading',
5775 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5781 * Disables the mask to prevent it from being displayed
5783 disable : function(){
5784 this.disabled = true;
5788 * Enables the mask so that it can be displayed
5790 enable : function(){
5791 this.disabled = false;
5794 onLoadException : function()
5798 if (typeof(arguments[3]) != 'undefined') {
5799 Roo.MessageBox.alert("Error loading",arguments[3]);
5803 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5804 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5811 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5816 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5820 onBeforeLoad : function(){
5822 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5827 destroy : function(){
5829 this.store.un('beforeload', this.onBeforeLoad, this);
5830 this.store.un('load', this.onLoad, this);
5831 this.store.un('loadexception', this.onLoadException, this);
5833 var um = this.el.getUpdateManager();
5834 um.un('beforeupdate', this.onBeforeLoad, this);
5835 um.un('update', this.onLoad, this);
5836 um.un('failure', this.onLoad, this);
5847 * @class Roo.bootstrap.Table
5848 * @extends Roo.bootstrap.Component
5849 * Bootstrap Table class
5850 * @cfg {String} cls table class
5851 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5852 * @cfg {String} bgcolor Specifies the background color for a table
5853 * @cfg {Number} border Specifies whether the table cells should have borders or not
5854 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5855 * @cfg {Number} cellspacing Specifies the space between cells
5856 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5857 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5858 * @cfg {String} sortable Specifies that the table should be sortable
5859 * @cfg {String} summary Specifies a summary of the content of a table
5860 * @cfg {Number} width Specifies the width of a table
5861 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5863 * @cfg {boolean} striped Should the rows be alternative striped
5864 * @cfg {boolean} bordered Add borders to the table
5865 * @cfg {boolean} hover Add hover highlighting
5866 * @cfg {boolean} condensed Format condensed
5867 * @cfg {boolean} responsive Format condensed
5868 * @cfg {Boolean} loadMask (true|false) default false
5869 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5870 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5871 * @cfg {Boolean} rowSelection (true|false) default false
5872 * @cfg {Boolean} cellSelection (true|false) default false
5873 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5874 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5875 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5879 * Create a new Table
5880 * @param {Object} config The config object
5883 Roo.bootstrap.Table = function(config){
5884 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5889 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5890 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5891 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5892 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5894 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5896 this.sm.grid = this;
5897 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5898 this.sm = this.selModel;
5899 this.sm.xmodule = this.xmodule || false;
5902 if (this.cm && typeof(this.cm.config) == 'undefined') {
5903 this.colModel = new Roo.grid.ColumnModel(this.cm);
5904 this.cm = this.colModel;
5905 this.cm.xmodule = this.xmodule || false;
5908 this.store= Roo.factory(this.store, Roo.data);
5909 this.ds = this.store;
5910 this.ds.xmodule = this.xmodule || false;
5913 if (this.footer && this.store) {
5914 this.footer.dataSource = this.ds;
5915 this.footer = Roo.factory(this.footer);
5922 * Fires when a cell is clicked
5923 * @param {Roo.bootstrap.Table} this
5924 * @param {Roo.Element} el
5925 * @param {Number} rowIndex
5926 * @param {Number} columnIndex
5927 * @param {Roo.EventObject} e
5931 * @event celldblclick
5932 * Fires when a cell is double clicked
5933 * @param {Roo.bootstrap.Table} this
5934 * @param {Roo.Element} el
5935 * @param {Number} rowIndex
5936 * @param {Number} columnIndex
5937 * @param {Roo.EventObject} e
5939 "celldblclick" : true,
5942 * Fires when a row is clicked
5943 * @param {Roo.bootstrap.Table} this
5944 * @param {Roo.Element} el
5945 * @param {Number} rowIndex
5946 * @param {Roo.EventObject} e
5950 * @event rowdblclick
5951 * Fires when a row is double clicked
5952 * @param {Roo.bootstrap.Table} this
5953 * @param {Roo.Element} el
5954 * @param {Number} rowIndex
5955 * @param {Roo.EventObject} e
5957 "rowdblclick" : true,
5960 * Fires when a mouseover occur
5961 * @param {Roo.bootstrap.Table} this
5962 * @param {Roo.Element} el
5963 * @param {Number} rowIndex
5964 * @param {Number} columnIndex
5965 * @param {Roo.EventObject} e
5970 * Fires when a mouseout occur
5971 * @param {Roo.bootstrap.Table} this
5972 * @param {Roo.Element} el
5973 * @param {Number} rowIndex
5974 * @param {Number} columnIndex
5975 * @param {Roo.EventObject} e
5980 * Fires when a row is rendered, so you can change add a style to it.
5981 * @param {Roo.bootstrap.Table} this
5982 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5986 * @event rowsrendered
5987 * Fires when all the rows have been rendered
5988 * @param {Roo.bootstrap.Table} this
5990 'rowsrendered' : true,
5992 * @event contextmenu
5993 * The raw contextmenu event for the entire grid.
5994 * @param {Roo.EventObject} e
5996 "contextmenu" : true,
5998 * @event rowcontextmenu
5999 * Fires when a row is right clicked
6000 * @param {Roo.bootstrap.Table} this
6001 * @param {Number} rowIndex
6002 * @param {Roo.EventObject} e
6004 "rowcontextmenu" : true,
6006 * @event cellcontextmenu
6007 * Fires when a cell is right clicked
6008 * @param {Roo.bootstrap.Table} this
6009 * @param {Number} rowIndex
6010 * @param {Number} cellIndex
6011 * @param {Roo.EventObject} e
6013 "cellcontextmenu" : true,
6015 * @event headercontextmenu
6016 * Fires when a header is right clicked
6017 * @param {Roo.bootstrap.Table} this
6018 * @param {Number} columnIndex
6019 * @param {Roo.EventObject} e
6021 "headercontextmenu" : true
6025 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6051 rowSelection : false,
6052 cellSelection : false,
6055 // Roo.Element - the tbody
6057 // Roo.Element - thead element
6060 container: false, // used by gridpanel...
6066 getAutoCreate : function()
6068 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6075 if (this.scrollBody) {
6076 cfg.cls += ' table-body-fixed';
6079 cfg.cls += ' table-striped';
6083 cfg.cls += ' table-hover';
6085 if (this.bordered) {
6086 cfg.cls += ' table-bordered';
6088 if (this.condensed) {
6089 cfg.cls += ' table-condensed';
6091 if (this.responsive) {
6092 cfg.cls += ' table-responsive';
6096 cfg.cls+= ' ' +this.cls;
6099 // this lot should be simplifed...
6102 cfg.align=this.align;
6105 cfg.bgcolor=this.bgcolor;
6108 cfg.border=this.border;
6110 if (this.cellpadding) {
6111 cfg.cellpadding=this.cellpadding;
6113 if (this.cellspacing) {
6114 cfg.cellspacing=this.cellspacing;
6117 cfg.frame=this.frame;
6120 cfg.rules=this.rules;
6122 if (this.sortable) {
6123 cfg.sortable=this.sortable;
6126 cfg.summary=this.summary;
6129 cfg.width=this.width;
6132 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6135 if(this.store || this.cm){
6136 if(this.headerShow){
6137 cfg.cn.push(this.renderHeader());
6140 cfg.cn.push(this.renderBody());
6142 if(this.footerShow){
6143 cfg.cn.push(this.renderFooter());
6145 // where does this come from?
6146 //cfg.cls+= ' TableGrid';
6149 return { cn : [ cfg ] };
6152 initEvents : function()
6154 if(!this.store || !this.cm){
6157 if (this.selModel) {
6158 this.selModel.initEvents();
6162 //Roo.log('initEvents with ds!!!!');
6164 this.mainBody = this.el.select('tbody', true).first();
6165 this.mainHead = this.el.select('thead', true).first();
6172 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6173 e.on('click', _this.sort, _this);
6176 this.mainBody.on("click", this.onClick, this);
6177 this.mainBody.on("dblclick", this.onDblClick, this);
6179 // why is this done????? = it breaks dialogs??
6180 //this.parent().el.setStyle('position', 'relative');
6184 this.footer.parentId = this.id;
6185 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6188 this.el.select('tfoot tr td').first().addClass('hide');
6192 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6194 this.store.on('load', this.onLoad, this);
6195 this.store.on('beforeload', this.onBeforeLoad, this);
6196 this.store.on('update', this.onUpdate, this);
6197 this.store.on('add', this.onAdd, this);
6198 this.store.on("clear", this.clear, this);
6200 this.el.on("contextmenu", this.onContextMenu, this);
6202 this.mainBody.on('scroll', this.onBodyScroll, this);
6204 this.cm.on("headerchange", this.onHeaderChange, this);
6206 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6210 onContextMenu : function(e, t)
6212 this.processEvent("contextmenu", e);
6215 processEvent : function(name, e)
6217 if (name != 'touchstart' ) {
6218 this.fireEvent(name, e);
6221 var t = e.getTarget();
6223 var cell = Roo.get(t);
6229 if(cell.findParent('tfoot', false, true)){
6233 if(cell.findParent('thead', false, true)){
6235 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6236 cell = Roo.get(t).findParent('th', false, true);
6238 Roo.log("failed to find th in thead?");
6239 Roo.log(e.getTarget());
6244 var cellIndex = cell.dom.cellIndex;
6246 var ename = name == 'touchstart' ? 'click' : name;
6247 this.fireEvent("header" + ename, this, cellIndex, e);
6252 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6253 cell = Roo.get(t).findParent('td', false, true);
6255 Roo.log("failed to find th in tbody?");
6256 Roo.log(e.getTarget());
6261 var row = cell.findParent('tr', false, true);
6262 var cellIndex = cell.dom.cellIndex;
6263 var rowIndex = row.dom.rowIndex - 1;
6267 this.fireEvent("row" + name, this, rowIndex, e);
6271 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6277 onMouseover : function(e, el)
6279 var cell = Roo.get(el);
6285 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6286 cell = cell.findParent('td', false, true);
6289 var row = cell.findParent('tr', false, true);
6290 var cellIndex = cell.dom.cellIndex;
6291 var rowIndex = row.dom.rowIndex - 1; // start from 0
6293 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6297 onMouseout : function(e, el)
6299 var cell = Roo.get(el);
6305 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6306 cell = cell.findParent('td', false, true);
6309 var row = cell.findParent('tr', false, true);
6310 var cellIndex = cell.dom.cellIndex;
6311 var rowIndex = row.dom.rowIndex - 1; // start from 0
6313 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6317 onClick : function(e, el)
6319 var cell = Roo.get(el);
6321 if(!cell || (!this.cellSelection && !this.rowSelection)){
6325 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6326 cell = cell.findParent('td', false, true);
6329 if(!cell || typeof(cell) == 'undefined'){
6333 var row = cell.findParent('tr', false, true);
6335 if(!row || typeof(row) == 'undefined'){
6339 var cellIndex = cell.dom.cellIndex;
6340 var rowIndex = this.getRowIndex(row);
6342 // why??? - should these not be based on SelectionModel?
6343 if(this.cellSelection){
6344 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6347 if(this.rowSelection){
6348 this.fireEvent('rowclick', this, row, rowIndex, e);
6354 onDblClick : function(e,el)
6356 var cell = Roo.get(el);
6358 if(!cell || (!this.cellSelection && !this.rowSelection)){
6362 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6363 cell = cell.findParent('td', false, true);
6366 if(!cell || typeof(cell) == 'undefined'){
6370 var row = cell.findParent('tr', false, true);
6372 if(!row || typeof(row) == 'undefined'){
6376 var cellIndex = cell.dom.cellIndex;
6377 var rowIndex = this.getRowIndex(row);
6379 if(this.cellSelection){
6380 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6383 if(this.rowSelection){
6384 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6388 sort : function(e,el)
6390 var col = Roo.get(el);
6392 if(!col.hasClass('sortable')){
6396 var sort = col.attr('sort');
6399 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6403 this.store.sortInfo = {field : sort, direction : dir};
6406 Roo.log("calling footer first");
6407 this.footer.onClick('first');
6410 this.store.load({ params : { start : 0 } });
6414 renderHeader : function()
6422 this.totalWidth = 0;
6424 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6426 var config = cm.config[i];
6430 cls : 'x-hcol-' + i,
6432 html: cm.getColumnHeader(i)
6437 if(typeof(config.sortable) != 'undefined' && config.sortable){
6439 c.html = '<i class="glyphicon"></i>' + c.html;
6442 if(typeof(config.lgHeader) != 'undefined'){
6443 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6446 if(typeof(config.mdHeader) != 'undefined'){
6447 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6450 if(typeof(config.smHeader) != 'undefined'){
6451 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6454 if(typeof(config.xsHeader) != 'undefined'){
6455 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6462 if(typeof(config.tooltip) != 'undefined'){
6463 c.tooltip = config.tooltip;
6466 if(typeof(config.colspan) != 'undefined'){
6467 c.colspan = config.colspan;
6470 if(typeof(config.hidden) != 'undefined' && config.hidden){
6471 c.style += ' display:none;';
6474 if(typeof(config.dataIndex) != 'undefined'){
6475 c.sort = config.dataIndex;
6480 if(typeof(config.align) != 'undefined' && config.align.length){
6481 c.style += ' text-align:' + config.align + ';';
6484 if(typeof(config.width) != 'undefined'){
6485 c.style += ' width:' + config.width + 'px;';
6486 this.totalWidth += config.width;
6488 this.totalWidth += 100; // assume minimum of 100 per column?
6491 if(typeof(config.cls) != 'undefined'){
6492 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6495 ['xs','sm','md','lg'].map(function(size){
6497 if(typeof(config[size]) == 'undefined'){
6501 if (!config[size]) { // 0 = hidden
6502 c.cls += ' hidden-' + size;
6506 c.cls += ' col-' + size + '-' + config[size];
6516 renderBody : function()
6526 colspan : this.cm.getColumnCount()
6536 renderFooter : function()
6546 colspan : this.cm.getColumnCount()
6560 // Roo.log('ds onload');
6565 var ds = this.store;
6567 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6568 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6569 if (_this.store.sortInfo) {
6571 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6572 e.select('i', true).addClass(['glyphicon-arrow-up']);
6575 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6576 e.select('i', true).addClass(['glyphicon-arrow-down']);
6581 var tbody = this.mainBody;
6583 if(ds.getCount() > 0){
6584 ds.data.each(function(d,rowIndex){
6585 var row = this.renderRow(cm, ds, rowIndex);
6587 tbody.createChild(row);
6591 if(row.cellObjects.length){
6592 Roo.each(row.cellObjects, function(r){
6593 _this.renderCellObject(r);
6600 Roo.each(this.el.select('tbody td', true).elements, function(e){
6601 e.on('mouseover', _this.onMouseover, _this);
6604 Roo.each(this.el.select('tbody td', true).elements, function(e){
6605 e.on('mouseout', _this.onMouseout, _this);
6607 this.fireEvent('rowsrendered', this);
6608 //if(this.loadMask){
6609 // this.maskEl.hide();
6616 onUpdate : function(ds,record)
6618 this.refreshRow(record);
6622 onRemove : function(ds, record, index, isUpdate){
6623 if(isUpdate !== true){
6624 this.fireEvent("beforerowremoved", this, index, record);
6626 var bt = this.mainBody.dom;
6628 var rows = this.el.select('tbody > tr', true).elements;
6630 if(typeof(rows[index]) != 'undefined'){
6631 bt.removeChild(rows[index].dom);
6634 // if(bt.rows[index]){
6635 // bt.removeChild(bt.rows[index]);
6638 if(isUpdate !== true){
6639 //this.stripeRows(index);
6640 //this.syncRowHeights(index, index);
6642 this.fireEvent("rowremoved", this, index, record);
6646 onAdd : function(ds, records, rowIndex)
6648 //Roo.log('on Add called');
6649 // - note this does not handle multiple adding very well..
6650 var bt = this.mainBody.dom;
6651 for (var i =0 ; i < records.length;i++) {
6652 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6653 //Roo.log(records[i]);
6654 //Roo.log(this.store.getAt(rowIndex+i));
6655 this.insertRow(this.store, rowIndex + i, false);
6662 refreshRow : function(record){
6663 var ds = this.store, index;
6664 if(typeof record == 'number'){
6666 record = ds.getAt(index);
6668 index = ds.indexOf(record);
6670 this.insertRow(ds, index, true);
6672 this.onRemove(ds, record, index+1, true);
6674 //this.syncRowHeights(index, index);
6676 this.fireEvent("rowupdated", this, index, record);
6679 insertRow : function(dm, rowIndex, isUpdate){
6682 this.fireEvent("beforerowsinserted", this, rowIndex);
6684 //var s = this.getScrollState();
6685 var row = this.renderRow(this.cm, this.store, rowIndex);
6686 // insert before rowIndex..
6687 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6691 if(row.cellObjects.length){
6692 Roo.each(row.cellObjects, function(r){
6693 _this.renderCellObject(r);
6698 this.fireEvent("rowsinserted", this, rowIndex);
6699 //this.syncRowHeights(firstRow, lastRow);
6700 //this.stripeRows(firstRow);
6707 getRowDom : function(rowIndex)
6709 var rows = this.el.select('tbody > tr', true).elements;
6711 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6714 // returns the object tree for a tr..
6717 renderRow : function(cm, ds, rowIndex)
6719 var d = ds.getAt(rowIndex);
6723 cls : 'x-row-' + rowIndex,
6727 var cellObjects = [];
6729 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6730 var config = cm.config[i];
6732 var renderer = cm.getRenderer(i);
6736 if(typeof(renderer) !== 'undefined'){
6737 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6739 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6740 // and are rendered into the cells after the row is rendered - using the id for the element.
6742 if(typeof(value) === 'object'){
6752 rowIndex : rowIndex,
6757 this.fireEvent('rowclass', this, rowcfg);
6761 cls : rowcfg.rowClass + ' x-col-' + i,
6763 html: (typeof(value) === 'object') ? '' : value
6770 if(typeof(config.colspan) != 'undefined'){
6771 td.colspan = config.colspan;
6774 if(typeof(config.hidden) != 'undefined' && config.hidden){
6775 td.style += ' display:none;';
6778 if(typeof(config.align) != 'undefined' && config.align.length){
6779 td.style += ' text-align:' + config.align + ';';
6782 if(typeof(config.width) != 'undefined'){
6783 td.style += ' width:' + config.width + 'px;';
6786 if(typeof(config.cursor) != 'undefined'){
6787 td.style += ' cursor:' + config.cursor + ';';
6790 if(typeof(config.cls) != 'undefined'){
6791 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6794 ['xs','sm','md','lg'].map(function(size){
6796 if(typeof(config[size]) == 'undefined'){
6800 if (!config[size]) { // 0 = hidden
6801 td.cls += ' hidden-' + size;
6805 td.cls += ' col-' + size + '-' + config[size];
6813 row.cellObjects = cellObjects;
6821 onBeforeLoad : function()
6823 //Roo.log('ds onBeforeLoad');
6827 //if(this.loadMask){
6828 // this.maskEl.show();
6836 this.el.select('tbody', true).first().dom.innerHTML = '';
6839 * Show or hide a row.
6840 * @param {Number} rowIndex to show or hide
6841 * @param {Boolean} state hide
6843 setRowVisibility : function(rowIndex, state)
6845 var bt = this.mainBody.dom;
6847 var rows = this.el.select('tbody > tr', true).elements;
6849 if(typeof(rows[rowIndex]) == 'undefined'){
6852 rows[rowIndex].dom.style.display = state ? '' : 'none';
6856 getSelectionModel : function(){
6858 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6860 return this.selModel;
6863 * Render the Roo.bootstrap object from renderder
6865 renderCellObject : function(r)
6869 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6871 var t = r.cfg.render(r.container);
6874 Roo.each(r.cfg.cn, function(c){
6876 container: t.getChildContainer(),
6879 _this.renderCellObject(child);
6884 getRowIndex : function(row)
6888 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6899 * Returns the grid's underlying element = used by panel.Grid
6900 * @return {Element} The element
6902 getGridEl : function(){
6906 * Forces a resize - used by panel.Grid
6907 * @return {Element} The element
6909 autoSize : function()
6911 //var ctr = Roo.get(this.container.dom.parentElement);
6912 var ctr = Roo.get(this.el.dom);
6914 var thd = this.getGridEl().select('thead',true).first();
6915 var tbd = this.getGridEl().select('tbody', true).first();
6916 var tfd = this.getGridEl().select('tfoot', true).first();
6918 var cw = ctr.getWidth();
6922 tbd.setSize(ctr.getWidth(),
6923 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6925 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6928 cw = Math.max(cw, this.totalWidth);
6929 this.getGridEl().select('tr',true).setWidth(cw);
6930 // resize 'expandable coloumn?
6932 return; // we doe not have a view in this design..
6935 onBodyScroll: function()
6937 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6939 this.mainHead.setStyle({
6940 'position' : 'relative',
6941 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6947 var scrollHeight = this.mainBody.dom.scrollHeight;
6949 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6951 var height = this.mainBody.getHeight();
6953 if(scrollHeight - height == scrollTop) {
6955 var total = this.ds.getTotalCount();
6957 if(this.footer.cursor + this.footer.pageSize < total){
6959 this.footer.ds.load({
6961 start : this.footer.cursor + this.footer.pageSize,
6962 limit : this.footer.pageSize
6972 onHeaderChange : function()
6974 var header = this.renderHeader();
6975 var table = this.el.select('table', true).first();
6977 this.mainHead.remove();
6978 this.mainHead = table.createChild(header, this.mainBody, false);
6981 onHiddenChange : function(colModel, colIndex, hidden)
6983 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6984 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6986 this.CSS.updateRule(thSelector, "display", "");
6987 this.CSS.updateRule(tdSelector, "display", "");
6990 this.CSS.updateRule(thSelector, "display", "none");
6991 this.CSS.updateRule(tdSelector, "display", "none");
6994 this.onHeaderChange();
7011 * @class Roo.bootstrap.TableCell
7012 * @extends Roo.bootstrap.Component
7013 * Bootstrap TableCell class
7014 * @cfg {String} html cell contain text
7015 * @cfg {String} cls cell class
7016 * @cfg {String} tag cell tag (td|th) default td
7017 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7018 * @cfg {String} align Aligns the content in a cell
7019 * @cfg {String} axis Categorizes cells
7020 * @cfg {String} bgcolor Specifies the background color of a cell
7021 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7022 * @cfg {Number} colspan Specifies the number of columns a cell should span
7023 * @cfg {String} headers Specifies one or more header cells a cell is related to
7024 * @cfg {Number} height Sets the height of a cell
7025 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7026 * @cfg {Number} rowspan Sets the number of rows a cell should span
7027 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7028 * @cfg {String} valign Vertical aligns the content in a cell
7029 * @cfg {Number} width Specifies the width of a cell
7032 * Create a new TableCell
7033 * @param {Object} config The config object
7036 Roo.bootstrap.TableCell = function(config){
7037 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7040 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7060 getAutoCreate : function(){
7061 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7081 cfg.align=this.align
7087 cfg.bgcolor=this.bgcolor
7090 cfg.charoff=this.charoff
7093 cfg.colspan=this.colspan
7096 cfg.headers=this.headers
7099 cfg.height=this.height
7102 cfg.nowrap=this.nowrap
7105 cfg.rowspan=this.rowspan
7108 cfg.scope=this.scope
7111 cfg.valign=this.valign
7114 cfg.width=this.width
7133 * @class Roo.bootstrap.TableRow
7134 * @extends Roo.bootstrap.Component
7135 * Bootstrap TableRow class
7136 * @cfg {String} cls row class
7137 * @cfg {String} align Aligns the content in a table row
7138 * @cfg {String} bgcolor Specifies a background color for a table row
7139 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7140 * @cfg {String} valign Vertical aligns the content in a table row
7143 * Create a new TableRow
7144 * @param {Object} config The config object
7147 Roo.bootstrap.TableRow = function(config){
7148 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7151 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7159 getAutoCreate : function(){
7160 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7170 cfg.align = this.align;
7173 cfg.bgcolor = this.bgcolor;
7176 cfg.charoff = this.charoff;
7179 cfg.valign = this.valign;
7197 * @class Roo.bootstrap.TableBody
7198 * @extends Roo.bootstrap.Component
7199 * Bootstrap TableBody class
7200 * @cfg {String} cls element class
7201 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7202 * @cfg {String} align Aligns the content inside the element
7203 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7204 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7207 * Create a new TableBody
7208 * @param {Object} config The config object
7211 Roo.bootstrap.TableBody = function(config){
7212 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7215 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7223 getAutoCreate : function(){
7224 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7238 cfg.align = this.align;
7241 cfg.charoff = this.charoff;
7244 cfg.valign = this.valign;
7251 // initEvents : function()
7258 // this.store = Roo.factory(this.store, Roo.data);
7259 // this.store.on('load', this.onLoad, this);
7261 // this.store.load();
7265 // onLoad: function ()
7267 // this.fireEvent('load', this);
7277 * Ext JS Library 1.1.1
7278 * Copyright(c) 2006-2007, Ext JS, LLC.
7280 * Originally Released Under LGPL - original licence link has changed is not relivant.
7283 * <script type="text/javascript">
7286 // as we use this in bootstrap.
7287 Roo.namespace('Roo.form');
7289 * @class Roo.form.Action
7290 * Internal Class used to handle form actions
7292 * @param {Roo.form.BasicForm} el The form element or its id
7293 * @param {Object} config Configuration options
7298 // define the action interface
7299 Roo.form.Action = function(form, options){
7301 this.options = options || {};
7304 * Client Validation Failed
7307 Roo.form.Action.CLIENT_INVALID = 'client';
7309 * Server Validation Failed
7312 Roo.form.Action.SERVER_INVALID = 'server';
7314 * Connect to Server Failed
7317 Roo.form.Action.CONNECT_FAILURE = 'connect';
7319 * Reading Data from Server Failed
7322 Roo.form.Action.LOAD_FAILURE = 'load';
7324 Roo.form.Action.prototype = {
7326 failureType : undefined,
7327 response : undefined,
7331 run : function(options){
7336 success : function(response){
7341 handleResponse : function(response){
7345 // default connection failure
7346 failure : function(response){
7348 this.response = response;
7349 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7350 this.form.afterAction(this, false);
7353 processResponse : function(response){
7354 this.response = response;
7355 if(!response.responseText){
7358 this.result = this.handleResponse(response);
7362 // utility functions used internally
7363 getUrl : function(appendParams){
7364 var url = this.options.url || this.form.url || this.form.el.dom.action;
7366 var p = this.getParams();
7368 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7374 getMethod : function(){
7375 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7378 getParams : function(){
7379 var bp = this.form.baseParams;
7380 var p = this.options.params;
7382 if(typeof p == "object"){
7383 p = Roo.urlEncode(Roo.applyIf(p, bp));
7384 }else if(typeof p == 'string' && bp){
7385 p += '&' + Roo.urlEncode(bp);
7388 p = Roo.urlEncode(bp);
7393 createCallback : function(){
7395 success: this.success,
7396 failure: this.failure,
7398 timeout: (this.form.timeout*1000),
7399 upload: this.form.fileUpload ? this.success : undefined
7404 Roo.form.Action.Submit = function(form, options){
7405 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7408 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7411 haveProgress : false,
7412 uploadComplete : false,
7414 // uploadProgress indicator.
7415 uploadProgress : function()
7417 if (!this.form.progressUrl) {
7421 if (!this.haveProgress) {
7422 Roo.MessageBox.progress("Uploading", "Uploading");
7424 if (this.uploadComplete) {
7425 Roo.MessageBox.hide();
7429 this.haveProgress = true;
7431 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7433 var c = new Roo.data.Connection();
7435 url : this.form.progressUrl,
7440 success : function(req){
7441 //console.log(data);
7445 rdata = Roo.decode(req.responseText)
7447 Roo.log("Invalid data from server..");
7451 if (!rdata || !rdata.success) {
7453 Roo.MessageBox.alert(Roo.encode(rdata));
7456 var data = rdata.data;
7458 if (this.uploadComplete) {
7459 Roo.MessageBox.hide();
7464 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7465 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7468 this.uploadProgress.defer(2000,this);
7471 failure: function(data) {
7472 Roo.log('progress url failed ');
7483 // run get Values on the form, so it syncs any secondary forms.
7484 this.form.getValues();
7486 var o = this.options;
7487 var method = this.getMethod();
7488 var isPost = method == 'POST';
7489 if(o.clientValidation === false || this.form.isValid()){
7491 if (this.form.progressUrl) {
7492 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7493 (new Date() * 1) + '' + Math.random());
7498 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7499 form:this.form.el.dom,
7500 url:this.getUrl(!isPost),
7502 params:isPost ? this.getParams() : null,
7503 isUpload: this.form.fileUpload
7506 this.uploadProgress();
7508 }else if (o.clientValidation !== false){ // client validation failed
7509 this.failureType = Roo.form.Action.CLIENT_INVALID;
7510 this.form.afterAction(this, false);
7514 success : function(response)
7516 this.uploadComplete= true;
7517 if (this.haveProgress) {
7518 Roo.MessageBox.hide();
7522 var result = this.processResponse(response);
7523 if(result === true || result.success){
7524 this.form.afterAction(this, true);
7528 this.form.markInvalid(result.errors);
7529 this.failureType = Roo.form.Action.SERVER_INVALID;
7531 this.form.afterAction(this, false);
7533 failure : function(response)
7535 this.uploadComplete= true;
7536 if (this.haveProgress) {
7537 Roo.MessageBox.hide();
7540 this.response = response;
7541 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7542 this.form.afterAction(this, false);
7545 handleResponse : function(response){
7546 if(this.form.errorReader){
7547 var rs = this.form.errorReader.read(response);
7550 for(var i = 0, len = rs.records.length; i < len; i++) {
7551 var r = rs.records[i];
7555 if(errors.length < 1){
7559 success : rs.success,
7565 ret = Roo.decode(response.responseText);
7569 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7579 Roo.form.Action.Load = function(form, options){
7580 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7581 this.reader = this.form.reader;
7584 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7589 Roo.Ajax.request(Roo.apply(
7590 this.createCallback(), {
7591 method:this.getMethod(),
7592 url:this.getUrl(false),
7593 params:this.getParams()
7597 success : function(response){
7599 var result = this.processResponse(response);
7600 if(result === true || !result.success || !result.data){
7601 this.failureType = Roo.form.Action.LOAD_FAILURE;
7602 this.form.afterAction(this, false);
7605 this.form.clearInvalid();
7606 this.form.setValues(result.data);
7607 this.form.afterAction(this, true);
7610 handleResponse : function(response){
7611 if(this.form.reader){
7612 var rs = this.form.reader.read(response);
7613 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7615 success : rs.success,
7619 return Roo.decode(response.responseText);
7623 Roo.form.Action.ACTION_TYPES = {
7624 'load' : Roo.form.Action.Load,
7625 'submit' : Roo.form.Action.Submit
7634 * @class Roo.bootstrap.Form
7635 * @extends Roo.bootstrap.Component
7636 * Bootstrap Form class
7637 * @cfg {String} method GET | POST (default POST)
7638 * @cfg {String} labelAlign top | left (default top)
7639 * @cfg {String} align left | right - for navbars
7640 * @cfg {Boolean} loadMask load mask when submit (default true)
7645 * @param {Object} config The config object
7649 Roo.bootstrap.Form = function(config){
7651 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7653 Roo.bootstrap.Form.popover.apply();
7657 * @event clientvalidation
7658 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7659 * @param {Form} this
7660 * @param {Boolean} valid true if the form has passed client-side validation
7662 clientvalidation: true,
7664 * @event beforeaction
7665 * Fires before any action is performed. Return false to cancel the action.
7666 * @param {Form} this
7667 * @param {Action} action The action to be performed
7671 * @event actionfailed
7672 * Fires when an action fails.
7673 * @param {Form} this
7674 * @param {Action} action The action that failed
7676 actionfailed : true,
7678 * @event actioncomplete
7679 * Fires when an action is completed.
7680 * @param {Form} this
7681 * @param {Action} action The action that completed
7683 actioncomplete : true
7687 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7690 * @cfg {String} method
7691 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7696 * The URL to use for form actions if one isn't supplied in the action options.
7699 * @cfg {Boolean} fileUpload
7700 * Set to true if this form is a file upload.
7704 * @cfg {Object} baseParams
7705 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7709 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7713 * @cfg {Sting} align (left|right) for navbar forms
7718 activeAction : null,
7721 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7722 * element by passing it or its id or mask the form itself by passing in true.
7725 waitMsgTarget : false,
7730 * @cfg {Boolean} errorMask (true|false) default false
7735 * @cfg {Number} maskOffset Default 100
7740 * @cfg {Boolean} maskBody
7744 getAutoCreate : function(){
7748 method : this.method || 'POST',
7749 id : this.id || Roo.id(),
7752 if (this.parent().xtype.match(/^Nav/)) {
7753 cfg.cls = 'navbar-form navbar-' + this.align;
7757 if (this.labelAlign == 'left' ) {
7758 cfg.cls += ' form-horizontal';
7764 initEvents : function()
7766 this.el.on('submit', this.onSubmit, this);
7767 // this was added as random key presses on the form where triggering form submit.
7768 this.el.on('keypress', function(e) {
7769 if (e.getCharCode() != 13) {
7772 // we might need to allow it for textareas.. and some other items.
7773 // check e.getTarget().
7775 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7779 Roo.log("keypress blocked");
7787 onSubmit : function(e){
7792 * Returns true if client-side validation on the form is successful.
7795 isValid : function(){
7796 var items = this.getItems();
7800 items.each(function(f){
7807 if(!target && f.el.isVisible(true)){
7813 if(this.errorMask && !valid){
7814 Roo.bootstrap.Form.popover.mask(this, target);
7821 * Returns true if any fields in this form have changed since their original load.
7824 isDirty : function(){
7826 var items = this.getItems();
7827 items.each(function(f){
7837 * Performs a predefined action (submit or load) or custom actions you define on this form.
7838 * @param {String} actionName The name of the action type
7839 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7840 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7841 * accept other config options):
7843 Property Type Description
7844 ---------------- --------------- ----------------------------------------------------------------------------------
7845 url String The url for the action (defaults to the form's url)
7846 method String The form method to use (defaults to the form's method, or POST if not defined)
7847 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7848 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7849 validate the form on the client (defaults to false)
7851 * @return {BasicForm} this
7853 doAction : function(action, options){
7854 if(typeof action == 'string'){
7855 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7857 if(this.fireEvent('beforeaction', this, action) !== false){
7858 this.beforeAction(action);
7859 action.run.defer(100, action);
7865 beforeAction : function(action){
7866 var o = action.options;
7871 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7873 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7876 // not really supported yet.. ??
7878 //if(this.waitMsgTarget === true){
7879 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7880 //}else if(this.waitMsgTarget){
7881 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7882 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7884 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7890 afterAction : function(action, success){
7891 this.activeAction = null;
7892 var o = action.options;
7897 Roo.get(document.body).unmask();
7903 //if(this.waitMsgTarget === true){
7904 // this.el.unmask();
7905 //}else if(this.waitMsgTarget){
7906 // this.waitMsgTarget.unmask();
7908 // Roo.MessageBox.updateProgress(1);
7909 // Roo.MessageBox.hide();
7916 Roo.callback(o.success, o.scope, [this, action]);
7917 this.fireEvent('actioncomplete', this, action);
7921 // failure condition..
7922 // we have a scenario where updates need confirming.
7923 // eg. if a locking scenario exists..
7924 // we look for { errors : { needs_confirm : true }} in the response.
7926 (typeof(action.result) != 'undefined') &&
7927 (typeof(action.result.errors) != 'undefined') &&
7928 (typeof(action.result.errors.needs_confirm) != 'undefined')
7931 Roo.log("not supported yet");
7934 Roo.MessageBox.confirm(
7935 "Change requires confirmation",
7936 action.result.errorMsg,
7941 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7951 Roo.callback(o.failure, o.scope, [this, action]);
7952 // show an error message if no failed handler is set..
7953 if (!this.hasListener('actionfailed')) {
7954 Roo.log("need to add dialog support");
7956 Roo.MessageBox.alert("Error",
7957 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7958 action.result.errorMsg :
7959 "Saving Failed, please check your entries or try again"
7964 this.fireEvent('actionfailed', this, action);
7969 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7970 * @param {String} id The value to search for
7973 findField : function(id){
7974 var items = this.getItems();
7975 var field = items.get(id);
7977 items.each(function(f){
7978 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7985 return field || null;
7988 * Mark fields in this form invalid in bulk.
7989 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7990 * @return {BasicForm} this
7992 markInvalid : function(errors){
7993 if(errors instanceof Array){
7994 for(var i = 0, len = errors.length; i < len; i++){
7995 var fieldError = errors[i];
7996 var f = this.findField(fieldError.id);
7998 f.markInvalid(fieldError.msg);
8004 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8005 field.markInvalid(errors[id]);
8009 //Roo.each(this.childForms || [], function (f) {
8010 // f.markInvalid(errors);
8017 * Set values for fields in this form in bulk.
8018 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8019 * @return {BasicForm} this
8021 setValues : function(values){
8022 if(values instanceof Array){ // array of objects
8023 for(var i = 0, len = values.length; i < len; i++){
8025 var f = this.findField(v.id);
8027 f.setValue(v.value);
8028 if(this.trackResetOnLoad){
8029 f.originalValue = f.getValue();
8033 }else{ // object hash
8036 if(typeof values[id] != 'function' && (field = this.findField(id))){
8038 if (field.setFromData &&
8040 field.displayField &&
8041 // combos' with local stores can
8042 // be queried via setValue()
8043 // to set their value..
8044 (field.store && !field.store.isLocal)
8048 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8049 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8050 field.setFromData(sd);
8052 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8054 field.setFromData(values);
8057 field.setValue(values[id]);
8061 if(this.trackResetOnLoad){
8062 field.originalValue = field.getValue();
8068 //Roo.each(this.childForms || [], function (f) {
8069 // f.setValues(values);
8076 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8077 * they are returned as an array.
8078 * @param {Boolean} asString
8081 getValues : function(asString){
8082 //if (this.childForms) {
8083 // copy values from the child forms
8084 // Roo.each(this.childForms, function (f) {
8085 // this.setValues(f.getValues());
8091 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8092 if(asString === true){
8095 return Roo.urlDecode(fs);
8099 * Returns the fields in this form as an object with key/value pairs.
8100 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8103 getFieldValues : function(with_hidden)
8105 var items = this.getItems();
8107 items.each(function(f){
8113 var v = f.getValue();
8115 if (f.inputType =='radio') {
8116 if (typeof(ret[f.getName()]) == 'undefined') {
8117 ret[f.getName()] = ''; // empty..
8120 if (!f.el.dom.checked) {
8128 if(f.xtype == 'MoneyField'){
8129 ret[f.currencyName] = f.getCurrency();
8132 // not sure if this supported any more..
8133 if ((typeof(v) == 'object') && f.getRawValue) {
8134 v = f.getRawValue() ; // dates..
8136 // combo boxes where name != hiddenName...
8137 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8138 ret[f.name] = f.getRawValue();
8140 ret[f.getName()] = v;
8147 * Clears all invalid messages in this form.
8148 * @return {BasicForm} this
8150 clearInvalid : function(){
8151 var items = this.getItems();
8153 items.each(function(f){
8162 * @return {BasicForm} this
8165 var items = this.getItems();
8166 items.each(function(f){
8170 Roo.each(this.childForms || [], function (f) {
8178 getItems : function()
8180 var r=new Roo.util.MixedCollection(false, function(o){
8181 return o.id || (o.id = Roo.id());
8183 var iter = function(el) {
8190 Roo.each(el.items,function(e) {
8199 hideFields : function(items)
8201 Roo.each(items, function(i){
8203 var f = this.findField(i);
8209 if(f.xtype == 'DateField'){
8210 f.setVisible(false);
8219 showFields : function(items)
8221 Roo.each(items, function(i){
8223 var f = this.findField(i);
8229 if(f.xtype == 'DateField'){
8241 Roo.apply(Roo.bootstrap.Form, {
8268 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8269 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8270 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8271 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8274 this.maskEl.top.enableDisplayMode("block");
8275 this.maskEl.left.enableDisplayMode("block");
8276 this.maskEl.bottom.enableDisplayMode("block");
8277 this.maskEl.right.enableDisplayMode("block");
8279 this.toolTip = new Roo.bootstrap.Tooltip({
8280 cls : 'roo-form-error-popover',
8282 'left' : ['r-l', [-2,0], 'right'],
8283 'right' : ['l-r', [2,0], 'left'],
8284 'bottom' : ['tl-bl', [0,2], 'top'],
8285 'top' : [ 'bl-tl', [0,-2], 'bottom']
8289 this.toolTip.render(Roo.get(document.body));
8291 this.toolTip.el.enableDisplayMode("block");
8293 Roo.get(document.body).on('click', function(){
8297 Roo.get(document.body).on('touchstart', function(){
8301 this.isApplied = true
8304 mask : function(form, target)
8308 this.target = target;
8310 if(!this.form.errorMask || !target.el){
8314 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8316 Roo.log(scrollable);
8318 var ot = this.target.el.calcOffsetsTo(scrollable);
8320 var scrollTo = ot[1] - this.form.maskOffset;
8322 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8324 scrollable.scrollTo('top', scrollTo);
8326 var box = this.target.el.getBox();
8328 var zIndex = Roo.bootstrap.Modal.zIndex++;
8331 this.maskEl.top.setStyle('position', 'absolute');
8332 this.maskEl.top.setStyle('z-index', zIndex);
8333 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8334 this.maskEl.top.setLeft(0);
8335 this.maskEl.top.setTop(0);
8336 this.maskEl.top.show();
8338 this.maskEl.left.setStyle('position', 'absolute');
8339 this.maskEl.left.setStyle('z-index', zIndex);
8340 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8341 this.maskEl.left.setLeft(0);
8342 this.maskEl.left.setTop(box.y - this.padding);
8343 this.maskEl.left.show();
8345 this.maskEl.bottom.setStyle('position', 'absolute');
8346 this.maskEl.bottom.setStyle('z-index', zIndex);
8347 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8348 this.maskEl.bottom.setLeft(0);
8349 this.maskEl.bottom.setTop(box.bottom + this.padding);
8350 this.maskEl.bottom.show();
8352 this.maskEl.right.setStyle('position', 'absolute');
8353 this.maskEl.right.setStyle('z-index', zIndex);
8354 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8355 this.maskEl.right.setLeft(box.right + this.padding);
8356 this.maskEl.right.setTop(box.y - this.padding);
8357 this.maskEl.right.show();
8359 this.toolTip.bindEl = this.target.el;
8361 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8363 var tip = this.target.blankText;
8365 if(this.target.getValue() !== '' ) {
8367 if (this.target.invalidText.length) {
8368 tip = this.target.invalidText;
8369 } else if (this.target.regexText.length){
8370 tip = this.target.regexText;
8374 this.toolTip.show(tip);
8376 this.intervalID = window.setInterval(function() {
8377 Roo.bootstrap.Form.popover.unmask();
8380 window.onwheel = function(){ return false;};
8382 (function(){ this.isMasked = true; }).defer(500, this);
8388 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8392 this.maskEl.top.setStyle('position', 'absolute');
8393 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8394 this.maskEl.top.hide();
8396 this.maskEl.left.setStyle('position', 'absolute');
8397 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8398 this.maskEl.left.hide();
8400 this.maskEl.bottom.setStyle('position', 'absolute');
8401 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8402 this.maskEl.bottom.hide();
8404 this.maskEl.right.setStyle('position', 'absolute');
8405 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8406 this.maskEl.right.hide();
8408 this.toolTip.hide();
8410 this.toolTip.el.hide();
8412 window.onwheel = function(){ return true;};
8414 if(this.intervalID){
8415 window.clearInterval(this.intervalID);
8416 this.intervalID = false;
8419 this.isMasked = false;
8429 * Ext JS Library 1.1.1
8430 * Copyright(c) 2006-2007, Ext JS, LLC.
8432 * Originally Released Under LGPL - original licence link has changed is not relivant.
8435 * <script type="text/javascript">
8438 * @class Roo.form.VTypes
8439 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8442 Roo.form.VTypes = function(){
8443 // closure these in so they are only created once.
8444 var alpha = /^[a-zA-Z_]+$/;
8445 var alphanum = /^[a-zA-Z0-9_]+$/;
8446 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8447 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8449 // All these messages and functions are configurable
8452 * The function used to validate email addresses
8453 * @param {String} value The email address
8455 'email' : function(v){
8456 return email.test(v);
8459 * The error text to display when the email validation function returns false
8462 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8464 * The keystroke filter mask to be applied on email input
8467 'emailMask' : /[a-z0-9_\.\-@]/i,
8470 * The function used to validate URLs
8471 * @param {String} value The URL
8473 'url' : function(v){
8477 * The error text to display when the url validation function returns false
8480 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8483 * The function used to validate alpha values
8484 * @param {String} value The value
8486 'alpha' : function(v){
8487 return alpha.test(v);
8490 * The error text to display when the alpha validation function returns false
8493 'alphaText' : 'This field should only contain letters and _',
8495 * The keystroke filter mask to be applied on alpha input
8498 'alphaMask' : /[a-z_]/i,
8501 * The function used to validate alphanumeric values
8502 * @param {String} value The value
8504 'alphanum' : function(v){
8505 return alphanum.test(v);
8508 * The error text to display when the alphanumeric validation function returns false
8511 'alphanumText' : 'This field should only contain letters, numbers and _',
8513 * The keystroke filter mask to be applied on alphanumeric input
8516 'alphanumMask' : /[a-z0-9_]/i
8526 * @class Roo.bootstrap.Input
8527 * @extends Roo.bootstrap.Component
8528 * Bootstrap Input class
8529 * @cfg {Boolean} disabled is it disabled
8530 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8531 * @cfg {String} name name of the input
8532 * @cfg {string} fieldLabel - the label associated
8533 * @cfg {string} placeholder - placeholder to put in text.
8534 * @cfg {string} before - input group add on before
8535 * @cfg {string} after - input group add on after
8536 * @cfg {string} size - (lg|sm) or leave empty..
8537 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8538 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8539 * @cfg {Number} md colspan out of 12 for computer-sized screens
8540 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8541 * @cfg {string} value default value of the input
8542 * @cfg {Number} labelWidth set the width of label
8543 * @cfg {Number} labellg set the width of label (1-12)
8544 * @cfg {Number} labelmd set the width of label (1-12)
8545 * @cfg {Number} labelsm set the width of label (1-12)
8546 * @cfg {Number} labelxs set the width of label (1-12)
8547 * @cfg {String} labelAlign (top|left)
8548 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8549 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8550 * @cfg {String} indicatorpos (left|right) default left
8551 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8552 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8554 * @cfg {String} align (left|center|right) Default left
8555 * @cfg {Boolean} forceFeedback (true|false) Default false
8558 * Create a new Input
8559 * @param {Object} config The config object
8562 Roo.bootstrap.Input = function(config){
8564 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8569 * Fires when this field receives input focus.
8570 * @param {Roo.form.Field} this
8575 * Fires when this field loses input focus.
8576 * @param {Roo.form.Field} this
8581 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8582 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8583 * @param {Roo.form.Field} this
8584 * @param {Roo.EventObject} e The event object
8589 * Fires just before the field blurs if the field value has changed.
8590 * @param {Roo.form.Field} this
8591 * @param {Mixed} newValue The new value
8592 * @param {Mixed} oldValue The original value
8597 * Fires after the field has been marked as invalid.
8598 * @param {Roo.form.Field} this
8599 * @param {String} msg The validation message
8604 * Fires after the field has been validated with no errors.
8605 * @param {Roo.form.Field} this
8610 * Fires after the key up
8611 * @param {Roo.form.Field} this
8612 * @param {Roo.EventObject} e The event Object
8618 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8620 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8621 automatic validation (defaults to "keyup").
8623 validationEvent : "keyup",
8625 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8627 validateOnBlur : true,
8629 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8631 validationDelay : 250,
8633 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8635 focusClass : "x-form-focus", // not needed???
8639 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8641 invalidClass : "has-warning",
8644 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8646 validClass : "has-success",
8649 * @cfg {Boolean} hasFeedback (true|false) default true
8654 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8656 invalidFeedbackClass : "glyphicon-warning-sign",
8659 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8661 validFeedbackClass : "glyphicon-ok",
8664 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8666 selectOnFocus : false,
8669 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8673 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8678 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8680 disableKeyFilter : false,
8683 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8687 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8691 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8693 blankText : "Please complete this mandatory field",
8696 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8700 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8702 maxLength : Number.MAX_VALUE,
8704 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8706 minLengthText : "The minimum length for this field is {0}",
8708 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8710 maxLengthText : "The maximum length for this field is {0}",
8714 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8715 * If available, this function will be called only after the basic validators all return true, and will be passed the
8716 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8720 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8721 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8722 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8726 * @cfg {String} regexText -- Depricated - use Invalid Text
8731 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8737 autocomplete: false,
8756 formatedValue : false,
8757 forceFeedback : false,
8759 indicatorpos : 'left',
8769 parentLabelAlign : function()
8772 while (parent.parent()) {
8773 parent = parent.parent();
8774 if (typeof(parent.labelAlign) !='undefined') {
8775 return parent.labelAlign;
8782 getAutoCreate : function()
8784 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8790 if(this.inputType != 'hidden'){
8791 cfg.cls = 'form-group' //input-group
8797 type : this.inputType,
8799 cls : 'form-control',
8800 placeholder : this.placeholder || '',
8801 autocomplete : this.autocomplete || 'new-password'
8804 if(this.capture.length){
8805 input.capture = this.capture;
8808 if(this.accept.length){
8809 input.accept = this.accept + "/*";
8813 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8816 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8817 input.maxLength = this.maxLength;
8820 if (this.disabled) {
8821 input.disabled=true;
8824 if (this.readOnly) {
8825 input.readonly=true;
8829 input.name = this.name;
8833 input.cls += ' input-' + this.size;
8837 ['xs','sm','md','lg'].map(function(size){
8838 if (settings[size]) {
8839 cfg.cls += ' col-' + size + '-' + settings[size];
8843 var inputblock = input;
8847 cls: 'glyphicon form-control-feedback'
8850 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8853 cls : 'has-feedback',
8861 if (this.before || this.after) {
8864 cls : 'input-group',
8868 if (this.before && typeof(this.before) == 'string') {
8870 inputblock.cn.push({
8872 cls : 'roo-input-before input-group-addon',
8876 if (this.before && typeof(this.before) == 'object') {
8877 this.before = Roo.factory(this.before);
8879 inputblock.cn.push({
8881 cls : 'roo-input-before input-group-' +
8882 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8886 inputblock.cn.push(input);
8888 if (this.after && typeof(this.after) == 'string') {
8889 inputblock.cn.push({
8891 cls : 'roo-input-after input-group-addon',
8895 if (this.after && typeof(this.after) == 'object') {
8896 this.after = Roo.factory(this.after);
8898 inputblock.cn.push({
8900 cls : 'roo-input-after input-group-' +
8901 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8905 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8906 inputblock.cls += ' has-feedback';
8907 inputblock.cn.push(feedback);
8911 if (align ==='left' && this.fieldLabel.length) {
8913 cfg.cls += ' roo-form-group-label-left';
8918 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8919 tooltip : 'This field is required'
8924 cls : 'control-label',
8925 html : this.fieldLabel
8936 var labelCfg = cfg.cn[1];
8937 var contentCfg = cfg.cn[2];
8939 if(this.indicatorpos == 'right'){
8944 cls : 'control-label',
8948 html : this.fieldLabel
8952 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8953 tooltip : 'This field is required'
8966 labelCfg = cfg.cn[0];
8967 contentCfg = cfg.cn[1];
8971 if(this.labelWidth > 12){
8972 labelCfg.style = "width: " + this.labelWidth + 'px';
8975 if(this.labelWidth < 13 && this.labelmd == 0){
8976 this.labelmd = this.labelWidth;
8979 if(this.labellg > 0){
8980 labelCfg.cls += ' col-lg-' + this.labellg;
8981 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8984 if(this.labelmd > 0){
8985 labelCfg.cls += ' col-md-' + this.labelmd;
8986 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8989 if(this.labelsm > 0){
8990 labelCfg.cls += ' col-sm-' + this.labelsm;
8991 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8994 if(this.labelxs > 0){
8995 labelCfg.cls += ' col-xs-' + this.labelxs;
8996 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9000 } else if ( this.fieldLabel.length) {
9005 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9006 tooltip : 'This field is required'
9010 //cls : 'input-group-addon',
9011 html : this.fieldLabel
9019 if(this.indicatorpos == 'right'){
9024 //cls : 'input-group-addon',
9025 html : this.fieldLabel
9030 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9031 tooltip : 'This field is required'
9051 if (this.parentType === 'Navbar' && this.parent().bar) {
9052 cfg.cls += ' navbar-form';
9055 if (this.parentType === 'NavGroup') {
9056 cfg.cls += ' navbar-form';
9064 * return the real input element.
9066 inputEl: function ()
9068 return this.el.select('input.form-control',true).first();
9071 tooltipEl : function()
9073 return this.inputEl();
9076 indicatorEl : function()
9078 var indicator = this.el.select('i.roo-required-indicator',true).first();
9088 setDisabled : function(v)
9090 var i = this.inputEl().dom;
9092 i.removeAttribute('disabled');
9096 i.setAttribute('disabled','true');
9098 initEvents : function()
9101 this.inputEl().on("keydown" , this.fireKey, this);
9102 this.inputEl().on("focus", this.onFocus, this);
9103 this.inputEl().on("blur", this.onBlur, this);
9105 this.inputEl().relayEvent('keyup', this);
9107 this.indicator = this.indicatorEl();
9110 this.indicator.addClass('invisible');
9113 // reference to original value for reset
9114 this.originalValue = this.getValue();
9115 //Roo.form.TextField.superclass.initEvents.call(this);
9116 if(this.validationEvent == 'keyup'){
9117 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9118 this.inputEl().on('keyup', this.filterValidation, this);
9120 else if(this.validationEvent !== false){
9121 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9124 if(this.selectOnFocus){
9125 this.on("focus", this.preFocus, this);
9128 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9129 this.inputEl().on("keypress", this.filterKeys, this);
9131 this.inputEl().relayEvent('keypress', this);
9134 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9135 this.el.on("click", this.autoSize, this);
9138 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9139 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9142 if (typeof(this.before) == 'object') {
9143 this.before.render(this.el.select('.roo-input-before',true).first());
9145 if (typeof(this.after) == 'object') {
9146 this.after.render(this.el.select('.roo-input-after',true).first());
9149 this.inputEl().on('change', this.onChange, this);
9152 filterValidation : function(e){
9153 if(!e.isNavKeyPress()){
9154 this.validationTask.delay(this.validationDelay);
9158 * Validates the field value
9159 * @return {Boolean} True if the value is valid, else false
9161 validate : function(){
9162 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9163 if(this.disabled || this.validateValue(this.getRawValue())){
9174 * Validates a value according to the field's validation rules and marks the field as invalid
9175 * if the validation fails
9176 * @param {Mixed} value The value to validate
9177 * @return {Boolean} True if the value is valid, else false
9179 validateValue : function(value)
9181 if(this.getVisibilityEl().hasClass('hidden')){
9185 if(value.length < 1) { // if it's blank
9186 if(this.allowBlank){
9192 if(value.length < this.minLength){
9195 if(value.length > this.maxLength){
9199 var vt = Roo.form.VTypes;
9200 if(!vt[this.vtype](value, this)){
9204 if(typeof this.validator == "function"){
9205 var msg = this.validator(value);
9209 if (typeof(msg) == 'string') {
9210 this.invalidText = msg;
9214 if(this.regex && !this.regex.test(value)){
9222 fireKey : function(e){
9223 //Roo.log('field ' + e.getKey());
9224 if(e.isNavKeyPress()){
9225 this.fireEvent("specialkey", this, e);
9228 focus : function (selectText){
9230 this.inputEl().focus();
9231 if(selectText === true){
9232 this.inputEl().dom.select();
9238 onFocus : function(){
9239 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9240 // this.el.addClass(this.focusClass);
9243 this.hasFocus = true;
9244 this.startValue = this.getValue();
9245 this.fireEvent("focus", this);
9249 beforeBlur : Roo.emptyFn,
9253 onBlur : function(){
9255 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9256 //this.el.removeClass(this.focusClass);
9258 this.hasFocus = false;
9259 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9262 var v = this.getValue();
9263 if(String(v) !== String(this.startValue)){
9264 this.fireEvent('change', this, v, this.startValue);
9266 this.fireEvent("blur", this);
9269 onChange : function(e)
9271 var v = this.getValue();
9272 if(String(v) !== String(this.startValue)){
9273 this.fireEvent('change', this, v, this.startValue);
9279 * Resets the current field value to the originally loaded value and clears any validation messages
9282 this.setValue(this.originalValue);
9286 * Returns the name of the field
9287 * @return {Mixed} name The name field
9289 getName: function(){
9293 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9294 * @return {Mixed} value The field value
9296 getValue : function(){
9298 var v = this.inputEl().getValue();
9303 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9304 * @return {Mixed} value The field value
9306 getRawValue : function(){
9307 var v = this.inputEl().getValue();
9313 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9314 * @param {Mixed} value The value to set
9316 setRawValue : function(v){
9317 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9320 selectText : function(start, end){
9321 var v = this.getRawValue();
9323 start = start === undefined ? 0 : start;
9324 end = end === undefined ? v.length : end;
9325 var d = this.inputEl().dom;
9326 if(d.setSelectionRange){
9327 d.setSelectionRange(start, end);
9328 }else if(d.createTextRange){
9329 var range = d.createTextRange();
9330 range.moveStart("character", start);
9331 range.moveEnd("character", v.length-end);
9338 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9339 * @param {Mixed} value The value to set
9341 setValue : function(v){
9344 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9350 processValue : function(value){
9351 if(this.stripCharsRe){
9352 var newValue = value.replace(this.stripCharsRe, '');
9353 if(newValue !== value){
9354 this.setRawValue(newValue);
9361 preFocus : function(){
9363 if(this.selectOnFocus){
9364 this.inputEl().dom.select();
9367 filterKeys : function(e){
9369 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9372 var c = e.getCharCode(), cc = String.fromCharCode(c);
9373 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9376 if(!this.maskRe.test(cc)){
9381 * Clear any invalid styles/messages for this field
9383 clearInvalid : function(){
9385 if(!this.el || this.preventMark){ // not rendered
9390 this.el.removeClass(this.invalidClass);
9392 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9394 var feedback = this.el.select('.form-control-feedback', true).first();
9397 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9402 this.fireEvent('valid', this);
9406 * Mark this field as valid
9408 markValid : function()
9410 if(!this.el || this.preventMark){ // not rendered...
9414 this.el.removeClass([this.invalidClass, this.validClass]);
9416 var feedback = this.el.select('.form-control-feedback', true).first();
9419 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9423 this.indicator.removeClass('visible');
9424 this.indicator.addClass('invisible');
9431 if(this.allowBlank && !this.getRawValue().length){
9435 this.el.addClass(this.validClass);
9437 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9439 var feedback = this.el.select('.form-control-feedback', true).first();
9442 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9443 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9448 this.fireEvent('valid', this);
9452 * Mark this field as invalid
9453 * @param {String} msg The validation message
9455 markInvalid : function(msg)
9457 if(!this.el || this.preventMark){ // not rendered
9461 this.el.removeClass([this.invalidClass, this.validClass]);
9463 var feedback = this.el.select('.form-control-feedback', true).first();
9466 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9473 if(this.allowBlank && !this.getRawValue().length){
9478 this.indicator.removeClass('invisible');
9479 this.indicator.addClass('visible');
9482 this.el.addClass(this.invalidClass);
9484 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9486 var feedback = this.el.select('.form-control-feedback', true).first();
9489 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9491 if(this.getValue().length || this.forceFeedback){
9492 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9499 this.fireEvent('invalid', this, msg);
9502 SafariOnKeyDown : function(event)
9504 // this is a workaround for a password hang bug on chrome/ webkit.
9505 if (this.inputEl().dom.type != 'password') {
9509 var isSelectAll = false;
9511 if(this.inputEl().dom.selectionEnd > 0){
9512 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9514 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9515 event.preventDefault();
9520 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9522 event.preventDefault();
9523 // this is very hacky as keydown always get's upper case.
9525 var cc = String.fromCharCode(event.getCharCode());
9526 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9530 adjustWidth : function(tag, w){
9531 tag = tag.toLowerCase();
9532 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9533 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9537 if(tag == 'textarea'){
9540 }else if(Roo.isOpera){
9544 if(tag == 'textarea'){
9552 setFieldLabel : function(v)
9559 var ar = this.el.select('label > span',true);
9561 if (ar.elements.length) {
9562 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9563 this.fieldLabel = v;
9567 var br = this.el.select('label',true);
9569 if(br.elements.length) {
9570 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9571 this.fieldLabel = v;
9575 Roo.log('Cannot Found any of label > span || label in input');
9579 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9580 this.fieldLabel = v;
9595 * @class Roo.bootstrap.TextArea
9596 * @extends Roo.bootstrap.Input
9597 * Bootstrap TextArea class
9598 * @cfg {Number} cols Specifies the visible width of a text area
9599 * @cfg {Number} rows Specifies the visible number of lines in a text area
9600 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9601 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9602 * @cfg {string} html text
9605 * Create a new TextArea
9606 * @param {Object} config The config object
9609 Roo.bootstrap.TextArea = function(config){
9610 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9614 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9624 getAutoCreate : function(){
9626 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9632 if(this.inputType != 'hidden'){
9633 cfg.cls = 'form-group' //input-group
9641 value : this.value || '',
9642 html: this.html || '',
9643 cls : 'form-control',
9644 placeholder : this.placeholder || ''
9648 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9649 input.maxLength = this.maxLength;
9653 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9657 input.cols = this.cols;
9660 if (this.readOnly) {
9661 input.readonly = true;
9665 input.name = this.name;
9669 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9673 ['xs','sm','md','lg'].map(function(size){
9674 if (settings[size]) {
9675 cfg.cls += ' col-' + size + '-' + settings[size];
9679 var inputblock = input;
9681 if(this.hasFeedback && !this.allowBlank){
9685 cls: 'glyphicon form-control-feedback'
9689 cls : 'has-feedback',
9698 if (this.before || this.after) {
9701 cls : 'input-group',
9705 inputblock.cn.push({
9707 cls : 'input-group-addon',
9712 inputblock.cn.push(input);
9714 if(this.hasFeedback && !this.allowBlank){
9715 inputblock.cls += ' has-feedback';
9716 inputblock.cn.push(feedback);
9720 inputblock.cn.push({
9722 cls : 'input-group-addon',
9729 if (align ==='left' && this.fieldLabel.length) {
9734 cls : 'control-label',
9735 html : this.fieldLabel
9746 if(this.labelWidth > 12){
9747 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9750 if(this.labelWidth < 13 && this.labelmd == 0){
9751 this.labelmd = this.labelWidth;
9754 if(this.labellg > 0){
9755 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9756 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9759 if(this.labelmd > 0){
9760 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9761 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9764 if(this.labelsm > 0){
9765 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9766 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9769 if(this.labelxs > 0){
9770 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9771 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9774 } else if ( this.fieldLabel.length) {
9779 //cls : 'input-group-addon',
9780 html : this.fieldLabel
9798 if (this.disabled) {
9799 input.disabled=true;
9806 * return the real textarea element.
9808 inputEl: function ()
9810 return this.el.select('textarea.form-control',true).first();
9814 * Clear any invalid styles/messages for this field
9816 clearInvalid : function()
9819 if(!this.el || this.preventMark){ // not rendered
9823 var label = this.el.select('label', true).first();
9824 var icon = this.el.select('i.fa-star', true).first();
9830 this.el.removeClass(this.invalidClass);
9832 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9834 var feedback = this.el.select('.form-control-feedback', true).first();
9837 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9842 this.fireEvent('valid', this);
9846 * Mark this field as valid
9848 markValid : function()
9850 if(!this.el || this.preventMark){ // not rendered
9854 this.el.removeClass([this.invalidClass, this.validClass]);
9856 var feedback = this.el.select('.form-control-feedback', true).first();
9859 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9862 if(this.disabled || this.allowBlank){
9866 var label = this.el.select('label', true).first();
9867 var icon = this.el.select('i.fa-star', true).first();
9873 this.el.addClass(this.validClass);
9875 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9877 var feedback = this.el.select('.form-control-feedback', true).first();
9880 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9881 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9886 this.fireEvent('valid', this);
9890 * Mark this field as invalid
9891 * @param {String} msg The validation message
9893 markInvalid : function(msg)
9895 if(!this.el || this.preventMark){ // not rendered
9899 this.el.removeClass([this.invalidClass, this.validClass]);
9901 var feedback = this.el.select('.form-control-feedback', true).first();
9904 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9907 if(this.disabled || this.allowBlank){
9911 var label = this.el.select('label', true).first();
9912 var icon = this.el.select('i.fa-star', true).first();
9914 if(!this.getValue().length && label && !icon){
9915 this.el.createChild({
9917 cls : 'text-danger fa fa-lg fa-star',
9918 tooltip : 'This field is required',
9919 style : 'margin-right:5px;'
9923 this.el.addClass(this.invalidClass);
9925 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9927 var feedback = this.el.select('.form-control-feedback', true).first();
9930 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9932 if(this.getValue().length || this.forceFeedback){
9933 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9940 this.fireEvent('invalid', this, msg);
9948 * trigger field - base class for combo..
9953 * @class Roo.bootstrap.TriggerField
9954 * @extends Roo.bootstrap.Input
9955 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9956 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9957 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9958 * for which you can provide a custom implementation. For example:
9960 var trigger = new Roo.bootstrap.TriggerField();
9961 trigger.onTriggerClick = myTriggerFn;
9962 trigger.applyTo('my-field');
9965 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9966 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9967 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9968 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9969 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9972 * Create a new TriggerField.
9973 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9974 * to the base TextField)
9976 Roo.bootstrap.TriggerField = function(config){
9977 this.mimicing = false;
9978 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9981 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9983 * @cfg {String} triggerClass A CSS class to apply to the trigger
9986 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9991 * @cfg {Boolean} removable (true|false) special filter default false
9995 /** @cfg {Boolean} grow @hide */
9996 /** @cfg {Number} growMin @hide */
9997 /** @cfg {Number} growMax @hide */
10003 autoSize: Roo.emptyFn,
10007 deferHeight : true,
10010 actionMode : 'wrap',
10015 getAutoCreate : function(){
10017 var align = this.labelAlign || this.parentLabelAlign();
10022 cls: 'form-group' //input-group
10029 type : this.inputType,
10030 cls : 'form-control',
10031 autocomplete: 'new-password',
10032 placeholder : this.placeholder || ''
10036 input.name = this.name;
10039 input.cls += ' input-' + this.size;
10042 if (this.disabled) {
10043 input.disabled=true;
10046 var inputblock = input;
10048 if(this.hasFeedback && !this.allowBlank){
10052 cls: 'glyphicon form-control-feedback'
10055 if(this.removable && !this.editable && !this.tickable){
10057 cls : 'has-feedback',
10063 cls : 'roo-combo-removable-btn close'
10070 cls : 'has-feedback',
10079 if(this.removable && !this.editable && !this.tickable){
10081 cls : 'roo-removable',
10087 cls : 'roo-combo-removable-btn close'
10094 if (this.before || this.after) {
10097 cls : 'input-group',
10101 inputblock.cn.push({
10103 cls : 'input-group-addon',
10108 inputblock.cn.push(input);
10110 if(this.hasFeedback && !this.allowBlank){
10111 inputblock.cls += ' has-feedback';
10112 inputblock.cn.push(feedback);
10116 inputblock.cn.push({
10118 cls : 'input-group-addon',
10131 cls: 'form-hidden-field'
10145 cls: 'form-hidden-field'
10149 cls: 'roo-select2-choices',
10153 cls: 'roo-select2-search-field',
10166 cls: 'roo-select2-container input-group',
10171 // cls: 'typeahead typeahead-long dropdown-menu',
10172 // style: 'display:none'
10177 if(!this.multiple && this.showToggleBtn){
10183 if (this.caret != false) {
10186 cls: 'fa fa-' + this.caret
10193 cls : 'input-group-addon btn dropdown-toggle',
10198 cls: 'combobox-clear',
10212 combobox.cls += ' roo-select2-container-multi';
10215 if (align ==='left' && this.fieldLabel.length) {
10217 cfg.cls += ' roo-form-group-label-left';
10222 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10223 tooltip : 'This field is required'
10228 cls : 'control-label',
10229 html : this.fieldLabel
10241 var labelCfg = cfg.cn[1];
10242 var contentCfg = cfg.cn[2];
10244 if(this.indicatorpos == 'right'){
10249 cls : 'control-label',
10253 html : this.fieldLabel
10257 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10258 tooltip : 'This field is required'
10271 labelCfg = cfg.cn[0];
10272 contentCfg = cfg.cn[1];
10275 if(this.labelWidth > 12){
10276 labelCfg.style = "width: " + this.labelWidth + 'px';
10279 if(this.labelWidth < 13 && this.labelmd == 0){
10280 this.labelmd = this.labelWidth;
10283 if(this.labellg > 0){
10284 labelCfg.cls += ' col-lg-' + this.labellg;
10285 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10288 if(this.labelmd > 0){
10289 labelCfg.cls += ' col-md-' + this.labelmd;
10290 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10293 if(this.labelsm > 0){
10294 labelCfg.cls += ' col-sm-' + this.labelsm;
10295 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10298 if(this.labelxs > 0){
10299 labelCfg.cls += ' col-xs-' + this.labelxs;
10300 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10303 } else if ( this.fieldLabel.length) {
10304 // Roo.log(" label");
10308 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10309 tooltip : 'This field is required'
10313 //cls : 'input-group-addon',
10314 html : this.fieldLabel
10322 if(this.indicatorpos == 'right'){
10330 html : this.fieldLabel
10334 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10335 tooltip : 'This field is required'
10348 // Roo.log(" no label && no align");
10355 ['xs','sm','md','lg'].map(function(size){
10356 if (settings[size]) {
10357 cfg.cls += ' col-' + size + '-' + settings[size];
10368 onResize : function(w, h){
10369 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10370 // if(typeof w == 'number'){
10371 // var x = w - this.trigger.getWidth();
10372 // this.inputEl().setWidth(this.adjustWidth('input', x));
10373 // this.trigger.setStyle('left', x+'px');
10378 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10381 getResizeEl : function(){
10382 return this.inputEl();
10386 getPositionEl : function(){
10387 return this.inputEl();
10391 alignErrorIcon : function(){
10392 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10396 initEvents : function(){
10400 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10401 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10402 if(!this.multiple && this.showToggleBtn){
10403 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10404 if(this.hideTrigger){
10405 this.trigger.setDisplayed(false);
10407 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10411 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10414 if(this.removable && !this.editable && !this.tickable){
10415 var close = this.closeTriggerEl();
10418 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10419 close.on('click', this.removeBtnClick, this, close);
10423 //this.trigger.addClassOnOver('x-form-trigger-over');
10424 //this.trigger.addClassOnClick('x-form-trigger-click');
10427 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10431 closeTriggerEl : function()
10433 var close = this.el.select('.roo-combo-removable-btn', true).first();
10434 return close ? close : false;
10437 removeBtnClick : function(e, h, el)
10439 e.preventDefault();
10441 if(this.fireEvent("remove", this) !== false){
10443 this.fireEvent("afterremove", this)
10447 createList : function()
10449 this.list = Roo.get(document.body).createChild({
10451 cls: 'typeahead typeahead-long dropdown-menu',
10452 style: 'display:none'
10455 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10460 initTrigger : function(){
10465 onDestroy : function(){
10467 this.trigger.removeAllListeners();
10468 // this.trigger.remove();
10471 // this.wrap.remove();
10473 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10477 onFocus : function(){
10478 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10480 if(!this.mimicing){
10481 this.wrap.addClass('x-trigger-wrap-focus');
10482 this.mimicing = true;
10483 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10484 if(this.monitorTab){
10485 this.el.on("keydown", this.checkTab, this);
10492 checkTab : function(e){
10493 if(e.getKey() == e.TAB){
10494 this.triggerBlur();
10499 onBlur : function(){
10504 mimicBlur : function(e, t){
10506 if(!this.wrap.contains(t) && this.validateBlur()){
10507 this.triggerBlur();
10513 triggerBlur : function(){
10514 this.mimicing = false;
10515 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10516 if(this.monitorTab){
10517 this.el.un("keydown", this.checkTab, this);
10519 //this.wrap.removeClass('x-trigger-wrap-focus');
10520 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10524 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10525 validateBlur : function(e, t){
10530 onDisable : function(){
10531 this.inputEl().dom.disabled = true;
10532 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10534 // this.wrap.addClass('x-item-disabled');
10539 onEnable : function(){
10540 this.inputEl().dom.disabled = false;
10541 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10543 // this.el.removeClass('x-item-disabled');
10548 onShow : function(){
10549 var ae = this.getActionEl();
10552 ae.dom.style.display = '';
10553 ae.dom.style.visibility = 'visible';
10559 onHide : function(){
10560 var ae = this.getActionEl();
10561 ae.dom.style.display = 'none';
10565 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10566 * by an implementing function.
10568 * @param {EventObject} e
10570 onTriggerClick : Roo.emptyFn
10574 * Ext JS Library 1.1.1
10575 * Copyright(c) 2006-2007, Ext JS, LLC.
10577 * Originally Released Under LGPL - original licence link has changed is not relivant.
10580 * <script type="text/javascript">
10585 * @class Roo.data.SortTypes
10587 * Defines the default sorting (casting?) comparison functions used when sorting data.
10589 Roo.data.SortTypes = {
10591 * Default sort that does nothing
10592 * @param {Mixed} s The value being converted
10593 * @return {Mixed} The comparison value
10595 none : function(s){
10600 * The regular expression used to strip tags
10604 stripTagsRE : /<\/?[^>]+>/gi,
10607 * Strips all HTML tags to sort on text only
10608 * @param {Mixed} s The value being converted
10609 * @return {String} The comparison value
10611 asText : function(s){
10612 return String(s).replace(this.stripTagsRE, "");
10616 * Strips all HTML tags to sort on text only - Case insensitive
10617 * @param {Mixed} s The value being converted
10618 * @return {String} The comparison value
10620 asUCText : function(s){
10621 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10625 * Case insensitive string
10626 * @param {Mixed} s The value being converted
10627 * @return {String} The comparison value
10629 asUCString : function(s) {
10630 return String(s).toUpperCase();
10635 * @param {Mixed} s The value being converted
10636 * @return {Number} The comparison value
10638 asDate : function(s) {
10642 if(s instanceof Date){
10643 return s.getTime();
10645 return Date.parse(String(s));
10650 * @param {Mixed} s The value being converted
10651 * @return {Float} The comparison value
10653 asFloat : function(s) {
10654 var val = parseFloat(String(s).replace(/,/g, ""));
10663 * @param {Mixed} s The value being converted
10664 * @return {Number} The comparison value
10666 asInt : function(s) {
10667 var val = parseInt(String(s).replace(/,/g, ""));
10675 * Ext JS Library 1.1.1
10676 * Copyright(c) 2006-2007, Ext JS, LLC.
10678 * Originally Released Under LGPL - original licence link has changed is not relivant.
10681 * <script type="text/javascript">
10685 * @class Roo.data.Record
10686 * Instances of this class encapsulate both record <em>definition</em> information, and record
10687 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10688 * to access Records cached in an {@link Roo.data.Store} object.<br>
10690 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10691 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10694 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10696 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10697 * {@link #create}. The parameters are the same.
10698 * @param {Array} data An associative Array of data values keyed by the field name.
10699 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10700 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10701 * not specified an integer id is generated.
10703 Roo.data.Record = function(data, id){
10704 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10709 * Generate a constructor for a specific record layout.
10710 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10711 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10712 * Each field definition object may contain the following properties: <ul>
10713 * <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,
10714 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10715 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10716 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10717 * is being used, then this is a string containing the javascript expression to reference the data relative to
10718 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10719 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10720 * this may be omitted.</p></li>
10721 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10722 * <ul><li>auto (Default, implies no conversion)</li>
10727 * <li>date</li></ul></p></li>
10728 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10729 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10730 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10731 * by the Reader into an object that will be stored in the Record. It is passed the
10732 * following parameters:<ul>
10733 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10735 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10737 * <br>usage:<br><pre><code>
10738 var TopicRecord = Roo.data.Record.create(
10739 {name: 'title', mapping: 'topic_title'},
10740 {name: 'author', mapping: 'username'},
10741 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10742 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10743 {name: 'lastPoster', mapping: 'user2'},
10744 {name: 'excerpt', mapping: 'post_text'}
10747 var myNewRecord = new TopicRecord({
10748 title: 'Do my job please',
10751 lastPost: new Date(),
10752 lastPoster: 'Animal',
10753 excerpt: 'No way dude!'
10755 myStore.add(myNewRecord);
10760 Roo.data.Record.create = function(o){
10761 var f = function(){
10762 f.superclass.constructor.apply(this, arguments);
10764 Roo.extend(f, Roo.data.Record);
10765 var p = f.prototype;
10766 p.fields = new Roo.util.MixedCollection(false, function(field){
10769 for(var i = 0, len = o.length; i < len; i++){
10770 p.fields.add(new Roo.data.Field(o[i]));
10772 f.getField = function(name){
10773 return p.fields.get(name);
10778 Roo.data.Record.AUTO_ID = 1000;
10779 Roo.data.Record.EDIT = 'edit';
10780 Roo.data.Record.REJECT = 'reject';
10781 Roo.data.Record.COMMIT = 'commit';
10783 Roo.data.Record.prototype = {
10785 * Readonly flag - true if this record has been modified.
10794 join : function(store){
10795 this.store = store;
10799 * Set the named field to the specified value.
10800 * @param {String} name The name of the field to set.
10801 * @param {Object} value The value to set the field to.
10803 set : function(name, value){
10804 if(this.data[name] == value){
10808 if(!this.modified){
10809 this.modified = {};
10811 if(typeof this.modified[name] == 'undefined'){
10812 this.modified[name] = this.data[name];
10814 this.data[name] = value;
10815 if(!this.editing && this.store){
10816 this.store.afterEdit(this);
10821 * Get the value of the named field.
10822 * @param {String} name The name of the field to get the value of.
10823 * @return {Object} The value of the field.
10825 get : function(name){
10826 return this.data[name];
10830 beginEdit : function(){
10831 this.editing = true;
10832 this.modified = {};
10836 cancelEdit : function(){
10837 this.editing = false;
10838 delete this.modified;
10842 endEdit : function(){
10843 this.editing = false;
10844 if(this.dirty && this.store){
10845 this.store.afterEdit(this);
10850 * Usually called by the {@link Roo.data.Store} which owns the Record.
10851 * Rejects all changes made to the Record since either creation, or the last commit operation.
10852 * Modified fields are reverted to their original values.
10854 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10855 * of reject operations.
10857 reject : function(){
10858 var m = this.modified;
10860 if(typeof m[n] != "function"){
10861 this.data[n] = m[n];
10864 this.dirty = false;
10865 delete this.modified;
10866 this.editing = false;
10868 this.store.afterReject(this);
10873 * Usually called by the {@link Roo.data.Store} which owns the Record.
10874 * Commits all changes made to the Record since either creation, or the last commit operation.
10876 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10877 * of commit operations.
10879 commit : function(){
10880 this.dirty = false;
10881 delete this.modified;
10882 this.editing = false;
10884 this.store.afterCommit(this);
10889 hasError : function(){
10890 return this.error != null;
10894 clearError : function(){
10899 * Creates a copy of this record.
10900 * @param {String} id (optional) A new record id if you don't want to use this record's id
10903 copy : function(newId) {
10904 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10908 * Ext JS Library 1.1.1
10909 * Copyright(c) 2006-2007, Ext JS, LLC.
10911 * Originally Released Under LGPL - original licence link has changed is not relivant.
10914 * <script type="text/javascript">
10920 * @class Roo.data.Store
10921 * @extends Roo.util.Observable
10922 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10923 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10925 * 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
10926 * has no knowledge of the format of the data returned by the Proxy.<br>
10928 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10929 * instances from the data object. These records are cached and made available through accessor functions.
10931 * Creates a new Store.
10932 * @param {Object} config A config object containing the objects needed for the Store to access data,
10933 * and read the data into Records.
10935 Roo.data.Store = function(config){
10936 this.data = new Roo.util.MixedCollection(false);
10937 this.data.getKey = function(o){
10940 this.baseParams = {};
10942 this.paramNames = {
10947 "multisort" : "_multisort"
10950 if(config && config.data){
10951 this.inlineData = config.data;
10952 delete config.data;
10955 Roo.apply(this, config);
10957 if(this.reader){ // reader passed
10958 this.reader = Roo.factory(this.reader, Roo.data);
10959 this.reader.xmodule = this.xmodule || false;
10960 if(!this.recordType){
10961 this.recordType = this.reader.recordType;
10963 if(this.reader.onMetaChange){
10964 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10968 if(this.recordType){
10969 this.fields = this.recordType.prototype.fields;
10971 this.modified = [];
10975 * @event datachanged
10976 * Fires when the data cache has changed, and a widget which is using this Store
10977 * as a Record cache should refresh its view.
10978 * @param {Store} this
10980 datachanged : true,
10982 * @event metachange
10983 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10984 * @param {Store} this
10985 * @param {Object} meta The JSON metadata
10990 * Fires when Records have been added to the Store
10991 * @param {Store} this
10992 * @param {Roo.data.Record[]} records The array of Records added
10993 * @param {Number} index The index at which the record(s) were added
10998 * Fires when a Record has been removed from the Store
10999 * @param {Store} this
11000 * @param {Roo.data.Record} record The Record that was removed
11001 * @param {Number} index The index at which the record was removed
11006 * Fires when a Record has been updated
11007 * @param {Store} this
11008 * @param {Roo.data.Record} record The Record that was updated
11009 * @param {String} operation The update operation being performed. Value may be one of:
11011 Roo.data.Record.EDIT
11012 Roo.data.Record.REJECT
11013 Roo.data.Record.COMMIT
11019 * Fires when the data cache has been cleared.
11020 * @param {Store} this
11024 * @event beforeload
11025 * Fires before a request is made for a new data object. If the beforeload handler returns false
11026 * the load action will be canceled.
11027 * @param {Store} this
11028 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11032 * @event beforeloadadd
11033 * Fires after a new set of Records has been loaded.
11034 * @param {Store} this
11035 * @param {Roo.data.Record[]} records The Records that were loaded
11036 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11038 beforeloadadd : true,
11041 * Fires after a new set of Records has been loaded, before they are added to the store.
11042 * @param {Store} this
11043 * @param {Roo.data.Record[]} records The Records that were loaded
11044 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11045 * @params {Object} return from reader
11049 * @event loadexception
11050 * Fires if an exception occurs in the Proxy during loading.
11051 * Called with the signature of the Proxy's "loadexception" event.
11052 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11055 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11056 * @param {Object} load options
11057 * @param {Object} jsonData from your request (normally this contains the Exception)
11059 loadexception : true
11063 this.proxy = Roo.factory(this.proxy, Roo.data);
11064 this.proxy.xmodule = this.xmodule || false;
11065 this.relayEvents(this.proxy, ["loadexception"]);
11067 this.sortToggle = {};
11068 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11070 Roo.data.Store.superclass.constructor.call(this);
11072 if(this.inlineData){
11073 this.loadData(this.inlineData);
11074 delete this.inlineData;
11078 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11080 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11081 * without a remote query - used by combo/forms at present.
11085 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11088 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11091 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11092 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11095 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11096 * on any HTTP request
11099 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11102 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11106 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11107 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11109 remoteSort : false,
11112 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11113 * loaded or when a record is removed. (defaults to false).
11115 pruneModifiedRecords : false,
11118 lastOptions : null,
11121 * Add Records to the Store and fires the add event.
11122 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11124 add : function(records){
11125 records = [].concat(records);
11126 for(var i = 0, len = records.length; i < len; i++){
11127 records[i].join(this);
11129 var index = this.data.length;
11130 this.data.addAll(records);
11131 this.fireEvent("add", this, records, index);
11135 * Remove a Record from the Store and fires the remove event.
11136 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11138 remove : function(record){
11139 var index = this.data.indexOf(record);
11140 this.data.removeAt(index);
11142 if(this.pruneModifiedRecords){
11143 this.modified.remove(record);
11145 this.fireEvent("remove", this, record, index);
11149 * Remove all Records from the Store and fires the clear event.
11151 removeAll : function(){
11153 if(this.pruneModifiedRecords){
11154 this.modified = [];
11156 this.fireEvent("clear", this);
11160 * Inserts Records to the Store at the given index and fires the add event.
11161 * @param {Number} index The start index at which to insert the passed Records.
11162 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11164 insert : function(index, records){
11165 records = [].concat(records);
11166 for(var i = 0, len = records.length; i < len; i++){
11167 this.data.insert(index, records[i]);
11168 records[i].join(this);
11170 this.fireEvent("add", this, records, index);
11174 * Get the index within the cache of the passed Record.
11175 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11176 * @return {Number} The index of the passed Record. Returns -1 if not found.
11178 indexOf : function(record){
11179 return this.data.indexOf(record);
11183 * Get the index within the cache of the Record with the passed id.
11184 * @param {String} id The id of the Record to find.
11185 * @return {Number} The index of the Record. Returns -1 if not found.
11187 indexOfId : function(id){
11188 return this.data.indexOfKey(id);
11192 * Get the Record with the specified id.
11193 * @param {String} id The id of the Record to find.
11194 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11196 getById : function(id){
11197 return this.data.key(id);
11201 * Get the Record at the specified index.
11202 * @param {Number} index The index of the Record to find.
11203 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11205 getAt : function(index){
11206 return this.data.itemAt(index);
11210 * Returns a range of Records between specified indices.
11211 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11212 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11213 * @return {Roo.data.Record[]} An array of Records
11215 getRange : function(start, end){
11216 return this.data.getRange(start, end);
11220 storeOptions : function(o){
11221 o = Roo.apply({}, o);
11224 this.lastOptions = o;
11228 * Loads the Record cache from the configured Proxy using the configured Reader.
11230 * If using remote paging, then the first load call must specify the <em>start</em>
11231 * and <em>limit</em> properties in the options.params property to establish the initial
11232 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11234 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11235 * and this call will return before the new data has been loaded. Perform any post-processing
11236 * in a callback function, or in a "load" event handler.</strong>
11238 * @param {Object} options An object containing properties which control loading options:<ul>
11239 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11240 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11241 * passed the following arguments:<ul>
11242 * <li>r : Roo.data.Record[]</li>
11243 * <li>options: Options object from the load call</li>
11244 * <li>success: Boolean success indicator</li></ul></li>
11245 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11246 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11249 load : function(options){
11250 options = options || {};
11251 if(this.fireEvent("beforeload", this, options) !== false){
11252 this.storeOptions(options);
11253 var p = Roo.apply(options.params || {}, this.baseParams);
11254 // if meta was not loaded from remote source.. try requesting it.
11255 if (!this.reader.metaFromRemote) {
11256 p._requestMeta = 1;
11258 if(this.sortInfo && this.remoteSort){
11259 var pn = this.paramNames;
11260 p[pn["sort"]] = this.sortInfo.field;
11261 p[pn["dir"]] = this.sortInfo.direction;
11263 if (this.multiSort) {
11264 var pn = this.paramNames;
11265 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11268 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11273 * Reloads the Record cache from the configured Proxy using the configured Reader and
11274 * the options from the last load operation performed.
11275 * @param {Object} options (optional) An object containing properties which may override the options
11276 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11277 * the most recently used options are reused).
11279 reload : function(options){
11280 this.load(Roo.applyIf(options||{}, this.lastOptions));
11284 // Called as a callback by the Reader during a load operation.
11285 loadRecords : function(o, options, success){
11286 if(!o || success === false){
11287 if(success !== false){
11288 this.fireEvent("load", this, [], options, o);
11290 if(options.callback){
11291 options.callback.call(options.scope || this, [], options, false);
11295 // if data returned failure - throw an exception.
11296 if (o.success === false) {
11297 // show a message if no listener is registered.
11298 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11299 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11301 // loadmask wil be hooked into this..
11302 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11305 var r = o.records, t = o.totalRecords || r.length;
11307 this.fireEvent("beforeloadadd", this, r, options, o);
11309 if(!options || options.add !== true){
11310 if(this.pruneModifiedRecords){
11311 this.modified = [];
11313 for(var i = 0, len = r.length; i < len; i++){
11317 this.data = this.snapshot;
11318 delete this.snapshot;
11321 this.data.addAll(r);
11322 this.totalLength = t;
11324 this.fireEvent("datachanged", this);
11326 this.totalLength = Math.max(t, this.data.length+r.length);
11330 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11332 var e = new Roo.data.Record({});
11334 e.set(this.parent.displayField, this.parent.emptyTitle);
11335 e.set(this.parent.valueField, '');
11340 this.fireEvent("load", this, r, options, o);
11341 if(options.callback){
11342 options.callback.call(options.scope || this, r, options, true);
11348 * Loads data from a passed data block. A Reader which understands the format of the data
11349 * must have been configured in the constructor.
11350 * @param {Object} data The data block from which to read the Records. The format of the data expected
11351 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11352 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11354 loadData : function(o, append){
11355 var r = this.reader.readRecords(o);
11356 this.loadRecords(r, {add: append}, true);
11360 * Gets the number of cached records.
11362 * <em>If using paging, this may not be the total size of the dataset. If the data object
11363 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11364 * the data set size</em>
11366 getCount : function(){
11367 return this.data.length || 0;
11371 * Gets the total number of records in the dataset as returned by the server.
11373 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11374 * the dataset size</em>
11376 getTotalCount : function(){
11377 return this.totalLength || 0;
11381 * Returns the sort state of the Store as an object with two properties:
11383 field {String} The name of the field by which the Records are sorted
11384 direction {String} The sort order, "ASC" or "DESC"
11387 getSortState : function(){
11388 return this.sortInfo;
11392 applySort : function(){
11393 if(this.sortInfo && !this.remoteSort){
11394 var s = this.sortInfo, f = s.field;
11395 var st = this.fields.get(f).sortType;
11396 var fn = function(r1, r2){
11397 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11398 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11400 this.data.sort(s.direction, fn);
11401 if(this.snapshot && this.snapshot != this.data){
11402 this.snapshot.sort(s.direction, fn);
11408 * Sets the default sort column and order to be used by the next load operation.
11409 * @param {String} fieldName The name of the field to sort by.
11410 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11412 setDefaultSort : function(field, dir){
11413 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11417 * Sort the Records.
11418 * If remote sorting is used, the sort is performed on the server, and the cache is
11419 * reloaded. If local sorting is used, the cache is sorted internally.
11420 * @param {String} fieldName The name of the field to sort by.
11421 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11423 sort : function(fieldName, dir){
11424 var f = this.fields.get(fieldName);
11426 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11428 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11429 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11434 this.sortToggle[f.name] = dir;
11435 this.sortInfo = {field: f.name, direction: dir};
11436 if(!this.remoteSort){
11438 this.fireEvent("datachanged", this);
11440 this.load(this.lastOptions);
11445 * Calls the specified function for each of the Records in the cache.
11446 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11447 * Returning <em>false</em> aborts and exits the iteration.
11448 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11450 each : function(fn, scope){
11451 this.data.each(fn, scope);
11455 * Gets all records modified since the last commit. Modified records are persisted across load operations
11456 * (e.g., during paging).
11457 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11459 getModifiedRecords : function(){
11460 return this.modified;
11464 createFilterFn : function(property, value, anyMatch){
11465 if(!value.exec){ // not a regex
11466 value = String(value);
11467 if(value.length == 0){
11470 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11472 return function(r){
11473 return value.test(r.data[property]);
11478 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11479 * @param {String} property A field on your records
11480 * @param {Number} start The record index to start at (defaults to 0)
11481 * @param {Number} end The last record index to include (defaults to length - 1)
11482 * @return {Number} The sum
11484 sum : function(property, start, end){
11485 var rs = this.data.items, v = 0;
11486 start = start || 0;
11487 end = (end || end === 0) ? end : rs.length-1;
11489 for(var i = start; i <= end; i++){
11490 v += (rs[i].data[property] || 0);
11496 * Filter the records by a specified property.
11497 * @param {String} field A field on your records
11498 * @param {String/RegExp} value Either a string that the field
11499 * should start with or a RegExp to test against the field
11500 * @param {Boolean} anyMatch True to match any part not just the beginning
11502 filter : function(property, value, anyMatch){
11503 var fn = this.createFilterFn(property, value, anyMatch);
11504 return fn ? this.filterBy(fn) : this.clearFilter();
11508 * Filter by a function. The specified function will be called with each
11509 * record in this data source. If the function returns true the record is included,
11510 * otherwise it is filtered.
11511 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11512 * @param {Object} scope (optional) The scope of the function (defaults to this)
11514 filterBy : function(fn, scope){
11515 this.snapshot = this.snapshot || this.data;
11516 this.data = this.queryBy(fn, scope||this);
11517 this.fireEvent("datachanged", this);
11521 * Query the records by a specified property.
11522 * @param {String} field A field on your records
11523 * @param {String/RegExp} value Either a string that the field
11524 * should start with or a RegExp to test against the field
11525 * @param {Boolean} anyMatch True to match any part not just the beginning
11526 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11528 query : function(property, value, anyMatch){
11529 var fn = this.createFilterFn(property, value, anyMatch);
11530 return fn ? this.queryBy(fn) : this.data.clone();
11534 * Query by a function. The specified function will be called with each
11535 * record in this data source. If the function returns true the record is included
11537 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11538 * @param {Object} scope (optional) The scope of the function (defaults to this)
11539 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11541 queryBy : function(fn, scope){
11542 var data = this.snapshot || this.data;
11543 return data.filterBy(fn, scope||this);
11547 * Collects unique values for a particular dataIndex from this store.
11548 * @param {String} dataIndex The property to collect
11549 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11550 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11551 * @return {Array} An array of the unique values
11553 collect : function(dataIndex, allowNull, bypassFilter){
11554 var d = (bypassFilter === true && this.snapshot) ?
11555 this.snapshot.items : this.data.items;
11556 var v, sv, r = [], l = {};
11557 for(var i = 0, len = d.length; i < len; i++){
11558 v = d[i].data[dataIndex];
11560 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11569 * Revert to a view of the Record cache with no filtering applied.
11570 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11572 clearFilter : function(suppressEvent){
11573 if(this.snapshot && this.snapshot != this.data){
11574 this.data = this.snapshot;
11575 delete this.snapshot;
11576 if(suppressEvent !== true){
11577 this.fireEvent("datachanged", this);
11583 afterEdit : function(record){
11584 if(this.modified.indexOf(record) == -1){
11585 this.modified.push(record);
11587 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11591 afterReject : function(record){
11592 this.modified.remove(record);
11593 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11597 afterCommit : function(record){
11598 this.modified.remove(record);
11599 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11603 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11604 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11606 commitChanges : function(){
11607 var m = this.modified.slice(0);
11608 this.modified = [];
11609 for(var i = 0, len = m.length; i < len; i++){
11615 * Cancel outstanding changes on all changed records.
11617 rejectChanges : function(){
11618 var m = this.modified.slice(0);
11619 this.modified = [];
11620 for(var i = 0, len = m.length; i < len; i++){
11625 onMetaChange : function(meta, rtype, o){
11626 this.recordType = rtype;
11627 this.fields = rtype.prototype.fields;
11628 delete this.snapshot;
11629 this.sortInfo = meta.sortInfo || this.sortInfo;
11630 this.modified = [];
11631 this.fireEvent('metachange', this, this.reader.meta);
11634 moveIndex : function(data, type)
11636 var index = this.indexOf(data);
11638 var newIndex = index + type;
11642 this.insert(newIndex, data);
11647 * Ext JS Library 1.1.1
11648 * Copyright(c) 2006-2007, Ext JS, LLC.
11650 * Originally Released Under LGPL - original licence link has changed is not relivant.
11653 * <script type="text/javascript">
11657 * @class Roo.data.SimpleStore
11658 * @extends Roo.data.Store
11659 * Small helper class to make creating Stores from Array data easier.
11660 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11661 * @cfg {Array} fields An array of field definition objects, or field name strings.
11662 * @cfg {Array} data The multi-dimensional array of data
11664 * @param {Object} config
11666 Roo.data.SimpleStore = function(config){
11667 Roo.data.SimpleStore.superclass.constructor.call(this, {
11669 reader: new Roo.data.ArrayReader({
11672 Roo.data.Record.create(config.fields)
11674 proxy : new Roo.data.MemoryProxy(config.data)
11678 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11680 * Ext JS Library 1.1.1
11681 * Copyright(c) 2006-2007, Ext JS, LLC.
11683 * Originally Released Under LGPL - original licence link has changed is not relivant.
11686 * <script type="text/javascript">
11691 * @extends Roo.data.Store
11692 * @class Roo.data.JsonStore
11693 * Small helper class to make creating Stores for JSON data easier. <br/>
11695 var store = new Roo.data.JsonStore({
11696 url: 'get-images.php',
11698 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11701 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11702 * JsonReader and HttpProxy (unless inline data is provided).</b>
11703 * @cfg {Array} fields An array of field definition objects, or field name strings.
11705 * @param {Object} config
11707 Roo.data.JsonStore = function(c){
11708 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11709 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11710 reader: new Roo.data.JsonReader(c, c.fields)
11713 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11715 * Ext JS Library 1.1.1
11716 * Copyright(c) 2006-2007, Ext JS, LLC.
11718 * Originally Released Under LGPL - original licence link has changed is not relivant.
11721 * <script type="text/javascript">
11725 Roo.data.Field = function(config){
11726 if(typeof config == "string"){
11727 config = {name: config};
11729 Roo.apply(this, config);
11732 this.type = "auto";
11735 var st = Roo.data.SortTypes;
11736 // named sortTypes are supported, here we look them up
11737 if(typeof this.sortType == "string"){
11738 this.sortType = st[this.sortType];
11741 // set default sortType for strings and dates
11742 if(!this.sortType){
11745 this.sortType = st.asUCString;
11748 this.sortType = st.asDate;
11751 this.sortType = st.none;
11756 var stripRe = /[\$,%]/g;
11758 // prebuilt conversion function for this field, instead of
11759 // switching every time we're reading a value
11761 var cv, dateFormat = this.dateFormat;
11766 cv = function(v){ return v; };
11769 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11773 return v !== undefined && v !== null && v !== '' ?
11774 parseInt(String(v).replace(stripRe, ""), 10) : '';
11779 return v !== undefined && v !== null && v !== '' ?
11780 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11785 cv = function(v){ return v === true || v === "true" || v == 1; };
11792 if(v instanceof Date){
11796 if(dateFormat == "timestamp"){
11797 return new Date(v*1000);
11799 return Date.parseDate(v, dateFormat);
11801 var parsed = Date.parse(v);
11802 return parsed ? new Date(parsed) : null;
11811 Roo.data.Field.prototype = {
11819 * Ext JS Library 1.1.1
11820 * Copyright(c) 2006-2007, Ext JS, LLC.
11822 * Originally Released Under LGPL - original licence link has changed is not relivant.
11825 * <script type="text/javascript">
11828 // Base class for reading structured data from a data source. This class is intended to be
11829 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11832 * @class Roo.data.DataReader
11833 * Base class for reading structured data from a data source. This class is intended to be
11834 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11837 Roo.data.DataReader = function(meta, recordType){
11841 this.recordType = recordType instanceof Array ?
11842 Roo.data.Record.create(recordType) : recordType;
11845 Roo.data.DataReader.prototype = {
11847 * Create an empty record
11848 * @param {Object} data (optional) - overlay some values
11849 * @return {Roo.data.Record} record created.
11851 newRow : function(d) {
11853 this.recordType.prototype.fields.each(function(c) {
11855 case 'int' : da[c.name] = 0; break;
11856 case 'date' : da[c.name] = new Date(); break;
11857 case 'float' : da[c.name] = 0.0; break;
11858 case 'boolean' : da[c.name] = false; break;
11859 default : da[c.name] = ""; break;
11863 return new this.recordType(Roo.apply(da, d));
11868 * Ext JS Library 1.1.1
11869 * Copyright(c) 2006-2007, Ext JS, LLC.
11871 * Originally Released Under LGPL - original licence link has changed is not relivant.
11874 * <script type="text/javascript">
11878 * @class Roo.data.DataProxy
11879 * @extends Roo.data.Observable
11880 * This class is an abstract base class for implementations which provide retrieval of
11881 * unformatted data objects.<br>
11883 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11884 * (of the appropriate type which knows how to parse the data object) to provide a block of
11885 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11887 * Custom implementations must implement the load method as described in
11888 * {@link Roo.data.HttpProxy#load}.
11890 Roo.data.DataProxy = function(){
11893 * @event beforeload
11894 * Fires before a network request is made to retrieve a data object.
11895 * @param {Object} This DataProxy object.
11896 * @param {Object} params The params parameter to the load function.
11901 * Fires before the load method's callback is called.
11902 * @param {Object} This DataProxy object.
11903 * @param {Object} o The data object.
11904 * @param {Object} arg The callback argument object passed to the load function.
11908 * @event loadexception
11909 * Fires if an Exception occurs during data retrieval.
11910 * @param {Object} This DataProxy object.
11911 * @param {Object} o The data object.
11912 * @param {Object} arg The callback argument object passed to the load function.
11913 * @param {Object} e The Exception.
11915 loadexception : true
11917 Roo.data.DataProxy.superclass.constructor.call(this);
11920 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11923 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11927 * Ext JS Library 1.1.1
11928 * Copyright(c) 2006-2007, Ext JS, LLC.
11930 * Originally Released Under LGPL - original licence link has changed is not relivant.
11933 * <script type="text/javascript">
11936 * @class Roo.data.MemoryProxy
11937 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11938 * to the Reader when its load method is called.
11940 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11942 Roo.data.MemoryProxy = function(data){
11946 Roo.data.MemoryProxy.superclass.constructor.call(this);
11950 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11953 * Load data from the requested source (in this case an in-memory
11954 * data object passed to the constructor), read the data object into
11955 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11956 * process that block using the passed callback.
11957 * @param {Object} params This parameter is not used by the MemoryProxy class.
11958 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11959 * object into a block of Roo.data.Records.
11960 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11961 * The function must be passed <ul>
11962 * <li>The Record block object</li>
11963 * <li>The "arg" argument from the load function</li>
11964 * <li>A boolean success indicator</li>
11966 * @param {Object} scope The scope in which to call the callback
11967 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11969 load : function(params, reader, callback, scope, arg){
11970 params = params || {};
11973 result = reader.readRecords(this.data);
11975 this.fireEvent("loadexception", this, arg, null, e);
11976 callback.call(scope, null, arg, false);
11979 callback.call(scope, result, arg, true);
11983 update : function(params, records){
11988 * Ext JS Library 1.1.1
11989 * Copyright(c) 2006-2007, Ext JS, LLC.
11991 * Originally Released Under LGPL - original licence link has changed is not relivant.
11994 * <script type="text/javascript">
11997 * @class Roo.data.HttpProxy
11998 * @extends Roo.data.DataProxy
11999 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12000 * configured to reference a certain URL.<br><br>
12002 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12003 * from which the running page was served.<br><br>
12005 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12007 * Be aware that to enable the browser to parse an XML document, the server must set
12008 * the Content-Type header in the HTTP response to "text/xml".
12010 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12011 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12012 * will be used to make the request.
12014 Roo.data.HttpProxy = function(conn){
12015 Roo.data.HttpProxy.superclass.constructor.call(this);
12016 // is conn a conn config or a real conn?
12018 this.useAjax = !conn || !conn.events;
12022 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12023 // thse are take from connection...
12026 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12029 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12030 * extra parameters to each request made by this object. (defaults to undefined)
12033 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12034 * to each request made by this object. (defaults to undefined)
12037 * @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)
12040 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12043 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12049 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12053 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12054 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12055 * a finer-grained basis than the DataProxy events.
12057 getConnection : function(){
12058 return this.useAjax ? Roo.Ajax : this.conn;
12062 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12063 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12064 * process that block using the passed callback.
12065 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12066 * for the request to the remote server.
12067 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12068 * object into a block of Roo.data.Records.
12069 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12070 * The function must be passed <ul>
12071 * <li>The Record block object</li>
12072 * <li>The "arg" argument from the load function</li>
12073 * <li>A boolean success indicator</li>
12075 * @param {Object} scope The scope in which to call the callback
12076 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12078 load : function(params, reader, callback, scope, arg){
12079 if(this.fireEvent("beforeload", this, params) !== false){
12081 params : params || {},
12083 callback : callback,
12088 callback : this.loadResponse,
12092 Roo.applyIf(o, this.conn);
12093 if(this.activeRequest){
12094 Roo.Ajax.abort(this.activeRequest);
12096 this.activeRequest = Roo.Ajax.request(o);
12098 this.conn.request(o);
12101 callback.call(scope||this, null, arg, false);
12106 loadResponse : function(o, success, response){
12107 delete this.activeRequest;
12109 this.fireEvent("loadexception", this, o, response);
12110 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12115 result = o.reader.read(response);
12117 this.fireEvent("loadexception", this, o, response, e);
12118 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12122 this.fireEvent("load", this, o, o.request.arg);
12123 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12127 update : function(dataSet){
12132 updateResponse : function(dataSet){
12137 * Ext JS Library 1.1.1
12138 * Copyright(c) 2006-2007, Ext JS, LLC.
12140 * Originally Released Under LGPL - original licence link has changed is not relivant.
12143 * <script type="text/javascript">
12147 * @class Roo.data.ScriptTagProxy
12148 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12149 * other than the originating domain of the running page.<br><br>
12151 * <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
12152 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12154 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12155 * source code that is used as the source inside a <script> tag.<br><br>
12157 * In order for the browser to process the returned data, the server must wrap the data object
12158 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12159 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12160 * depending on whether the callback name was passed:
12163 boolean scriptTag = false;
12164 String cb = request.getParameter("callback");
12167 response.setContentType("text/javascript");
12169 response.setContentType("application/x-json");
12171 Writer out = response.getWriter();
12173 out.write(cb + "(");
12175 out.print(dataBlock.toJsonString());
12182 * @param {Object} config A configuration object.
12184 Roo.data.ScriptTagProxy = function(config){
12185 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12186 Roo.apply(this, config);
12187 this.head = document.getElementsByTagName("head")[0];
12190 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12192 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12194 * @cfg {String} url The URL from which to request the data object.
12197 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12201 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12202 * the server the name of the callback function set up by the load call to process the returned data object.
12203 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12204 * javascript output which calls this named function passing the data object as its only parameter.
12206 callbackParam : "callback",
12208 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12209 * name to the request.
12214 * Load data from the configured URL, read the data object into
12215 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12216 * process that block using the passed callback.
12217 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12218 * for the request to the remote server.
12219 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12220 * object into a block of Roo.data.Records.
12221 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12222 * The function must be passed <ul>
12223 * <li>The Record block object</li>
12224 * <li>The "arg" argument from the load function</li>
12225 * <li>A boolean success indicator</li>
12227 * @param {Object} scope The scope in which to call the callback
12228 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12230 load : function(params, reader, callback, scope, arg){
12231 if(this.fireEvent("beforeload", this, params) !== false){
12233 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12235 var url = this.url;
12236 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12238 url += "&_dc=" + (new Date().getTime());
12240 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12243 cb : "stcCallback"+transId,
12244 scriptId : "stcScript"+transId,
12248 callback : callback,
12254 window[trans.cb] = function(o){
12255 conn.handleResponse(o, trans);
12258 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12260 if(this.autoAbort !== false){
12264 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12266 var script = document.createElement("script");
12267 script.setAttribute("src", url);
12268 script.setAttribute("type", "text/javascript");
12269 script.setAttribute("id", trans.scriptId);
12270 this.head.appendChild(script);
12272 this.trans = trans;
12274 callback.call(scope||this, null, arg, false);
12279 isLoading : function(){
12280 return this.trans ? true : false;
12284 * Abort the current server request.
12286 abort : function(){
12287 if(this.isLoading()){
12288 this.destroyTrans(this.trans);
12293 destroyTrans : function(trans, isLoaded){
12294 this.head.removeChild(document.getElementById(trans.scriptId));
12295 clearTimeout(trans.timeoutId);
12297 window[trans.cb] = undefined;
12299 delete window[trans.cb];
12302 // if hasn't been loaded, wait for load to remove it to prevent script error
12303 window[trans.cb] = function(){
12304 window[trans.cb] = undefined;
12306 delete window[trans.cb];
12313 handleResponse : function(o, trans){
12314 this.trans = false;
12315 this.destroyTrans(trans, true);
12318 result = trans.reader.readRecords(o);
12320 this.fireEvent("loadexception", this, o, trans.arg, e);
12321 trans.callback.call(trans.scope||window, null, trans.arg, false);
12324 this.fireEvent("load", this, o, trans.arg);
12325 trans.callback.call(trans.scope||window, result, trans.arg, true);
12329 handleFailure : function(trans){
12330 this.trans = false;
12331 this.destroyTrans(trans, false);
12332 this.fireEvent("loadexception", this, null, trans.arg);
12333 trans.callback.call(trans.scope||window, null, trans.arg, false);
12337 * Ext JS Library 1.1.1
12338 * Copyright(c) 2006-2007, Ext JS, LLC.
12340 * Originally Released Under LGPL - original licence link has changed is not relivant.
12343 * <script type="text/javascript">
12347 * @class Roo.data.JsonReader
12348 * @extends Roo.data.DataReader
12349 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12350 * based on mappings in a provided Roo.data.Record constructor.
12352 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12353 * in the reply previously.
12358 var RecordDef = Roo.data.Record.create([
12359 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12360 {name: 'occupation'} // This field will use "occupation" as the mapping.
12362 var myReader = new Roo.data.JsonReader({
12363 totalProperty: "results", // The property which contains the total dataset size (optional)
12364 root: "rows", // The property which contains an Array of row objects
12365 id: "id" // The property within each row object that provides an ID for the record (optional)
12369 * This would consume a JSON file like this:
12371 { 'results': 2, 'rows': [
12372 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12373 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12376 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12377 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12378 * paged from the remote server.
12379 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12380 * @cfg {String} root name of the property which contains the Array of row objects.
12381 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12382 * @cfg {Array} fields Array of field definition objects
12384 * Create a new JsonReader
12385 * @param {Object} meta Metadata configuration options
12386 * @param {Object} recordType Either an Array of field definition objects,
12387 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12389 Roo.data.JsonReader = function(meta, recordType){
12392 // set some defaults:
12393 Roo.applyIf(meta, {
12394 totalProperty: 'total',
12395 successProperty : 'success',
12400 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12402 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12405 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12406 * Used by Store query builder to append _requestMeta to params.
12409 metaFromRemote : false,
12411 * This method is only used by a DataProxy which has retrieved data from a remote server.
12412 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12413 * @return {Object} data A data block which is used by an Roo.data.Store object as
12414 * a cache of Roo.data.Records.
12416 read : function(response){
12417 var json = response.responseText;
12419 var o = /* eval:var:o */ eval("("+json+")");
12421 throw {message: "JsonReader.read: Json object not found"};
12427 this.metaFromRemote = true;
12428 this.meta = o.metaData;
12429 this.recordType = Roo.data.Record.create(o.metaData.fields);
12430 this.onMetaChange(this.meta, this.recordType, o);
12432 return this.readRecords(o);
12435 // private function a store will implement
12436 onMetaChange : function(meta, recordType, o){
12443 simpleAccess: function(obj, subsc) {
12450 getJsonAccessor: function(){
12452 return function(expr) {
12454 return(re.test(expr))
12455 ? new Function("obj", "return obj." + expr)
12460 return Roo.emptyFn;
12465 * Create a data block containing Roo.data.Records from an XML document.
12466 * @param {Object} o An object which contains an Array of row objects in the property specified
12467 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12468 * which contains the total size of the dataset.
12469 * @return {Object} data A data block which is used by an Roo.data.Store object as
12470 * a cache of Roo.data.Records.
12472 readRecords : function(o){
12474 * After any data loads, the raw JSON data is available for further custom processing.
12478 var s = this.meta, Record = this.recordType,
12479 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12481 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12483 if(s.totalProperty) {
12484 this.getTotal = this.getJsonAccessor(s.totalProperty);
12486 if(s.successProperty) {
12487 this.getSuccess = this.getJsonAccessor(s.successProperty);
12489 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12491 var g = this.getJsonAccessor(s.id);
12492 this.getId = function(rec) {
12494 return (r === undefined || r === "") ? null : r;
12497 this.getId = function(){return null;};
12500 for(var jj = 0; jj < fl; jj++){
12502 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12503 this.ef[jj] = this.getJsonAccessor(map);
12507 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12508 if(s.totalProperty){
12509 var vt = parseInt(this.getTotal(o), 10);
12514 if(s.successProperty){
12515 var vs = this.getSuccess(o);
12516 if(vs === false || vs === 'false'){
12521 for(var i = 0; i < c; i++){
12524 var id = this.getId(n);
12525 for(var j = 0; j < fl; j++){
12527 var v = this.ef[j](n);
12529 Roo.log('missing convert for ' + f.name);
12533 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12535 var record = new Record(values, id);
12537 records[i] = record;
12543 totalRecords : totalRecords
12548 * Ext JS Library 1.1.1
12549 * Copyright(c) 2006-2007, Ext JS, LLC.
12551 * Originally Released Under LGPL - original licence link has changed is not relivant.
12554 * <script type="text/javascript">
12558 * @class Roo.data.ArrayReader
12559 * @extends Roo.data.DataReader
12560 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12561 * Each element of that Array represents a row of data fields. The
12562 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12563 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12567 var RecordDef = Roo.data.Record.create([
12568 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12569 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12571 var myReader = new Roo.data.ArrayReader({
12572 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12576 * This would consume an Array like this:
12578 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12580 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12582 * Create a new JsonReader
12583 * @param {Object} meta Metadata configuration options.
12584 * @param {Object} recordType Either an Array of field definition objects
12585 * as specified to {@link Roo.data.Record#create},
12586 * or an {@link Roo.data.Record} object
12587 * created using {@link Roo.data.Record#create}.
12589 Roo.data.ArrayReader = function(meta, recordType){
12590 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12593 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12595 * Create a data block containing Roo.data.Records from an XML document.
12596 * @param {Object} o An Array of row objects which represents the dataset.
12597 * @return {Object} data A data block which is used by an Roo.data.Store object as
12598 * a cache of Roo.data.Records.
12600 readRecords : function(o){
12601 var sid = this.meta ? this.meta.id : null;
12602 var recordType = this.recordType, fields = recordType.prototype.fields;
12605 for(var i = 0; i < root.length; i++){
12608 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12609 for(var j = 0, jlen = fields.length; j < jlen; j++){
12610 var f = fields.items[j];
12611 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12612 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12614 values[f.name] = v;
12616 var record = new recordType(values, id);
12618 records[records.length] = record;
12622 totalRecords : records.length
12631 * @class Roo.bootstrap.ComboBox
12632 * @extends Roo.bootstrap.TriggerField
12633 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12634 * @cfg {Boolean} append (true|false) default false
12635 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12636 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12637 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12638 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12639 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12640 * @cfg {Boolean} animate default true
12641 * @cfg {Boolean} emptyResultText only for touch device
12642 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12643 * @cfg {String} emptyTitle default ''
12645 * Create a new ComboBox.
12646 * @param {Object} config Configuration options
12648 Roo.bootstrap.ComboBox = function(config){
12649 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12653 * Fires when the dropdown list is expanded
12654 * @param {Roo.bootstrap.ComboBox} combo This combo box
12659 * Fires when the dropdown list is collapsed
12660 * @param {Roo.bootstrap.ComboBox} combo This combo box
12664 * @event beforeselect
12665 * Fires before a list item is selected. Return false to cancel the selection.
12666 * @param {Roo.bootstrap.ComboBox} combo This combo box
12667 * @param {Roo.data.Record} record The data record returned from the underlying store
12668 * @param {Number} index The index of the selected item in the dropdown list
12670 'beforeselect' : true,
12673 * Fires when a list item is selected
12674 * @param {Roo.bootstrap.ComboBox} combo This combo box
12675 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12676 * @param {Number} index The index of the selected item in the dropdown list
12680 * @event beforequery
12681 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12682 * The event object passed has these properties:
12683 * @param {Roo.bootstrap.ComboBox} combo This combo box
12684 * @param {String} query The query
12685 * @param {Boolean} forceAll true to force "all" query
12686 * @param {Boolean} cancel true to cancel the query
12687 * @param {Object} e The query event object
12689 'beforequery': true,
12692 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12693 * @param {Roo.bootstrap.ComboBox} combo This combo box
12698 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12699 * @param {Roo.bootstrap.ComboBox} combo This combo box
12700 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12705 * Fires when the remove value from the combobox array
12706 * @param {Roo.bootstrap.ComboBox} combo This combo box
12710 * @event afterremove
12711 * Fires when the remove value from the combobox array
12712 * @param {Roo.bootstrap.ComboBox} combo This combo box
12714 'afterremove' : true,
12716 * @event specialfilter
12717 * Fires when specialfilter
12718 * @param {Roo.bootstrap.ComboBox} combo This combo box
12720 'specialfilter' : true,
12723 * Fires when tick the element
12724 * @param {Roo.bootstrap.ComboBox} combo This combo box
12728 * @event touchviewdisplay
12729 * Fires when touch view require special display (default is using displayField)
12730 * @param {Roo.bootstrap.ComboBox} combo This combo box
12731 * @param {Object} cfg set html .
12733 'touchviewdisplay' : true
12738 this.tickItems = [];
12740 this.selectedIndex = -1;
12741 if(this.mode == 'local'){
12742 if(config.queryDelay === undefined){
12743 this.queryDelay = 10;
12745 if(config.minChars === undefined){
12751 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12754 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12755 * rendering into an Roo.Editor, defaults to false)
12758 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12759 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12762 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12765 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12766 * the dropdown list (defaults to undefined, with no header element)
12770 * @cfg {String/Roo.Template} tpl The template to use to render the output
12774 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12776 listWidth: undefined,
12778 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12779 * mode = 'remote' or 'text' if mode = 'local')
12781 displayField: undefined,
12784 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12785 * mode = 'remote' or 'value' if mode = 'local').
12786 * Note: use of a valueField requires the user make a selection
12787 * in order for a value to be mapped.
12789 valueField: undefined,
12791 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12796 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12797 * field's data value (defaults to the underlying DOM element's name)
12799 hiddenName: undefined,
12801 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12805 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12807 selectedClass: 'active',
12810 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12814 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12815 * anchor positions (defaults to 'tl-bl')
12817 listAlign: 'tl-bl?',
12819 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12823 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12824 * query specified by the allQuery config option (defaults to 'query')
12826 triggerAction: 'query',
12828 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12829 * (defaults to 4, does not apply if editable = false)
12833 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12834 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12838 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12839 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12843 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12844 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12848 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12849 * when editable = true (defaults to false)
12851 selectOnFocus:false,
12853 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12855 queryParam: 'query',
12857 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12858 * when mode = 'remote' (defaults to 'Loading...')
12860 loadingText: 'Loading...',
12862 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12866 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12870 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12871 * traditional select (defaults to true)
12875 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12879 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12883 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12884 * listWidth has a higher value)
12888 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12889 * allow the user to set arbitrary text into the field (defaults to false)
12891 forceSelection:false,
12893 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12894 * if typeAhead = true (defaults to 250)
12896 typeAheadDelay : 250,
12898 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12899 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12901 valueNotFoundText : undefined,
12903 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12905 blockFocus : false,
12908 * @cfg {Boolean} disableClear Disable showing of clear button.
12910 disableClear : false,
12912 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12914 alwaysQuery : false,
12917 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12922 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12924 invalidClass : "has-warning",
12927 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12929 validClass : "has-success",
12932 * @cfg {Boolean} specialFilter (true|false) special filter default false
12934 specialFilter : false,
12937 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12939 mobileTouchView : true,
12942 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12944 useNativeIOS : false,
12946 ios_options : false,
12958 btnPosition : 'right',
12959 triggerList : true,
12960 showToggleBtn : true,
12962 emptyResultText: 'Empty',
12963 triggerText : 'Select',
12966 // element that contains real text value.. (when hidden is used..)
12968 getAutoCreate : function()
12973 * Render classic select for iso
12976 if(Roo.isIOS && this.useNativeIOS){
12977 cfg = this.getAutoCreateNativeIOS();
12985 if(Roo.isTouch && this.mobileTouchView){
12986 cfg = this.getAutoCreateTouchView();
12993 if(!this.tickable){
12994 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12999 * ComboBox with tickable selections
13002 var align = this.labelAlign || this.parentLabelAlign();
13005 cls : 'form-group roo-combobox-tickable' //input-group
13008 var btn_text_select = '';
13009 var btn_text_done = '';
13010 var btn_text_cancel = '';
13012 if (this.btn_text_show) {
13013 btn_text_select = 'Select';
13014 btn_text_done = 'Done';
13015 btn_text_cancel = 'Cancel';
13020 cls : 'tickable-buttons',
13025 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13026 //html : this.triggerText
13027 html: btn_text_select
13033 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13035 html: btn_text_done
13041 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13043 html: btn_text_cancel
13049 buttons.cn.unshift({
13051 cls: 'roo-select2-search-field-input'
13057 Roo.each(buttons.cn, function(c){
13059 c.cls += ' btn-' + _this.size;
13062 if (_this.disabled) {
13073 cls: 'form-hidden-field'
13077 cls: 'roo-select2-choices',
13081 cls: 'roo-select2-search-field',
13092 cls: 'roo-select2-container input-group roo-select2-container-multi',
13097 // cls: 'typeahead typeahead-long dropdown-menu',
13098 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13103 if(this.hasFeedback && !this.allowBlank){
13107 cls: 'glyphicon form-control-feedback'
13110 combobox.cn.push(feedback);
13114 if (align ==='left' && this.fieldLabel.length) {
13116 cfg.cls += ' roo-form-group-label-left';
13121 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13122 tooltip : 'This field is required'
13127 cls : 'control-label',
13128 html : this.fieldLabel
13140 var labelCfg = cfg.cn[1];
13141 var contentCfg = cfg.cn[2];
13144 if(this.indicatorpos == 'right'){
13150 cls : 'control-label',
13154 html : this.fieldLabel
13158 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13159 tooltip : 'This field is required'
13174 labelCfg = cfg.cn[0];
13175 contentCfg = cfg.cn[1];
13179 if(this.labelWidth > 12){
13180 labelCfg.style = "width: " + this.labelWidth + 'px';
13183 if(this.labelWidth < 13 && this.labelmd == 0){
13184 this.labelmd = this.labelWidth;
13187 if(this.labellg > 0){
13188 labelCfg.cls += ' col-lg-' + this.labellg;
13189 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13192 if(this.labelmd > 0){
13193 labelCfg.cls += ' col-md-' + this.labelmd;
13194 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13197 if(this.labelsm > 0){
13198 labelCfg.cls += ' col-sm-' + this.labelsm;
13199 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13202 if(this.labelxs > 0){
13203 labelCfg.cls += ' col-xs-' + this.labelxs;
13204 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13208 } else if ( this.fieldLabel.length) {
13209 // Roo.log(" label");
13213 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13214 tooltip : 'This field is required'
13218 //cls : 'input-group-addon',
13219 html : this.fieldLabel
13224 if(this.indicatorpos == 'right'){
13228 //cls : 'input-group-addon',
13229 html : this.fieldLabel
13233 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13234 tooltip : 'This field is required'
13243 // Roo.log(" no label && no align");
13250 ['xs','sm','md','lg'].map(function(size){
13251 if (settings[size]) {
13252 cfg.cls += ' col-' + size + '-' + settings[size];
13260 _initEventsCalled : false,
13263 initEvents: function()
13265 if (this._initEventsCalled) { // as we call render... prevent looping...
13268 this._initEventsCalled = true;
13271 throw "can not find store for combo";
13274 this.indicator = this.indicatorEl();
13276 this.store = Roo.factory(this.store, Roo.data);
13277 this.store.parent = this;
13279 // if we are building from html. then this element is so complex, that we can not really
13280 // use the rendered HTML.
13281 // so we have to trash and replace the previous code.
13282 if (Roo.XComponent.build_from_html) {
13283 // remove this element....
13284 var e = this.el.dom, k=0;
13285 while (e ) { e = e.previousSibling; ++k;}
13290 this.rendered = false;
13292 this.render(this.parent().getChildContainer(true), k);
13295 if(Roo.isIOS && this.useNativeIOS){
13296 this.initIOSView();
13304 if(Roo.isTouch && this.mobileTouchView){
13305 this.initTouchView();
13310 this.initTickableEvents();
13314 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13316 if(this.hiddenName){
13318 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13320 this.hiddenField.dom.value =
13321 this.hiddenValue !== undefined ? this.hiddenValue :
13322 this.value !== undefined ? this.value : '';
13324 // prevent input submission
13325 this.el.dom.removeAttribute('name');
13326 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13331 // this.el.dom.setAttribute('autocomplete', 'off');
13334 var cls = 'x-combo-list';
13336 //this.list = new Roo.Layer({
13337 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13343 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13344 _this.list.setWidth(lw);
13347 this.list.on('mouseover', this.onViewOver, this);
13348 this.list.on('mousemove', this.onViewMove, this);
13349 this.list.on('scroll', this.onViewScroll, this);
13352 this.list.swallowEvent('mousewheel');
13353 this.assetHeight = 0;
13356 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13357 this.assetHeight += this.header.getHeight();
13360 this.innerList = this.list.createChild({cls:cls+'-inner'});
13361 this.innerList.on('mouseover', this.onViewOver, this);
13362 this.innerList.on('mousemove', this.onViewMove, this);
13363 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13365 if(this.allowBlank && !this.pageSize && !this.disableClear){
13366 this.footer = this.list.createChild({cls:cls+'-ft'});
13367 this.pageTb = new Roo.Toolbar(this.footer);
13371 this.footer = this.list.createChild({cls:cls+'-ft'});
13372 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13373 {pageSize: this.pageSize});
13377 if (this.pageTb && this.allowBlank && !this.disableClear) {
13379 this.pageTb.add(new Roo.Toolbar.Fill(), {
13380 cls: 'x-btn-icon x-btn-clear',
13382 handler: function()
13385 _this.clearValue();
13386 _this.onSelect(false, -1);
13391 this.assetHeight += this.footer.getHeight();
13396 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13399 this.view = new Roo.View(this.list, this.tpl, {
13400 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13402 //this.view.wrapEl.setDisplayed(false);
13403 this.view.on('click', this.onViewClick, this);
13406 this.store.on('beforeload', this.onBeforeLoad, this);
13407 this.store.on('load', this.onLoad, this);
13408 this.store.on('loadexception', this.onLoadException, this);
13410 if(this.resizable){
13411 this.resizer = new Roo.Resizable(this.list, {
13412 pinned:true, handles:'se'
13414 this.resizer.on('resize', function(r, w, h){
13415 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13416 this.listWidth = w;
13417 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13418 this.restrictHeight();
13420 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13423 if(!this.editable){
13424 this.editable = true;
13425 this.setEditable(false);
13430 if (typeof(this.events.add.listeners) != 'undefined') {
13432 this.addicon = this.wrap.createChild(
13433 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13435 this.addicon.on('click', function(e) {
13436 this.fireEvent('add', this);
13439 if (typeof(this.events.edit.listeners) != 'undefined') {
13441 this.editicon = this.wrap.createChild(
13442 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13443 if (this.addicon) {
13444 this.editicon.setStyle('margin-left', '40px');
13446 this.editicon.on('click', function(e) {
13448 // we fire even if inothing is selected..
13449 this.fireEvent('edit', this, this.lastData );
13455 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13456 "up" : function(e){
13457 this.inKeyMode = true;
13461 "down" : function(e){
13462 if(!this.isExpanded()){
13463 this.onTriggerClick();
13465 this.inKeyMode = true;
13470 "enter" : function(e){
13471 // this.onViewClick();
13475 if(this.fireEvent("specialkey", this, e)){
13476 this.onViewClick(false);
13482 "esc" : function(e){
13486 "tab" : function(e){
13489 if(this.fireEvent("specialkey", this, e)){
13490 this.onViewClick(false);
13498 doRelay : function(foo, bar, hname){
13499 if(hname == 'down' || this.scope.isExpanded()){
13500 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13509 this.queryDelay = Math.max(this.queryDelay || 10,
13510 this.mode == 'local' ? 10 : 250);
13513 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13515 if(this.typeAhead){
13516 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13518 if(this.editable !== false){
13519 this.inputEl().on("keyup", this.onKeyUp, this);
13521 if(this.forceSelection){
13522 this.inputEl().on('blur', this.doForce, this);
13526 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13527 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13531 initTickableEvents: function()
13535 if(this.hiddenName){
13537 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13539 this.hiddenField.dom.value =
13540 this.hiddenValue !== undefined ? this.hiddenValue :
13541 this.value !== undefined ? this.value : '';
13543 // prevent input submission
13544 this.el.dom.removeAttribute('name');
13545 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13550 // this.list = this.el.select('ul.dropdown-menu',true).first();
13552 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13553 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13554 if(this.triggerList){
13555 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13558 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13559 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13561 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13562 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13564 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13565 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13567 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13568 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13569 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13572 this.cancelBtn.hide();
13577 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13578 _this.list.setWidth(lw);
13581 this.list.on('mouseover', this.onViewOver, this);
13582 this.list.on('mousemove', this.onViewMove, this);
13584 this.list.on('scroll', this.onViewScroll, this);
13587 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13590 this.view = new Roo.View(this.list, this.tpl, {
13591 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13594 //this.view.wrapEl.setDisplayed(false);
13595 this.view.on('click', this.onViewClick, this);
13599 this.store.on('beforeload', this.onBeforeLoad, this);
13600 this.store.on('load', this.onLoad, this);
13601 this.store.on('loadexception', this.onLoadException, this);
13604 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13605 "up" : function(e){
13606 this.inKeyMode = true;
13610 "down" : function(e){
13611 this.inKeyMode = true;
13615 "enter" : function(e){
13616 if(this.fireEvent("specialkey", this, e)){
13617 this.onViewClick(false);
13623 "esc" : function(e){
13624 this.onTickableFooterButtonClick(e, false, false);
13627 "tab" : function(e){
13628 this.fireEvent("specialkey", this, e);
13630 this.onTickableFooterButtonClick(e, false, false);
13637 doRelay : function(e, fn, key){
13638 if(this.scope.isExpanded()){
13639 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13648 this.queryDelay = Math.max(this.queryDelay || 10,
13649 this.mode == 'local' ? 10 : 250);
13652 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13654 if(this.typeAhead){
13655 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13658 if(this.editable !== false){
13659 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13662 this.indicator = this.indicatorEl();
13664 if(this.indicator){
13665 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13666 this.indicator.hide();
13671 onDestroy : function(){
13673 this.view.setStore(null);
13674 this.view.el.removeAllListeners();
13675 this.view.el.remove();
13676 this.view.purgeListeners();
13679 this.list.dom.innerHTML = '';
13683 this.store.un('beforeload', this.onBeforeLoad, this);
13684 this.store.un('load', this.onLoad, this);
13685 this.store.un('loadexception', this.onLoadException, this);
13687 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13691 fireKey : function(e){
13692 if(e.isNavKeyPress() && !this.list.isVisible()){
13693 this.fireEvent("specialkey", this, e);
13698 onResize: function(w, h){
13699 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13701 // if(typeof w != 'number'){
13702 // // we do not handle it!?!?
13705 // var tw = this.trigger.getWidth();
13706 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13707 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13709 // this.inputEl().setWidth( this.adjustWidth('input', x));
13711 // //this.trigger.setStyle('left', x+'px');
13713 // if(this.list && this.listWidth === undefined){
13714 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13715 // this.list.setWidth(lw);
13716 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13724 * Allow or prevent the user from directly editing the field text. If false is passed,
13725 * the user will only be able to select from the items defined in the dropdown list. This method
13726 * is the runtime equivalent of setting the 'editable' config option at config time.
13727 * @param {Boolean} value True to allow the user to directly edit the field text
13729 setEditable : function(value){
13730 if(value == this.editable){
13733 this.editable = value;
13735 this.inputEl().dom.setAttribute('readOnly', true);
13736 this.inputEl().on('mousedown', this.onTriggerClick, this);
13737 this.inputEl().addClass('x-combo-noedit');
13739 this.inputEl().dom.setAttribute('readOnly', false);
13740 this.inputEl().un('mousedown', this.onTriggerClick, this);
13741 this.inputEl().removeClass('x-combo-noedit');
13747 onBeforeLoad : function(combo,opts){
13748 if(!this.hasFocus){
13752 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13754 this.restrictHeight();
13755 this.selectedIndex = -1;
13759 onLoad : function(){
13761 this.hasQuery = false;
13763 if(!this.hasFocus){
13767 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13768 this.loading.hide();
13771 if(this.store.getCount() > 0){
13774 this.restrictHeight();
13775 if(this.lastQuery == this.allQuery){
13776 if(this.editable && !this.tickable){
13777 this.inputEl().dom.select();
13781 !this.selectByValue(this.value, true) &&
13784 !this.store.lastOptions ||
13785 typeof(this.store.lastOptions.add) == 'undefined' ||
13786 this.store.lastOptions.add != true
13789 this.select(0, true);
13792 if(this.autoFocus){
13795 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13796 this.taTask.delay(this.typeAheadDelay);
13800 this.onEmptyResults();
13806 onLoadException : function()
13808 this.hasQuery = false;
13810 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13811 this.loading.hide();
13814 if(this.tickable && this.editable){
13819 // only causes errors at present
13820 //Roo.log(this.store.reader.jsonData);
13821 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13823 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13829 onTypeAhead : function(){
13830 if(this.store.getCount() > 0){
13831 var r = this.store.getAt(0);
13832 var newValue = r.data[this.displayField];
13833 var len = newValue.length;
13834 var selStart = this.getRawValue().length;
13836 if(selStart != len){
13837 this.setRawValue(newValue);
13838 this.selectText(selStart, newValue.length);
13844 onSelect : function(record, index){
13846 if(this.fireEvent('beforeselect', this, record, index) !== false){
13848 this.setFromData(index > -1 ? record.data : false);
13851 this.fireEvent('select', this, record, index);
13856 * Returns the currently selected field value or empty string if no value is set.
13857 * @return {String} value The selected value
13859 getValue : function()
13861 if(Roo.isIOS && this.useNativeIOS){
13862 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13866 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13869 if(this.valueField){
13870 return typeof this.value != 'undefined' ? this.value : '';
13872 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13876 getRawValue : function()
13878 if(Roo.isIOS && this.useNativeIOS){
13879 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13882 var v = this.inputEl().getValue();
13888 * Clears any text/value currently set in the field
13890 clearValue : function(){
13892 if(this.hiddenField){
13893 this.hiddenField.dom.value = '';
13896 this.setRawValue('');
13897 this.lastSelectionText = '';
13898 this.lastData = false;
13900 var close = this.closeTriggerEl();
13911 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13912 * will be displayed in the field. If the value does not match the data value of an existing item,
13913 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13914 * Otherwise the field will be blank (although the value will still be set).
13915 * @param {String} value The value to match
13917 setValue : function(v)
13919 if(Roo.isIOS && this.useNativeIOS){
13920 this.setIOSValue(v);
13930 if(this.valueField){
13931 var r = this.findRecord(this.valueField, v);
13933 text = r.data[this.displayField];
13934 }else if(this.valueNotFoundText !== undefined){
13935 text = this.valueNotFoundText;
13938 this.lastSelectionText = text;
13939 if(this.hiddenField){
13940 this.hiddenField.dom.value = v;
13942 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13945 var close = this.closeTriggerEl();
13948 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13954 * @property {Object} the last set data for the element
13959 * Sets the value of the field based on a object which is related to the record format for the store.
13960 * @param {Object} value the value to set as. or false on reset?
13962 setFromData : function(o){
13969 var dv = ''; // display value
13970 var vv = ''; // value value..
13972 if (this.displayField) {
13973 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13975 // this is an error condition!!!
13976 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13979 if(this.valueField){
13980 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13983 var close = this.closeTriggerEl();
13986 if(dv.length || vv * 1 > 0){
13988 this.blockFocus=true;
13994 if(this.hiddenField){
13995 this.hiddenField.dom.value = vv;
13997 this.lastSelectionText = dv;
13998 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14002 // no hidden field.. - we store the value in 'value', but still display
14003 // display field!!!!
14004 this.lastSelectionText = dv;
14005 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14012 reset : function(){
14013 // overridden so that last data is reset..
14020 this.setValue(this.originalValue);
14021 //this.clearInvalid();
14022 this.lastData = false;
14024 this.view.clearSelections();
14030 findRecord : function(prop, value){
14032 if(this.store.getCount() > 0){
14033 this.store.each(function(r){
14034 if(r.data[prop] == value){
14044 getName: function()
14046 // returns hidden if it's set..
14047 if (!this.rendered) {return ''};
14048 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14052 onViewMove : function(e, t){
14053 this.inKeyMode = false;
14057 onViewOver : function(e, t){
14058 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14061 var item = this.view.findItemFromChild(t);
14064 var index = this.view.indexOf(item);
14065 this.select(index, false);
14070 onViewClick : function(view, doFocus, el, e)
14072 var index = this.view.getSelectedIndexes()[0];
14074 var r = this.store.getAt(index);
14078 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14085 Roo.each(this.tickItems, function(v,k){
14087 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14089 _this.tickItems.splice(k, 1);
14091 if(typeof(e) == 'undefined' && view == false){
14092 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14104 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14105 this.tickItems.push(r.data);
14108 if(typeof(e) == 'undefined' && view == false){
14109 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14116 this.onSelect(r, index);
14118 if(doFocus !== false && !this.blockFocus){
14119 this.inputEl().focus();
14124 restrictHeight : function(){
14125 //this.innerList.dom.style.height = '';
14126 //var inner = this.innerList.dom;
14127 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14128 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14129 //this.list.beginUpdate();
14130 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14131 this.list.alignTo(this.inputEl(), this.listAlign);
14132 this.list.alignTo(this.inputEl(), this.listAlign);
14133 //this.list.endUpdate();
14137 onEmptyResults : function(){
14139 if(this.tickable && this.editable){
14140 this.hasFocus = false;
14141 this.restrictHeight();
14149 * Returns true if the dropdown list is expanded, else false.
14151 isExpanded : function(){
14152 return this.list.isVisible();
14156 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14157 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14158 * @param {String} value The data value of the item to select
14159 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14160 * selected item if it is not currently in view (defaults to true)
14161 * @return {Boolean} True if the value matched an item in the list, else false
14163 selectByValue : function(v, scrollIntoView){
14164 if(v !== undefined && v !== null){
14165 var r = this.findRecord(this.valueField || this.displayField, v);
14167 this.select(this.store.indexOf(r), scrollIntoView);
14175 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14176 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14177 * @param {Number} index The zero-based index of the list item to select
14178 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14179 * selected item if it is not currently in view (defaults to true)
14181 select : function(index, scrollIntoView){
14182 this.selectedIndex = index;
14183 this.view.select(index);
14184 if(scrollIntoView !== false){
14185 var el = this.view.getNode(index);
14187 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14190 this.list.scrollChildIntoView(el, false);
14196 selectNext : function(){
14197 var ct = this.store.getCount();
14199 if(this.selectedIndex == -1){
14201 }else if(this.selectedIndex < ct-1){
14202 this.select(this.selectedIndex+1);
14208 selectPrev : function(){
14209 var ct = this.store.getCount();
14211 if(this.selectedIndex == -1){
14213 }else if(this.selectedIndex != 0){
14214 this.select(this.selectedIndex-1);
14220 onKeyUp : function(e){
14221 if(this.editable !== false && !e.isSpecialKey()){
14222 this.lastKey = e.getKey();
14223 this.dqTask.delay(this.queryDelay);
14228 validateBlur : function(){
14229 return !this.list || !this.list.isVisible();
14233 initQuery : function(){
14235 var v = this.getRawValue();
14237 if(this.tickable && this.editable){
14238 v = this.tickableInputEl().getValue();
14245 doForce : function(){
14246 if(this.inputEl().dom.value.length > 0){
14247 this.inputEl().dom.value =
14248 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14254 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14255 * query allowing the query action to be canceled if needed.
14256 * @param {String} query The SQL query to execute
14257 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14258 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14259 * saved in the current store (defaults to false)
14261 doQuery : function(q, forceAll){
14263 if(q === undefined || q === null){
14268 forceAll: forceAll,
14272 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14277 forceAll = qe.forceAll;
14278 if(forceAll === true || (q.length >= this.minChars)){
14280 this.hasQuery = true;
14282 if(this.lastQuery != q || this.alwaysQuery){
14283 this.lastQuery = q;
14284 if(this.mode == 'local'){
14285 this.selectedIndex = -1;
14287 this.store.clearFilter();
14290 if(this.specialFilter){
14291 this.fireEvent('specialfilter', this);
14296 this.store.filter(this.displayField, q);
14299 this.store.fireEvent("datachanged", this.store);
14306 this.store.baseParams[this.queryParam] = q;
14308 var options = {params : this.getParams(q)};
14311 options.add = true;
14312 options.params.start = this.page * this.pageSize;
14315 this.store.load(options);
14318 * this code will make the page width larger, at the beginning, the list not align correctly,
14319 * we should expand the list on onLoad
14320 * so command out it
14325 this.selectedIndex = -1;
14330 this.loadNext = false;
14334 getParams : function(q){
14336 //p[this.queryParam] = q;
14340 p.limit = this.pageSize;
14346 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14348 collapse : function(){
14349 if(!this.isExpanded()){
14355 this.hasFocus = false;
14359 this.cancelBtn.hide();
14360 this.trigger.show();
14363 this.tickableInputEl().dom.value = '';
14364 this.tickableInputEl().blur();
14369 Roo.get(document).un('mousedown', this.collapseIf, this);
14370 Roo.get(document).un('mousewheel', this.collapseIf, this);
14371 if (!this.editable) {
14372 Roo.get(document).un('keydown', this.listKeyPress, this);
14374 this.fireEvent('collapse', this);
14380 collapseIf : function(e){
14381 var in_combo = e.within(this.el);
14382 var in_list = e.within(this.list);
14383 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14385 if (in_combo || in_list || is_list) {
14386 //e.stopPropagation();
14391 this.onTickableFooterButtonClick(e, false, false);
14399 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14401 expand : function(){
14403 if(this.isExpanded() || !this.hasFocus){
14407 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14408 this.list.setWidth(lw);
14414 this.restrictHeight();
14418 this.tickItems = Roo.apply([], this.item);
14421 this.cancelBtn.show();
14422 this.trigger.hide();
14425 this.tickableInputEl().focus();
14430 Roo.get(document).on('mousedown', this.collapseIf, this);
14431 Roo.get(document).on('mousewheel', this.collapseIf, this);
14432 if (!this.editable) {
14433 Roo.get(document).on('keydown', this.listKeyPress, this);
14436 this.fireEvent('expand', this);
14440 // Implements the default empty TriggerField.onTriggerClick function
14441 onTriggerClick : function(e)
14443 Roo.log('trigger click');
14445 if(this.disabled || !this.triggerList){
14450 this.loadNext = false;
14452 if(this.isExpanded()){
14454 if (!this.blockFocus) {
14455 this.inputEl().focus();
14459 this.hasFocus = true;
14460 if(this.triggerAction == 'all') {
14461 this.doQuery(this.allQuery, true);
14463 this.doQuery(this.getRawValue());
14465 if (!this.blockFocus) {
14466 this.inputEl().focus();
14471 onTickableTriggerClick : function(e)
14478 this.loadNext = false;
14479 this.hasFocus = true;
14481 if(this.triggerAction == 'all') {
14482 this.doQuery(this.allQuery, true);
14484 this.doQuery(this.getRawValue());
14488 onSearchFieldClick : function(e)
14490 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14491 this.onTickableFooterButtonClick(e, false, false);
14495 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14500 this.loadNext = false;
14501 this.hasFocus = true;
14503 if(this.triggerAction == 'all') {
14504 this.doQuery(this.allQuery, true);
14506 this.doQuery(this.getRawValue());
14510 listKeyPress : function(e)
14512 //Roo.log('listkeypress');
14513 // scroll to first matching element based on key pres..
14514 if (e.isSpecialKey()) {
14517 var k = String.fromCharCode(e.getKey()).toUpperCase();
14520 var csel = this.view.getSelectedNodes();
14521 var cselitem = false;
14523 var ix = this.view.indexOf(csel[0]);
14524 cselitem = this.store.getAt(ix);
14525 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14531 this.store.each(function(v) {
14533 // start at existing selection.
14534 if (cselitem.id == v.id) {
14540 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14541 match = this.store.indexOf(v);
14547 if (match === false) {
14548 return true; // no more action?
14551 this.view.select(match);
14552 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14553 sn.scrollIntoView(sn.dom.parentNode, false);
14556 onViewScroll : function(e, t){
14558 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){
14562 this.hasQuery = true;
14564 this.loading = this.list.select('.loading', true).first();
14566 if(this.loading === null){
14567 this.list.createChild({
14569 cls: 'loading roo-select2-more-results roo-select2-active',
14570 html: 'Loading more results...'
14573 this.loading = this.list.select('.loading', true).first();
14575 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14577 this.loading.hide();
14580 this.loading.show();
14585 this.loadNext = true;
14587 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14592 addItem : function(o)
14594 var dv = ''; // display value
14596 if (this.displayField) {
14597 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14599 // this is an error condition!!!
14600 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14607 var choice = this.choices.createChild({
14609 cls: 'roo-select2-search-choice',
14618 cls: 'roo-select2-search-choice-close fa fa-times',
14623 }, this.searchField);
14625 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14627 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14635 this.inputEl().dom.value = '';
14640 onRemoveItem : function(e, _self, o)
14642 e.preventDefault();
14644 this.lastItem = Roo.apply([], this.item);
14646 var index = this.item.indexOf(o.data) * 1;
14649 Roo.log('not this item?!');
14653 this.item.splice(index, 1);
14658 this.fireEvent('remove', this, e);
14664 syncValue : function()
14666 if(!this.item.length){
14673 Roo.each(this.item, function(i){
14674 if(_this.valueField){
14675 value.push(i[_this.valueField]);
14682 this.value = value.join(',');
14684 if(this.hiddenField){
14685 this.hiddenField.dom.value = this.value;
14688 this.store.fireEvent("datachanged", this.store);
14693 clearItem : function()
14695 if(!this.multiple){
14701 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14709 if(this.tickable && !Roo.isTouch){
14710 this.view.refresh();
14714 inputEl: function ()
14716 if(Roo.isIOS && this.useNativeIOS){
14717 return this.el.select('select.roo-ios-select', true).first();
14720 if(Roo.isTouch && this.mobileTouchView){
14721 return this.el.select('input.form-control',true).first();
14725 return this.searchField;
14728 return this.el.select('input.form-control',true).first();
14731 onTickableFooterButtonClick : function(e, btn, el)
14733 e.preventDefault();
14735 this.lastItem = Roo.apply([], this.item);
14737 if(btn && btn.name == 'cancel'){
14738 this.tickItems = Roo.apply([], this.item);
14747 Roo.each(this.tickItems, function(o){
14755 validate : function()
14757 if(this.getVisibilityEl().hasClass('hidden')){
14761 var v = this.getRawValue();
14764 v = this.getValue();
14767 if(this.disabled || this.allowBlank || v.length){
14772 this.markInvalid();
14776 tickableInputEl : function()
14778 if(!this.tickable || !this.editable){
14779 return this.inputEl();
14782 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14786 getAutoCreateTouchView : function()
14791 cls: 'form-group' //input-group
14797 type : this.inputType,
14798 cls : 'form-control x-combo-noedit',
14799 autocomplete: 'new-password',
14800 placeholder : this.placeholder || '',
14805 input.name = this.name;
14809 input.cls += ' input-' + this.size;
14812 if (this.disabled) {
14813 input.disabled = true;
14824 inputblock.cls += ' input-group';
14826 inputblock.cn.unshift({
14828 cls : 'input-group-addon',
14833 if(this.removable && !this.multiple){
14834 inputblock.cls += ' roo-removable';
14836 inputblock.cn.push({
14839 cls : 'roo-combo-removable-btn close'
14843 if(this.hasFeedback && !this.allowBlank){
14845 inputblock.cls += ' has-feedback';
14847 inputblock.cn.push({
14849 cls: 'glyphicon form-control-feedback'
14856 inputblock.cls += (this.before) ? '' : ' input-group';
14858 inputblock.cn.push({
14860 cls : 'input-group-addon',
14871 cls: 'form-hidden-field'
14885 cls: 'form-hidden-field'
14889 cls: 'roo-select2-choices',
14893 cls: 'roo-select2-search-field',
14906 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14912 if(!this.multiple && this.showToggleBtn){
14919 if (this.caret != false) {
14922 cls: 'fa fa-' + this.caret
14929 cls : 'input-group-addon btn dropdown-toggle',
14934 cls: 'combobox-clear',
14948 combobox.cls += ' roo-select2-container-multi';
14951 var align = this.labelAlign || this.parentLabelAlign();
14953 if (align ==='left' && this.fieldLabel.length) {
14958 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14959 tooltip : 'This field is required'
14963 cls : 'control-label',
14964 html : this.fieldLabel
14975 var labelCfg = cfg.cn[1];
14976 var contentCfg = cfg.cn[2];
14979 if(this.indicatorpos == 'right'){
14984 cls : 'control-label',
14988 html : this.fieldLabel
14992 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14993 tooltip : 'This field is required'
15006 labelCfg = cfg.cn[0];
15007 contentCfg = cfg.cn[1];
15012 if(this.labelWidth > 12){
15013 labelCfg.style = "width: " + this.labelWidth + 'px';
15016 if(this.labelWidth < 13 && this.labelmd == 0){
15017 this.labelmd = this.labelWidth;
15020 if(this.labellg > 0){
15021 labelCfg.cls += ' col-lg-' + this.labellg;
15022 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15025 if(this.labelmd > 0){
15026 labelCfg.cls += ' col-md-' + this.labelmd;
15027 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15030 if(this.labelsm > 0){
15031 labelCfg.cls += ' col-sm-' + this.labelsm;
15032 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15035 if(this.labelxs > 0){
15036 labelCfg.cls += ' col-xs-' + this.labelxs;
15037 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15041 } else if ( this.fieldLabel.length) {
15045 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15046 tooltip : 'This field is required'
15050 cls : 'control-label',
15051 html : this.fieldLabel
15062 if(this.indicatorpos == 'right'){
15066 cls : 'control-label',
15067 html : this.fieldLabel,
15071 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15072 tooltip : 'This field is required'
15089 var settings = this;
15091 ['xs','sm','md','lg'].map(function(size){
15092 if (settings[size]) {
15093 cfg.cls += ' col-' + size + '-' + settings[size];
15100 initTouchView : function()
15102 this.renderTouchView();
15104 this.touchViewEl.on('scroll', function(){
15105 this.el.dom.scrollTop = 0;
15108 this.originalValue = this.getValue();
15110 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15112 this.inputEl().on("click", this.showTouchView, this);
15113 if (this.triggerEl) {
15114 this.triggerEl.on("click", this.showTouchView, this);
15118 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15119 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15121 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15123 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15124 this.store.on('load', this.onTouchViewLoad, this);
15125 this.store.on('loadexception', this.onTouchViewLoadException, this);
15127 if(this.hiddenName){
15129 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15131 this.hiddenField.dom.value =
15132 this.hiddenValue !== undefined ? this.hiddenValue :
15133 this.value !== undefined ? this.value : '';
15135 this.el.dom.removeAttribute('name');
15136 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15140 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15141 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15144 if(this.removable && !this.multiple){
15145 var close = this.closeTriggerEl();
15147 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15148 close.on('click', this.removeBtnClick, this, close);
15152 * fix the bug in Safari iOS8
15154 this.inputEl().on("focus", function(e){
15155 document.activeElement.blur();
15163 renderTouchView : function()
15165 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15166 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15168 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15169 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15171 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15172 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15173 this.touchViewBodyEl.setStyle('overflow', 'auto');
15175 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15176 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15178 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15179 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15183 showTouchView : function()
15189 this.touchViewHeaderEl.hide();
15191 if(this.modalTitle.length){
15192 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15193 this.touchViewHeaderEl.show();
15196 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15197 this.touchViewEl.show();
15199 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15201 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15202 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15204 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15206 if(this.modalTitle.length){
15207 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15210 this.touchViewBodyEl.setHeight(bodyHeight);
15214 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15216 this.touchViewEl.addClass('in');
15219 this.doTouchViewQuery();
15223 hideTouchView : function()
15225 this.touchViewEl.removeClass('in');
15229 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15231 this.touchViewEl.setStyle('display', 'none');
15236 setTouchViewValue : function()
15243 Roo.each(this.tickItems, function(o){
15248 this.hideTouchView();
15251 doTouchViewQuery : function()
15260 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15264 if(!this.alwaysQuery || this.mode == 'local'){
15265 this.onTouchViewLoad();
15272 onTouchViewBeforeLoad : function(combo,opts)
15278 onTouchViewLoad : function()
15280 if(this.store.getCount() < 1){
15281 this.onTouchViewEmptyResults();
15285 this.clearTouchView();
15287 var rawValue = this.getRawValue();
15289 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15291 this.tickItems = [];
15293 this.store.data.each(function(d, rowIndex){
15294 var row = this.touchViewListGroup.createChild(template);
15296 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15297 row.addClass(d.data.cls);
15300 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15303 html : d.data[this.displayField]
15306 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15307 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15310 row.removeClass('selected');
15311 if(!this.multiple && this.valueField &&
15312 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15315 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15316 row.addClass('selected');
15319 if(this.multiple && this.valueField &&
15320 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15324 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15325 this.tickItems.push(d.data);
15328 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15332 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15334 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15336 if(this.modalTitle.length){
15337 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15340 var listHeight = this.touchViewListGroup.getHeight();
15344 if(firstChecked && listHeight > bodyHeight){
15345 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15350 onTouchViewLoadException : function()
15352 this.hideTouchView();
15355 onTouchViewEmptyResults : function()
15357 this.clearTouchView();
15359 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15361 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15365 clearTouchView : function()
15367 this.touchViewListGroup.dom.innerHTML = '';
15370 onTouchViewClick : function(e, el, o)
15372 e.preventDefault();
15375 var rowIndex = o.rowIndex;
15377 var r = this.store.getAt(rowIndex);
15379 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15381 if(!this.multiple){
15382 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15383 c.dom.removeAttribute('checked');
15386 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15388 this.setFromData(r.data);
15390 var close = this.closeTriggerEl();
15396 this.hideTouchView();
15398 this.fireEvent('select', this, r, rowIndex);
15403 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15404 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15405 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15409 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15410 this.addItem(r.data);
15411 this.tickItems.push(r.data);
15415 getAutoCreateNativeIOS : function()
15418 cls: 'form-group' //input-group,
15423 cls : 'roo-ios-select'
15427 combobox.name = this.name;
15430 if (this.disabled) {
15431 combobox.disabled = true;
15434 var settings = this;
15436 ['xs','sm','md','lg'].map(function(size){
15437 if (settings[size]) {
15438 cfg.cls += ' col-' + size + '-' + settings[size];
15448 initIOSView : function()
15450 this.store.on('load', this.onIOSViewLoad, this);
15455 onIOSViewLoad : function()
15457 if(this.store.getCount() < 1){
15461 this.clearIOSView();
15463 if(this.allowBlank) {
15465 var default_text = '-- SELECT --';
15467 if(this.placeholder.length){
15468 default_text = this.placeholder;
15471 if(this.emptyTitle.length){
15472 default_text += ' - ' + this.emptyTitle + ' -';
15475 var opt = this.inputEl().createChild({
15478 html : default_text
15482 o[this.valueField] = 0;
15483 o[this.displayField] = default_text;
15485 this.ios_options.push({
15492 this.store.data.each(function(d, rowIndex){
15496 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15497 html = d.data[this.displayField];
15502 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15503 value = d.data[this.valueField];
15512 if(this.value == d.data[this.valueField]){
15513 option['selected'] = true;
15516 var opt = this.inputEl().createChild(option);
15518 this.ios_options.push({
15525 this.inputEl().on('change', function(){
15526 this.fireEvent('select', this);
15531 clearIOSView: function()
15533 this.inputEl().dom.innerHTML = '';
15535 this.ios_options = [];
15538 setIOSValue: function(v)
15542 if(!this.ios_options){
15546 Roo.each(this.ios_options, function(opts){
15548 opts.el.dom.removeAttribute('selected');
15550 if(opts.data[this.valueField] != v){
15554 opts.el.dom.setAttribute('selected', true);
15560 * @cfg {Boolean} grow
15564 * @cfg {Number} growMin
15568 * @cfg {Number} growMax
15577 Roo.apply(Roo.bootstrap.ComboBox, {
15581 cls: 'modal-header',
15603 cls: 'list-group-item',
15607 cls: 'roo-combobox-list-group-item-value'
15611 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15625 listItemCheckbox : {
15627 cls: 'list-group-item',
15631 cls: 'roo-combobox-list-group-item-value'
15635 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15651 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15656 cls: 'modal-footer',
15664 cls: 'col-xs-6 text-left',
15667 cls: 'btn btn-danger roo-touch-view-cancel',
15673 cls: 'col-xs-6 text-right',
15676 cls: 'btn btn-success roo-touch-view-ok',
15687 Roo.apply(Roo.bootstrap.ComboBox, {
15689 touchViewTemplate : {
15691 cls: 'modal fade roo-combobox-touch-view',
15695 cls: 'modal-dialog',
15696 style : 'position:fixed', // we have to fix position....
15700 cls: 'modal-content',
15702 Roo.bootstrap.ComboBox.header,
15703 Roo.bootstrap.ComboBox.body,
15704 Roo.bootstrap.ComboBox.footer
15713 * Ext JS Library 1.1.1
15714 * Copyright(c) 2006-2007, Ext JS, LLC.
15716 * Originally Released Under LGPL - original licence link has changed is not relivant.
15719 * <script type="text/javascript">
15724 * @extends Roo.util.Observable
15725 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15726 * This class also supports single and multi selection modes. <br>
15727 * Create a data model bound view:
15729 var store = new Roo.data.Store(...);
15731 var view = new Roo.View({
15733 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15735 singleSelect: true,
15736 selectedClass: "ydataview-selected",
15740 // listen for node click?
15741 view.on("click", function(vw, index, node, e){
15742 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15746 dataModel.load("foobar.xml");
15748 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15750 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15751 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15753 * Note: old style constructor is still suported (container, template, config)
15756 * Create a new View
15757 * @param {Object} config The config object
15760 Roo.View = function(config, depreciated_tpl, depreciated_config){
15762 this.parent = false;
15764 if (typeof(depreciated_tpl) == 'undefined') {
15765 // new way.. - universal constructor.
15766 Roo.apply(this, config);
15767 this.el = Roo.get(this.el);
15770 this.el = Roo.get(config);
15771 this.tpl = depreciated_tpl;
15772 Roo.apply(this, depreciated_config);
15774 this.wrapEl = this.el.wrap().wrap();
15775 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15778 if(typeof(this.tpl) == "string"){
15779 this.tpl = new Roo.Template(this.tpl);
15781 // support xtype ctors..
15782 this.tpl = new Roo.factory(this.tpl, Roo);
15786 this.tpl.compile();
15791 * @event beforeclick
15792 * Fires before a click is processed. Returns false to cancel the default action.
15793 * @param {Roo.View} this
15794 * @param {Number} index The index of the target node
15795 * @param {HTMLElement} node The target node
15796 * @param {Roo.EventObject} e The raw event object
15798 "beforeclick" : true,
15801 * Fires when a template node is clicked.
15802 * @param {Roo.View} this
15803 * @param {Number} index The index of the target node
15804 * @param {HTMLElement} node The target node
15805 * @param {Roo.EventObject} e The raw event object
15810 * Fires when a template node is double clicked.
15811 * @param {Roo.View} this
15812 * @param {Number} index The index of the target node
15813 * @param {HTMLElement} node The target node
15814 * @param {Roo.EventObject} e The raw event object
15818 * @event contextmenu
15819 * Fires when a template node is right clicked.
15820 * @param {Roo.View} this
15821 * @param {Number} index The index of the target node
15822 * @param {HTMLElement} node The target node
15823 * @param {Roo.EventObject} e The raw event object
15825 "contextmenu" : true,
15827 * @event selectionchange
15828 * Fires when the selected nodes change.
15829 * @param {Roo.View} this
15830 * @param {Array} selections Array of the selected nodes
15832 "selectionchange" : true,
15835 * @event beforeselect
15836 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15837 * @param {Roo.View} this
15838 * @param {HTMLElement} node The node to be selected
15839 * @param {Array} selections Array of currently selected nodes
15841 "beforeselect" : true,
15843 * @event preparedata
15844 * Fires on every row to render, to allow you to change the data.
15845 * @param {Roo.View} this
15846 * @param {Object} data to be rendered (change this)
15848 "preparedata" : true
15856 "click": this.onClick,
15857 "dblclick": this.onDblClick,
15858 "contextmenu": this.onContextMenu,
15862 this.selections = [];
15864 this.cmp = new Roo.CompositeElementLite([]);
15866 this.store = Roo.factory(this.store, Roo.data);
15867 this.setStore(this.store, true);
15870 if ( this.footer && this.footer.xtype) {
15872 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15874 this.footer.dataSource = this.store;
15875 this.footer.container = fctr;
15876 this.footer = Roo.factory(this.footer, Roo);
15877 fctr.insertFirst(this.el);
15879 // this is a bit insane - as the paging toolbar seems to detach the el..
15880 // dom.parentNode.parentNode.parentNode
15881 // they get detached?
15885 Roo.View.superclass.constructor.call(this);
15890 Roo.extend(Roo.View, Roo.util.Observable, {
15893 * @cfg {Roo.data.Store} store Data store to load data from.
15898 * @cfg {String|Roo.Element} el The container element.
15903 * @cfg {String|Roo.Template} tpl The template used by this View
15907 * @cfg {String} dataName the named area of the template to use as the data area
15908 * Works with domtemplates roo-name="name"
15912 * @cfg {String} selectedClass The css class to add to selected nodes
15914 selectedClass : "x-view-selected",
15916 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15921 * @cfg {String} text to display on mask (default Loading)
15925 * @cfg {Boolean} multiSelect Allow multiple selection
15927 multiSelect : false,
15929 * @cfg {Boolean} singleSelect Allow single selection
15931 singleSelect: false,
15934 * @cfg {Boolean} toggleSelect - selecting
15936 toggleSelect : false,
15939 * @cfg {Boolean} tickable - selecting
15944 * Returns the element this view is bound to.
15945 * @return {Roo.Element}
15947 getEl : function(){
15948 return this.wrapEl;
15954 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15956 refresh : function(){
15957 //Roo.log('refresh');
15960 // if we are using something like 'domtemplate', then
15961 // the what gets used is:
15962 // t.applySubtemplate(NAME, data, wrapping data..)
15963 // the outer template then get' applied with
15964 // the store 'extra data'
15965 // and the body get's added to the
15966 // roo-name="data" node?
15967 // <span class='roo-tpl-{name}'></span> ?????
15971 this.clearSelections();
15972 this.el.update("");
15974 var records = this.store.getRange();
15975 if(records.length < 1) {
15977 // is this valid?? = should it render a template??
15979 this.el.update(this.emptyText);
15983 if (this.dataName) {
15984 this.el.update(t.apply(this.store.meta)); //????
15985 el = this.el.child('.roo-tpl-' + this.dataName);
15988 for(var i = 0, len = records.length; i < len; i++){
15989 var data = this.prepareData(records[i].data, i, records[i]);
15990 this.fireEvent("preparedata", this, data, i, records[i]);
15992 var d = Roo.apply({}, data);
15995 Roo.apply(d, {'roo-id' : Roo.id()});
15999 Roo.each(this.parent.item, function(item){
16000 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16003 Roo.apply(d, {'roo-data-checked' : 'checked'});
16007 html[html.length] = Roo.util.Format.trim(
16009 t.applySubtemplate(this.dataName, d, this.store.meta) :
16016 el.update(html.join(""));
16017 this.nodes = el.dom.childNodes;
16018 this.updateIndexes(0);
16023 * Function to override to reformat the data that is sent to
16024 * the template for each node.
16025 * DEPRICATED - use the preparedata event handler.
16026 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16027 * a JSON object for an UpdateManager bound view).
16029 prepareData : function(data, index, record)
16031 this.fireEvent("preparedata", this, data, index, record);
16035 onUpdate : function(ds, record){
16036 // Roo.log('on update');
16037 this.clearSelections();
16038 var index = this.store.indexOf(record);
16039 var n = this.nodes[index];
16040 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16041 n.parentNode.removeChild(n);
16042 this.updateIndexes(index, index);
16048 onAdd : function(ds, records, index)
16050 //Roo.log(['on Add', ds, records, index] );
16051 this.clearSelections();
16052 if(this.nodes.length == 0){
16056 var n = this.nodes[index];
16057 for(var i = 0, len = records.length; i < len; i++){
16058 var d = this.prepareData(records[i].data, i, records[i]);
16060 this.tpl.insertBefore(n, d);
16063 this.tpl.append(this.el, d);
16066 this.updateIndexes(index);
16069 onRemove : function(ds, record, index){
16070 // Roo.log('onRemove');
16071 this.clearSelections();
16072 var el = this.dataName ?
16073 this.el.child('.roo-tpl-' + this.dataName) :
16076 el.dom.removeChild(this.nodes[index]);
16077 this.updateIndexes(index);
16081 * Refresh an individual node.
16082 * @param {Number} index
16084 refreshNode : function(index){
16085 this.onUpdate(this.store, this.store.getAt(index));
16088 updateIndexes : function(startIndex, endIndex){
16089 var ns = this.nodes;
16090 startIndex = startIndex || 0;
16091 endIndex = endIndex || ns.length - 1;
16092 for(var i = startIndex; i <= endIndex; i++){
16093 ns[i].nodeIndex = i;
16098 * Changes the data store this view uses and refresh the view.
16099 * @param {Store} store
16101 setStore : function(store, initial){
16102 if(!initial && this.store){
16103 this.store.un("datachanged", this.refresh);
16104 this.store.un("add", this.onAdd);
16105 this.store.un("remove", this.onRemove);
16106 this.store.un("update", this.onUpdate);
16107 this.store.un("clear", this.refresh);
16108 this.store.un("beforeload", this.onBeforeLoad);
16109 this.store.un("load", this.onLoad);
16110 this.store.un("loadexception", this.onLoad);
16114 store.on("datachanged", this.refresh, this);
16115 store.on("add", this.onAdd, this);
16116 store.on("remove", this.onRemove, this);
16117 store.on("update", this.onUpdate, this);
16118 store.on("clear", this.refresh, this);
16119 store.on("beforeload", this.onBeforeLoad, this);
16120 store.on("load", this.onLoad, this);
16121 store.on("loadexception", this.onLoad, this);
16129 * onbeforeLoad - masks the loading area.
16132 onBeforeLoad : function(store,opts)
16134 //Roo.log('onBeforeLoad');
16136 this.el.update("");
16138 this.el.mask(this.mask ? this.mask : "Loading" );
16140 onLoad : function ()
16147 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16148 * @param {HTMLElement} node
16149 * @return {HTMLElement} The template node
16151 findItemFromChild : function(node){
16152 var el = this.dataName ?
16153 this.el.child('.roo-tpl-' + this.dataName,true) :
16156 if(!node || node.parentNode == el){
16159 var p = node.parentNode;
16160 while(p && p != el){
16161 if(p.parentNode == el){
16170 onClick : function(e){
16171 var item = this.findItemFromChild(e.getTarget());
16173 var index = this.indexOf(item);
16174 if(this.onItemClick(item, index, e) !== false){
16175 this.fireEvent("click", this, index, item, e);
16178 this.clearSelections();
16183 onContextMenu : function(e){
16184 var item = this.findItemFromChild(e.getTarget());
16186 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16191 onDblClick : function(e){
16192 var item = this.findItemFromChild(e.getTarget());
16194 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16198 onItemClick : function(item, index, e)
16200 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16203 if (this.toggleSelect) {
16204 var m = this.isSelected(item) ? 'unselect' : 'select';
16207 _t[m](item, true, false);
16210 if(this.multiSelect || this.singleSelect){
16211 if(this.multiSelect && e.shiftKey && this.lastSelection){
16212 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16214 this.select(item, this.multiSelect && e.ctrlKey);
16215 this.lastSelection = item;
16218 if(!this.tickable){
16219 e.preventDefault();
16227 * Get the number of selected nodes.
16230 getSelectionCount : function(){
16231 return this.selections.length;
16235 * Get the currently selected nodes.
16236 * @return {Array} An array of HTMLElements
16238 getSelectedNodes : function(){
16239 return this.selections;
16243 * Get the indexes of the selected nodes.
16246 getSelectedIndexes : function(){
16247 var indexes = [], s = this.selections;
16248 for(var i = 0, len = s.length; i < len; i++){
16249 indexes.push(s[i].nodeIndex);
16255 * Clear all selections
16256 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16258 clearSelections : function(suppressEvent){
16259 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16260 this.cmp.elements = this.selections;
16261 this.cmp.removeClass(this.selectedClass);
16262 this.selections = [];
16263 if(!suppressEvent){
16264 this.fireEvent("selectionchange", this, this.selections);
16270 * Returns true if the passed node is selected
16271 * @param {HTMLElement/Number} node The node or node index
16272 * @return {Boolean}
16274 isSelected : function(node){
16275 var s = this.selections;
16279 node = this.getNode(node);
16280 return s.indexOf(node) !== -1;
16285 * @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
16286 * @param {Boolean} keepExisting (optional) true to keep existing selections
16287 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16289 select : function(nodeInfo, keepExisting, suppressEvent){
16290 if(nodeInfo instanceof Array){
16292 this.clearSelections(true);
16294 for(var i = 0, len = nodeInfo.length; i < len; i++){
16295 this.select(nodeInfo[i], true, true);
16299 var node = this.getNode(nodeInfo);
16300 if(!node || this.isSelected(node)){
16301 return; // already selected.
16304 this.clearSelections(true);
16307 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16308 Roo.fly(node).addClass(this.selectedClass);
16309 this.selections.push(node);
16310 if(!suppressEvent){
16311 this.fireEvent("selectionchange", this, this.selections);
16319 * @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
16320 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16321 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16323 unselect : function(nodeInfo, keepExisting, suppressEvent)
16325 if(nodeInfo instanceof Array){
16326 Roo.each(this.selections, function(s) {
16327 this.unselect(s, nodeInfo);
16331 var node = this.getNode(nodeInfo);
16332 if(!node || !this.isSelected(node)){
16333 //Roo.log("not selected");
16334 return; // not selected.
16338 Roo.each(this.selections, function(s) {
16340 Roo.fly(node).removeClass(this.selectedClass);
16347 this.selections= ns;
16348 this.fireEvent("selectionchange", this, this.selections);
16352 * Gets a template node.
16353 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16354 * @return {HTMLElement} The node or null if it wasn't found
16356 getNode : function(nodeInfo){
16357 if(typeof nodeInfo == "string"){
16358 return document.getElementById(nodeInfo);
16359 }else if(typeof nodeInfo == "number"){
16360 return this.nodes[nodeInfo];
16366 * Gets a range template nodes.
16367 * @param {Number} startIndex
16368 * @param {Number} endIndex
16369 * @return {Array} An array of nodes
16371 getNodes : function(start, end){
16372 var ns = this.nodes;
16373 start = start || 0;
16374 end = typeof end == "undefined" ? ns.length - 1 : end;
16377 for(var i = start; i <= end; i++){
16381 for(var i = start; i >= end; i--){
16389 * Finds the index of the passed node
16390 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16391 * @return {Number} The index of the node or -1
16393 indexOf : function(node){
16394 node = this.getNode(node);
16395 if(typeof node.nodeIndex == "number"){
16396 return node.nodeIndex;
16398 var ns = this.nodes;
16399 for(var i = 0, len = ns.length; i < len; i++){
16410 * based on jquery fullcalendar
16414 Roo.bootstrap = Roo.bootstrap || {};
16416 * @class Roo.bootstrap.Calendar
16417 * @extends Roo.bootstrap.Component
16418 * Bootstrap Calendar class
16419 * @cfg {Boolean} loadMask (true|false) default false
16420 * @cfg {Object} header generate the user specific header of the calendar, default false
16423 * Create a new Container
16424 * @param {Object} config The config object
16429 Roo.bootstrap.Calendar = function(config){
16430 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16434 * Fires when a date is selected
16435 * @param {DatePicker} this
16436 * @param {Date} date The selected date
16440 * @event monthchange
16441 * Fires when the displayed month changes
16442 * @param {DatePicker} this
16443 * @param {Date} date The selected month
16445 'monthchange': true,
16447 * @event evententer
16448 * Fires when mouse over an event
16449 * @param {Calendar} this
16450 * @param {event} Event
16452 'evententer': true,
16454 * @event eventleave
16455 * Fires when the mouse leaves an
16456 * @param {Calendar} this
16459 'eventleave': true,
16461 * @event eventclick
16462 * Fires when the mouse click an
16463 * @param {Calendar} this
16472 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16475 * @cfg {Number} startDay
16476 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16484 getAutoCreate : function(){
16487 var fc_button = function(name, corner, style, content ) {
16488 return Roo.apply({},{
16490 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16492 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16495 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16506 style : 'width:100%',
16513 cls : 'fc-header-left',
16515 fc_button('prev', 'left', 'arrow', '‹' ),
16516 fc_button('next', 'right', 'arrow', '›' ),
16517 { tag: 'span', cls: 'fc-header-space' },
16518 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16526 cls : 'fc-header-center',
16530 cls: 'fc-header-title',
16533 html : 'month / year'
16541 cls : 'fc-header-right',
16543 /* fc_button('month', 'left', '', 'month' ),
16544 fc_button('week', '', '', 'week' ),
16545 fc_button('day', 'right', '', 'day' )
16557 header = this.header;
16560 var cal_heads = function() {
16562 // fixme - handle this.
16564 for (var i =0; i < Date.dayNames.length; i++) {
16565 var d = Date.dayNames[i];
16568 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16569 html : d.substring(0,3)
16573 ret[0].cls += ' fc-first';
16574 ret[6].cls += ' fc-last';
16577 var cal_cell = function(n) {
16580 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16585 cls: 'fc-day-number',
16589 cls: 'fc-day-content',
16593 style: 'position: relative;' // height: 17px;
16605 var cal_rows = function() {
16608 for (var r = 0; r < 6; r++) {
16615 for (var i =0; i < Date.dayNames.length; i++) {
16616 var d = Date.dayNames[i];
16617 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16620 row.cn[0].cls+=' fc-first';
16621 row.cn[0].cn[0].style = 'min-height:90px';
16622 row.cn[6].cls+=' fc-last';
16626 ret[0].cls += ' fc-first';
16627 ret[4].cls += ' fc-prev-last';
16628 ret[5].cls += ' fc-last';
16635 cls: 'fc-border-separate',
16636 style : 'width:100%',
16644 cls : 'fc-first fc-last',
16662 cls : 'fc-content',
16663 style : "position: relative;",
16666 cls : 'fc-view fc-view-month fc-grid',
16667 style : 'position: relative',
16668 unselectable : 'on',
16671 cls : 'fc-event-container',
16672 style : 'position:absolute;z-index:8;top:0;left:0;'
16690 initEvents : function()
16693 throw "can not find store for calendar";
16699 style: "text-align:center",
16703 style: "background-color:white;width:50%;margin:250 auto",
16707 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16718 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16720 var size = this.el.select('.fc-content', true).first().getSize();
16721 this.maskEl.setSize(size.width, size.height);
16722 this.maskEl.enableDisplayMode("block");
16723 if(!this.loadMask){
16724 this.maskEl.hide();
16727 this.store = Roo.factory(this.store, Roo.data);
16728 this.store.on('load', this.onLoad, this);
16729 this.store.on('beforeload', this.onBeforeLoad, this);
16733 this.cells = this.el.select('.fc-day',true);
16734 //Roo.log(this.cells);
16735 this.textNodes = this.el.query('.fc-day-number');
16736 this.cells.addClassOnOver('fc-state-hover');
16738 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16739 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16740 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16741 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16743 this.on('monthchange', this.onMonthChange, this);
16745 this.update(new Date().clearTime());
16748 resize : function() {
16749 var sz = this.el.getSize();
16751 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16752 this.el.select('.fc-day-content div',true).setHeight(34);
16757 showPrevMonth : function(e){
16758 this.update(this.activeDate.add("mo", -1));
16760 showToday : function(e){
16761 this.update(new Date().clearTime());
16764 showNextMonth : function(e){
16765 this.update(this.activeDate.add("mo", 1));
16769 showPrevYear : function(){
16770 this.update(this.activeDate.add("y", -1));
16774 showNextYear : function(){
16775 this.update(this.activeDate.add("y", 1));
16780 update : function(date)
16782 var vd = this.activeDate;
16783 this.activeDate = date;
16784 // if(vd && this.el){
16785 // var t = date.getTime();
16786 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16787 // Roo.log('using add remove');
16789 // this.fireEvent('monthchange', this, date);
16791 // this.cells.removeClass("fc-state-highlight");
16792 // this.cells.each(function(c){
16793 // if(c.dateValue == t){
16794 // c.addClass("fc-state-highlight");
16795 // setTimeout(function(){
16796 // try{c.dom.firstChild.focus();}catch(e){}
16806 var days = date.getDaysInMonth();
16808 var firstOfMonth = date.getFirstDateOfMonth();
16809 var startingPos = firstOfMonth.getDay()-this.startDay;
16811 if(startingPos < this.startDay){
16815 var pm = date.add(Date.MONTH, -1);
16816 var prevStart = pm.getDaysInMonth()-startingPos;
16818 this.cells = this.el.select('.fc-day',true);
16819 this.textNodes = this.el.query('.fc-day-number');
16820 this.cells.addClassOnOver('fc-state-hover');
16822 var cells = this.cells.elements;
16823 var textEls = this.textNodes;
16825 Roo.each(cells, function(cell){
16826 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16829 days += startingPos;
16831 // convert everything to numbers so it's fast
16832 var day = 86400000;
16833 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16836 //Roo.log(prevStart);
16838 var today = new Date().clearTime().getTime();
16839 var sel = date.clearTime().getTime();
16840 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16841 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16842 var ddMatch = this.disabledDatesRE;
16843 var ddText = this.disabledDatesText;
16844 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16845 var ddaysText = this.disabledDaysText;
16846 var format = this.format;
16848 var setCellClass = function(cal, cell){
16852 //Roo.log('set Cell Class');
16854 var t = d.getTime();
16858 cell.dateValue = t;
16860 cell.className += " fc-today";
16861 cell.className += " fc-state-highlight";
16862 cell.title = cal.todayText;
16865 // disable highlight in other month..
16866 //cell.className += " fc-state-highlight";
16871 cell.className = " fc-state-disabled";
16872 cell.title = cal.minText;
16876 cell.className = " fc-state-disabled";
16877 cell.title = cal.maxText;
16881 if(ddays.indexOf(d.getDay()) != -1){
16882 cell.title = ddaysText;
16883 cell.className = " fc-state-disabled";
16886 if(ddMatch && format){
16887 var fvalue = d.dateFormat(format);
16888 if(ddMatch.test(fvalue)){
16889 cell.title = ddText.replace("%0", fvalue);
16890 cell.className = " fc-state-disabled";
16894 if (!cell.initialClassName) {
16895 cell.initialClassName = cell.dom.className;
16898 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16903 for(; i < startingPos; i++) {
16904 textEls[i].innerHTML = (++prevStart);
16905 d.setDate(d.getDate()+1);
16907 cells[i].className = "fc-past fc-other-month";
16908 setCellClass(this, cells[i]);
16913 for(; i < days; i++){
16914 intDay = i - startingPos + 1;
16915 textEls[i].innerHTML = (intDay);
16916 d.setDate(d.getDate()+1);
16918 cells[i].className = ''; // "x-date-active";
16919 setCellClass(this, cells[i]);
16923 for(; i < 42; i++) {
16924 textEls[i].innerHTML = (++extraDays);
16925 d.setDate(d.getDate()+1);
16927 cells[i].className = "fc-future fc-other-month";
16928 setCellClass(this, cells[i]);
16931 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16933 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16935 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16936 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16938 if(totalRows != 6){
16939 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16940 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16943 this.fireEvent('monthchange', this, date);
16947 if(!this.internalRender){
16948 var main = this.el.dom.firstChild;
16949 var w = main.offsetWidth;
16950 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16951 Roo.fly(main).setWidth(w);
16952 this.internalRender = true;
16953 // opera does not respect the auto grow header center column
16954 // then, after it gets a width opera refuses to recalculate
16955 // without a second pass
16956 if(Roo.isOpera && !this.secondPass){
16957 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16958 this.secondPass = true;
16959 this.update.defer(10, this, [date]);
16966 findCell : function(dt) {
16967 dt = dt.clearTime().getTime();
16969 this.cells.each(function(c){
16970 //Roo.log("check " +c.dateValue + '?=' + dt);
16971 if(c.dateValue == dt){
16981 findCells : function(ev) {
16982 var s = ev.start.clone().clearTime().getTime();
16984 var e= ev.end.clone().clearTime().getTime();
16987 this.cells.each(function(c){
16988 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16990 if(c.dateValue > e){
16993 if(c.dateValue < s){
17002 // findBestRow: function(cells)
17006 // for (var i =0 ; i < cells.length;i++) {
17007 // ret = Math.max(cells[i].rows || 0,ret);
17014 addItem : function(ev)
17016 // look for vertical location slot in
17017 var cells = this.findCells(ev);
17019 // ev.row = this.findBestRow(cells);
17021 // work out the location.
17025 for(var i =0; i < cells.length; i++) {
17027 cells[i].row = cells[0].row;
17030 cells[i].row = cells[i].row + 1;
17040 if (crow.start.getY() == cells[i].getY()) {
17042 crow.end = cells[i];
17059 cells[0].events.push(ev);
17061 this.calevents.push(ev);
17064 clearEvents: function() {
17066 if(!this.calevents){
17070 Roo.each(this.cells.elements, function(c){
17076 Roo.each(this.calevents, function(e) {
17077 Roo.each(e.els, function(el) {
17078 el.un('mouseenter' ,this.onEventEnter, this);
17079 el.un('mouseleave' ,this.onEventLeave, this);
17084 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17090 renderEvents: function()
17094 this.cells.each(function(c) {
17103 if(c.row != c.events.length){
17104 r = 4 - (4 - (c.row - c.events.length));
17107 c.events = ev.slice(0, r);
17108 c.more = ev.slice(r);
17110 if(c.more.length && c.more.length == 1){
17111 c.events.push(c.more.pop());
17114 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17118 this.cells.each(function(c) {
17120 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17123 for (var e = 0; e < c.events.length; e++){
17124 var ev = c.events[e];
17125 var rows = ev.rows;
17127 for(var i = 0; i < rows.length; i++) {
17129 // how many rows should it span..
17132 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17133 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17135 unselectable : "on",
17138 cls: 'fc-event-inner',
17142 // cls: 'fc-event-time',
17143 // html : cells.length > 1 ? '' : ev.time
17147 cls: 'fc-event-title',
17148 html : String.format('{0}', ev.title)
17155 cls: 'ui-resizable-handle ui-resizable-e',
17156 html : '  '
17163 cfg.cls += ' fc-event-start';
17165 if ((i+1) == rows.length) {
17166 cfg.cls += ' fc-event-end';
17169 var ctr = _this.el.select('.fc-event-container',true).first();
17170 var cg = ctr.createChild(cfg);
17172 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17173 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17175 var r = (c.more.length) ? 1 : 0;
17176 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17177 cg.setWidth(ebox.right - sbox.x -2);
17179 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17180 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17181 cg.on('click', _this.onEventClick, _this, ev);
17192 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17193 style : 'position: absolute',
17194 unselectable : "on",
17197 cls: 'fc-event-inner',
17201 cls: 'fc-event-title',
17209 cls: 'ui-resizable-handle ui-resizable-e',
17210 html : '  '
17216 var ctr = _this.el.select('.fc-event-container',true).first();
17217 var cg = ctr.createChild(cfg);
17219 var sbox = c.select('.fc-day-content',true).first().getBox();
17220 var ebox = c.select('.fc-day-content',true).first().getBox();
17222 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17223 cg.setWidth(ebox.right - sbox.x -2);
17225 cg.on('click', _this.onMoreEventClick, _this, c.more);
17235 onEventEnter: function (e, el,event,d) {
17236 this.fireEvent('evententer', this, el, event);
17239 onEventLeave: function (e, el,event,d) {
17240 this.fireEvent('eventleave', this, el, event);
17243 onEventClick: function (e, el,event,d) {
17244 this.fireEvent('eventclick', this, el, event);
17247 onMonthChange: function () {
17251 onMoreEventClick: function(e, el, more)
17255 this.calpopover.placement = 'right';
17256 this.calpopover.setTitle('More');
17258 this.calpopover.setContent('');
17260 var ctr = this.calpopover.el.select('.popover-content', true).first();
17262 Roo.each(more, function(m){
17264 cls : 'fc-event-hori fc-event-draggable',
17267 var cg = ctr.createChild(cfg);
17269 cg.on('click', _this.onEventClick, _this, m);
17272 this.calpopover.show(el);
17277 onLoad: function ()
17279 this.calevents = [];
17282 if(this.store.getCount() > 0){
17283 this.store.data.each(function(d){
17286 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17287 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17288 time : d.data.start_time,
17289 title : d.data.title,
17290 description : d.data.description,
17291 venue : d.data.venue
17296 this.renderEvents();
17298 if(this.calevents.length && this.loadMask){
17299 this.maskEl.hide();
17303 onBeforeLoad: function()
17305 this.clearEvents();
17307 this.maskEl.show();
17321 * @class Roo.bootstrap.Popover
17322 * @extends Roo.bootstrap.Component
17323 * Bootstrap Popover class
17324 * @cfg {String} html contents of the popover (or false to use children..)
17325 * @cfg {String} title of popover (or false to hide)
17326 * @cfg {String} placement how it is placed
17327 * @cfg {String} trigger click || hover (or false to trigger manually)
17328 * @cfg {String} over what (parent or false to trigger manually.)
17329 * @cfg {Number} delay - delay before showing
17332 * Create a new Popover
17333 * @param {Object} config The config object
17336 Roo.bootstrap.Popover = function(config){
17337 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17343 * After the popover show
17345 * @param {Roo.bootstrap.Popover} this
17350 * After the popover hide
17352 * @param {Roo.bootstrap.Popover} this
17358 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17360 title: 'Fill in a title',
17363 placement : 'right',
17364 trigger : 'hover', // hover
17370 can_build_overlaid : false,
17372 getChildContainer : function()
17374 return this.el.select('.popover-content',true).first();
17377 getAutoCreate : function(){
17380 cls : 'popover roo-dynamic',
17381 style: 'display:block',
17387 cls : 'popover-inner',
17391 cls: 'popover-title',
17395 cls : 'popover-content',
17406 setTitle: function(str)
17409 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17411 setContent: function(str)
17414 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17416 // as it get's added to the bottom of the page.
17417 onRender : function(ct, position)
17419 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17421 var cfg = Roo.apply({}, this.getAutoCreate());
17425 cfg.cls += ' ' + this.cls;
17428 cfg.style = this.style;
17430 //Roo.log("adding to ");
17431 this.el = Roo.get(document.body).createChild(cfg, position);
17432 // Roo.log(this.el);
17437 initEvents : function()
17439 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17440 this.el.enableDisplayMode('block');
17442 if (this.over === false) {
17445 if (this.triggers === false) {
17448 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17449 var triggers = this.trigger ? this.trigger.split(' ') : [];
17450 Roo.each(triggers, function(trigger) {
17452 if (trigger == 'click') {
17453 on_el.on('click', this.toggle, this);
17454 } else if (trigger != 'manual') {
17455 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17456 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17458 on_el.on(eventIn ,this.enter, this);
17459 on_el.on(eventOut, this.leave, this);
17470 toggle : function () {
17471 this.hoverState == 'in' ? this.leave() : this.enter();
17474 enter : function () {
17476 clearTimeout(this.timeout);
17478 this.hoverState = 'in';
17480 if (!this.delay || !this.delay.show) {
17485 this.timeout = setTimeout(function () {
17486 if (_t.hoverState == 'in') {
17489 }, this.delay.show)
17492 leave : function() {
17493 clearTimeout(this.timeout);
17495 this.hoverState = 'out';
17497 if (!this.delay || !this.delay.hide) {
17502 this.timeout = setTimeout(function () {
17503 if (_t.hoverState == 'out') {
17506 }, this.delay.hide)
17509 show : function (on_el)
17512 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17516 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17517 if (this.html !== false) {
17518 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17520 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17521 if (!this.title.length) {
17522 this.el.select('.popover-title',true).hide();
17525 var placement = typeof this.placement == 'function' ?
17526 this.placement.call(this, this.el, on_el) :
17529 var autoToken = /\s?auto?\s?/i;
17530 var autoPlace = autoToken.test(placement);
17532 placement = placement.replace(autoToken, '') || 'top';
17536 //this.el.setXY([0,0]);
17538 this.el.dom.style.display='block';
17539 this.el.addClass(placement);
17541 //this.el.appendTo(on_el);
17543 var p = this.getPosition();
17544 var box = this.el.getBox();
17549 var align = Roo.bootstrap.Popover.alignment[placement];
17552 this.el.alignTo(on_el, align[0],align[1]);
17553 //var arrow = this.el.select('.arrow',true).first();
17554 //arrow.set(align[2],
17556 this.el.addClass('in');
17559 if (this.el.hasClass('fade')) {
17563 this.hoverState = 'in';
17565 this.fireEvent('show', this);
17570 this.el.setXY([0,0]);
17571 this.el.removeClass('in');
17573 this.hoverState = null;
17575 this.fireEvent('hide', this);
17580 Roo.bootstrap.Popover.alignment = {
17581 'left' : ['r-l', [-10,0], 'right'],
17582 'right' : ['l-r', [10,0], 'left'],
17583 'bottom' : ['t-b', [0,10], 'top'],
17584 'top' : [ 'b-t', [0,-10], 'bottom']
17595 * @class Roo.bootstrap.Progress
17596 * @extends Roo.bootstrap.Component
17597 * Bootstrap Progress class
17598 * @cfg {Boolean} striped striped of the progress bar
17599 * @cfg {Boolean} active animated of the progress bar
17603 * Create a new Progress
17604 * @param {Object} config The config object
17607 Roo.bootstrap.Progress = function(config){
17608 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17611 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17616 getAutoCreate : function(){
17624 cfg.cls += ' progress-striped';
17628 cfg.cls += ' active';
17647 * @class Roo.bootstrap.ProgressBar
17648 * @extends Roo.bootstrap.Component
17649 * Bootstrap ProgressBar class
17650 * @cfg {Number} aria_valuenow aria-value now
17651 * @cfg {Number} aria_valuemin aria-value min
17652 * @cfg {Number} aria_valuemax aria-value max
17653 * @cfg {String} label label for the progress bar
17654 * @cfg {String} panel (success | info | warning | danger )
17655 * @cfg {String} role role of the progress bar
17656 * @cfg {String} sr_only text
17660 * Create a new ProgressBar
17661 * @param {Object} config The config object
17664 Roo.bootstrap.ProgressBar = function(config){
17665 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17668 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17672 aria_valuemax : 100,
17678 getAutoCreate : function()
17683 cls: 'progress-bar',
17684 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17696 cfg.role = this.role;
17699 if(this.aria_valuenow){
17700 cfg['aria-valuenow'] = this.aria_valuenow;
17703 if(this.aria_valuemin){
17704 cfg['aria-valuemin'] = this.aria_valuemin;
17707 if(this.aria_valuemax){
17708 cfg['aria-valuemax'] = this.aria_valuemax;
17711 if(this.label && !this.sr_only){
17712 cfg.html = this.label;
17716 cfg.cls += ' progress-bar-' + this.panel;
17722 update : function(aria_valuenow)
17724 this.aria_valuenow = aria_valuenow;
17726 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17741 * @class Roo.bootstrap.TabGroup
17742 * @extends Roo.bootstrap.Column
17743 * Bootstrap Column class
17744 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17745 * @cfg {Boolean} carousel true to make the group behave like a carousel
17746 * @cfg {Boolean} bullets show bullets for the panels
17747 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17748 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17749 * @cfg {Boolean} showarrow (true|false) show arrow default true
17752 * Create a new TabGroup
17753 * @param {Object} config The config object
17756 Roo.bootstrap.TabGroup = function(config){
17757 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17759 this.navId = Roo.id();
17762 Roo.bootstrap.TabGroup.register(this);
17766 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17769 transition : false,
17774 slideOnTouch : false,
17777 getAutoCreate : function()
17779 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17781 cfg.cls += ' tab-content';
17783 if (this.carousel) {
17784 cfg.cls += ' carousel slide';
17787 cls : 'carousel-inner',
17791 if(this.bullets && !Roo.isTouch){
17794 cls : 'carousel-bullets',
17798 if(this.bullets_cls){
17799 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17806 cfg.cn[0].cn.push(bullets);
17809 if(this.showarrow){
17810 cfg.cn[0].cn.push({
17812 class : 'carousel-arrow',
17816 class : 'carousel-prev',
17820 class : 'fa fa-chevron-left'
17826 class : 'carousel-next',
17830 class : 'fa fa-chevron-right'
17843 initEvents: function()
17845 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17846 // this.el.on("touchstart", this.onTouchStart, this);
17849 if(this.autoslide){
17852 this.slideFn = window.setInterval(function() {
17853 _this.showPanelNext();
17857 if(this.showarrow){
17858 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17859 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17865 // onTouchStart : function(e, el, o)
17867 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17871 // this.showPanelNext();
17875 getChildContainer : function()
17877 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17881 * register a Navigation item
17882 * @param {Roo.bootstrap.NavItem} the navitem to add
17884 register : function(item)
17886 this.tabs.push( item);
17887 item.navId = this.navId; // not really needed..
17892 getActivePanel : function()
17895 Roo.each(this.tabs, function(t) {
17905 getPanelByName : function(n)
17908 Roo.each(this.tabs, function(t) {
17909 if (t.tabId == n) {
17917 indexOfPanel : function(p)
17920 Roo.each(this.tabs, function(t,i) {
17921 if (t.tabId == p.tabId) {
17930 * show a specific panel
17931 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17932 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17934 showPanel : function (pan)
17936 if(this.transition || typeof(pan) == 'undefined'){
17937 Roo.log("waiting for the transitionend");
17941 if (typeof(pan) == 'number') {
17942 pan = this.tabs[pan];
17945 if (typeof(pan) == 'string') {
17946 pan = this.getPanelByName(pan);
17949 var cur = this.getActivePanel();
17952 Roo.log('pan or acitve pan is undefined');
17956 if (pan.tabId == this.getActivePanel().tabId) {
17960 if (false === cur.fireEvent('beforedeactivate')) {
17964 if(this.bullets > 0 && !Roo.isTouch){
17965 this.setActiveBullet(this.indexOfPanel(pan));
17968 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17970 this.transition = true;
17971 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17972 var lr = dir == 'next' ? 'left' : 'right';
17973 pan.el.addClass(dir); // or prev
17974 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17975 cur.el.addClass(lr); // or right
17976 pan.el.addClass(lr);
17979 cur.el.on('transitionend', function() {
17980 Roo.log("trans end?");
17982 pan.el.removeClass([lr,dir]);
17983 pan.setActive(true);
17985 cur.el.removeClass([lr]);
17986 cur.setActive(false);
17988 _this.transition = false;
17990 }, this, { single: true } );
17995 cur.setActive(false);
17996 pan.setActive(true);
18001 showPanelNext : function()
18003 var i = this.indexOfPanel(this.getActivePanel());
18005 if (i >= this.tabs.length - 1 && !this.autoslide) {
18009 if (i >= this.tabs.length - 1 && this.autoslide) {
18013 this.showPanel(this.tabs[i+1]);
18016 showPanelPrev : function()
18018 var i = this.indexOfPanel(this.getActivePanel());
18020 if (i < 1 && !this.autoslide) {
18024 if (i < 1 && this.autoslide) {
18025 i = this.tabs.length;
18028 this.showPanel(this.tabs[i-1]);
18032 addBullet: function()
18034 if(!this.bullets || Roo.isTouch){
18037 var ctr = this.el.select('.carousel-bullets',true).first();
18038 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18039 var bullet = ctr.createChild({
18040 cls : 'bullet bullet-' + i
18041 },ctr.dom.lastChild);
18046 bullet.on('click', (function(e, el, o, ii, t){
18048 e.preventDefault();
18050 this.showPanel(ii);
18052 if(this.autoslide && this.slideFn){
18053 clearInterval(this.slideFn);
18054 this.slideFn = window.setInterval(function() {
18055 _this.showPanelNext();
18059 }).createDelegate(this, [i, bullet], true));
18064 setActiveBullet : function(i)
18070 Roo.each(this.el.select('.bullet', true).elements, function(el){
18071 el.removeClass('selected');
18074 var bullet = this.el.select('.bullet-' + i, true).first();
18080 bullet.addClass('selected');
18091 Roo.apply(Roo.bootstrap.TabGroup, {
18095 * register a Navigation Group
18096 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18098 register : function(navgrp)
18100 this.groups[navgrp.navId] = navgrp;
18104 * fetch a Navigation Group based on the navigation ID
18105 * if one does not exist , it will get created.
18106 * @param {string} the navgroup to add
18107 * @returns {Roo.bootstrap.NavGroup} the navgroup
18109 get: function(navId) {
18110 if (typeof(this.groups[navId]) == 'undefined') {
18111 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18113 return this.groups[navId] ;
18128 * @class Roo.bootstrap.TabPanel
18129 * @extends Roo.bootstrap.Component
18130 * Bootstrap TabPanel class
18131 * @cfg {Boolean} active panel active
18132 * @cfg {String} html panel content
18133 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18134 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18135 * @cfg {String} href click to link..
18139 * Create a new TabPanel
18140 * @param {Object} config The config object
18143 Roo.bootstrap.TabPanel = function(config){
18144 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18148 * Fires when the active status changes
18149 * @param {Roo.bootstrap.TabPanel} this
18150 * @param {Boolean} state the new state
18155 * @event beforedeactivate
18156 * Fires before a tab is de-activated - can be used to do validation on a form.
18157 * @param {Roo.bootstrap.TabPanel} this
18158 * @return {Boolean} false if there is an error
18161 'beforedeactivate': true
18164 this.tabId = this.tabId || Roo.id();
18168 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18176 getAutoCreate : function(){
18179 // item is needed for carousel - not sure if it has any effect otherwise
18180 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18181 html: this.html || ''
18185 cfg.cls += ' active';
18189 cfg.tabId = this.tabId;
18196 initEvents: function()
18198 var p = this.parent();
18200 this.navId = this.navId || p.navId;
18202 if (typeof(this.navId) != 'undefined') {
18203 // not really needed.. but just in case.. parent should be a NavGroup.
18204 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18208 var i = tg.tabs.length - 1;
18210 if(this.active && tg.bullets > 0 && i < tg.bullets){
18211 tg.setActiveBullet(i);
18215 this.el.on('click', this.onClick, this);
18218 this.el.on("touchstart", this.onTouchStart, this);
18219 this.el.on("touchmove", this.onTouchMove, this);
18220 this.el.on("touchend", this.onTouchEnd, this);
18225 onRender : function(ct, position)
18227 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18230 setActive : function(state)
18232 Roo.log("panel - set active " + this.tabId + "=" + state);
18234 this.active = state;
18236 this.el.removeClass('active');
18238 } else if (!this.el.hasClass('active')) {
18239 this.el.addClass('active');
18242 this.fireEvent('changed', this, state);
18245 onClick : function(e)
18247 e.preventDefault();
18249 if(!this.href.length){
18253 window.location.href = this.href;
18262 onTouchStart : function(e)
18264 this.swiping = false;
18266 this.startX = e.browserEvent.touches[0].clientX;
18267 this.startY = e.browserEvent.touches[0].clientY;
18270 onTouchMove : function(e)
18272 this.swiping = true;
18274 this.endX = e.browserEvent.touches[0].clientX;
18275 this.endY = e.browserEvent.touches[0].clientY;
18278 onTouchEnd : function(e)
18285 var tabGroup = this.parent();
18287 if(this.endX > this.startX){ // swiping right
18288 tabGroup.showPanelPrev();
18292 if(this.startX > this.endX){ // swiping left
18293 tabGroup.showPanelNext();
18312 * @class Roo.bootstrap.DateField
18313 * @extends Roo.bootstrap.Input
18314 * Bootstrap DateField class
18315 * @cfg {Number} weekStart default 0
18316 * @cfg {String} viewMode default empty, (months|years)
18317 * @cfg {String} minViewMode default empty, (months|years)
18318 * @cfg {Number} startDate default -Infinity
18319 * @cfg {Number} endDate default Infinity
18320 * @cfg {Boolean} todayHighlight default false
18321 * @cfg {Boolean} todayBtn default false
18322 * @cfg {Boolean} calendarWeeks default false
18323 * @cfg {Object} daysOfWeekDisabled default empty
18324 * @cfg {Boolean} singleMode default false (true | false)
18326 * @cfg {Boolean} keyboardNavigation default true
18327 * @cfg {String} language default en
18330 * Create a new DateField
18331 * @param {Object} config The config object
18334 Roo.bootstrap.DateField = function(config){
18335 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18339 * Fires when this field show.
18340 * @param {Roo.bootstrap.DateField} this
18341 * @param {Mixed} date The date value
18346 * Fires when this field hide.
18347 * @param {Roo.bootstrap.DateField} this
18348 * @param {Mixed} date The date value
18353 * Fires when select a date.
18354 * @param {Roo.bootstrap.DateField} this
18355 * @param {Mixed} date The date value
18359 * @event beforeselect
18360 * Fires when before select a date.
18361 * @param {Roo.bootstrap.DateField} this
18362 * @param {Mixed} date The date value
18364 beforeselect : true
18368 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18371 * @cfg {String} format
18372 * The default date format string which can be overriden for localization support. The format must be
18373 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18377 * @cfg {String} altFormats
18378 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18379 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18381 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18389 todayHighlight : false,
18395 keyboardNavigation: true,
18397 calendarWeeks: false,
18399 startDate: -Infinity,
18403 daysOfWeekDisabled: [],
18407 singleMode : false,
18409 UTCDate: function()
18411 return new Date(Date.UTC.apply(Date, arguments));
18414 UTCToday: function()
18416 var today = new Date();
18417 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18420 getDate: function() {
18421 var d = this.getUTCDate();
18422 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18425 getUTCDate: function() {
18429 setDate: function(d) {
18430 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18433 setUTCDate: function(d) {
18435 this.setValue(this.formatDate(this.date));
18438 onRender: function(ct, position)
18441 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18443 this.language = this.language || 'en';
18444 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18445 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18447 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18448 this.format = this.format || 'm/d/y';
18449 this.isInline = false;
18450 this.isInput = true;
18451 this.component = this.el.select('.add-on', true).first() || false;
18452 this.component = (this.component && this.component.length === 0) ? false : this.component;
18453 this.hasInput = this.component && this.inputEl().length;
18455 if (typeof(this.minViewMode === 'string')) {
18456 switch (this.minViewMode) {
18458 this.minViewMode = 1;
18461 this.minViewMode = 2;
18464 this.minViewMode = 0;
18469 if (typeof(this.viewMode === 'string')) {
18470 switch (this.viewMode) {
18483 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18485 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18487 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18489 this.picker().on('mousedown', this.onMousedown, this);
18490 this.picker().on('click', this.onClick, this);
18492 this.picker().addClass('datepicker-dropdown');
18494 this.startViewMode = this.viewMode;
18496 if(this.singleMode){
18497 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18498 v.setVisibilityMode(Roo.Element.DISPLAY);
18502 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18503 v.setStyle('width', '189px');
18507 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18508 if(!this.calendarWeeks){
18513 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18514 v.attr('colspan', function(i, val){
18515 return parseInt(val) + 1;
18520 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18522 this.setStartDate(this.startDate);
18523 this.setEndDate(this.endDate);
18525 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18532 if(this.isInline) {
18537 picker : function()
18539 return this.pickerEl;
18540 // return this.el.select('.datepicker', true).first();
18543 fillDow: function()
18545 var dowCnt = this.weekStart;
18554 if(this.calendarWeeks){
18562 while (dowCnt < this.weekStart + 7) {
18566 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18570 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18573 fillMonths: function()
18576 var months = this.picker().select('>.datepicker-months td', true).first();
18578 months.dom.innerHTML = '';
18584 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18587 months.createChild(month);
18594 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;
18596 if (this.date < this.startDate) {
18597 this.viewDate = new Date(this.startDate);
18598 } else if (this.date > this.endDate) {
18599 this.viewDate = new Date(this.endDate);
18601 this.viewDate = new Date(this.date);
18609 var d = new Date(this.viewDate),
18610 year = d.getUTCFullYear(),
18611 month = d.getUTCMonth(),
18612 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18613 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18614 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18615 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18616 currentDate = this.date && this.date.valueOf(),
18617 today = this.UTCToday();
18619 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18621 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18623 // this.picker.select('>tfoot th.today').
18624 // .text(dates[this.language].today)
18625 // .toggle(this.todayBtn !== false);
18627 this.updateNavArrows();
18630 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18632 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18634 prevMonth.setUTCDate(day);
18636 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18638 var nextMonth = new Date(prevMonth);
18640 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18642 nextMonth = nextMonth.valueOf();
18644 var fillMonths = false;
18646 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18648 while(prevMonth.valueOf() < nextMonth) {
18651 if (prevMonth.getUTCDay() === this.weekStart) {
18653 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18661 if(this.calendarWeeks){
18662 // ISO 8601: First week contains first thursday.
18663 // ISO also states week starts on Monday, but we can be more abstract here.
18665 // Start of current week: based on weekstart/current date
18666 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18667 // Thursday of this week
18668 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18669 // First Thursday of year, year from thursday
18670 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18671 // Calendar week: ms between thursdays, div ms per day, div 7 days
18672 calWeek = (th - yth) / 864e5 / 7 + 1;
18674 fillMonths.cn.push({
18682 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18684 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18687 if (this.todayHighlight &&
18688 prevMonth.getUTCFullYear() == today.getFullYear() &&
18689 prevMonth.getUTCMonth() == today.getMonth() &&
18690 prevMonth.getUTCDate() == today.getDate()) {
18691 clsName += ' today';
18694 if (currentDate && prevMonth.valueOf() === currentDate) {
18695 clsName += ' active';
18698 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18699 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18700 clsName += ' disabled';
18703 fillMonths.cn.push({
18705 cls: 'day ' + clsName,
18706 html: prevMonth.getDate()
18709 prevMonth.setDate(prevMonth.getDate()+1);
18712 var currentYear = this.date && this.date.getUTCFullYear();
18713 var currentMonth = this.date && this.date.getUTCMonth();
18715 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18717 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18718 v.removeClass('active');
18720 if(currentYear === year && k === currentMonth){
18721 v.addClass('active');
18724 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18725 v.addClass('disabled');
18731 year = parseInt(year/10, 10) * 10;
18733 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18735 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18738 for (var i = -1; i < 11; i++) {
18739 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18741 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18749 showMode: function(dir)
18752 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18755 Roo.each(this.picker().select('>div',true).elements, function(v){
18756 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18759 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18764 if(this.isInline) {
18768 this.picker().removeClass(['bottom', 'top']);
18770 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18772 * place to the top of element!
18776 this.picker().addClass('top');
18777 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18782 this.picker().addClass('bottom');
18784 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18787 parseDate : function(value)
18789 if(!value || value instanceof Date){
18792 var v = Date.parseDate(value, this.format);
18793 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18794 v = Date.parseDate(value, 'Y-m-d');
18796 if(!v && this.altFormats){
18797 if(!this.altFormatsArray){
18798 this.altFormatsArray = this.altFormats.split("|");
18800 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18801 v = Date.parseDate(value, this.altFormatsArray[i]);
18807 formatDate : function(date, fmt)
18809 return (!date || !(date instanceof Date)) ?
18810 date : date.dateFormat(fmt || this.format);
18813 onFocus : function()
18815 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18819 onBlur : function()
18821 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18823 var d = this.inputEl().getValue();
18832 this.picker().show();
18836 this.fireEvent('show', this, this.date);
18841 if(this.isInline) {
18844 this.picker().hide();
18845 this.viewMode = this.startViewMode;
18848 this.fireEvent('hide', this, this.date);
18852 onMousedown: function(e)
18854 e.stopPropagation();
18855 e.preventDefault();
18860 Roo.bootstrap.DateField.superclass.keyup.call(this);
18864 setValue: function(v)
18866 if(this.fireEvent('beforeselect', this, v) !== false){
18867 var d = new Date(this.parseDate(v) ).clearTime();
18869 if(isNaN(d.getTime())){
18870 this.date = this.viewDate = '';
18871 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18875 v = this.formatDate(d);
18877 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18879 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18883 this.fireEvent('select', this, this.date);
18887 getValue: function()
18889 return this.formatDate(this.date);
18892 fireKey: function(e)
18894 if (!this.picker().isVisible()){
18895 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18901 var dateChanged = false,
18903 newDate, newViewDate;
18908 e.preventDefault();
18912 if (!this.keyboardNavigation) {
18915 dir = e.keyCode == 37 ? -1 : 1;
18918 newDate = this.moveYear(this.date, dir);
18919 newViewDate = this.moveYear(this.viewDate, dir);
18920 } else if (e.shiftKey){
18921 newDate = this.moveMonth(this.date, dir);
18922 newViewDate = this.moveMonth(this.viewDate, dir);
18924 newDate = new Date(this.date);
18925 newDate.setUTCDate(this.date.getUTCDate() + dir);
18926 newViewDate = new Date(this.viewDate);
18927 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18929 if (this.dateWithinRange(newDate)){
18930 this.date = newDate;
18931 this.viewDate = newViewDate;
18932 this.setValue(this.formatDate(this.date));
18934 e.preventDefault();
18935 dateChanged = true;
18940 if (!this.keyboardNavigation) {
18943 dir = e.keyCode == 38 ? -1 : 1;
18945 newDate = this.moveYear(this.date, dir);
18946 newViewDate = this.moveYear(this.viewDate, dir);
18947 } else if (e.shiftKey){
18948 newDate = this.moveMonth(this.date, dir);
18949 newViewDate = this.moveMonth(this.viewDate, dir);
18951 newDate = new Date(this.date);
18952 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18953 newViewDate = new Date(this.viewDate);
18954 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18956 if (this.dateWithinRange(newDate)){
18957 this.date = newDate;
18958 this.viewDate = newViewDate;
18959 this.setValue(this.formatDate(this.date));
18961 e.preventDefault();
18962 dateChanged = true;
18966 this.setValue(this.formatDate(this.date));
18968 e.preventDefault();
18971 this.setValue(this.formatDate(this.date));
18985 onClick: function(e)
18987 e.stopPropagation();
18988 e.preventDefault();
18990 var target = e.getTarget();
18992 if(target.nodeName.toLowerCase() === 'i'){
18993 target = Roo.get(target).dom.parentNode;
18996 var nodeName = target.nodeName;
18997 var className = target.className;
18998 var html = target.innerHTML;
18999 //Roo.log(nodeName);
19001 switch(nodeName.toLowerCase()) {
19003 switch(className) {
19009 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19010 switch(this.viewMode){
19012 this.viewDate = this.moveMonth(this.viewDate, dir);
19016 this.viewDate = this.moveYear(this.viewDate, dir);
19022 var date = new Date();
19023 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19025 this.setValue(this.formatDate(this.date));
19032 if (className.indexOf('disabled') < 0) {
19033 this.viewDate.setUTCDate(1);
19034 if (className.indexOf('month') > -1) {
19035 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19037 var year = parseInt(html, 10) || 0;
19038 this.viewDate.setUTCFullYear(year);
19042 if(this.singleMode){
19043 this.setValue(this.formatDate(this.viewDate));
19054 //Roo.log(className);
19055 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19056 var day = parseInt(html, 10) || 1;
19057 var year = this.viewDate.getUTCFullYear(),
19058 month = this.viewDate.getUTCMonth();
19060 if (className.indexOf('old') > -1) {
19067 } else if (className.indexOf('new') > -1) {
19075 //Roo.log([year,month,day]);
19076 this.date = this.UTCDate(year, month, day,0,0,0,0);
19077 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19079 //Roo.log(this.formatDate(this.date));
19080 this.setValue(this.formatDate(this.date));
19087 setStartDate: function(startDate)
19089 this.startDate = startDate || -Infinity;
19090 if (this.startDate !== -Infinity) {
19091 this.startDate = this.parseDate(this.startDate);
19094 this.updateNavArrows();
19097 setEndDate: function(endDate)
19099 this.endDate = endDate || Infinity;
19100 if (this.endDate !== Infinity) {
19101 this.endDate = this.parseDate(this.endDate);
19104 this.updateNavArrows();
19107 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19109 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19110 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19111 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19113 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19114 return parseInt(d, 10);
19117 this.updateNavArrows();
19120 updateNavArrows: function()
19122 if(this.singleMode){
19126 var d = new Date(this.viewDate),
19127 year = d.getUTCFullYear(),
19128 month = d.getUTCMonth();
19130 Roo.each(this.picker().select('.prev', true).elements, function(v){
19132 switch (this.viewMode) {
19135 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19141 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19148 Roo.each(this.picker().select('.next', true).elements, function(v){
19150 switch (this.viewMode) {
19153 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19159 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19167 moveMonth: function(date, dir)
19172 var new_date = new Date(date.valueOf()),
19173 day = new_date.getUTCDate(),
19174 month = new_date.getUTCMonth(),
19175 mag = Math.abs(dir),
19177 dir = dir > 0 ? 1 : -1;
19180 // If going back one month, make sure month is not current month
19181 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19183 return new_date.getUTCMonth() == month;
19185 // If going forward one month, make sure month is as expected
19186 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19188 return new_date.getUTCMonth() != new_month;
19190 new_month = month + dir;
19191 new_date.setUTCMonth(new_month);
19192 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19193 if (new_month < 0 || new_month > 11) {
19194 new_month = (new_month + 12) % 12;
19197 // For magnitudes >1, move one month at a time...
19198 for (var i=0; i<mag; i++) {
19199 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19200 new_date = this.moveMonth(new_date, dir);
19202 // ...then reset the day, keeping it in the new month
19203 new_month = new_date.getUTCMonth();
19204 new_date.setUTCDate(day);
19206 return new_month != new_date.getUTCMonth();
19209 // Common date-resetting loop -- if date is beyond end of month, make it
19212 new_date.setUTCDate(--day);
19213 new_date.setUTCMonth(new_month);
19218 moveYear: function(date, dir)
19220 return this.moveMonth(date, dir*12);
19223 dateWithinRange: function(date)
19225 return date >= this.startDate && date <= this.endDate;
19231 this.picker().remove();
19234 validateValue : function(value)
19236 if(this.getVisibilityEl().hasClass('hidden')){
19240 if(value.length < 1) {
19241 if(this.allowBlank){
19247 if(value.length < this.minLength){
19250 if(value.length > this.maxLength){
19254 var vt = Roo.form.VTypes;
19255 if(!vt[this.vtype](value, this)){
19259 if(typeof this.validator == "function"){
19260 var msg = this.validator(value);
19266 if(this.regex && !this.regex.test(value)){
19270 if(typeof(this.parseDate(value)) == 'undefined'){
19274 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19278 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19286 setVisible : function(visible)
19292 this.getEl().removeClass('hidden');
19298 this.getEl().addClass('hidden');
19303 Roo.apply(Roo.bootstrap.DateField, {
19314 html: '<i class="fa fa-arrow-left"/>'
19324 html: '<i class="fa fa-arrow-right"/>'
19366 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19367 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19368 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19369 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19370 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19383 navFnc: 'FullYear',
19388 navFnc: 'FullYear',
19393 Roo.apply(Roo.bootstrap.DateField, {
19397 cls: 'datepicker dropdown-menu roo-dynamic',
19401 cls: 'datepicker-days',
19405 cls: 'table-condensed',
19407 Roo.bootstrap.DateField.head,
19411 Roo.bootstrap.DateField.footer
19418 cls: 'datepicker-months',
19422 cls: 'table-condensed',
19424 Roo.bootstrap.DateField.head,
19425 Roo.bootstrap.DateField.content,
19426 Roo.bootstrap.DateField.footer
19433 cls: 'datepicker-years',
19437 cls: 'table-condensed',
19439 Roo.bootstrap.DateField.head,
19440 Roo.bootstrap.DateField.content,
19441 Roo.bootstrap.DateField.footer
19460 * @class Roo.bootstrap.TimeField
19461 * @extends Roo.bootstrap.Input
19462 * Bootstrap DateField class
19466 * Create a new TimeField
19467 * @param {Object} config The config object
19470 Roo.bootstrap.TimeField = function(config){
19471 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19475 * Fires when this field show.
19476 * @param {Roo.bootstrap.DateField} thisthis
19477 * @param {Mixed} date The date value
19482 * Fires when this field hide.
19483 * @param {Roo.bootstrap.DateField} this
19484 * @param {Mixed} date The date value
19489 * Fires when select a date.
19490 * @param {Roo.bootstrap.DateField} this
19491 * @param {Mixed} date The date value
19497 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19500 * @cfg {String} format
19501 * The default time format string which can be overriden for localization support. The format must be
19502 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19506 onRender: function(ct, position)
19509 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19511 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19513 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19515 this.pop = this.picker().select('>.datepicker-time',true).first();
19516 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19518 this.picker().on('mousedown', this.onMousedown, this);
19519 this.picker().on('click', this.onClick, this);
19521 this.picker().addClass('datepicker-dropdown');
19526 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19527 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19528 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19529 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19530 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19531 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19535 fireKey: function(e){
19536 if (!this.picker().isVisible()){
19537 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19543 e.preventDefault();
19551 this.onTogglePeriod();
19554 this.onIncrementMinutes();
19557 this.onDecrementMinutes();
19566 onClick: function(e) {
19567 e.stopPropagation();
19568 e.preventDefault();
19571 picker : function()
19573 return this.el.select('.datepicker', true).first();
19576 fillTime: function()
19578 var time = this.pop.select('tbody', true).first();
19580 time.dom.innerHTML = '';
19595 cls: 'hours-up glyphicon glyphicon-chevron-up'
19615 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19636 cls: 'timepicker-hour',
19651 cls: 'timepicker-minute',
19666 cls: 'btn btn-primary period',
19688 cls: 'hours-down glyphicon glyphicon-chevron-down'
19708 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19726 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19733 var hours = this.time.getHours();
19734 var minutes = this.time.getMinutes();
19747 hours = hours - 12;
19751 hours = '0' + hours;
19755 minutes = '0' + minutes;
19758 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19759 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19760 this.pop.select('button', true).first().dom.innerHTML = period;
19766 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19768 var cls = ['bottom'];
19770 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19777 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19782 this.picker().addClass(cls.join('-'));
19786 Roo.each(cls, function(c){
19788 _this.picker().setTop(_this.inputEl().getHeight());
19792 _this.picker().setTop(0 - _this.picker().getHeight());
19797 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19801 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19808 onFocus : function()
19810 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19814 onBlur : function()
19816 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19822 this.picker().show();
19827 this.fireEvent('show', this, this.date);
19832 this.picker().hide();
19835 this.fireEvent('hide', this, this.date);
19838 setTime : function()
19841 this.setValue(this.time.format(this.format));
19843 this.fireEvent('select', this, this.date);
19848 onMousedown: function(e){
19849 e.stopPropagation();
19850 e.preventDefault();
19853 onIncrementHours: function()
19855 Roo.log('onIncrementHours');
19856 this.time = this.time.add(Date.HOUR, 1);
19861 onDecrementHours: function()
19863 Roo.log('onDecrementHours');
19864 this.time = this.time.add(Date.HOUR, -1);
19868 onIncrementMinutes: function()
19870 Roo.log('onIncrementMinutes');
19871 this.time = this.time.add(Date.MINUTE, 1);
19875 onDecrementMinutes: function()
19877 Roo.log('onDecrementMinutes');
19878 this.time = this.time.add(Date.MINUTE, -1);
19882 onTogglePeriod: function()
19884 Roo.log('onTogglePeriod');
19885 this.time = this.time.add(Date.HOUR, 12);
19892 Roo.apply(Roo.bootstrap.TimeField, {
19922 cls: 'btn btn-info ok',
19934 Roo.apply(Roo.bootstrap.TimeField, {
19938 cls: 'datepicker dropdown-menu',
19942 cls: 'datepicker-time',
19946 cls: 'table-condensed',
19948 Roo.bootstrap.TimeField.content,
19949 Roo.bootstrap.TimeField.footer
19968 * @class Roo.bootstrap.MonthField
19969 * @extends Roo.bootstrap.Input
19970 * Bootstrap MonthField class
19972 * @cfg {String} language default en
19975 * Create a new MonthField
19976 * @param {Object} config The config object
19979 Roo.bootstrap.MonthField = function(config){
19980 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19985 * Fires when this field show.
19986 * @param {Roo.bootstrap.MonthField} this
19987 * @param {Mixed} date The date value
19992 * Fires when this field hide.
19993 * @param {Roo.bootstrap.MonthField} this
19994 * @param {Mixed} date The date value
19999 * Fires when select a date.
20000 * @param {Roo.bootstrap.MonthField} this
20001 * @param {String} oldvalue The old value
20002 * @param {String} newvalue The new value
20008 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20010 onRender: function(ct, position)
20013 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20015 this.language = this.language || 'en';
20016 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20017 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20019 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20020 this.isInline = false;
20021 this.isInput = true;
20022 this.component = this.el.select('.add-on', true).first() || false;
20023 this.component = (this.component && this.component.length === 0) ? false : this.component;
20024 this.hasInput = this.component && this.inputEL().length;
20026 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20028 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20030 this.picker().on('mousedown', this.onMousedown, this);
20031 this.picker().on('click', this.onClick, this);
20033 this.picker().addClass('datepicker-dropdown');
20035 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20036 v.setStyle('width', '189px');
20043 if(this.isInline) {
20049 setValue: function(v, suppressEvent)
20051 var o = this.getValue();
20053 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20057 if(suppressEvent !== true){
20058 this.fireEvent('select', this, o, v);
20063 getValue: function()
20068 onClick: function(e)
20070 e.stopPropagation();
20071 e.preventDefault();
20073 var target = e.getTarget();
20075 if(target.nodeName.toLowerCase() === 'i'){
20076 target = Roo.get(target).dom.parentNode;
20079 var nodeName = target.nodeName;
20080 var className = target.className;
20081 var html = target.innerHTML;
20083 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20087 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20089 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20095 picker : function()
20097 return this.pickerEl;
20100 fillMonths: function()
20103 var months = this.picker().select('>.datepicker-months td', true).first();
20105 months.dom.innerHTML = '';
20111 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20114 months.createChild(month);
20123 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20124 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20127 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20128 e.removeClass('active');
20130 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20131 e.addClass('active');
20138 if(this.isInline) {
20142 this.picker().removeClass(['bottom', 'top']);
20144 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20146 * place to the top of element!
20150 this.picker().addClass('top');
20151 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20156 this.picker().addClass('bottom');
20158 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20161 onFocus : function()
20163 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20167 onBlur : function()
20169 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20171 var d = this.inputEl().getValue();
20180 this.picker().show();
20181 this.picker().select('>.datepicker-months', true).first().show();
20185 this.fireEvent('show', this, this.date);
20190 if(this.isInline) {
20193 this.picker().hide();
20194 this.fireEvent('hide', this, this.date);
20198 onMousedown: function(e)
20200 e.stopPropagation();
20201 e.preventDefault();
20206 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20210 fireKey: function(e)
20212 if (!this.picker().isVisible()){
20213 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20224 e.preventDefault();
20228 dir = e.keyCode == 37 ? -1 : 1;
20230 this.vIndex = this.vIndex + dir;
20232 if(this.vIndex < 0){
20236 if(this.vIndex > 11){
20240 if(isNaN(this.vIndex)){
20244 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20250 dir = e.keyCode == 38 ? -1 : 1;
20252 this.vIndex = this.vIndex + dir * 4;
20254 if(this.vIndex < 0){
20258 if(this.vIndex > 11){
20262 if(isNaN(this.vIndex)){
20266 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20271 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20272 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20276 e.preventDefault();
20279 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20280 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20296 this.picker().remove();
20301 Roo.apply(Roo.bootstrap.MonthField, {
20320 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20321 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20326 Roo.apply(Roo.bootstrap.MonthField, {
20330 cls: 'datepicker dropdown-menu roo-dynamic',
20334 cls: 'datepicker-months',
20338 cls: 'table-condensed',
20340 Roo.bootstrap.DateField.content
20360 * @class Roo.bootstrap.CheckBox
20361 * @extends Roo.bootstrap.Input
20362 * Bootstrap CheckBox class
20364 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20365 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20366 * @cfg {String} boxLabel The text that appears beside the checkbox
20367 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20368 * @cfg {Boolean} checked initnal the element
20369 * @cfg {Boolean} inline inline the element (default false)
20370 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20371 * @cfg {String} tooltip label tooltip
20374 * Create a new CheckBox
20375 * @param {Object} config The config object
20378 Roo.bootstrap.CheckBox = function(config){
20379 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20384 * Fires when the element is checked or unchecked.
20385 * @param {Roo.bootstrap.CheckBox} this This input
20386 * @param {Boolean} checked The new checked value
20391 * Fires when the element is click.
20392 * @param {Roo.bootstrap.CheckBox} this This input
20399 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20401 inputType: 'checkbox',
20410 getAutoCreate : function()
20412 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20418 cfg.cls = 'form-group ' + this.inputType; //input-group
20421 cfg.cls += ' ' + this.inputType + '-inline';
20427 type : this.inputType,
20428 value : this.inputValue,
20429 cls : 'roo-' + this.inputType, //'form-box',
20430 placeholder : this.placeholder || ''
20434 if(this.inputType != 'radio'){
20438 cls : 'roo-hidden-value',
20439 value : this.checked ? this.inputValue : this.valueOff
20444 if (this.weight) { // Validity check?
20445 cfg.cls += " " + this.inputType + "-" + this.weight;
20448 if (this.disabled) {
20449 input.disabled=true;
20453 input.checked = this.checked;
20458 input.name = this.name;
20460 if(this.inputType != 'radio'){
20461 hidden.name = this.name;
20462 input.name = '_hidden_' + this.name;
20467 input.cls += ' input-' + this.size;
20472 ['xs','sm','md','lg'].map(function(size){
20473 if (settings[size]) {
20474 cfg.cls += ' col-' + size + '-' + settings[size];
20478 var inputblock = input;
20480 if (this.before || this.after) {
20483 cls : 'input-group',
20488 inputblock.cn.push({
20490 cls : 'input-group-addon',
20495 inputblock.cn.push(input);
20497 if(this.inputType != 'radio'){
20498 inputblock.cn.push(hidden);
20502 inputblock.cn.push({
20504 cls : 'input-group-addon',
20511 if (align ==='left' && this.fieldLabel.length) {
20512 // Roo.log("left and has label");
20517 cls : 'control-label',
20518 html : this.fieldLabel
20528 if(this.labelWidth > 12){
20529 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20532 if(this.labelWidth < 13 && this.labelmd == 0){
20533 this.labelmd = this.labelWidth;
20536 if(this.labellg > 0){
20537 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20538 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20541 if(this.labelmd > 0){
20542 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20543 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20546 if(this.labelsm > 0){
20547 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20548 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20551 if(this.labelxs > 0){
20552 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20553 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20556 } else if ( this.fieldLabel.length) {
20557 // Roo.log(" label");
20561 tag: this.boxLabel ? 'span' : 'label',
20563 cls: 'control-label box-input-label',
20564 //cls : 'input-group-addon',
20565 html : this.fieldLabel
20574 // Roo.log(" no label && no align");
20575 cfg.cn = [ inputblock ] ;
20581 var boxLabelCfg = {
20583 //'for': id, // box label is handled by onclick - so no for...
20585 html: this.boxLabel
20589 boxLabelCfg.tooltip = this.tooltip;
20592 cfg.cn.push(boxLabelCfg);
20595 if(this.inputType != 'radio'){
20596 cfg.cn.push(hidden);
20604 * return the real input element.
20606 inputEl: function ()
20608 return this.el.select('input.roo-' + this.inputType,true).first();
20610 hiddenEl: function ()
20612 return this.el.select('input.roo-hidden-value',true).first();
20615 labelEl: function()
20617 return this.el.select('label.control-label',true).first();
20619 /* depricated... */
20623 return this.labelEl();
20626 boxLabelEl: function()
20628 return this.el.select('label.box-label',true).first();
20631 initEvents : function()
20633 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20635 this.inputEl().on('click', this.onClick, this);
20637 if (this.boxLabel) {
20638 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20641 this.startValue = this.getValue();
20644 Roo.bootstrap.CheckBox.register(this);
20648 onClick : function(e)
20650 if(this.fireEvent('click', this, e) !== false){
20651 this.setChecked(!this.checked);
20656 setChecked : function(state,suppressEvent)
20658 this.startValue = this.getValue();
20660 if(this.inputType == 'radio'){
20662 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20663 e.dom.checked = false;
20666 this.inputEl().dom.checked = true;
20668 this.inputEl().dom.value = this.inputValue;
20670 if(suppressEvent !== true){
20671 this.fireEvent('check', this, true);
20679 this.checked = state;
20681 this.inputEl().dom.checked = state;
20684 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20686 if(suppressEvent !== true){
20687 this.fireEvent('check', this, state);
20693 getValue : function()
20695 if(this.inputType == 'radio'){
20696 return this.getGroupValue();
20699 return this.hiddenEl().dom.value;
20703 getGroupValue : function()
20705 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20709 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20712 setValue : function(v,suppressEvent)
20714 if(this.inputType == 'radio'){
20715 this.setGroupValue(v, suppressEvent);
20719 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20724 setGroupValue : function(v, suppressEvent)
20726 this.startValue = this.getValue();
20728 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20729 e.dom.checked = false;
20731 if(e.dom.value == v){
20732 e.dom.checked = true;
20736 if(suppressEvent !== true){
20737 this.fireEvent('check', this, true);
20745 validate : function()
20747 if(this.getVisibilityEl().hasClass('hidden')){
20753 (this.inputType == 'radio' && this.validateRadio()) ||
20754 (this.inputType == 'checkbox' && this.validateCheckbox())
20760 this.markInvalid();
20764 validateRadio : function()
20766 if(this.getVisibilityEl().hasClass('hidden')){
20770 if(this.allowBlank){
20776 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20777 if(!e.dom.checked){
20789 validateCheckbox : function()
20792 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20793 //return (this.getValue() == this.inputValue) ? true : false;
20796 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20804 for(var i in group){
20805 if(group[i].el.isVisible(true)){
20813 for(var i in group){
20818 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20825 * Mark this field as valid
20827 markValid : function()
20831 this.fireEvent('valid', this);
20833 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20836 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20843 if(this.inputType == 'radio'){
20844 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20845 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20846 e.findParent('.form-group', false, true).addClass(_this.validClass);
20853 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20854 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20858 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20864 for(var i in group){
20865 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20866 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20871 * Mark this field as invalid
20872 * @param {String} msg The validation message
20874 markInvalid : function(msg)
20876 if(this.allowBlank){
20882 this.fireEvent('invalid', this, msg);
20884 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20887 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20891 label.markInvalid();
20894 if(this.inputType == 'radio'){
20895 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20896 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20897 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20904 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20905 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20909 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20915 for(var i in group){
20916 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20917 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20922 clearInvalid : function()
20924 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20926 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20928 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20930 if (label && label.iconEl) {
20931 label.iconEl.removeClass(label.validClass);
20932 label.iconEl.removeClass(label.invalidClass);
20936 disable : function()
20938 if(this.inputType != 'radio'){
20939 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20946 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20947 _this.getActionEl().addClass(this.disabledClass);
20948 e.dom.disabled = true;
20952 this.disabled = true;
20953 this.fireEvent("disable", this);
20957 enable : function()
20959 if(this.inputType != 'radio'){
20960 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20967 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20968 _this.getActionEl().removeClass(this.disabledClass);
20969 e.dom.disabled = false;
20973 this.disabled = false;
20974 this.fireEvent("enable", this);
20978 setBoxLabel : function(v)
20983 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20989 Roo.apply(Roo.bootstrap.CheckBox, {
20994 * register a CheckBox Group
20995 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20997 register : function(checkbox)
20999 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21000 this.groups[checkbox.groupId] = {};
21003 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21007 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21011 * fetch a CheckBox Group based on the group ID
21012 * @param {string} the group ID
21013 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21015 get: function(groupId) {
21016 if (typeof(this.groups[groupId]) == 'undefined') {
21020 return this.groups[groupId] ;
21033 * @class Roo.bootstrap.Radio
21034 * @extends Roo.bootstrap.Component
21035 * Bootstrap Radio class
21036 * @cfg {String} boxLabel - the label associated
21037 * @cfg {String} value - the value of radio
21040 * Create a new Radio
21041 * @param {Object} config The config object
21043 Roo.bootstrap.Radio = function(config){
21044 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21048 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21054 getAutoCreate : function()
21058 cls : 'form-group radio',
21063 html : this.boxLabel
21071 initEvents : function()
21073 this.parent().register(this);
21075 this.el.on('click', this.onClick, this);
21079 onClick : function(e)
21081 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21082 this.setChecked(true);
21086 setChecked : function(state, suppressEvent)
21088 this.parent().setValue(this.value, suppressEvent);
21092 setBoxLabel : function(v)
21097 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21112 * @class Roo.bootstrap.SecurePass
21113 * @extends Roo.bootstrap.Input
21114 * Bootstrap SecurePass class
21118 * Create a new SecurePass
21119 * @param {Object} config The config object
21122 Roo.bootstrap.SecurePass = function (config) {
21123 // these go here, so the translation tool can replace them..
21125 PwdEmpty: "Please type a password, and then retype it to confirm.",
21126 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21127 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21128 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21129 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21130 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21131 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21132 TooWeak: "Your password is Too Weak."
21134 this.meterLabel = "Password strength:";
21135 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21136 this.meterClass = [
21137 "roo-password-meter-tooweak",
21138 "roo-password-meter-weak",
21139 "roo-password-meter-medium",
21140 "roo-password-meter-strong",
21141 "roo-password-meter-grey"
21146 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21149 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21151 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21153 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21154 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21155 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21156 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21157 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21158 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21159 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21169 * @cfg {String/Object} Label for the strength meter (defaults to
21170 * 'Password strength:')
21175 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21176 * ['Weak', 'Medium', 'Strong'])
21179 pwdStrengths: false,
21192 initEvents: function ()
21194 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21196 if (this.el.is('input[type=password]') && Roo.isSafari) {
21197 this.el.on('keydown', this.SafariOnKeyDown, this);
21200 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21203 onRender: function (ct, position)
21205 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21206 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21207 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21209 this.trigger.createChild({
21214 cls: 'roo-password-meter-grey col-xs-12',
21217 //width: this.meterWidth + 'px'
21221 cls: 'roo-password-meter-text'
21227 if (this.hideTrigger) {
21228 this.trigger.setDisplayed(false);
21230 this.setSize(this.width || '', this.height || '');
21233 onDestroy: function ()
21235 if (this.trigger) {
21236 this.trigger.removeAllListeners();
21237 this.trigger.remove();
21240 this.wrap.remove();
21242 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21245 checkStrength: function ()
21247 var pwd = this.inputEl().getValue();
21248 if (pwd == this._lastPwd) {
21253 if (this.ClientSideStrongPassword(pwd)) {
21255 } else if (this.ClientSideMediumPassword(pwd)) {
21257 } else if (this.ClientSideWeakPassword(pwd)) {
21263 Roo.log('strength1: ' + strength);
21265 //var pm = this.trigger.child('div/div/div').dom;
21266 var pm = this.trigger.child('div/div');
21267 pm.removeClass(this.meterClass);
21268 pm.addClass(this.meterClass[strength]);
21271 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21273 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21275 this._lastPwd = pwd;
21279 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21281 this._lastPwd = '';
21283 var pm = this.trigger.child('div/div');
21284 pm.removeClass(this.meterClass);
21285 pm.addClass('roo-password-meter-grey');
21288 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21291 this.inputEl().dom.type='password';
21294 validateValue: function (value)
21297 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21300 if (value.length == 0) {
21301 if (this.allowBlank) {
21302 this.clearInvalid();
21306 this.markInvalid(this.errors.PwdEmpty);
21307 this.errorMsg = this.errors.PwdEmpty;
21315 if ('[\x21-\x7e]*'.match(value)) {
21316 this.markInvalid(this.errors.PwdBadChar);
21317 this.errorMsg = this.errors.PwdBadChar;
21320 if (value.length < 6) {
21321 this.markInvalid(this.errors.PwdShort);
21322 this.errorMsg = this.errors.PwdShort;
21325 if (value.length > 16) {
21326 this.markInvalid(this.errors.PwdLong);
21327 this.errorMsg = this.errors.PwdLong;
21331 if (this.ClientSideStrongPassword(value)) {
21333 } else if (this.ClientSideMediumPassword(value)) {
21335 } else if (this.ClientSideWeakPassword(value)) {
21342 if (strength < 2) {
21343 //this.markInvalid(this.errors.TooWeak);
21344 this.errorMsg = this.errors.TooWeak;
21349 console.log('strength2: ' + strength);
21351 //var pm = this.trigger.child('div/div/div').dom;
21353 var pm = this.trigger.child('div/div');
21354 pm.removeClass(this.meterClass);
21355 pm.addClass(this.meterClass[strength]);
21357 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21359 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21361 this.errorMsg = '';
21365 CharacterSetChecks: function (type)
21368 this.fResult = false;
21371 isctype: function (character, type)
21374 case this.kCapitalLetter:
21375 if (character >= 'A' && character <= 'Z') {
21380 case this.kSmallLetter:
21381 if (character >= 'a' && character <= 'z') {
21387 if (character >= '0' && character <= '9') {
21392 case this.kPunctuation:
21393 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21404 IsLongEnough: function (pwd, size)
21406 return !(pwd == null || isNaN(size) || pwd.length < size);
21409 SpansEnoughCharacterSets: function (word, nb)
21411 if (!this.IsLongEnough(word, nb))
21416 var characterSetChecks = new Array(
21417 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21418 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21421 for (var index = 0; index < word.length; ++index) {
21422 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21423 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21424 characterSetChecks[nCharSet].fResult = true;
21431 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21432 if (characterSetChecks[nCharSet].fResult) {
21437 if (nCharSets < nb) {
21443 ClientSideStrongPassword: function (pwd)
21445 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21448 ClientSideMediumPassword: function (pwd)
21450 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21453 ClientSideWeakPassword: function (pwd)
21455 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21458 })//<script type="text/javascript">
21461 * Based Ext JS Library 1.1.1
21462 * Copyright(c) 2006-2007, Ext JS, LLC.
21468 * @class Roo.HtmlEditorCore
21469 * @extends Roo.Component
21470 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21472 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21475 Roo.HtmlEditorCore = function(config){
21478 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21483 * @event initialize
21484 * Fires when the editor is fully initialized (including the iframe)
21485 * @param {Roo.HtmlEditorCore} this
21490 * Fires when the editor is first receives the focus. Any insertion must wait
21491 * until after this event.
21492 * @param {Roo.HtmlEditorCore} this
21496 * @event beforesync
21497 * Fires before the textarea is updated with content from the editor iframe. Return false
21498 * to cancel the sync.
21499 * @param {Roo.HtmlEditorCore} this
21500 * @param {String} html
21504 * @event beforepush
21505 * Fires before the iframe editor is updated with content from the textarea. Return false
21506 * to cancel the push.
21507 * @param {Roo.HtmlEditorCore} this
21508 * @param {String} html
21513 * Fires when the textarea is updated with content from the editor iframe.
21514 * @param {Roo.HtmlEditorCore} this
21515 * @param {String} html
21520 * Fires when the iframe editor is updated with content from the textarea.
21521 * @param {Roo.HtmlEditorCore} this
21522 * @param {String} html
21527 * @event editorevent
21528 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21529 * @param {Roo.HtmlEditorCore} this
21535 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21537 // defaults : white / black...
21538 this.applyBlacklists();
21545 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21549 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21555 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21560 * @cfg {Number} height (in pixels)
21564 * @cfg {Number} width (in pixels)
21569 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21572 stylesheets: false,
21577 // private properties
21578 validationEvent : false,
21580 initialized : false,
21582 sourceEditMode : false,
21583 onFocus : Roo.emptyFn,
21585 hideMode:'offsets',
21589 // blacklist + whitelisted elements..
21596 * Protected method that will not generally be called directly. It
21597 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21598 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21600 getDocMarkup : function(){
21604 // inherit styels from page...??
21605 if (this.stylesheets === false) {
21607 Roo.get(document.head).select('style').each(function(node) {
21608 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21611 Roo.get(document.head).select('link').each(function(node) {
21612 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21615 } else if (!this.stylesheets.length) {
21617 st = '<style type="text/css">' +
21618 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21621 st = '<style type="text/css">' +
21626 st += '<style type="text/css">' +
21627 'IMG { cursor: pointer } ' +
21630 var cls = 'roo-htmleditor-body';
21632 if(this.bodyCls.length){
21633 cls += ' ' + this.bodyCls;
21636 return '<html><head>' + st +
21637 //<style type="text/css">' +
21638 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21640 ' </head><body class="' + cls + '"></body></html>';
21644 onRender : function(ct, position)
21647 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21648 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21651 this.el.dom.style.border = '0 none';
21652 this.el.dom.setAttribute('tabIndex', -1);
21653 this.el.addClass('x-hidden hide');
21657 if(Roo.isIE){ // fix IE 1px bogus margin
21658 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21662 this.frameId = Roo.id();
21666 var iframe = this.owner.wrap.createChild({
21668 cls: 'form-control', // bootstrap..
21670 name: this.frameId,
21671 frameBorder : 'no',
21672 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21677 this.iframe = iframe.dom;
21679 this.assignDocWin();
21681 this.doc.designMode = 'on';
21684 this.doc.write(this.getDocMarkup());
21688 var task = { // must defer to wait for browser to be ready
21690 //console.log("run task?" + this.doc.readyState);
21691 this.assignDocWin();
21692 if(this.doc.body || this.doc.readyState == 'complete'){
21694 this.doc.designMode="on";
21698 Roo.TaskMgr.stop(task);
21699 this.initEditor.defer(10, this);
21706 Roo.TaskMgr.start(task);
21711 onResize : function(w, h)
21713 Roo.log('resize: ' +w + ',' + h );
21714 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21718 if(typeof w == 'number'){
21720 this.iframe.style.width = w + 'px';
21722 if(typeof h == 'number'){
21724 this.iframe.style.height = h + 'px';
21726 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21733 * Toggles the editor between standard and source edit mode.
21734 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21736 toggleSourceEdit : function(sourceEditMode){
21738 this.sourceEditMode = sourceEditMode === true;
21740 if(this.sourceEditMode){
21742 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21745 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21746 //this.iframe.className = '';
21749 //this.setSize(this.owner.wrap.getSize());
21750 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21757 * Protected method that will not generally be called directly. If you need/want
21758 * custom HTML cleanup, this is the method you should override.
21759 * @param {String} html The HTML to be cleaned
21760 * return {String} The cleaned HTML
21762 cleanHtml : function(html){
21763 html = String(html);
21764 if(html.length > 5){
21765 if(Roo.isSafari){ // strip safari nonsense
21766 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21769 if(html == ' '){
21776 * HTML Editor -> Textarea
21777 * Protected method that will not generally be called directly. Syncs the contents
21778 * of the editor iframe with the textarea.
21780 syncValue : function(){
21781 if(this.initialized){
21782 var bd = (this.doc.body || this.doc.documentElement);
21783 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21784 var html = bd.innerHTML;
21786 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21787 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21789 html = '<div style="'+m[0]+'">' + html + '</div>';
21792 html = this.cleanHtml(html);
21793 // fix up the special chars.. normaly like back quotes in word...
21794 // however we do not want to do this with chinese..
21795 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21796 var cc = b.charCodeAt();
21798 (cc >= 0x4E00 && cc < 0xA000 ) ||
21799 (cc >= 0x3400 && cc < 0x4E00 ) ||
21800 (cc >= 0xf900 && cc < 0xfb00 )
21806 if(this.owner.fireEvent('beforesync', this, html) !== false){
21807 this.el.dom.value = html;
21808 this.owner.fireEvent('sync', this, html);
21814 * Protected method that will not generally be called directly. Pushes the value of the textarea
21815 * into the iframe editor.
21817 pushValue : function(){
21818 if(this.initialized){
21819 var v = this.el.dom.value.trim();
21821 // if(v.length < 1){
21825 if(this.owner.fireEvent('beforepush', this, v) !== false){
21826 var d = (this.doc.body || this.doc.documentElement);
21828 this.cleanUpPaste();
21829 this.el.dom.value = d.innerHTML;
21830 this.owner.fireEvent('push', this, v);
21836 deferFocus : function(){
21837 this.focus.defer(10, this);
21841 focus : function(){
21842 if(this.win && !this.sourceEditMode){
21849 assignDocWin: function()
21851 var iframe = this.iframe;
21854 this.doc = iframe.contentWindow.document;
21855 this.win = iframe.contentWindow;
21857 // if (!Roo.get(this.frameId)) {
21860 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21861 // this.win = Roo.get(this.frameId).dom.contentWindow;
21863 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21867 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21868 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21873 initEditor : function(){
21874 //console.log("INIT EDITOR");
21875 this.assignDocWin();
21879 this.doc.designMode="on";
21881 this.doc.write(this.getDocMarkup());
21884 var dbody = (this.doc.body || this.doc.documentElement);
21885 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21886 // this copies styles from the containing element into thsi one..
21887 // not sure why we need all of this..
21888 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21890 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21891 //ss['background-attachment'] = 'fixed'; // w3c
21892 dbody.bgProperties = 'fixed'; // ie
21893 //Roo.DomHelper.applyStyles(dbody, ss);
21894 Roo.EventManager.on(this.doc, {
21895 //'mousedown': this.onEditorEvent,
21896 'mouseup': this.onEditorEvent,
21897 'dblclick': this.onEditorEvent,
21898 'click': this.onEditorEvent,
21899 'keyup': this.onEditorEvent,
21904 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21906 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21907 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21909 this.initialized = true;
21911 this.owner.fireEvent('initialize', this);
21916 onDestroy : function(){
21922 //for (var i =0; i < this.toolbars.length;i++) {
21923 // // fixme - ask toolbars for heights?
21924 // this.toolbars[i].onDestroy();
21927 //this.wrap.dom.innerHTML = '';
21928 //this.wrap.remove();
21933 onFirstFocus : function(){
21935 this.assignDocWin();
21938 this.activated = true;
21941 if(Roo.isGecko){ // prevent silly gecko errors
21943 var s = this.win.getSelection();
21944 if(!s.focusNode || s.focusNode.nodeType != 3){
21945 var r = s.getRangeAt(0);
21946 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21951 this.execCmd('useCSS', true);
21952 this.execCmd('styleWithCSS', false);
21955 this.owner.fireEvent('activate', this);
21959 adjustFont: function(btn){
21960 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21961 //if(Roo.isSafari){ // safari
21964 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21965 if(Roo.isSafari){ // safari
21966 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21967 v = (v < 10) ? 10 : v;
21968 v = (v > 48) ? 48 : v;
21969 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21974 v = Math.max(1, v+adjust);
21976 this.execCmd('FontSize', v );
21979 onEditorEvent : function(e)
21981 this.owner.fireEvent('editorevent', this, e);
21982 // this.updateToolbar();
21983 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21986 insertTag : function(tg)
21988 // could be a bit smarter... -> wrap the current selected tRoo..
21989 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21991 range = this.createRange(this.getSelection());
21992 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21993 wrappingNode.appendChild(range.extractContents());
21994 range.insertNode(wrappingNode);
22001 this.execCmd("formatblock", tg);
22005 insertText : function(txt)
22009 var range = this.createRange();
22010 range.deleteContents();
22011 //alert(Sender.getAttribute('label'));
22013 range.insertNode(this.doc.createTextNode(txt));
22019 * Executes a Midas editor command on the editor document and performs necessary focus and
22020 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22021 * @param {String} cmd The Midas command
22022 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22024 relayCmd : function(cmd, value){
22026 this.execCmd(cmd, value);
22027 this.owner.fireEvent('editorevent', this);
22028 //this.updateToolbar();
22029 this.owner.deferFocus();
22033 * Executes a Midas editor command directly on the editor document.
22034 * For visual commands, you should use {@link #relayCmd} instead.
22035 * <b>This should only be called after the editor is initialized.</b>
22036 * @param {String} cmd The Midas command
22037 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22039 execCmd : function(cmd, value){
22040 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22047 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22049 * @param {String} text | dom node..
22051 insertAtCursor : function(text)
22054 if(!this.activated){
22060 var r = this.doc.selection.createRange();
22071 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22075 // from jquery ui (MIT licenced)
22077 var win = this.win;
22079 if (win.getSelection && win.getSelection().getRangeAt) {
22080 range = win.getSelection().getRangeAt(0);
22081 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22082 range.insertNode(node);
22083 } else if (win.document.selection && win.document.selection.createRange) {
22084 // no firefox support
22085 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22086 win.document.selection.createRange().pasteHTML(txt);
22088 // no firefox support
22089 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22090 this.execCmd('InsertHTML', txt);
22099 mozKeyPress : function(e){
22101 var c = e.getCharCode(), cmd;
22104 c = String.fromCharCode(c).toLowerCase();
22118 this.cleanUpPaste.defer(100, this);
22126 e.preventDefault();
22134 fixKeys : function(){ // load time branching for fastest keydown performance
22136 return function(e){
22137 var k = e.getKey(), r;
22140 r = this.doc.selection.createRange();
22143 r.pasteHTML('    ');
22150 r = this.doc.selection.createRange();
22152 var target = r.parentElement();
22153 if(!target || target.tagName.toLowerCase() != 'li'){
22155 r.pasteHTML('<br />');
22161 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22162 this.cleanUpPaste.defer(100, this);
22168 }else if(Roo.isOpera){
22169 return function(e){
22170 var k = e.getKey();
22174 this.execCmd('InsertHTML','    ');
22177 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22178 this.cleanUpPaste.defer(100, this);
22183 }else if(Roo.isSafari){
22184 return function(e){
22185 var k = e.getKey();
22189 this.execCmd('InsertText','\t');
22193 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22194 this.cleanUpPaste.defer(100, this);
22202 getAllAncestors: function()
22204 var p = this.getSelectedNode();
22207 a.push(p); // push blank onto stack..
22208 p = this.getParentElement();
22212 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22216 a.push(this.doc.body);
22220 lastSelNode : false,
22223 getSelection : function()
22225 this.assignDocWin();
22226 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22229 getSelectedNode: function()
22231 // this may only work on Gecko!!!
22233 // should we cache this!!!!
22238 var range = this.createRange(this.getSelection()).cloneRange();
22241 var parent = range.parentElement();
22243 var testRange = range.duplicate();
22244 testRange.moveToElementText(parent);
22245 if (testRange.inRange(range)) {
22248 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22251 parent = parent.parentElement;
22256 // is ancestor a text element.
22257 var ac = range.commonAncestorContainer;
22258 if (ac.nodeType == 3) {
22259 ac = ac.parentNode;
22262 var ar = ac.childNodes;
22265 var other_nodes = [];
22266 var has_other_nodes = false;
22267 for (var i=0;i<ar.length;i++) {
22268 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22271 // fullly contained node.
22273 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22278 // probably selected..
22279 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22280 other_nodes.push(ar[i]);
22284 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22289 has_other_nodes = true;
22291 if (!nodes.length && other_nodes.length) {
22292 nodes= other_nodes;
22294 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22300 createRange: function(sel)
22302 // this has strange effects when using with
22303 // top toolbar - not sure if it's a great idea.
22304 //this.editor.contentWindow.focus();
22305 if (typeof sel != "undefined") {
22307 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22309 return this.doc.createRange();
22312 return this.doc.createRange();
22315 getParentElement: function()
22318 this.assignDocWin();
22319 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22321 var range = this.createRange(sel);
22324 var p = range.commonAncestorContainer;
22325 while (p.nodeType == 3) { // text node
22336 * Range intersection.. the hard stuff...
22340 * [ -- selected range --- ]
22344 * if end is before start or hits it. fail.
22345 * if start is after end or hits it fail.
22347 * if either hits (but other is outside. - then it's not
22353 // @see http://www.thismuchiknow.co.uk/?p=64.
22354 rangeIntersectsNode : function(range, node)
22356 var nodeRange = node.ownerDocument.createRange();
22358 nodeRange.selectNode(node);
22360 nodeRange.selectNodeContents(node);
22363 var rangeStartRange = range.cloneRange();
22364 rangeStartRange.collapse(true);
22366 var rangeEndRange = range.cloneRange();
22367 rangeEndRange.collapse(false);
22369 var nodeStartRange = nodeRange.cloneRange();
22370 nodeStartRange.collapse(true);
22372 var nodeEndRange = nodeRange.cloneRange();
22373 nodeEndRange.collapse(false);
22375 return rangeStartRange.compareBoundaryPoints(
22376 Range.START_TO_START, nodeEndRange) == -1 &&
22377 rangeEndRange.compareBoundaryPoints(
22378 Range.START_TO_START, nodeStartRange) == 1;
22382 rangeCompareNode : function(range, node)
22384 var nodeRange = node.ownerDocument.createRange();
22386 nodeRange.selectNode(node);
22388 nodeRange.selectNodeContents(node);
22392 range.collapse(true);
22394 nodeRange.collapse(true);
22396 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22397 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22399 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22401 var nodeIsBefore = ss == 1;
22402 var nodeIsAfter = ee == -1;
22404 if (nodeIsBefore && nodeIsAfter) {
22407 if (!nodeIsBefore && nodeIsAfter) {
22408 return 1; //right trailed.
22411 if (nodeIsBefore && !nodeIsAfter) {
22412 return 2; // left trailed.
22418 // private? - in a new class?
22419 cleanUpPaste : function()
22421 // cleans up the whole document..
22422 Roo.log('cleanuppaste');
22424 this.cleanUpChildren(this.doc.body);
22425 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22426 if (clean != this.doc.body.innerHTML) {
22427 this.doc.body.innerHTML = clean;
22432 cleanWordChars : function(input) {// change the chars to hex code
22433 var he = Roo.HtmlEditorCore;
22435 var output = input;
22436 Roo.each(he.swapCodes, function(sw) {
22437 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22439 output = output.replace(swapper, sw[1]);
22446 cleanUpChildren : function (n)
22448 if (!n.childNodes.length) {
22451 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22452 this.cleanUpChild(n.childNodes[i]);
22459 cleanUpChild : function (node)
22462 //console.log(node);
22463 if (node.nodeName == "#text") {
22464 // clean up silly Windows -- stuff?
22467 if (node.nodeName == "#comment") {
22468 node.parentNode.removeChild(node);
22469 // clean up silly Windows -- stuff?
22472 var lcname = node.tagName.toLowerCase();
22473 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22474 // whitelist of tags..
22476 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22478 node.parentNode.removeChild(node);
22483 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22485 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22486 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22488 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22489 // remove_keep_children = true;
22492 if (remove_keep_children) {
22493 this.cleanUpChildren(node);
22494 // inserts everything just before this node...
22495 while (node.childNodes.length) {
22496 var cn = node.childNodes[0];
22497 node.removeChild(cn);
22498 node.parentNode.insertBefore(cn, node);
22500 node.parentNode.removeChild(node);
22504 if (!node.attributes || !node.attributes.length) {
22505 this.cleanUpChildren(node);
22509 function cleanAttr(n,v)
22512 if (v.match(/^\./) || v.match(/^\//)) {
22515 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22518 if (v.match(/^#/)) {
22521 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22522 node.removeAttribute(n);
22526 var cwhite = this.cwhite;
22527 var cblack = this.cblack;
22529 function cleanStyle(n,v)
22531 if (v.match(/expression/)) { //XSS?? should we even bother..
22532 node.removeAttribute(n);
22536 var parts = v.split(/;/);
22539 Roo.each(parts, function(p) {
22540 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22544 var l = p.split(':').shift().replace(/\s+/g,'');
22545 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22547 if ( cwhite.length && cblack.indexOf(l) > -1) {
22548 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22549 //node.removeAttribute(n);
22553 // only allow 'c whitelisted system attributes'
22554 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22555 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22556 //node.removeAttribute(n);
22566 if (clean.length) {
22567 node.setAttribute(n, clean.join(';'));
22569 node.removeAttribute(n);
22575 for (var i = node.attributes.length-1; i > -1 ; i--) {
22576 var a = node.attributes[i];
22579 if (a.name.toLowerCase().substr(0,2)=='on') {
22580 node.removeAttribute(a.name);
22583 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22584 node.removeAttribute(a.name);
22587 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22588 cleanAttr(a.name,a.value); // fixme..
22591 if (a.name == 'style') {
22592 cleanStyle(a.name,a.value);
22595 /// clean up MS crap..
22596 // tecnically this should be a list of valid class'es..
22599 if (a.name == 'class') {
22600 if (a.value.match(/^Mso/)) {
22601 node.className = '';
22604 if (a.value.match(/^body$/)) {
22605 node.className = '';
22616 this.cleanUpChildren(node);
22622 * Clean up MS wordisms...
22624 cleanWord : function(node)
22629 this.cleanWord(this.doc.body);
22632 if (node.nodeName == "#text") {
22633 // clean up silly Windows -- stuff?
22636 if (node.nodeName == "#comment") {
22637 node.parentNode.removeChild(node);
22638 // clean up silly Windows -- stuff?
22642 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22643 node.parentNode.removeChild(node);
22647 // remove - but keep children..
22648 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22649 while (node.childNodes.length) {
22650 var cn = node.childNodes[0];
22651 node.removeChild(cn);
22652 node.parentNode.insertBefore(cn, node);
22654 node.parentNode.removeChild(node);
22655 this.iterateChildren(node, this.cleanWord);
22659 if (node.className.length) {
22661 var cn = node.className.split(/\W+/);
22663 Roo.each(cn, function(cls) {
22664 if (cls.match(/Mso[a-zA-Z]+/)) {
22669 node.className = cna.length ? cna.join(' ') : '';
22671 node.removeAttribute("class");
22675 if (node.hasAttribute("lang")) {
22676 node.removeAttribute("lang");
22679 if (node.hasAttribute("style")) {
22681 var styles = node.getAttribute("style").split(";");
22683 Roo.each(styles, function(s) {
22684 if (!s.match(/:/)) {
22687 var kv = s.split(":");
22688 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22691 // what ever is left... we allow.
22694 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22695 if (!nstyle.length) {
22696 node.removeAttribute('style');
22699 this.iterateChildren(node, this.cleanWord);
22705 * iterateChildren of a Node, calling fn each time, using this as the scole..
22706 * @param {DomNode} node node to iterate children of.
22707 * @param {Function} fn method of this class to call on each item.
22709 iterateChildren : function(node, fn)
22711 if (!node.childNodes.length) {
22714 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22715 fn.call(this, node.childNodes[i])
22721 * cleanTableWidths.
22723 * Quite often pasting from word etc.. results in tables with column and widths.
22724 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22727 cleanTableWidths : function(node)
22732 this.cleanTableWidths(this.doc.body);
22737 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22740 Roo.log(node.tagName);
22741 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22742 this.iterateChildren(node, this.cleanTableWidths);
22745 if (node.hasAttribute('width')) {
22746 node.removeAttribute('width');
22750 if (node.hasAttribute("style")) {
22753 var styles = node.getAttribute("style").split(";");
22755 Roo.each(styles, function(s) {
22756 if (!s.match(/:/)) {
22759 var kv = s.split(":");
22760 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22763 // what ever is left... we allow.
22766 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22767 if (!nstyle.length) {
22768 node.removeAttribute('style');
22772 this.iterateChildren(node, this.cleanTableWidths);
22780 domToHTML : function(currentElement, depth, nopadtext) {
22782 depth = depth || 0;
22783 nopadtext = nopadtext || false;
22785 if (!currentElement) {
22786 return this.domToHTML(this.doc.body);
22789 //Roo.log(currentElement);
22791 var allText = false;
22792 var nodeName = currentElement.nodeName;
22793 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22795 if (nodeName == '#text') {
22797 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22802 if (nodeName != 'BODY') {
22805 // Prints the node tagName, such as <A>, <IMG>, etc
22808 for(i = 0; i < currentElement.attributes.length;i++) {
22810 var aname = currentElement.attributes.item(i).name;
22811 if (!currentElement.attributes.item(i).value.length) {
22814 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22817 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22826 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22829 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22834 // Traverse the tree
22836 var currentElementChild = currentElement.childNodes.item(i);
22837 var allText = true;
22838 var innerHTML = '';
22840 while (currentElementChild) {
22841 // Formatting code (indent the tree so it looks nice on the screen)
22842 var nopad = nopadtext;
22843 if (lastnode == 'SPAN') {
22847 if (currentElementChild.nodeName == '#text') {
22848 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22849 toadd = nopadtext ? toadd : toadd.trim();
22850 if (!nopad && toadd.length > 80) {
22851 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22853 innerHTML += toadd;
22856 currentElementChild = currentElement.childNodes.item(i);
22862 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22864 // Recursively traverse the tree structure of the child node
22865 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22866 lastnode = currentElementChild.nodeName;
22868 currentElementChild=currentElement.childNodes.item(i);
22874 // The remaining code is mostly for formatting the tree
22875 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22880 ret+= "</"+tagName+">";
22886 applyBlacklists : function()
22888 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22889 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22893 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22894 if (b.indexOf(tag) > -1) {
22897 this.white.push(tag);
22901 Roo.each(w, function(tag) {
22902 if (b.indexOf(tag) > -1) {
22905 if (this.white.indexOf(tag) > -1) {
22908 this.white.push(tag);
22913 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22914 if (w.indexOf(tag) > -1) {
22917 this.black.push(tag);
22921 Roo.each(b, function(tag) {
22922 if (w.indexOf(tag) > -1) {
22925 if (this.black.indexOf(tag) > -1) {
22928 this.black.push(tag);
22933 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22934 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22938 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22939 if (b.indexOf(tag) > -1) {
22942 this.cwhite.push(tag);
22946 Roo.each(w, function(tag) {
22947 if (b.indexOf(tag) > -1) {
22950 if (this.cwhite.indexOf(tag) > -1) {
22953 this.cwhite.push(tag);
22958 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22959 if (w.indexOf(tag) > -1) {
22962 this.cblack.push(tag);
22966 Roo.each(b, function(tag) {
22967 if (w.indexOf(tag) > -1) {
22970 if (this.cblack.indexOf(tag) > -1) {
22973 this.cblack.push(tag);
22978 setStylesheets : function(stylesheets)
22980 if(typeof(stylesheets) == 'string'){
22981 Roo.get(this.iframe.contentDocument.head).createChild({
22983 rel : 'stylesheet',
22992 Roo.each(stylesheets, function(s) {
22997 Roo.get(_this.iframe.contentDocument.head).createChild({
22999 rel : 'stylesheet',
23008 removeStylesheets : function()
23012 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23017 setStyle : function(style)
23019 Roo.get(this.iframe.contentDocument.head).createChild({
23028 // hide stuff that is not compatible
23042 * @event specialkey
23046 * @cfg {String} fieldClass @hide
23049 * @cfg {String} focusClass @hide
23052 * @cfg {String} autoCreate @hide
23055 * @cfg {String} inputType @hide
23058 * @cfg {String} invalidClass @hide
23061 * @cfg {String} invalidText @hide
23064 * @cfg {String} msgFx @hide
23067 * @cfg {String} validateOnBlur @hide
23071 Roo.HtmlEditorCore.white = [
23072 'area', 'br', 'img', 'input', 'hr', 'wbr',
23074 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23075 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23076 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23077 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23078 'table', 'ul', 'xmp',
23080 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23083 'dir', 'menu', 'ol', 'ul', 'dl',
23089 Roo.HtmlEditorCore.black = [
23090 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23092 'base', 'basefont', 'bgsound', 'blink', 'body',
23093 'frame', 'frameset', 'head', 'html', 'ilayer',
23094 'iframe', 'layer', 'link', 'meta', 'object',
23095 'script', 'style' ,'title', 'xml' // clean later..
23097 Roo.HtmlEditorCore.clean = [
23098 'script', 'style', 'title', 'xml'
23100 Roo.HtmlEditorCore.remove = [
23105 Roo.HtmlEditorCore.ablack = [
23109 Roo.HtmlEditorCore.aclean = [
23110 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23114 Roo.HtmlEditorCore.pwhite= [
23115 'http', 'https', 'mailto'
23118 // white listed style attributes.
23119 Roo.HtmlEditorCore.cwhite= [
23120 // 'text-align', /// default is to allow most things..
23126 // black listed style attributes.
23127 Roo.HtmlEditorCore.cblack= [
23128 // 'font-size' -- this can be set by the project
23132 Roo.HtmlEditorCore.swapCodes =[
23151 * @class Roo.bootstrap.HtmlEditor
23152 * @extends Roo.bootstrap.TextArea
23153 * Bootstrap HtmlEditor class
23156 * Create a new HtmlEditor
23157 * @param {Object} config The config object
23160 Roo.bootstrap.HtmlEditor = function(config){
23161 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23162 if (!this.toolbars) {
23163 this.toolbars = [];
23166 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23169 * @event initialize
23170 * Fires when the editor is fully initialized (including the iframe)
23171 * @param {HtmlEditor} this
23176 * Fires when the editor is first receives the focus. Any insertion must wait
23177 * until after this event.
23178 * @param {HtmlEditor} this
23182 * @event beforesync
23183 * Fires before the textarea is updated with content from the editor iframe. Return false
23184 * to cancel the sync.
23185 * @param {HtmlEditor} this
23186 * @param {String} html
23190 * @event beforepush
23191 * Fires before the iframe editor is updated with content from the textarea. Return false
23192 * to cancel the push.
23193 * @param {HtmlEditor} this
23194 * @param {String} html
23199 * Fires when the textarea is updated with content from the editor iframe.
23200 * @param {HtmlEditor} this
23201 * @param {String} html
23206 * Fires when the iframe editor is updated with content from the textarea.
23207 * @param {HtmlEditor} this
23208 * @param {String} html
23212 * @event editmodechange
23213 * Fires when the editor switches edit modes
23214 * @param {HtmlEditor} this
23215 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23217 editmodechange: true,
23219 * @event editorevent
23220 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23221 * @param {HtmlEditor} this
23225 * @event firstfocus
23226 * Fires when on first focus - needed by toolbars..
23227 * @param {HtmlEditor} this
23232 * Auto save the htmlEditor value as a file into Events
23233 * @param {HtmlEditor} this
23237 * @event savedpreview
23238 * preview the saved version of htmlEditor
23239 * @param {HtmlEditor} this
23246 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23250 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23255 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23260 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23265 * @cfg {Number} height (in pixels)
23269 * @cfg {Number} width (in pixels)
23274 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23277 stylesheets: false,
23282 // private properties
23283 validationEvent : false,
23285 initialized : false,
23288 onFocus : Roo.emptyFn,
23290 hideMode:'offsets',
23292 tbContainer : false,
23296 toolbarContainer :function() {
23297 return this.wrap.select('.x-html-editor-tb',true).first();
23301 * Protected method that will not generally be called directly. It
23302 * is called when the editor creates its toolbar. Override this method if you need to
23303 * add custom toolbar buttons.
23304 * @param {HtmlEditor} editor
23306 createToolbar : function(){
23307 Roo.log('renewing');
23308 Roo.log("create toolbars");
23310 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23311 this.toolbars[0].render(this.toolbarContainer());
23315 // if (!editor.toolbars || !editor.toolbars.length) {
23316 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23319 // for (var i =0 ; i < editor.toolbars.length;i++) {
23320 // editor.toolbars[i] = Roo.factory(
23321 // typeof(editor.toolbars[i]) == 'string' ?
23322 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23323 // Roo.bootstrap.HtmlEditor);
23324 // editor.toolbars[i].init(editor);
23330 onRender : function(ct, position)
23332 // Roo.log("Call onRender: " + this.xtype);
23334 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23336 this.wrap = this.inputEl().wrap({
23337 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23340 this.editorcore.onRender(ct, position);
23342 if (this.resizable) {
23343 this.resizeEl = new Roo.Resizable(this.wrap, {
23347 minHeight : this.height,
23348 height: this.height,
23349 handles : this.resizable,
23352 resize : function(r, w, h) {
23353 _t.onResize(w,h); // -something
23359 this.createToolbar(this);
23362 if(!this.width && this.resizable){
23363 this.setSize(this.wrap.getSize());
23365 if (this.resizeEl) {
23366 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23367 // should trigger onReize..
23373 onResize : function(w, h)
23375 Roo.log('resize: ' +w + ',' + h );
23376 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23380 if(this.inputEl() ){
23381 if(typeof w == 'number'){
23382 var aw = w - this.wrap.getFrameWidth('lr');
23383 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23386 if(typeof h == 'number'){
23387 var tbh = -11; // fixme it needs to tool bar size!
23388 for (var i =0; i < this.toolbars.length;i++) {
23389 // fixme - ask toolbars for heights?
23390 tbh += this.toolbars[i].el.getHeight();
23391 //if (this.toolbars[i].footer) {
23392 // tbh += this.toolbars[i].footer.el.getHeight();
23400 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23401 ah -= 5; // knock a few pixes off for look..
23402 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23406 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23407 this.editorcore.onResize(ew,eh);
23412 * Toggles the editor between standard and source edit mode.
23413 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23415 toggleSourceEdit : function(sourceEditMode)
23417 this.editorcore.toggleSourceEdit(sourceEditMode);
23419 if(this.editorcore.sourceEditMode){
23420 Roo.log('editor - showing textarea');
23423 // Roo.log(this.syncValue());
23425 this.inputEl().removeClass(['hide', 'x-hidden']);
23426 this.inputEl().dom.removeAttribute('tabIndex');
23427 this.inputEl().focus();
23429 Roo.log('editor - hiding textarea');
23431 // Roo.log(this.pushValue());
23434 this.inputEl().addClass(['hide', 'x-hidden']);
23435 this.inputEl().dom.setAttribute('tabIndex', -1);
23436 //this.deferFocus();
23439 if(this.resizable){
23440 this.setSize(this.wrap.getSize());
23443 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23446 // private (for BoxComponent)
23447 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23449 // private (for BoxComponent)
23450 getResizeEl : function(){
23454 // private (for BoxComponent)
23455 getPositionEl : function(){
23460 initEvents : function(){
23461 this.originalValue = this.getValue();
23465 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23468 // markInvalid : Roo.emptyFn,
23470 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23473 // clearInvalid : Roo.emptyFn,
23475 setValue : function(v){
23476 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23477 this.editorcore.pushValue();
23482 deferFocus : function(){
23483 this.focus.defer(10, this);
23487 focus : function(){
23488 this.editorcore.focus();
23494 onDestroy : function(){
23500 for (var i =0; i < this.toolbars.length;i++) {
23501 // fixme - ask toolbars for heights?
23502 this.toolbars[i].onDestroy();
23505 this.wrap.dom.innerHTML = '';
23506 this.wrap.remove();
23511 onFirstFocus : function(){
23512 //Roo.log("onFirstFocus");
23513 this.editorcore.onFirstFocus();
23514 for (var i =0; i < this.toolbars.length;i++) {
23515 this.toolbars[i].onFirstFocus();
23521 syncValue : function()
23523 this.editorcore.syncValue();
23526 pushValue : function()
23528 this.editorcore.pushValue();
23532 // hide stuff that is not compatible
23546 * @event specialkey
23550 * @cfg {String} fieldClass @hide
23553 * @cfg {String} focusClass @hide
23556 * @cfg {String} autoCreate @hide
23559 * @cfg {String} inputType @hide
23562 * @cfg {String} invalidClass @hide
23565 * @cfg {String} invalidText @hide
23568 * @cfg {String} msgFx @hide
23571 * @cfg {String} validateOnBlur @hide
23580 Roo.namespace('Roo.bootstrap.htmleditor');
23582 * @class Roo.bootstrap.HtmlEditorToolbar1
23587 new Roo.bootstrap.HtmlEditor({
23590 new Roo.bootstrap.HtmlEditorToolbar1({
23591 disable : { fonts: 1 , format: 1, ..., ... , ...],
23597 * @cfg {Object} disable List of elements to disable..
23598 * @cfg {Array} btns List of additional buttons.
23602 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23605 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23608 Roo.apply(this, config);
23610 // default disabled, based on 'good practice'..
23611 this.disable = this.disable || {};
23612 Roo.applyIf(this.disable, {
23615 specialElements : true
23617 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23619 this.editor = config.editor;
23620 this.editorcore = config.editor.editorcore;
23622 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23624 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23625 // dont call parent... till later.
23627 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23632 editorcore : false,
23637 "h1","h2","h3","h4","h5","h6",
23639 "abbr", "acronym", "address", "cite", "samp", "var",
23643 onRender : function(ct, position)
23645 // Roo.log("Call onRender: " + this.xtype);
23647 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23649 this.el.dom.style.marginBottom = '0';
23651 var editorcore = this.editorcore;
23652 var editor= this.editor;
23655 var btn = function(id,cmd , toggle, handler, html){
23657 var event = toggle ? 'toggle' : 'click';
23662 xns: Roo.bootstrap,
23665 enableToggle:toggle !== false,
23667 pressed : toggle ? false : null,
23670 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23671 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23677 // var cb_box = function...
23682 xns: Roo.bootstrap,
23683 glyphicon : 'font',
23687 xns: Roo.bootstrap,
23691 Roo.each(this.formats, function(f) {
23692 style.menu.items.push({
23694 xns: Roo.bootstrap,
23695 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23700 editorcore.insertTag(this.tagname);
23707 children.push(style);
23709 btn('bold',false,true);
23710 btn('italic',false,true);
23711 btn('align-left', 'justifyleft',true);
23712 btn('align-center', 'justifycenter',true);
23713 btn('align-right' , 'justifyright',true);
23714 btn('link', false, false, function(btn) {
23715 //Roo.log("create link?");
23716 var url = prompt(this.createLinkText, this.defaultLinkValue);
23717 if(url && url != 'http:/'+'/'){
23718 this.editorcore.relayCmd('createlink', url);
23721 btn('list','insertunorderedlist',true);
23722 btn('pencil', false,true, function(btn){
23724 this.toggleSourceEdit(btn.pressed);
23727 if (this.editor.btns.length > 0) {
23728 for (var i = 0; i<this.editor.btns.length; i++) {
23729 children.push(this.editor.btns[i]);
23737 xns: Roo.bootstrap,
23742 xns: Roo.bootstrap,
23747 cog.menu.items.push({
23749 xns: Roo.bootstrap,
23750 html : Clean styles,
23755 editorcore.insertTag(this.tagname);
23764 this.xtype = 'NavSimplebar';
23766 for(var i=0;i< children.length;i++) {
23768 this.buttons.add(this.addxtypeChild(children[i]));
23772 editor.on('editorevent', this.updateToolbar, this);
23774 onBtnClick : function(id)
23776 this.editorcore.relayCmd(id);
23777 this.editorcore.focus();
23781 * Protected method that will not generally be called directly. It triggers
23782 * a toolbar update by reading the markup state of the current selection in the editor.
23784 updateToolbar: function(){
23786 if(!this.editorcore.activated){
23787 this.editor.onFirstFocus(); // is this neeed?
23791 var btns = this.buttons;
23792 var doc = this.editorcore.doc;
23793 btns.get('bold').setActive(doc.queryCommandState('bold'));
23794 btns.get('italic').setActive(doc.queryCommandState('italic'));
23795 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23797 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23798 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23799 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23801 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23802 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23805 var ans = this.editorcore.getAllAncestors();
23806 if (this.formatCombo) {
23809 var store = this.formatCombo.store;
23810 this.formatCombo.setValue("");
23811 for (var i =0; i < ans.length;i++) {
23812 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23814 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23822 // hides menus... - so this cant be on a menu...
23823 Roo.bootstrap.MenuMgr.hideAll();
23825 Roo.bootstrap.MenuMgr.hideAll();
23826 //this.editorsyncValue();
23828 onFirstFocus: function() {
23829 this.buttons.each(function(item){
23833 toggleSourceEdit : function(sourceEditMode){
23836 if(sourceEditMode){
23837 Roo.log("disabling buttons");
23838 this.buttons.each( function(item){
23839 if(item.cmd != 'pencil'){
23845 Roo.log("enabling buttons");
23846 if(this.editorcore.initialized){
23847 this.buttons.each( function(item){
23853 Roo.log("calling toggole on editor");
23854 // tell the editor that it's been pressed..
23855 this.editor.toggleSourceEdit(sourceEditMode);
23865 * @class Roo.bootstrap.Table.AbstractSelectionModel
23866 * @extends Roo.util.Observable
23867 * Abstract base class for grid SelectionModels. It provides the interface that should be
23868 * implemented by descendant classes. This class should not be directly instantiated.
23871 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23872 this.locked = false;
23873 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23877 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23878 /** @ignore Called by the grid automatically. Do not call directly. */
23879 init : function(grid){
23885 * Locks the selections.
23888 this.locked = true;
23892 * Unlocks the selections.
23894 unlock : function(){
23895 this.locked = false;
23899 * Returns true if the selections are locked.
23900 * @return {Boolean}
23902 isLocked : function(){
23903 return this.locked;
23907 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23908 * @class Roo.bootstrap.Table.RowSelectionModel
23909 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23910 * It supports multiple selections and keyboard selection/navigation.
23912 * @param {Object} config
23915 Roo.bootstrap.Table.RowSelectionModel = function(config){
23916 Roo.apply(this, config);
23917 this.selections = new Roo.util.MixedCollection(false, function(o){
23922 this.lastActive = false;
23926 * @event selectionchange
23927 * Fires when the selection changes
23928 * @param {SelectionModel} this
23930 "selectionchange" : true,
23932 * @event afterselectionchange
23933 * Fires after the selection changes (eg. by key press or clicking)
23934 * @param {SelectionModel} this
23936 "afterselectionchange" : true,
23938 * @event beforerowselect
23939 * Fires when a row is selected being selected, return false to cancel.
23940 * @param {SelectionModel} this
23941 * @param {Number} rowIndex The selected index
23942 * @param {Boolean} keepExisting False if other selections will be cleared
23944 "beforerowselect" : true,
23947 * Fires when a row is selected.
23948 * @param {SelectionModel} this
23949 * @param {Number} rowIndex The selected index
23950 * @param {Roo.data.Record} r The record
23952 "rowselect" : true,
23954 * @event rowdeselect
23955 * Fires when a row is deselected.
23956 * @param {SelectionModel} this
23957 * @param {Number} rowIndex The selected index
23959 "rowdeselect" : true
23961 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23962 this.locked = false;
23965 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23967 * @cfg {Boolean} singleSelect
23968 * True to allow selection of only one row at a time (defaults to false)
23970 singleSelect : false,
23973 initEvents : function()
23976 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23977 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23978 //}else{ // allow click to work like normal
23979 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23981 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23982 this.grid.on("rowclick", this.handleMouseDown, this);
23984 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23985 "up" : function(e){
23987 this.selectPrevious(e.shiftKey);
23988 }else if(this.last !== false && this.lastActive !== false){
23989 var last = this.last;
23990 this.selectRange(this.last, this.lastActive-1);
23991 this.grid.getView().focusRow(this.lastActive);
23992 if(last !== false){
23996 this.selectFirstRow();
23998 this.fireEvent("afterselectionchange", this);
24000 "down" : function(e){
24002 this.selectNext(e.shiftKey);
24003 }else if(this.last !== false && this.lastActive !== false){
24004 var last = this.last;
24005 this.selectRange(this.last, this.lastActive+1);
24006 this.grid.getView().focusRow(this.lastActive);
24007 if(last !== false){
24011 this.selectFirstRow();
24013 this.fireEvent("afterselectionchange", this);
24017 this.grid.store.on('load', function(){
24018 this.selections.clear();
24021 var view = this.grid.view;
24022 view.on("refresh", this.onRefresh, this);
24023 view.on("rowupdated", this.onRowUpdated, this);
24024 view.on("rowremoved", this.onRemove, this);
24029 onRefresh : function()
24031 var ds = this.grid.store, i, v = this.grid.view;
24032 var s = this.selections;
24033 s.each(function(r){
24034 if((i = ds.indexOfId(r.id)) != -1){
24043 onRemove : function(v, index, r){
24044 this.selections.remove(r);
24048 onRowUpdated : function(v, index, r){
24049 if(this.isSelected(r)){
24050 v.onRowSelect(index);
24056 * @param {Array} records The records to select
24057 * @param {Boolean} keepExisting (optional) True to keep existing selections
24059 selectRecords : function(records, keepExisting)
24062 this.clearSelections();
24064 var ds = this.grid.store;
24065 for(var i = 0, len = records.length; i < len; i++){
24066 this.selectRow(ds.indexOf(records[i]), true);
24071 * Gets the number of selected rows.
24074 getCount : function(){
24075 return this.selections.length;
24079 * Selects the first row in the grid.
24081 selectFirstRow : function(){
24086 * Select the last row.
24087 * @param {Boolean} keepExisting (optional) True to keep existing selections
24089 selectLastRow : function(keepExisting){
24090 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24091 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24095 * Selects the row immediately following the last selected row.
24096 * @param {Boolean} keepExisting (optional) True to keep existing selections
24098 selectNext : function(keepExisting)
24100 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24101 this.selectRow(this.last+1, keepExisting);
24102 this.grid.getView().focusRow(this.last);
24107 * Selects the row that precedes the last selected row.
24108 * @param {Boolean} keepExisting (optional) True to keep existing selections
24110 selectPrevious : function(keepExisting){
24112 this.selectRow(this.last-1, keepExisting);
24113 this.grid.getView().focusRow(this.last);
24118 * Returns the selected records
24119 * @return {Array} Array of selected records
24121 getSelections : function(){
24122 return [].concat(this.selections.items);
24126 * Returns the first selected record.
24129 getSelected : function(){
24130 return this.selections.itemAt(0);
24135 * Clears all selections.
24137 clearSelections : function(fast)
24143 var ds = this.grid.store;
24144 var s = this.selections;
24145 s.each(function(r){
24146 this.deselectRow(ds.indexOfId(r.id));
24150 this.selections.clear();
24157 * Selects all rows.
24159 selectAll : function(){
24163 this.selections.clear();
24164 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24165 this.selectRow(i, true);
24170 * Returns True if there is a selection.
24171 * @return {Boolean}
24173 hasSelection : function(){
24174 return this.selections.length > 0;
24178 * Returns True if the specified row is selected.
24179 * @param {Number/Record} record The record or index of the record to check
24180 * @return {Boolean}
24182 isSelected : function(index){
24183 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24184 return (r && this.selections.key(r.id) ? true : false);
24188 * Returns True if the specified record id is selected.
24189 * @param {String} id The id of record to check
24190 * @return {Boolean}
24192 isIdSelected : function(id){
24193 return (this.selections.key(id) ? true : false);
24198 handleMouseDBClick : function(e, t){
24202 handleMouseDown : function(e, t)
24204 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24205 if(this.isLocked() || rowIndex < 0 ){
24208 if(e.shiftKey && this.last !== false){
24209 var last = this.last;
24210 this.selectRange(last, rowIndex, e.ctrlKey);
24211 this.last = last; // reset the last
24215 var isSelected = this.isSelected(rowIndex);
24216 //Roo.log("select row:" + rowIndex);
24218 this.deselectRow(rowIndex);
24220 this.selectRow(rowIndex, true);
24224 if(e.button !== 0 && isSelected){
24225 alert('rowIndex 2: ' + rowIndex);
24226 view.focusRow(rowIndex);
24227 }else if(e.ctrlKey && isSelected){
24228 this.deselectRow(rowIndex);
24229 }else if(!isSelected){
24230 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24231 view.focusRow(rowIndex);
24235 this.fireEvent("afterselectionchange", this);
24238 handleDragableRowClick : function(grid, rowIndex, e)
24240 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24241 this.selectRow(rowIndex, false);
24242 grid.view.focusRow(rowIndex);
24243 this.fireEvent("afterselectionchange", this);
24248 * Selects multiple rows.
24249 * @param {Array} rows Array of the indexes of the row to select
24250 * @param {Boolean} keepExisting (optional) True to keep existing selections
24252 selectRows : function(rows, keepExisting){
24254 this.clearSelections();
24256 for(var i = 0, len = rows.length; i < len; i++){
24257 this.selectRow(rows[i], true);
24262 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24263 * @param {Number} startRow The index of the first row in the range
24264 * @param {Number} endRow The index of the last row in the range
24265 * @param {Boolean} keepExisting (optional) True to retain existing selections
24267 selectRange : function(startRow, endRow, keepExisting){
24272 this.clearSelections();
24274 if(startRow <= endRow){
24275 for(var i = startRow; i <= endRow; i++){
24276 this.selectRow(i, true);
24279 for(var i = startRow; i >= endRow; i--){
24280 this.selectRow(i, true);
24286 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24287 * @param {Number} startRow The index of the first row in the range
24288 * @param {Number} endRow The index of the last row in the range
24290 deselectRange : function(startRow, endRow, preventViewNotify){
24294 for(var i = startRow; i <= endRow; i++){
24295 this.deselectRow(i, preventViewNotify);
24301 * @param {Number} row The index of the row to select
24302 * @param {Boolean} keepExisting (optional) True to keep existing selections
24304 selectRow : function(index, keepExisting, preventViewNotify)
24306 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24309 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24310 if(!keepExisting || this.singleSelect){
24311 this.clearSelections();
24314 var r = this.grid.store.getAt(index);
24315 //console.log('selectRow - record id :' + r.id);
24317 this.selections.add(r);
24318 this.last = this.lastActive = index;
24319 if(!preventViewNotify){
24320 var proxy = new Roo.Element(
24321 this.grid.getRowDom(index)
24323 proxy.addClass('bg-info info');
24325 this.fireEvent("rowselect", this, index, r);
24326 this.fireEvent("selectionchange", this);
24332 * @param {Number} row The index of the row to deselect
24334 deselectRow : function(index, preventViewNotify)
24339 if(this.last == index){
24342 if(this.lastActive == index){
24343 this.lastActive = false;
24346 var r = this.grid.store.getAt(index);
24351 this.selections.remove(r);
24352 //.console.log('deselectRow - record id :' + r.id);
24353 if(!preventViewNotify){
24355 var proxy = new Roo.Element(
24356 this.grid.getRowDom(index)
24358 proxy.removeClass('bg-info info');
24360 this.fireEvent("rowdeselect", this, index);
24361 this.fireEvent("selectionchange", this);
24365 restoreLast : function(){
24367 this.last = this._last;
24372 acceptsNav : function(row, col, cm){
24373 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24377 onEditorKey : function(field, e){
24378 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24383 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24385 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24387 }else if(k == e.ENTER && !e.ctrlKey){
24391 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24393 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24395 }else if(k == e.ESC){
24399 g.startEditing(newCell[0], newCell[1]);
24405 * Ext JS Library 1.1.1
24406 * Copyright(c) 2006-2007, Ext JS, LLC.
24408 * Originally Released Under LGPL - original licence link has changed is not relivant.
24411 * <script type="text/javascript">
24415 * @class Roo.bootstrap.PagingToolbar
24416 * @extends Roo.bootstrap.NavSimplebar
24417 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24419 * Create a new PagingToolbar
24420 * @param {Object} config The config object
24421 * @param {Roo.data.Store} store
24423 Roo.bootstrap.PagingToolbar = function(config)
24425 // old args format still supported... - xtype is prefered..
24426 // created from xtype...
24428 this.ds = config.dataSource;
24430 if (config.store && !this.ds) {
24431 this.store= Roo.factory(config.store, Roo.data);
24432 this.ds = this.store;
24433 this.ds.xmodule = this.xmodule || false;
24436 this.toolbarItems = [];
24437 if (config.items) {
24438 this.toolbarItems = config.items;
24441 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24446 this.bind(this.ds);
24449 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24453 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24455 * @cfg {Roo.data.Store} dataSource
24456 * The underlying data store providing the paged data
24459 * @cfg {String/HTMLElement/Element} container
24460 * container The id or element that will contain the toolbar
24463 * @cfg {Boolean} displayInfo
24464 * True to display the displayMsg (defaults to false)
24467 * @cfg {Number} pageSize
24468 * The number of records to display per page (defaults to 20)
24472 * @cfg {String} displayMsg
24473 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24475 displayMsg : 'Displaying {0} - {1} of {2}',
24477 * @cfg {String} emptyMsg
24478 * The message to display when no records are found (defaults to "No data to display")
24480 emptyMsg : 'No data to display',
24482 * Customizable piece of the default paging text (defaults to "Page")
24485 beforePageText : "Page",
24487 * Customizable piece of the default paging text (defaults to "of %0")
24490 afterPageText : "of {0}",
24492 * Customizable piece of the default paging text (defaults to "First Page")
24495 firstText : "First Page",
24497 * Customizable piece of the default paging text (defaults to "Previous Page")
24500 prevText : "Previous Page",
24502 * Customizable piece of the default paging text (defaults to "Next Page")
24505 nextText : "Next Page",
24507 * Customizable piece of the default paging text (defaults to "Last Page")
24510 lastText : "Last Page",
24512 * Customizable piece of the default paging text (defaults to "Refresh")
24515 refreshText : "Refresh",
24519 onRender : function(ct, position)
24521 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24522 this.navgroup.parentId = this.id;
24523 this.navgroup.onRender(this.el, null);
24524 // add the buttons to the navgroup
24526 if(this.displayInfo){
24527 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24528 this.displayEl = this.el.select('.x-paging-info', true).first();
24529 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24530 // this.displayEl = navel.el.select('span',true).first();
24536 Roo.each(_this.buttons, function(e){ // this might need to use render????
24537 Roo.factory(e).render(_this.el);
24541 Roo.each(_this.toolbarItems, function(e) {
24542 _this.navgroup.addItem(e);
24546 this.first = this.navgroup.addItem({
24547 tooltip: this.firstText,
24549 icon : 'fa fa-backward',
24551 preventDefault: true,
24552 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24555 this.prev = this.navgroup.addItem({
24556 tooltip: this.prevText,
24558 icon : 'fa fa-step-backward',
24560 preventDefault: true,
24561 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24563 //this.addSeparator();
24566 var field = this.navgroup.addItem( {
24568 cls : 'x-paging-position',
24570 html : this.beforePageText +
24571 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24572 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24575 this.field = field.el.select('input', true).first();
24576 this.field.on("keydown", this.onPagingKeydown, this);
24577 this.field.on("focus", function(){this.dom.select();});
24580 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24581 //this.field.setHeight(18);
24582 //this.addSeparator();
24583 this.next = this.navgroup.addItem({
24584 tooltip: this.nextText,
24586 html : ' <i class="fa fa-step-forward">',
24588 preventDefault: true,
24589 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24591 this.last = this.navgroup.addItem({
24592 tooltip: this.lastText,
24593 icon : 'fa fa-forward',
24596 preventDefault: true,
24597 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24599 //this.addSeparator();
24600 this.loading = this.navgroup.addItem({
24601 tooltip: this.refreshText,
24602 icon: 'fa fa-refresh',
24603 preventDefault: true,
24604 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24610 updateInfo : function(){
24611 if(this.displayEl){
24612 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24613 var msg = count == 0 ?
24617 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24619 this.displayEl.update(msg);
24624 onLoad : function(ds, r, o)
24626 this.cursor = o.params.start ? o.params.start : 0;
24628 var d = this.getPageData(),
24633 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24634 this.field.dom.value = ap;
24635 this.first.setDisabled(ap == 1);
24636 this.prev.setDisabled(ap == 1);
24637 this.next.setDisabled(ap == ps);
24638 this.last.setDisabled(ap == ps);
24639 this.loading.enable();
24644 getPageData : function(){
24645 var total = this.ds.getTotalCount();
24648 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24649 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24654 onLoadError : function(){
24655 this.loading.enable();
24659 onPagingKeydown : function(e){
24660 var k = e.getKey();
24661 var d = this.getPageData();
24663 var v = this.field.dom.value, pageNum;
24664 if(!v || isNaN(pageNum = parseInt(v, 10))){
24665 this.field.dom.value = d.activePage;
24668 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24669 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24672 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))
24674 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24675 this.field.dom.value = pageNum;
24676 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24679 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24681 var v = this.field.dom.value, pageNum;
24682 var increment = (e.shiftKey) ? 10 : 1;
24683 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24686 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24687 this.field.dom.value = d.activePage;
24690 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24692 this.field.dom.value = parseInt(v, 10) + increment;
24693 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24694 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24701 beforeLoad : function(){
24703 this.loading.disable();
24708 onClick : function(which){
24717 ds.load({params:{start: 0, limit: this.pageSize}});
24720 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24723 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24726 var total = ds.getTotalCount();
24727 var extra = total % this.pageSize;
24728 var lastStart = extra ? (total - extra) : total-this.pageSize;
24729 ds.load({params:{start: lastStart, limit: this.pageSize}});
24732 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24738 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24739 * @param {Roo.data.Store} store The data store to unbind
24741 unbind : function(ds){
24742 ds.un("beforeload", this.beforeLoad, this);
24743 ds.un("load", this.onLoad, this);
24744 ds.un("loadexception", this.onLoadError, this);
24745 ds.un("remove", this.updateInfo, this);
24746 ds.un("add", this.updateInfo, this);
24747 this.ds = undefined;
24751 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24752 * @param {Roo.data.Store} store The data store to bind
24754 bind : function(ds){
24755 ds.on("beforeload", this.beforeLoad, this);
24756 ds.on("load", this.onLoad, this);
24757 ds.on("loadexception", this.onLoadError, this);
24758 ds.on("remove", this.updateInfo, this);
24759 ds.on("add", this.updateInfo, this);
24770 * @class Roo.bootstrap.MessageBar
24771 * @extends Roo.bootstrap.Component
24772 * Bootstrap MessageBar class
24773 * @cfg {String} html contents of the MessageBar
24774 * @cfg {String} weight (info | success | warning | danger) default info
24775 * @cfg {String} beforeClass insert the bar before the given class
24776 * @cfg {Boolean} closable (true | false) default false
24777 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24780 * Create a new Element
24781 * @param {Object} config The config object
24784 Roo.bootstrap.MessageBar = function(config){
24785 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24788 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24794 beforeClass: 'bootstrap-sticky-wrap',
24796 getAutoCreate : function(){
24800 cls: 'alert alert-dismissable alert-' + this.weight,
24805 html: this.html || ''
24811 cfg.cls += ' alert-messages-fixed';
24825 onRender : function(ct, position)
24827 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24830 var cfg = Roo.apply({}, this.getAutoCreate());
24834 cfg.cls += ' ' + this.cls;
24837 cfg.style = this.style;
24839 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24841 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24844 this.el.select('>button.close').on('click', this.hide, this);
24850 if (!this.rendered) {
24856 this.fireEvent('show', this);
24862 if (!this.rendered) {
24868 this.fireEvent('hide', this);
24871 update : function()
24873 // var e = this.el.dom.firstChild;
24875 // if(this.closable){
24876 // e = e.nextSibling;
24879 // e.data = this.html || '';
24881 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24897 * @class Roo.bootstrap.Graph
24898 * @extends Roo.bootstrap.Component
24899 * Bootstrap Graph class
24903 @cfg {String} graphtype bar | vbar | pie
24904 @cfg {number} g_x coodinator | centre x (pie)
24905 @cfg {number} g_y coodinator | centre y (pie)
24906 @cfg {number} g_r radius (pie)
24907 @cfg {number} g_height height of the chart (respected by all elements in the set)
24908 @cfg {number} g_width width of the chart (respected by all elements in the set)
24909 @cfg {Object} title The title of the chart
24912 -opts (object) options for the chart
24914 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24915 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24917 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.
24918 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24920 o stretch (boolean)
24922 -opts (object) options for the pie
24925 o startAngle (number)
24926 o endAngle (number)
24930 * Create a new Input
24931 * @param {Object} config The config object
24934 Roo.bootstrap.Graph = function(config){
24935 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24941 * The img click event for the img.
24942 * @param {Roo.EventObject} e
24948 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24959 //g_colors: this.colors,
24966 getAutoCreate : function(){
24977 onRender : function(ct,position){
24980 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24982 if (typeof(Raphael) == 'undefined') {
24983 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24987 this.raphael = Raphael(this.el.dom);
24989 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24990 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24991 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24992 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24994 r.text(160, 10, "Single Series Chart").attr(txtattr);
24995 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24996 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24997 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24999 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25000 r.barchart(330, 10, 300, 220, data1);
25001 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25002 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25005 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25006 // r.barchart(30, 30, 560, 250, xdata, {
25007 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25008 // axis : "0 0 1 1",
25009 // axisxlabels : xdata
25010 // //yvalues : cols,
25013 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25015 // this.load(null,xdata,{
25016 // axis : "0 0 1 1",
25017 // axisxlabels : xdata
25022 load : function(graphtype,xdata,opts)
25024 this.raphael.clear();
25026 graphtype = this.graphtype;
25031 var r = this.raphael,
25032 fin = function () {
25033 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25035 fout = function () {
25036 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25038 pfin = function() {
25039 this.sector.stop();
25040 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25043 this.label[0].stop();
25044 this.label[0].attr({ r: 7.5 });
25045 this.label[1].attr({ "font-weight": 800 });
25048 pfout = function() {
25049 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25052 this.label[0].animate({ r: 5 }, 500, "bounce");
25053 this.label[1].attr({ "font-weight": 400 });
25059 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25062 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25065 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25066 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25068 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25075 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25080 setTitle: function(o)
25085 initEvents: function() {
25088 this.el.on('click', this.onClick, this);
25092 onClick : function(e)
25094 Roo.log('img onclick');
25095 this.fireEvent('click', this, e);
25107 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25110 * @class Roo.bootstrap.dash.NumberBox
25111 * @extends Roo.bootstrap.Component
25112 * Bootstrap NumberBox class
25113 * @cfg {String} headline Box headline
25114 * @cfg {String} content Box content
25115 * @cfg {String} icon Box icon
25116 * @cfg {String} footer Footer text
25117 * @cfg {String} fhref Footer href
25120 * Create a new NumberBox
25121 * @param {Object} config The config object
25125 Roo.bootstrap.dash.NumberBox = function(config){
25126 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25130 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25139 getAutoCreate : function(){
25143 cls : 'small-box ',
25151 cls : 'roo-headline',
25152 html : this.headline
25156 cls : 'roo-content',
25157 html : this.content
25171 cls : 'ion ' + this.icon
25180 cls : 'small-box-footer',
25181 href : this.fhref || '#',
25185 cfg.cn.push(footer);
25192 onRender : function(ct,position){
25193 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25200 setHeadline: function (value)
25202 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25205 setFooter: function (value, href)
25207 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25210 this.el.select('a.small-box-footer',true).first().attr('href', href);
25215 setContent: function (value)
25217 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25220 initEvents: function()
25234 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25237 * @class Roo.bootstrap.dash.TabBox
25238 * @extends Roo.bootstrap.Component
25239 * Bootstrap TabBox class
25240 * @cfg {String} title Title of the TabBox
25241 * @cfg {String} icon Icon of the TabBox
25242 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25243 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25246 * Create a new TabBox
25247 * @param {Object} config The config object
25251 Roo.bootstrap.dash.TabBox = function(config){
25252 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25257 * When a pane is added
25258 * @param {Roo.bootstrap.dash.TabPane} pane
25262 * @event activatepane
25263 * When a pane is activated
25264 * @param {Roo.bootstrap.dash.TabPane} pane
25266 "activatepane" : true
25274 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25279 tabScrollable : false,
25281 getChildContainer : function()
25283 return this.el.select('.tab-content', true).first();
25286 getAutoCreate : function(){
25290 cls: 'pull-left header',
25298 cls: 'fa ' + this.icon
25304 cls: 'nav nav-tabs pull-right',
25310 if(this.tabScrollable){
25317 cls: 'nav nav-tabs pull-right',
25328 cls: 'nav-tabs-custom',
25333 cls: 'tab-content no-padding',
25341 initEvents : function()
25343 //Roo.log('add add pane handler');
25344 this.on('addpane', this.onAddPane, this);
25347 * Updates the box title
25348 * @param {String} html to set the title to.
25350 setTitle : function(value)
25352 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25354 onAddPane : function(pane)
25356 this.panes.push(pane);
25357 //Roo.log('addpane');
25359 // tabs are rendere left to right..
25360 if(!this.showtabs){
25364 var ctr = this.el.select('.nav-tabs', true).first();
25367 var existing = ctr.select('.nav-tab',true);
25368 var qty = existing.getCount();;
25371 var tab = ctr.createChild({
25373 cls : 'nav-tab' + (qty ? '' : ' active'),
25381 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25384 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25386 pane.el.addClass('active');
25391 onTabClick : function(ev,un,ob,pane)
25393 //Roo.log('tab - prev default');
25394 ev.preventDefault();
25397 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25398 pane.tab.addClass('active');
25399 //Roo.log(pane.title);
25400 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25401 // technically we should have a deactivate event.. but maybe add later.
25402 // and it should not de-activate the selected tab...
25403 this.fireEvent('activatepane', pane);
25404 pane.el.addClass('active');
25405 pane.fireEvent('activate');
25410 getActivePane : function()
25413 Roo.each(this.panes, function(p) {
25414 if(p.el.hasClass('active')){
25435 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25437 * @class Roo.bootstrap.TabPane
25438 * @extends Roo.bootstrap.Component
25439 * Bootstrap TabPane class
25440 * @cfg {Boolean} active (false | true) Default false
25441 * @cfg {String} title title of panel
25445 * Create a new TabPane
25446 * @param {Object} config The config object
25449 Roo.bootstrap.dash.TabPane = function(config){
25450 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25456 * When a pane is activated
25457 * @param {Roo.bootstrap.dash.TabPane} pane
25464 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25469 // the tabBox that this is attached to.
25472 getAutoCreate : function()
25480 cfg.cls += ' active';
25485 initEvents : function()
25487 //Roo.log('trigger add pane handler');
25488 this.parent().fireEvent('addpane', this)
25492 * Updates the tab title
25493 * @param {String} html to set the title to.
25495 setTitle: function(str)
25501 this.tab.select('a', true).first().dom.innerHTML = str;
25518 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25521 * @class Roo.bootstrap.menu.Menu
25522 * @extends Roo.bootstrap.Component
25523 * Bootstrap Menu class - container for Menu
25524 * @cfg {String} html Text of the menu
25525 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25526 * @cfg {String} icon Font awesome icon
25527 * @cfg {String} pos Menu align to (top | bottom) default bottom
25531 * Create a new Menu
25532 * @param {Object} config The config object
25536 Roo.bootstrap.menu.Menu = function(config){
25537 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25541 * @event beforeshow
25542 * Fires before this menu is displayed
25543 * @param {Roo.bootstrap.menu.Menu} this
25547 * @event beforehide
25548 * Fires before this menu is hidden
25549 * @param {Roo.bootstrap.menu.Menu} this
25554 * Fires after this menu is displayed
25555 * @param {Roo.bootstrap.menu.Menu} this
25560 * Fires after this menu is hidden
25561 * @param {Roo.bootstrap.menu.Menu} this
25566 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25567 * @param {Roo.bootstrap.menu.Menu} this
25568 * @param {Roo.EventObject} e
25575 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25579 weight : 'default',
25584 getChildContainer : function() {
25585 if(this.isSubMenu){
25589 return this.el.select('ul.dropdown-menu', true).first();
25592 getAutoCreate : function()
25597 cls : 'roo-menu-text',
25605 cls : 'fa ' + this.icon
25616 cls : 'dropdown-button btn btn-' + this.weight,
25621 cls : 'dropdown-toggle btn btn-' + this.weight,
25631 cls : 'dropdown-menu'
25637 if(this.pos == 'top'){
25638 cfg.cls += ' dropup';
25641 if(this.isSubMenu){
25644 cls : 'dropdown-menu'
25651 onRender : function(ct, position)
25653 this.isSubMenu = ct.hasClass('dropdown-submenu');
25655 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25658 initEvents : function()
25660 if(this.isSubMenu){
25664 this.hidden = true;
25666 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25667 this.triggerEl.on('click', this.onTriggerPress, this);
25669 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25670 this.buttonEl.on('click', this.onClick, this);
25676 if(this.isSubMenu){
25680 return this.el.select('ul.dropdown-menu', true).first();
25683 onClick : function(e)
25685 this.fireEvent("click", this, e);
25688 onTriggerPress : function(e)
25690 if (this.isVisible()) {
25697 isVisible : function(){
25698 return !this.hidden;
25703 this.fireEvent("beforeshow", this);
25705 this.hidden = false;
25706 this.el.addClass('open');
25708 Roo.get(document).on("mouseup", this.onMouseUp, this);
25710 this.fireEvent("show", this);
25717 this.fireEvent("beforehide", this);
25719 this.hidden = true;
25720 this.el.removeClass('open');
25722 Roo.get(document).un("mouseup", this.onMouseUp);
25724 this.fireEvent("hide", this);
25727 onMouseUp : function()
25741 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25744 * @class Roo.bootstrap.menu.Item
25745 * @extends Roo.bootstrap.Component
25746 * Bootstrap MenuItem class
25747 * @cfg {Boolean} submenu (true | false) default false
25748 * @cfg {String} html text of the item
25749 * @cfg {String} href the link
25750 * @cfg {Boolean} disable (true | false) default false
25751 * @cfg {Boolean} preventDefault (true | false) default true
25752 * @cfg {String} icon Font awesome icon
25753 * @cfg {String} pos Submenu align to (left | right) default right
25757 * Create a new Item
25758 * @param {Object} config The config object
25762 Roo.bootstrap.menu.Item = function(config){
25763 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25767 * Fires when the mouse is hovering over this menu
25768 * @param {Roo.bootstrap.menu.Item} this
25769 * @param {Roo.EventObject} e
25774 * Fires when the mouse exits this menu
25775 * @param {Roo.bootstrap.menu.Item} this
25776 * @param {Roo.EventObject} e
25782 * The raw click event for the entire grid.
25783 * @param {Roo.EventObject} e
25789 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25794 preventDefault: true,
25799 getAutoCreate : function()
25804 cls : 'roo-menu-item-text',
25812 cls : 'fa ' + this.icon
25821 href : this.href || '#',
25828 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25832 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25834 if(this.pos == 'left'){
25835 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25842 initEvents : function()
25844 this.el.on('mouseover', this.onMouseOver, this);
25845 this.el.on('mouseout', this.onMouseOut, this);
25847 this.el.select('a', true).first().on('click', this.onClick, this);
25851 onClick : function(e)
25853 if(this.preventDefault){
25854 e.preventDefault();
25857 this.fireEvent("click", this, e);
25860 onMouseOver : function(e)
25862 if(this.submenu && this.pos == 'left'){
25863 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25866 this.fireEvent("mouseover", this, e);
25869 onMouseOut : function(e)
25871 this.fireEvent("mouseout", this, e);
25883 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25886 * @class Roo.bootstrap.menu.Separator
25887 * @extends Roo.bootstrap.Component
25888 * Bootstrap Separator class
25891 * Create a new Separator
25892 * @param {Object} config The config object
25896 Roo.bootstrap.menu.Separator = function(config){
25897 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25900 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25902 getAutoCreate : function(){
25923 * @class Roo.bootstrap.Tooltip
25924 * Bootstrap Tooltip class
25925 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25926 * to determine which dom element triggers the tooltip.
25928 * It needs to add support for additional attributes like tooltip-position
25931 * Create a new Toolti
25932 * @param {Object} config The config object
25935 Roo.bootstrap.Tooltip = function(config){
25936 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25938 this.alignment = Roo.bootstrap.Tooltip.alignment;
25940 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25941 this.alignment = config.alignment;
25946 Roo.apply(Roo.bootstrap.Tooltip, {
25948 * @function init initialize tooltip monitoring.
25952 currentTip : false,
25953 currentRegion : false,
25959 Roo.get(document).on('mouseover', this.enter ,this);
25960 Roo.get(document).on('mouseout', this.leave, this);
25963 this.currentTip = new Roo.bootstrap.Tooltip();
25966 enter : function(ev)
25968 var dom = ev.getTarget();
25970 //Roo.log(['enter',dom]);
25971 var el = Roo.fly(dom);
25972 if (this.currentEl) {
25974 //Roo.log(this.currentEl);
25975 //Roo.log(this.currentEl.contains(dom));
25976 if (this.currentEl == el) {
25979 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25985 if (this.currentTip.el) {
25986 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25990 if(!el || el.dom == document){
25996 // you can not look for children, as if el is the body.. then everythign is the child..
25997 if (!el.attr('tooltip')) { //
25998 if (!el.select("[tooltip]").elements.length) {
26001 // is the mouse over this child...?
26002 bindEl = el.select("[tooltip]").first();
26003 var xy = ev.getXY();
26004 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26005 //Roo.log("not in region.");
26008 //Roo.log("child element over..");
26011 this.currentEl = bindEl;
26012 this.currentTip.bind(bindEl);
26013 this.currentRegion = Roo.lib.Region.getRegion(dom);
26014 this.currentTip.enter();
26017 leave : function(ev)
26019 var dom = ev.getTarget();
26020 //Roo.log(['leave',dom]);
26021 if (!this.currentEl) {
26026 if (dom != this.currentEl.dom) {
26029 var xy = ev.getXY();
26030 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26033 // only activate leave if mouse cursor is outside... bounding box..
26038 if (this.currentTip) {
26039 this.currentTip.leave();
26041 //Roo.log('clear currentEl');
26042 this.currentEl = false;
26047 'left' : ['r-l', [-2,0], 'right'],
26048 'right' : ['l-r', [2,0], 'left'],
26049 'bottom' : ['t-b', [0,2], 'top'],
26050 'top' : [ 'b-t', [0,-2], 'bottom']
26056 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26061 delay : null, // can be { show : 300 , hide: 500}
26065 hoverState : null, //???
26067 placement : 'bottom',
26071 getAutoCreate : function(){
26078 cls : 'tooltip-arrow'
26081 cls : 'tooltip-inner'
26088 bind : function(el)
26094 enter : function () {
26096 if (this.timeout != null) {
26097 clearTimeout(this.timeout);
26100 this.hoverState = 'in';
26101 //Roo.log("enter - show");
26102 if (!this.delay || !this.delay.show) {
26107 this.timeout = setTimeout(function () {
26108 if (_t.hoverState == 'in') {
26111 }, this.delay.show);
26115 clearTimeout(this.timeout);
26117 this.hoverState = 'out';
26118 if (!this.delay || !this.delay.hide) {
26124 this.timeout = setTimeout(function () {
26125 //Roo.log("leave - timeout");
26127 if (_t.hoverState == 'out') {
26129 Roo.bootstrap.Tooltip.currentEl = false;
26134 show : function (msg)
26137 this.render(document.body);
26140 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26142 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26144 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26146 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26148 var placement = typeof this.placement == 'function' ?
26149 this.placement.call(this, this.el, on_el) :
26152 var autoToken = /\s?auto?\s?/i;
26153 var autoPlace = autoToken.test(placement);
26155 placement = placement.replace(autoToken, '') || 'top';
26159 //this.el.setXY([0,0]);
26161 //this.el.dom.style.display='block';
26163 //this.el.appendTo(on_el);
26165 var p = this.getPosition();
26166 var box = this.el.getBox();
26172 var align = this.alignment[placement];
26174 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26176 if(placement == 'top' || placement == 'bottom'){
26178 placement = 'right';
26181 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26182 placement = 'left';
26185 var scroll = Roo.select('body', true).first().getScroll();
26187 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26193 this.el.alignTo(this.bindEl, align[0],align[1]);
26194 //var arrow = this.el.select('.arrow',true).first();
26195 //arrow.set(align[2],
26197 this.el.addClass(placement);
26199 this.el.addClass('in fade');
26201 this.hoverState = null;
26203 if (this.el.hasClass('fade')) {
26214 //this.el.setXY([0,0]);
26215 this.el.removeClass('in');
26231 * @class Roo.bootstrap.LocationPicker
26232 * @extends Roo.bootstrap.Component
26233 * Bootstrap LocationPicker class
26234 * @cfg {Number} latitude Position when init default 0
26235 * @cfg {Number} longitude Position when init default 0
26236 * @cfg {Number} zoom default 15
26237 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26238 * @cfg {Boolean} mapTypeControl default false
26239 * @cfg {Boolean} disableDoubleClickZoom default false
26240 * @cfg {Boolean} scrollwheel default true
26241 * @cfg {Boolean} streetViewControl default false
26242 * @cfg {Number} radius default 0
26243 * @cfg {String} locationName
26244 * @cfg {Boolean} draggable default true
26245 * @cfg {Boolean} enableAutocomplete default false
26246 * @cfg {Boolean} enableReverseGeocode default true
26247 * @cfg {String} markerTitle
26250 * Create a new LocationPicker
26251 * @param {Object} config The config object
26255 Roo.bootstrap.LocationPicker = function(config){
26257 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26262 * Fires when the picker initialized.
26263 * @param {Roo.bootstrap.LocationPicker} this
26264 * @param {Google Location} location
26268 * @event positionchanged
26269 * Fires when the picker position changed.
26270 * @param {Roo.bootstrap.LocationPicker} this
26271 * @param {Google Location} location
26273 positionchanged : true,
26276 * Fires when the map resize.
26277 * @param {Roo.bootstrap.LocationPicker} this
26282 * Fires when the map show.
26283 * @param {Roo.bootstrap.LocationPicker} this
26288 * Fires when the map hide.
26289 * @param {Roo.bootstrap.LocationPicker} this
26294 * Fires when click the map.
26295 * @param {Roo.bootstrap.LocationPicker} this
26296 * @param {Map event} e
26300 * @event mapRightClick
26301 * Fires when right click the map.
26302 * @param {Roo.bootstrap.LocationPicker} this
26303 * @param {Map event} e
26305 mapRightClick : true,
26307 * @event markerClick
26308 * Fires when click the marker.
26309 * @param {Roo.bootstrap.LocationPicker} this
26310 * @param {Map event} e
26312 markerClick : true,
26314 * @event markerRightClick
26315 * Fires when right click the marker.
26316 * @param {Roo.bootstrap.LocationPicker} this
26317 * @param {Map event} e
26319 markerRightClick : true,
26321 * @event OverlayViewDraw
26322 * Fires when OverlayView Draw
26323 * @param {Roo.bootstrap.LocationPicker} this
26325 OverlayViewDraw : true,
26327 * @event OverlayViewOnAdd
26328 * Fires when OverlayView Draw
26329 * @param {Roo.bootstrap.LocationPicker} this
26331 OverlayViewOnAdd : true,
26333 * @event OverlayViewOnRemove
26334 * Fires when OverlayView Draw
26335 * @param {Roo.bootstrap.LocationPicker} this
26337 OverlayViewOnRemove : true,
26339 * @event OverlayViewShow
26340 * Fires when OverlayView Draw
26341 * @param {Roo.bootstrap.LocationPicker} this
26342 * @param {Pixel} cpx
26344 OverlayViewShow : true,
26346 * @event OverlayViewHide
26347 * Fires when OverlayView Draw
26348 * @param {Roo.bootstrap.LocationPicker} this
26350 OverlayViewHide : true,
26352 * @event loadexception
26353 * Fires when load google lib failed.
26354 * @param {Roo.bootstrap.LocationPicker} this
26356 loadexception : true
26361 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26363 gMapContext: false,
26369 mapTypeControl: false,
26370 disableDoubleClickZoom: false,
26372 streetViewControl: false,
26376 enableAutocomplete: false,
26377 enableReverseGeocode: true,
26380 getAutoCreate: function()
26385 cls: 'roo-location-picker'
26391 initEvents: function(ct, position)
26393 if(!this.el.getWidth() || this.isApplied()){
26397 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26402 initial: function()
26404 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26405 this.fireEvent('loadexception', this);
26409 if(!this.mapTypeId){
26410 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26413 this.gMapContext = this.GMapContext();
26415 this.initOverlayView();
26417 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26421 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26422 _this.setPosition(_this.gMapContext.marker.position);
26425 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26426 _this.fireEvent('mapClick', this, event);
26430 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26431 _this.fireEvent('mapRightClick', this, event);
26435 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26436 _this.fireEvent('markerClick', this, event);
26440 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26441 _this.fireEvent('markerRightClick', this, event);
26445 this.setPosition(this.gMapContext.location);
26447 this.fireEvent('initial', this, this.gMapContext.location);
26450 initOverlayView: function()
26454 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26458 _this.fireEvent('OverlayViewDraw', _this);
26463 _this.fireEvent('OverlayViewOnAdd', _this);
26466 onRemove: function()
26468 _this.fireEvent('OverlayViewOnRemove', _this);
26471 show: function(cpx)
26473 _this.fireEvent('OverlayViewShow', _this, cpx);
26478 _this.fireEvent('OverlayViewHide', _this);
26484 fromLatLngToContainerPixel: function(event)
26486 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26489 isApplied: function()
26491 return this.getGmapContext() == false ? false : true;
26494 getGmapContext: function()
26496 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26499 GMapContext: function()
26501 var position = new google.maps.LatLng(this.latitude, this.longitude);
26503 var _map = new google.maps.Map(this.el.dom, {
26506 mapTypeId: this.mapTypeId,
26507 mapTypeControl: this.mapTypeControl,
26508 disableDoubleClickZoom: this.disableDoubleClickZoom,
26509 scrollwheel: this.scrollwheel,
26510 streetViewControl: this.streetViewControl,
26511 locationName: this.locationName,
26512 draggable: this.draggable,
26513 enableAutocomplete: this.enableAutocomplete,
26514 enableReverseGeocode: this.enableReverseGeocode
26517 var _marker = new google.maps.Marker({
26518 position: position,
26520 title: this.markerTitle,
26521 draggable: this.draggable
26528 location: position,
26529 radius: this.radius,
26530 locationName: this.locationName,
26531 addressComponents: {
26532 formatted_address: null,
26533 addressLine1: null,
26534 addressLine2: null,
26536 streetNumber: null,
26540 stateOrProvince: null
26543 domContainer: this.el.dom,
26544 geodecoder: new google.maps.Geocoder()
26548 drawCircle: function(center, radius, options)
26550 if (this.gMapContext.circle != null) {
26551 this.gMapContext.circle.setMap(null);
26555 options = Roo.apply({}, options, {
26556 strokeColor: "#0000FF",
26557 strokeOpacity: .35,
26559 fillColor: "#0000FF",
26563 options.map = this.gMapContext.map;
26564 options.radius = radius;
26565 options.center = center;
26566 this.gMapContext.circle = new google.maps.Circle(options);
26567 return this.gMapContext.circle;
26573 setPosition: function(location)
26575 this.gMapContext.location = location;
26576 this.gMapContext.marker.setPosition(location);
26577 this.gMapContext.map.panTo(location);
26578 this.drawCircle(location, this.gMapContext.radius, {});
26582 if (this.gMapContext.settings.enableReverseGeocode) {
26583 this.gMapContext.geodecoder.geocode({
26584 latLng: this.gMapContext.location
26585 }, function(results, status) {
26587 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26588 _this.gMapContext.locationName = results[0].formatted_address;
26589 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26591 _this.fireEvent('positionchanged', this, location);
26598 this.fireEvent('positionchanged', this, location);
26603 google.maps.event.trigger(this.gMapContext.map, "resize");
26605 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26607 this.fireEvent('resize', this);
26610 setPositionByLatLng: function(latitude, longitude)
26612 this.setPosition(new google.maps.LatLng(latitude, longitude));
26615 getCurrentPosition: function()
26618 latitude: this.gMapContext.location.lat(),
26619 longitude: this.gMapContext.location.lng()
26623 getAddressName: function()
26625 return this.gMapContext.locationName;
26628 getAddressComponents: function()
26630 return this.gMapContext.addressComponents;
26633 address_component_from_google_geocode: function(address_components)
26637 for (var i = 0; i < address_components.length; i++) {
26638 var component = address_components[i];
26639 if (component.types.indexOf("postal_code") >= 0) {
26640 result.postalCode = component.short_name;
26641 } else if (component.types.indexOf("street_number") >= 0) {
26642 result.streetNumber = component.short_name;
26643 } else if (component.types.indexOf("route") >= 0) {
26644 result.streetName = component.short_name;
26645 } else if (component.types.indexOf("neighborhood") >= 0) {
26646 result.city = component.short_name;
26647 } else if (component.types.indexOf("locality") >= 0) {
26648 result.city = component.short_name;
26649 } else if (component.types.indexOf("sublocality") >= 0) {
26650 result.district = component.short_name;
26651 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26652 result.stateOrProvince = component.short_name;
26653 } else if (component.types.indexOf("country") >= 0) {
26654 result.country = component.short_name;
26658 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26659 result.addressLine2 = "";
26663 setZoomLevel: function(zoom)
26665 this.gMapContext.map.setZoom(zoom);
26678 this.fireEvent('show', this);
26689 this.fireEvent('hide', this);
26694 Roo.apply(Roo.bootstrap.LocationPicker, {
26696 OverlayView : function(map, options)
26698 options = options || {};
26712 * @class Roo.bootstrap.Alert
26713 * @extends Roo.bootstrap.Component
26714 * Bootstrap Alert class
26715 * @cfg {String} title The title of alert
26716 * @cfg {String} html The content of alert
26717 * @cfg {String} weight ( success | info | warning | danger )
26718 * @cfg {String} faicon font-awesomeicon
26721 * Create a new alert
26722 * @param {Object} config The config object
26726 Roo.bootstrap.Alert = function(config){
26727 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26731 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26738 getAutoCreate : function()
26747 cls : 'roo-alert-icon'
26752 cls : 'roo-alert-title',
26757 cls : 'roo-alert-text',
26764 cfg.cn[0].cls += ' fa ' + this.faicon;
26768 cfg.cls += ' alert-' + this.weight;
26774 initEvents: function()
26776 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26779 setTitle : function(str)
26781 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26784 setText : function(str)
26786 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26789 setWeight : function(weight)
26792 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26795 this.weight = weight;
26797 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26800 setIcon : function(icon)
26803 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26806 this.faicon = icon;
26808 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26829 * @class Roo.bootstrap.UploadCropbox
26830 * @extends Roo.bootstrap.Component
26831 * Bootstrap UploadCropbox class
26832 * @cfg {String} emptyText show when image has been loaded
26833 * @cfg {String} rotateNotify show when image too small to rotate
26834 * @cfg {Number} errorTimeout default 3000
26835 * @cfg {Number} minWidth default 300
26836 * @cfg {Number} minHeight default 300
26837 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26838 * @cfg {Boolean} isDocument (true|false) default false
26839 * @cfg {String} url action url
26840 * @cfg {String} paramName default 'imageUpload'
26841 * @cfg {String} method default POST
26842 * @cfg {Boolean} loadMask (true|false) default true
26843 * @cfg {Boolean} loadingText default 'Loading...'
26846 * Create a new UploadCropbox
26847 * @param {Object} config The config object
26850 Roo.bootstrap.UploadCropbox = function(config){
26851 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26855 * @event beforeselectfile
26856 * Fire before select file
26857 * @param {Roo.bootstrap.UploadCropbox} this
26859 "beforeselectfile" : true,
26862 * Fire after initEvent
26863 * @param {Roo.bootstrap.UploadCropbox} this
26868 * Fire after initEvent
26869 * @param {Roo.bootstrap.UploadCropbox} this
26870 * @param {String} data
26875 * Fire when preparing the file data
26876 * @param {Roo.bootstrap.UploadCropbox} this
26877 * @param {Object} file
26882 * Fire when get exception
26883 * @param {Roo.bootstrap.UploadCropbox} this
26884 * @param {XMLHttpRequest} xhr
26886 "exception" : true,
26888 * @event beforeloadcanvas
26889 * Fire before load the canvas
26890 * @param {Roo.bootstrap.UploadCropbox} this
26891 * @param {String} src
26893 "beforeloadcanvas" : true,
26896 * Fire when trash image
26897 * @param {Roo.bootstrap.UploadCropbox} this
26902 * Fire when download the image
26903 * @param {Roo.bootstrap.UploadCropbox} this
26907 * @event footerbuttonclick
26908 * Fire when footerbuttonclick
26909 * @param {Roo.bootstrap.UploadCropbox} this
26910 * @param {String} type
26912 "footerbuttonclick" : true,
26916 * @param {Roo.bootstrap.UploadCropbox} this
26921 * Fire when rotate the image
26922 * @param {Roo.bootstrap.UploadCropbox} this
26923 * @param {String} pos
26928 * Fire when inspect the file
26929 * @param {Roo.bootstrap.UploadCropbox} this
26930 * @param {Object} file
26935 * Fire when xhr upload the file
26936 * @param {Roo.bootstrap.UploadCropbox} this
26937 * @param {Object} data
26942 * Fire when arrange the file data
26943 * @param {Roo.bootstrap.UploadCropbox} this
26944 * @param {Object} formData
26949 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26952 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26954 emptyText : 'Click to upload image',
26955 rotateNotify : 'Image is too small to rotate',
26956 errorTimeout : 3000,
26970 cropType : 'image/jpeg',
26972 canvasLoaded : false,
26973 isDocument : false,
26975 paramName : 'imageUpload',
26977 loadingText : 'Loading...',
26980 getAutoCreate : function()
26984 cls : 'roo-upload-cropbox',
26988 cls : 'roo-upload-cropbox-selector',
26993 cls : 'roo-upload-cropbox-body',
26994 style : 'cursor:pointer',
26998 cls : 'roo-upload-cropbox-preview'
27002 cls : 'roo-upload-cropbox-thumb'
27006 cls : 'roo-upload-cropbox-empty-notify',
27007 html : this.emptyText
27011 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27012 html : this.rotateNotify
27018 cls : 'roo-upload-cropbox-footer',
27021 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27031 onRender : function(ct, position)
27033 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27035 if (this.buttons.length) {
27037 Roo.each(this.buttons, function(bb) {
27039 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27041 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27047 this.maskEl = this.el;
27051 initEvents : function()
27053 this.urlAPI = (window.createObjectURL && window) ||
27054 (window.URL && URL.revokeObjectURL && URL) ||
27055 (window.webkitURL && webkitURL);
27057 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27058 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27060 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27061 this.selectorEl.hide();
27063 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27064 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27066 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27067 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27068 this.thumbEl.hide();
27070 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27071 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27073 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27074 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27075 this.errorEl.hide();
27077 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27078 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27079 this.footerEl.hide();
27081 this.setThumbBoxSize();
27087 this.fireEvent('initial', this);
27094 window.addEventListener("resize", function() { _this.resize(); } );
27096 this.bodyEl.on('click', this.beforeSelectFile, this);
27099 this.bodyEl.on('touchstart', this.onTouchStart, this);
27100 this.bodyEl.on('touchmove', this.onTouchMove, this);
27101 this.bodyEl.on('touchend', this.onTouchEnd, this);
27105 this.bodyEl.on('mousedown', this.onMouseDown, this);
27106 this.bodyEl.on('mousemove', this.onMouseMove, this);
27107 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27108 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27109 Roo.get(document).on('mouseup', this.onMouseUp, this);
27112 this.selectorEl.on('change', this.onFileSelected, this);
27118 this.baseScale = 1;
27120 this.baseRotate = 1;
27121 this.dragable = false;
27122 this.pinching = false;
27125 this.cropData = false;
27126 this.notifyEl.dom.innerHTML = this.emptyText;
27128 this.selectorEl.dom.value = '';
27132 resize : function()
27134 if(this.fireEvent('resize', this) != false){
27135 this.setThumbBoxPosition();
27136 this.setCanvasPosition();
27140 onFooterButtonClick : function(e, el, o, type)
27143 case 'rotate-left' :
27144 this.onRotateLeft(e);
27146 case 'rotate-right' :
27147 this.onRotateRight(e);
27150 this.beforeSelectFile(e);
27165 this.fireEvent('footerbuttonclick', this, type);
27168 beforeSelectFile : function(e)
27170 e.preventDefault();
27172 if(this.fireEvent('beforeselectfile', this) != false){
27173 this.selectorEl.dom.click();
27177 onFileSelected : function(e)
27179 e.preventDefault();
27181 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27185 var file = this.selectorEl.dom.files[0];
27187 if(this.fireEvent('inspect', this, file) != false){
27188 this.prepare(file);
27193 trash : function(e)
27195 this.fireEvent('trash', this);
27198 download : function(e)
27200 this.fireEvent('download', this);
27203 loadCanvas : function(src)
27205 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27209 this.imageEl = document.createElement('img');
27213 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27215 this.imageEl.src = src;
27219 onLoadCanvas : function()
27221 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27222 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27224 this.bodyEl.un('click', this.beforeSelectFile, this);
27226 this.notifyEl.hide();
27227 this.thumbEl.show();
27228 this.footerEl.show();
27230 this.baseRotateLevel();
27232 if(this.isDocument){
27233 this.setThumbBoxSize();
27236 this.setThumbBoxPosition();
27238 this.baseScaleLevel();
27244 this.canvasLoaded = true;
27247 this.maskEl.unmask();
27252 setCanvasPosition : function()
27254 if(!this.canvasEl){
27258 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27259 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27261 this.previewEl.setLeft(pw);
27262 this.previewEl.setTop(ph);
27266 onMouseDown : function(e)
27270 this.dragable = true;
27271 this.pinching = false;
27273 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27274 this.dragable = false;
27278 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27279 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27283 onMouseMove : function(e)
27287 if(!this.canvasLoaded){
27291 if (!this.dragable){
27295 var minX = Math.ceil(this.thumbEl.getLeft(true));
27296 var minY = Math.ceil(this.thumbEl.getTop(true));
27298 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27299 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27301 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27302 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27304 x = x - this.mouseX;
27305 y = y - this.mouseY;
27307 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27308 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27310 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27311 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27313 this.previewEl.setLeft(bgX);
27314 this.previewEl.setTop(bgY);
27316 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27317 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27320 onMouseUp : function(e)
27324 this.dragable = false;
27327 onMouseWheel : function(e)
27331 this.startScale = this.scale;
27333 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27335 if(!this.zoomable()){
27336 this.scale = this.startScale;
27345 zoomable : function()
27347 var minScale = this.thumbEl.getWidth() / this.minWidth;
27349 if(this.minWidth < this.minHeight){
27350 minScale = this.thumbEl.getHeight() / this.minHeight;
27353 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27354 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27358 (this.rotate == 0 || this.rotate == 180) &&
27360 width > this.imageEl.OriginWidth ||
27361 height > this.imageEl.OriginHeight ||
27362 (width < this.minWidth && height < this.minHeight)
27370 (this.rotate == 90 || this.rotate == 270) &&
27372 width > this.imageEl.OriginWidth ||
27373 height > this.imageEl.OriginHeight ||
27374 (width < this.minHeight && height < this.minWidth)
27381 !this.isDocument &&
27382 (this.rotate == 0 || this.rotate == 180) &&
27384 width < this.minWidth ||
27385 width > this.imageEl.OriginWidth ||
27386 height < this.minHeight ||
27387 height > this.imageEl.OriginHeight
27394 !this.isDocument &&
27395 (this.rotate == 90 || this.rotate == 270) &&
27397 width < this.minHeight ||
27398 width > this.imageEl.OriginWidth ||
27399 height < this.minWidth ||
27400 height > this.imageEl.OriginHeight
27410 onRotateLeft : function(e)
27412 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27414 var minScale = this.thumbEl.getWidth() / this.minWidth;
27416 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27417 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27419 this.startScale = this.scale;
27421 while (this.getScaleLevel() < minScale){
27423 this.scale = this.scale + 1;
27425 if(!this.zoomable()){
27430 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27431 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27436 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27443 this.scale = this.startScale;
27445 this.onRotateFail();
27450 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27452 if(this.isDocument){
27453 this.setThumbBoxSize();
27454 this.setThumbBoxPosition();
27455 this.setCanvasPosition();
27460 this.fireEvent('rotate', this, 'left');
27464 onRotateRight : function(e)
27466 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27468 var minScale = this.thumbEl.getWidth() / this.minWidth;
27470 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27471 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27473 this.startScale = this.scale;
27475 while (this.getScaleLevel() < minScale){
27477 this.scale = this.scale + 1;
27479 if(!this.zoomable()){
27484 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27485 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27490 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27497 this.scale = this.startScale;
27499 this.onRotateFail();
27504 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27506 if(this.isDocument){
27507 this.setThumbBoxSize();
27508 this.setThumbBoxPosition();
27509 this.setCanvasPosition();
27514 this.fireEvent('rotate', this, 'right');
27517 onRotateFail : function()
27519 this.errorEl.show(true);
27523 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27528 this.previewEl.dom.innerHTML = '';
27530 var canvasEl = document.createElement("canvas");
27532 var contextEl = canvasEl.getContext("2d");
27534 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27535 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27536 var center = this.imageEl.OriginWidth / 2;
27538 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27539 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27540 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27541 center = this.imageEl.OriginHeight / 2;
27544 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27546 contextEl.translate(center, center);
27547 contextEl.rotate(this.rotate * Math.PI / 180);
27549 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27551 this.canvasEl = document.createElement("canvas");
27553 this.contextEl = this.canvasEl.getContext("2d");
27555 switch (this.rotate) {
27558 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27559 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27561 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27566 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27567 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27569 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27570 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);
27574 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27579 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27580 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27582 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27583 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);
27587 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);
27592 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27593 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27595 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27596 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27600 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);
27607 this.previewEl.appendChild(this.canvasEl);
27609 this.setCanvasPosition();
27614 if(!this.canvasLoaded){
27618 var imageCanvas = document.createElement("canvas");
27620 var imageContext = imageCanvas.getContext("2d");
27622 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27623 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27625 var center = imageCanvas.width / 2;
27627 imageContext.translate(center, center);
27629 imageContext.rotate(this.rotate * Math.PI / 180);
27631 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27633 var canvas = document.createElement("canvas");
27635 var context = canvas.getContext("2d");
27637 canvas.width = this.minWidth;
27638 canvas.height = this.minHeight;
27640 switch (this.rotate) {
27643 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27644 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27646 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27647 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27649 var targetWidth = this.minWidth - 2 * x;
27650 var targetHeight = this.minHeight - 2 * y;
27654 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27655 scale = targetWidth / width;
27658 if(x > 0 && y == 0){
27659 scale = targetHeight / height;
27662 if(x > 0 && y > 0){
27663 scale = targetWidth / width;
27665 if(width < height){
27666 scale = targetHeight / height;
27670 context.scale(scale, scale);
27672 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27673 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27675 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27676 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27678 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27683 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27684 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27686 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27687 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27689 var targetWidth = this.minWidth - 2 * x;
27690 var targetHeight = this.minHeight - 2 * y;
27694 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27695 scale = targetWidth / width;
27698 if(x > 0 && y == 0){
27699 scale = targetHeight / height;
27702 if(x > 0 && y > 0){
27703 scale = targetWidth / width;
27705 if(width < height){
27706 scale = targetHeight / height;
27710 context.scale(scale, scale);
27712 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27713 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27715 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27716 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27718 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27720 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27725 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27726 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27728 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27729 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27731 var targetWidth = this.minWidth - 2 * x;
27732 var targetHeight = this.minHeight - 2 * y;
27736 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27737 scale = targetWidth / width;
27740 if(x > 0 && y == 0){
27741 scale = targetHeight / height;
27744 if(x > 0 && y > 0){
27745 scale = targetWidth / width;
27747 if(width < height){
27748 scale = targetHeight / height;
27752 context.scale(scale, scale);
27754 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27755 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27757 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27758 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27760 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27761 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27763 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27768 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27769 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27771 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27772 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27774 var targetWidth = this.minWidth - 2 * x;
27775 var targetHeight = this.minHeight - 2 * y;
27779 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27780 scale = targetWidth / width;
27783 if(x > 0 && y == 0){
27784 scale = targetHeight / height;
27787 if(x > 0 && y > 0){
27788 scale = targetWidth / width;
27790 if(width < height){
27791 scale = targetHeight / height;
27795 context.scale(scale, scale);
27797 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27798 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27800 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27801 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27803 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27805 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27812 this.cropData = canvas.toDataURL(this.cropType);
27814 if(this.fireEvent('crop', this, this.cropData) !== false){
27815 this.process(this.file, this.cropData);
27822 setThumbBoxSize : function()
27826 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27827 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27828 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27830 this.minWidth = width;
27831 this.minHeight = height;
27833 if(this.rotate == 90 || this.rotate == 270){
27834 this.minWidth = height;
27835 this.minHeight = width;
27840 width = Math.ceil(this.minWidth * height / this.minHeight);
27842 if(this.minWidth > this.minHeight){
27844 height = Math.ceil(this.minHeight * width / this.minWidth);
27847 this.thumbEl.setStyle({
27848 width : width + 'px',
27849 height : height + 'px'
27856 setThumbBoxPosition : function()
27858 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27859 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27861 this.thumbEl.setLeft(x);
27862 this.thumbEl.setTop(y);
27866 baseRotateLevel : function()
27868 this.baseRotate = 1;
27871 typeof(this.exif) != 'undefined' &&
27872 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27873 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27875 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27878 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27882 baseScaleLevel : function()
27886 if(this.isDocument){
27888 if(this.baseRotate == 6 || this.baseRotate == 8){
27890 height = this.thumbEl.getHeight();
27891 this.baseScale = height / this.imageEl.OriginWidth;
27893 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27894 width = this.thumbEl.getWidth();
27895 this.baseScale = width / this.imageEl.OriginHeight;
27901 height = this.thumbEl.getHeight();
27902 this.baseScale = height / this.imageEl.OriginHeight;
27904 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27905 width = this.thumbEl.getWidth();
27906 this.baseScale = width / this.imageEl.OriginWidth;
27912 if(this.baseRotate == 6 || this.baseRotate == 8){
27914 width = this.thumbEl.getHeight();
27915 this.baseScale = width / this.imageEl.OriginHeight;
27917 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27918 height = this.thumbEl.getWidth();
27919 this.baseScale = height / this.imageEl.OriginHeight;
27922 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27923 height = this.thumbEl.getWidth();
27924 this.baseScale = height / this.imageEl.OriginHeight;
27926 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27927 width = this.thumbEl.getHeight();
27928 this.baseScale = width / this.imageEl.OriginWidth;
27935 width = this.thumbEl.getWidth();
27936 this.baseScale = width / this.imageEl.OriginWidth;
27938 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27939 height = this.thumbEl.getHeight();
27940 this.baseScale = height / this.imageEl.OriginHeight;
27943 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27945 height = this.thumbEl.getHeight();
27946 this.baseScale = height / this.imageEl.OriginHeight;
27948 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27949 width = this.thumbEl.getWidth();
27950 this.baseScale = width / this.imageEl.OriginWidth;
27958 getScaleLevel : function()
27960 return this.baseScale * Math.pow(1.1, this.scale);
27963 onTouchStart : function(e)
27965 if(!this.canvasLoaded){
27966 this.beforeSelectFile(e);
27970 var touches = e.browserEvent.touches;
27976 if(touches.length == 1){
27977 this.onMouseDown(e);
27981 if(touches.length != 2){
27987 for(var i = 0, finger; finger = touches[i]; i++){
27988 coords.push(finger.pageX, finger.pageY);
27991 var x = Math.pow(coords[0] - coords[2], 2);
27992 var y = Math.pow(coords[1] - coords[3], 2);
27994 this.startDistance = Math.sqrt(x + y);
27996 this.startScale = this.scale;
27998 this.pinching = true;
27999 this.dragable = false;
28003 onTouchMove : function(e)
28005 if(!this.pinching && !this.dragable){
28009 var touches = e.browserEvent.touches;
28016 this.onMouseMove(e);
28022 for(var i = 0, finger; finger = touches[i]; i++){
28023 coords.push(finger.pageX, finger.pageY);
28026 var x = Math.pow(coords[0] - coords[2], 2);
28027 var y = Math.pow(coords[1] - coords[3], 2);
28029 this.endDistance = Math.sqrt(x + y);
28031 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28033 if(!this.zoomable()){
28034 this.scale = this.startScale;
28042 onTouchEnd : function(e)
28044 this.pinching = false;
28045 this.dragable = false;
28049 process : function(file, crop)
28052 this.maskEl.mask(this.loadingText);
28055 this.xhr = new XMLHttpRequest();
28057 file.xhr = this.xhr;
28059 this.xhr.open(this.method, this.url, true);
28062 "Accept": "application/json",
28063 "Cache-Control": "no-cache",
28064 "X-Requested-With": "XMLHttpRequest"
28067 for (var headerName in headers) {
28068 var headerValue = headers[headerName];
28070 this.xhr.setRequestHeader(headerName, headerValue);
28076 this.xhr.onload = function()
28078 _this.xhrOnLoad(_this.xhr);
28081 this.xhr.onerror = function()
28083 _this.xhrOnError(_this.xhr);
28086 var formData = new FormData();
28088 formData.append('returnHTML', 'NO');
28091 formData.append('crop', crop);
28094 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28095 formData.append(this.paramName, file, file.name);
28098 if(typeof(file.filename) != 'undefined'){
28099 formData.append('filename', file.filename);
28102 if(typeof(file.mimetype) != 'undefined'){
28103 formData.append('mimetype', file.mimetype);
28106 if(this.fireEvent('arrange', this, formData) != false){
28107 this.xhr.send(formData);
28111 xhrOnLoad : function(xhr)
28114 this.maskEl.unmask();
28117 if (xhr.readyState !== 4) {
28118 this.fireEvent('exception', this, xhr);
28122 var response = Roo.decode(xhr.responseText);
28124 if(!response.success){
28125 this.fireEvent('exception', this, xhr);
28129 var response = Roo.decode(xhr.responseText);
28131 this.fireEvent('upload', this, response);
28135 xhrOnError : function()
28138 this.maskEl.unmask();
28141 Roo.log('xhr on error');
28143 var response = Roo.decode(xhr.responseText);
28149 prepare : function(file)
28152 this.maskEl.mask(this.loadingText);
28158 if(typeof(file) === 'string'){
28159 this.loadCanvas(file);
28163 if(!file || !this.urlAPI){
28168 this.cropType = file.type;
28172 if(this.fireEvent('prepare', this, this.file) != false){
28174 var reader = new FileReader();
28176 reader.onload = function (e) {
28177 if (e.target.error) {
28178 Roo.log(e.target.error);
28182 var buffer = e.target.result,
28183 dataView = new DataView(buffer),
28185 maxOffset = dataView.byteLength - 4,
28189 if (dataView.getUint16(0) === 0xffd8) {
28190 while (offset < maxOffset) {
28191 markerBytes = dataView.getUint16(offset);
28193 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28194 markerLength = dataView.getUint16(offset + 2) + 2;
28195 if (offset + markerLength > dataView.byteLength) {
28196 Roo.log('Invalid meta data: Invalid segment size.');
28200 if(markerBytes == 0xffe1){
28201 _this.parseExifData(
28208 offset += markerLength;
28218 var url = _this.urlAPI.createObjectURL(_this.file);
28220 _this.loadCanvas(url);
28225 reader.readAsArrayBuffer(this.file);
28231 parseExifData : function(dataView, offset, length)
28233 var tiffOffset = offset + 10,
28237 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28238 // No Exif data, might be XMP data instead
28242 // Check for the ASCII code for "Exif" (0x45786966):
28243 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28244 // No Exif data, might be XMP data instead
28247 if (tiffOffset + 8 > dataView.byteLength) {
28248 Roo.log('Invalid Exif data: Invalid segment size.');
28251 // Check for the two null bytes:
28252 if (dataView.getUint16(offset + 8) !== 0x0000) {
28253 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28256 // Check the byte alignment:
28257 switch (dataView.getUint16(tiffOffset)) {
28259 littleEndian = true;
28262 littleEndian = false;
28265 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28268 // Check for the TIFF tag marker (0x002A):
28269 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28270 Roo.log('Invalid Exif data: Missing TIFF marker.');
28273 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28274 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28276 this.parseExifTags(
28279 tiffOffset + dirOffset,
28284 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28289 if (dirOffset + 6 > dataView.byteLength) {
28290 Roo.log('Invalid Exif data: Invalid directory offset.');
28293 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28294 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28295 if (dirEndOffset + 4 > dataView.byteLength) {
28296 Roo.log('Invalid Exif data: Invalid directory size.');
28299 for (i = 0; i < tagsNumber; i += 1) {
28303 dirOffset + 2 + 12 * i, // tag offset
28307 // Return the offset to the next directory:
28308 return dataView.getUint32(dirEndOffset, littleEndian);
28311 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28313 var tag = dataView.getUint16(offset, littleEndian);
28315 this.exif[tag] = this.getExifValue(
28319 dataView.getUint16(offset + 2, littleEndian), // tag type
28320 dataView.getUint32(offset + 4, littleEndian), // tag length
28325 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28327 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28336 Roo.log('Invalid Exif data: Invalid tag type.');
28340 tagSize = tagType.size * length;
28341 // Determine if the value is contained in the dataOffset bytes,
28342 // or if the value at the dataOffset is a pointer to the actual data:
28343 dataOffset = tagSize > 4 ?
28344 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28345 if (dataOffset + tagSize > dataView.byteLength) {
28346 Roo.log('Invalid Exif data: Invalid data offset.');
28349 if (length === 1) {
28350 return tagType.getValue(dataView, dataOffset, littleEndian);
28353 for (i = 0; i < length; i += 1) {
28354 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28357 if (tagType.ascii) {
28359 // Concatenate the chars:
28360 for (i = 0; i < values.length; i += 1) {
28362 // Ignore the terminating NULL byte(s):
28363 if (c === '\u0000') {
28375 Roo.apply(Roo.bootstrap.UploadCropbox, {
28377 'Orientation': 0x0112
28381 1: 0, //'top-left',
28383 3: 180, //'bottom-right',
28384 // 4: 'bottom-left',
28386 6: 90, //'right-top',
28387 // 7: 'right-bottom',
28388 8: 270 //'left-bottom'
28392 // byte, 8-bit unsigned int:
28394 getValue: function (dataView, dataOffset) {
28395 return dataView.getUint8(dataOffset);
28399 // ascii, 8-bit byte:
28401 getValue: function (dataView, dataOffset) {
28402 return String.fromCharCode(dataView.getUint8(dataOffset));
28407 // short, 16 bit int:
28409 getValue: function (dataView, dataOffset, littleEndian) {
28410 return dataView.getUint16(dataOffset, littleEndian);
28414 // long, 32 bit int:
28416 getValue: function (dataView, dataOffset, littleEndian) {
28417 return dataView.getUint32(dataOffset, littleEndian);
28421 // rational = two long values, first is numerator, second is denominator:
28423 getValue: function (dataView, dataOffset, littleEndian) {
28424 return dataView.getUint32(dataOffset, littleEndian) /
28425 dataView.getUint32(dataOffset + 4, littleEndian);
28429 // slong, 32 bit signed int:
28431 getValue: function (dataView, dataOffset, littleEndian) {
28432 return dataView.getInt32(dataOffset, littleEndian);
28436 // srational, two slongs, first is numerator, second is denominator:
28438 getValue: function (dataView, dataOffset, littleEndian) {
28439 return dataView.getInt32(dataOffset, littleEndian) /
28440 dataView.getInt32(dataOffset + 4, littleEndian);
28450 cls : 'btn-group roo-upload-cropbox-rotate-left',
28451 action : 'rotate-left',
28455 cls : 'btn btn-default',
28456 html : '<i class="fa fa-undo"></i>'
28462 cls : 'btn-group roo-upload-cropbox-picture',
28463 action : 'picture',
28467 cls : 'btn btn-default',
28468 html : '<i class="fa fa-picture-o"></i>'
28474 cls : 'btn-group roo-upload-cropbox-rotate-right',
28475 action : 'rotate-right',
28479 cls : 'btn btn-default',
28480 html : '<i class="fa fa-repeat"></i>'
28488 cls : 'btn-group roo-upload-cropbox-rotate-left',
28489 action : 'rotate-left',
28493 cls : 'btn btn-default',
28494 html : '<i class="fa fa-undo"></i>'
28500 cls : 'btn-group roo-upload-cropbox-download',
28501 action : 'download',
28505 cls : 'btn btn-default',
28506 html : '<i class="fa fa-download"></i>'
28512 cls : 'btn-group roo-upload-cropbox-crop',
28517 cls : 'btn btn-default',
28518 html : '<i class="fa fa-crop"></i>'
28524 cls : 'btn-group roo-upload-cropbox-trash',
28529 cls : 'btn btn-default',
28530 html : '<i class="fa fa-trash"></i>'
28536 cls : 'btn-group roo-upload-cropbox-rotate-right',
28537 action : 'rotate-right',
28541 cls : 'btn btn-default',
28542 html : '<i class="fa fa-repeat"></i>'
28550 cls : 'btn-group roo-upload-cropbox-rotate-left',
28551 action : 'rotate-left',
28555 cls : 'btn btn-default',
28556 html : '<i class="fa fa-undo"></i>'
28562 cls : 'btn-group roo-upload-cropbox-rotate-right',
28563 action : 'rotate-right',
28567 cls : 'btn btn-default',
28568 html : '<i class="fa fa-repeat"></i>'
28581 * @class Roo.bootstrap.DocumentManager
28582 * @extends Roo.bootstrap.Component
28583 * Bootstrap DocumentManager class
28584 * @cfg {String} paramName default 'imageUpload'
28585 * @cfg {String} toolTipName default 'filename'
28586 * @cfg {String} method default POST
28587 * @cfg {String} url action url
28588 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28589 * @cfg {Boolean} multiple multiple upload default true
28590 * @cfg {Number} thumbSize default 300
28591 * @cfg {String} fieldLabel
28592 * @cfg {Number} labelWidth default 4
28593 * @cfg {String} labelAlign (left|top) default left
28594 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28595 * @cfg {Number} labellg set the width of label (1-12)
28596 * @cfg {Number} labelmd set the width of label (1-12)
28597 * @cfg {Number} labelsm set the width of label (1-12)
28598 * @cfg {Number} labelxs set the width of label (1-12)
28601 * Create a new DocumentManager
28602 * @param {Object} config The config object
28605 Roo.bootstrap.DocumentManager = function(config){
28606 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28609 this.delegates = [];
28614 * Fire when initial the DocumentManager
28615 * @param {Roo.bootstrap.DocumentManager} this
28620 * inspect selected file
28621 * @param {Roo.bootstrap.DocumentManager} this
28622 * @param {File} file
28627 * Fire when xhr load exception
28628 * @param {Roo.bootstrap.DocumentManager} this
28629 * @param {XMLHttpRequest} xhr
28631 "exception" : true,
28633 * @event afterupload
28634 * Fire when xhr load exception
28635 * @param {Roo.bootstrap.DocumentManager} this
28636 * @param {XMLHttpRequest} xhr
28638 "afterupload" : true,
28641 * prepare the form data
28642 * @param {Roo.bootstrap.DocumentManager} this
28643 * @param {Object} formData
28648 * Fire when remove the file
28649 * @param {Roo.bootstrap.DocumentManager} this
28650 * @param {Object} file
28655 * Fire after refresh the file
28656 * @param {Roo.bootstrap.DocumentManager} this
28661 * Fire after click the image
28662 * @param {Roo.bootstrap.DocumentManager} this
28663 * @param {Object} file
28668 * Fire when upload a image and editable set to true
28669 * @param {Roo.bootstrap.DocumentManager} this
28670 * @param {Object} file
28674 * @event beforeselectfile
28675 * Fire before select file
28676 * @param {Roo.bootstrap.DocumentManager} this
28678 "beforeselectfile" : true,
28681 * Fire before process file
28682 * @param {Roo.bootstrap.DocumentManager} this
28683 * @param {Object} file
28687 * @event previewrendered
28688 * Fire when preview rendered
28689 * @param {Roo.bootstrap.DocumentManager} this
28690 * @param {Object} file
28692 "previewrendered" : true
28697 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28706 paramName : 'imageUpload',
28707 toolTipName : 'filename',
28710 labelAlign : 'left',
28720 getAutoCreate : function()
28722 var managerWidget = {
28724 cls : 'roo-document-manager',
28728 cls : 'roo-document-manager-selector',
28733 cls : 'roo-document-manager-uploader',
28737 cls : 'roo-document-manager-upload-btn',
28738 html : '<i class="fa fa-plus"></i>'
28749 cls : 'column col-md-12',
28754 if(this.fieldLabel.length){
28759 cls : 'column col-md-12',
28760 html : this.fieldLabel
28764 cls : 'column col-md-12',
28769 if(this.labelAlign == 'left'){
28774 html : this.fieldLabel
28783 if(this.labelWidth > 12){
28784 content[0].style = "width: " + this.labelWidth + 'px';
28787 if(this.labelWidth < 13 && this.labelmd == 0){
28788 this.labelmd = this.labelWidth;
28791 if(this.labellg > 0){
28792 content[0].cls += ' col-lg-' + this.labellg;
28793 content[1].cls += ' col-lg-' + (12 - this.labellg);
28796 if(this.labelmd > 0){
28797 content[0].cls += ' col-md-' + this.labelmd;
28798 content[1].cls += ' col-md-' + (12 - this.labelmd);
28801 if(this.labelsm > 0){
28802 content[0].cls += ' col-sm-' + this.labelsm;
28803 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28806 if(this.labelxs > 0){
28807 content[0].cls += ' col-xs-' + this.labelxs;
28808 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28816 cls : 'row clearfix',
28824 initEvents : function()
28826 this.managerEl = this.el.select('.roo-document-manager', true).first();
28827 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28829 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28830 this.selectorEl.hide();
28833 this.selectorEl.attr('multiple', 'multiple');
28836 this.selectorEl.on('change', this.onFileSelected, this);
28838 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28839 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28841 this.uploader.on('click', this.onUploaderClick, this);
28843 this.renderProgressDialog();
28847 window.addEventListener("resize", function() { _this.refresh(); } );
28849 this.fireEvent('initial', this);
28852 renderProgressDialog : function()
28856 this.progressDialog = new Roo.bootstrap.Modal({
28857 cls : 'roo-document-manager-progress-dialog',
28858 allow_close : false,
28868 btnclick : function() {
28869 _this.uploadCancel();
28875 this.progressDialog.render(Roo.get(document.body));
28877 this.progress = new Roo.bootstrap.Progress({
28878 cls : 'roo-document-manager-progress',
28883 this.progress.render(this.progressDialog.getChildContainer());
28885 this.progressBar = new Roo.bootstrap.ProgressBar({
28886 cls : 'roo-document-manager-progress-bar',
28889 aria_valuemax : 12,
28893 this.progressBar.render(this.progress.getChildContainer());
28896 onUploaderClick : function(e)
28898 e.preventDefault();
28900 if(this.fireEvent('beforeselectfile', this) != false){
28901 this.selectorEl.dom.click();
28906 onFileSelected : function(e)
28908 e.preventDefault();
28910 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28914 Roo.each(this.selectorEl.dom.files, function(file){
28915 if(this.fireEvent('inspect', this, file) != false){
28916 this.files.push(file);
28926 this.selectorEl.dom.value = '';
28928 if(!this.files || !this.files.length){
28932 if(this.boxes > 0 && this.files.length > this.boxes){
28933 this.files = this.files.slice(0, this.boxes);
28936 this.uploader.show();
28938 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28939 this.uploader.hide();
28948 Roo.each(this.files, function(file){
28950 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28951 var f = this.renderPreview(file);
28956 if(file.type.indexOf('image') != -1){
28957 this.delegates.push(
28959 _this.process(file);
28960 }).createDelegate(this)
28968 _this.process(file);
28969 }).createDelegate(this)
28974 this.files = files;
28976 this.delegates = this.delegates.concat(docs);
28978 if(!this.delegates.length){
28983 this.progressBar.aria_valuemax = this.delegates.length;
28990 arrange : function()
28992 if(!this.delegates.length){
28993 this.progressDialog.hide();
28998 var delegate = this.delegates.shift();
29000 this.progressDialog.show();
29002 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29004 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29009 refresh : function()
29011 this.uploader.show();
29013 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29014 this.uploader.hide();
29017 Roo.isTouch ? this.closable(false) : this.closable(true);
29019 this.fireEvent('refresh', this);
29022 onRemove : function(e, el, o)
29024 e.preventDefault();
29026 this.fireEvent('remove', this, o);
29030 remove : function(o)
29034 Roo.each(this.files, function(file){
29035 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29044 this.files = files;
29051 Roo.each(this.files, function(file){
29056 file.target.remove();
29065 onClick : function(e, el, o)
29067 e.preventDefault();
29069 this.fireEvent('click', this, o);
29073 closable : function(closable)
29075 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29077 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29089 xhrOnLoad : function(xhr)
29091 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29095 if (xhr.readyState !== 4) {
29097 this.fireEvent('exception', this, xhr);
29101 var response = Roo.decode(xhr.responseText);
29103 if(!response.success){
29105 this.fireEvent('exception', this, xhr);
29109 var file = this.renderPreview(response.data);
29111 this.files.push(file);
29115 this.fireEvent('afterupload', this, xhr);
29119 xhrOnError : function(xhr)
29121 Roo.log('xhr on error');
29123 var response = Roo.decode(xhr.responseText);
29130 process : function(file)
29132 if(this.fireEvent('process', this, file) !== false){
29133 if(this.editable && file.type.indexOf('image') != -1){
29134 this.fireEvent('edit', this, file);
29138 this.uploadStart(file, false);
29145 uploadStart : function(file, crop)
29147 this.xhr = new XMLHttpRequest();
29149 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29154 file.xhr = this.xhr;
29156 this.managerEl.createChild({
29158 cls : 'roo-document-manager-loading',
29162 tooltip : file.name,
29163 cls : 'roo-document-manager-thumb',
29164 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29170 this.xhr.open(this.method, this.url, true);
29173 "Accept": "application/json",
29174 "Cache-Control": "no-cache",
29175 "X-Requested-With": "XMLHttpRequest"
29178 for (var headerName in headers) {
29179 var headerValue = headers[headerName];
29181 this.xhr.setRequestHeader(headerName, headerValue);
29187 this.xhr.onload = function()
29189 _this.xhrOnLoad(_this.xhr);
29192 this.xhr.onerror = function()
29194 _this.xhrOnError(_this.xhr);
29197 var formData = new FormData();
29199 formData.append('returnHTML', 'NO');
29202 formData.append('crop', crop);
29205 formData.append(this.paramName, file, file.name);
29212 if(this.fireEvent('prepare', this, formData, options) != false){
29214 if(options.manually){
29218 this.xhr.send(formData);
29222 this.uploadCancel();
29225 uploadCancel : function()
29231 this.delegates = [];
29233 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29240 renderPreview : function(file)
29242 if(typeof(file.target) != 'undefined' && file.target){
29246 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29248 var previewEl = this.managerEl.createChild({
29250 cls : 'roo-document-manager-preview',
29254 tooltip : file[this.toolTipName],
29255 cls : 'roo-document-manager-thumb',
29256 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29261 html : '<i class="fa fa-times-circle"></i>'
29266 var close = previewEl.select('button.close', true).first();
29268 close.on('click', this.onRemove, this, file);
29270 file.target = previewEl;
29272 var image = previewEl.select('img', true).first();
29276 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29278 image.on('click', this.onClick, this, file);
29280 this.fireEvent('previewrendered', this, file);
29286 onPreviewLoad : function(file, image)
29288 if(typeof(file.target) == 'undefined' || !file.target){
29292 var width = image.dom.naturalWidth || image.dom.width;
29293 var height = image.dom.naturalHeight || image.dom.height;
29295 if(width > height){
29296 file.target.addClass('wide');
29300 file.target.addClass('tall');
29305 uploadFromSource : function(file, crop)
29307 this.xhr = new XMLHttpRequest();
29309 this.managerEl.createChild({
29311 cls : 'roo-document-manager-loading',
29315 tooltip : file.name,
29316 cls : 'roo-document-manager-thumb',
29317 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29323 this.xhr.open(this.method, this.url, true);
29326 "Accept": "application/json",
29327 "Cache-Control": "no-cache",
29328 "X-Requested-With": "XMLHttpRequest"
29331 for (var headerName in headers) {
29332 var headerValue = headers[headerName];
29334 this.xhr.setRequestHeader(headerName, headerValue);
29340 this.xhr.onload = function()
29342 _this.xhrOnLoad(_this.xhr);
29345 this.xhr.onerror = function()
29347 _this.xhrOnError(_this.xhr);
29350 var formData = new FormData();
29352 formData.append('returnHTML', 'NO');
29354 formData.append('crop', crop);
29356 if(typeof(file.filename) != 'undefined'){
29357 formData.append('filename', file.filename);
29360 if(typeof(file.mimetype) != 'undefined'){
29361 formData.append('mimetype', file.mimetype);
29366 if(this.fireEvent('prepare', this, formData) != false){
29367 this.xhr.send(formData);
29377 * @class Roo.bootstrap.DocumentViewer
29378 * @extends Roo.bootstrap.Component
29379 * Bootstrap DocumentViewer class
29380 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29381 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29384 * Create a new DocumentViewer
29385 * @param {Object} config The config object
29388 Roo.bootstrap.DocumentViewer = function(config){
29389 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29394 * Fire after initEvent
29395 * @param {Roo.bootstrap.DocumentViewer} this
29401 * @param {Roo.bootstrap.DocumentViewer} this
29406 * Fire after download button
29407 * @param {Roo.bootstrap.DocumentViewer} this
29412 * Fire after trash button
29413 * @param {Roo.bootstrap.DocumentViewer} this
29420 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29422 showDownload : true,
29426 getAutoCreate : function()
29430 cls : 'roo-document-viewer',
29434 cls : 'roo-document-viewer-body',
29438 cls : 'roo-document-viewer-thumb',
29442 cls : 'roo-document-viewer-image'
29450 cls : 'roo-document-viewer-footer',
29453 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29457 cls : 'btn-group roo-document-viewer-download',
29461 cls : 'btn btn-default',
29462 html : '<i class="fa fa-download"></i>'
29468 cls : 'btn-group roo-document-viewer-trash',
29472 cls : 'btn btn-default',
29473 html : '<i class="fa fa-trash"></i>'
29486 initEvents : function()
29488 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29489 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29491 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29492 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29494 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29495 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29497 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29498 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29500 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29501 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29503 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29504 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29506 this.bodyEl.on('click', this.onClick, this);
29507 this.downloadBtn.on('click', this.onDownload, this);
29508 this.trashBtn.on('click', this.onTrash, this);
29510 this.downloadBtn.hide();
29511 this.trashBtn.hide();
29513 if(this.showDownload){
29514 this.downloadBtn.show();
29517 if(this.showTrash){
29518 this.trashBtn.show();
29521 if(!this.showDownload && !this.showTrash) {
29522 this.footerEl.hide();
29527 initial : function()
29529 this.fireEvent('initial', this);
29533 onClick : function(e)
29535 e.preventDefault();
29537 this.fireEvent('click', this);
29540 onDownload : function(e)
29542 e.preventDefault();
29544 this.fireEvent('download', this);
29547 onTrash : function(e)
29549 e.preventDefault();
29551 this.fireEvent('trash', this);
29563 * @class Roo.bootstrap.NavProgressBar
29564 * @extends Roo.bootstrap.Component
29565 * Bootstrap NavProgressBar class
29568 * Create a new nav progress bar
29569 * @param {Object} config The config object
29572 Roo.bootstrap.NavProgressBar = function(config){
29573 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29575 this.bullets = this.bullets || [];
29577 // Roo.bootstrap.NavProgressBar.register(this);
29581 * Fires when the active item changes
29582 * @param {Roo.bootstrap.NavProgressBar} this
29583 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29584 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29591 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29596 getAutoCreate : function()
29598 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29602 cls : 'roo-navigation-bar-group',
29606 cls : 'roo-navigation-top-bar'
29610 cls : 'roo-navigation-bullets-bar',
29614 cls : 'roo-navigation-bar'
29621 cls : 'roo-navigation-bottom-bar'
29631 initEvents: function()
29636 onRender : function(ct, position)
29638 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29640 if(this.bullets.length){
29641 Roo.each(this.bullets, function(b){
29650 addItem : function(cfg)
29652 var item = new Roo.bootstrap.NavProgressItem(cfg);
29654 item.parentId = this.id;
29655 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29658 var top = new Roo.bootstrap.Element({
29660 cls : 'roo-navigation-bar-text'
29663 var bottom = new Roo.bootstrap.Element({
29665 cls : 'roo-navigation-bar-text'
29668 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29669 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29671 var topText = new Roo.bootstrap.Element({
29673 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29676 var bottomText = new Roo.bootstrap.Element({
29678 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29681 topText.onRender(top.el, null);
29682 bottomText.onRender(bottom.el, null);
29685 item.bottomEl = bottom;
29688 this.barItems.push(item);
29693 getActive : function()
29695 var active = false;
29697 Roo.each(this.barItems, function(v){
29699 if (!v.isActive()) {
29711 setActiveItem : function(item)
29715 Roo.each(this.barItems, function(v){
29716 if (v.rid == item.rid) {
29720 if (v.isActive()) {
29721 v.setActive(false);
29726 item.setActive(true);
29728 this.fireEvent('changed', this, item, prev);
29731 getBarItem: function(rid)
29735 Roo.each(this.barItems, function(e) {
29736 if (e.rid != rid) {
29747 indexOfItem : function(item)
29751 Roo.each(this.barItems, function(v, i){
29753 if (v.rid != item.rid) {
29764 setActiveNext : function()
29766 var i = this.indexOfItem(this.getActive());
29768 if (i > this.barItems.length) {
29772 this.setActiveItem(this.barItems[i+1]);
29775 setActivePrev : function()
29777 var i = this.indexOfItem(this.getActive());
29783 this.setActiveItem(this.barItems[i-1]);
29786 format : function()
29788 if(!this.barItems.length){
29792 var width = 100 / this.barItems.length;
29794 Roo.each(this.barItems, function(i){
29795 i.el.setStyle('width', width + '%');
29796 i.topEl.el.setStyle('width', width + '%');
29797 i.bottomEl.el.setStyle('width', width + '%');
29806 * Nav Progress Item
29811 * @class Roo.bootstrap.NavProgressItem
29812 * @extends Roo.bootstrap.Component
29813 * Bootstrap NavProgressItem class
29814 * @cfg {String} rid the reference id
29815 * @cfg {Boolean} active (true|false) Is item active default false
29816 * @cfg {Boolean} disabled (true|false) Is item active default false
29817 * @cfg {String} html
29818 * @cfg {String} position (top|bottom) text position default bottom
29819 * @cfg {String} icon show icon instead of number
29822 * Create a new NavProgressItem
29823 * @param {Object} config The config object
29825 Roo.bootstrap.NavProgressItem = function(config){
29826 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29831 * The raw click event for the entire grid.
29832 * @param {Roo.bootstrap.NavProgressItem} this
29833 * @param {Roo.EventObject} e
29840 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29846 position : 'bottom',
29849 getAutoCreate : function()
29851 var iconCls = 'roo-navigation-bar-item-icon';
29853 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29857 cls: 'roo-navigation-bar-item',
29867 cfg.cls += ' active';
29870 cfg.cls += ' disabled';
29876 disable : function()
29878 this.setDisabled(true);
29881 enable : function()
29883 this.setDisabled(false);
29886 initEvents: function()
29888 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29890 this.iconEl.on('click', this.onClick, this);
29893 onClick : function(e)
29895 e.preventDefault();
29901 if(this.fireEvent('click', this, e) === false){
29905 this.parent().setActiveItem(this);
29908 isActive: function ()
29910 return this.active;
29913 setActive : function(state)
29915 if(this.active == state){
29919 this.active = state;
29922 this.el.addClass('active');
29926 this.el.removeClass('active');
29931 setDisabled : function(state)
29933 if(this.disabled == state){
29937 this.disabled = state;
29940 this.el.addClass('disabled');
29944 this.el.removeClass('disabled');
29947 tooltipEl : function()
29949 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29962 * @class Roo.bootstrap.FieldLabel
29963 * @extends Roo.bootstrap.Component
29964 * Bootstrap FieldLabel class
29965 * @cfg {String} html contents of the element
29966 * @cfg {String} tag tag of the element default label
29967 * @cfg {String} cls class of the element
29968 * @cfg {String} target label target
29969 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29970 * @cfg {String} invalidClass default "text-warning"
29971 * @cfg {String} validClass default "text-success"
29972 * @cfg {String} iconTooltip default "This field is required"
29973 * @cfg {String} indicatorpos (left|right) default left
29976 * Create a new FieldLabel
29977 * @param {Object} config The config object
29980 Roo.bootstrap.FieldLabel = function(config){
29981 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29986 * Fires after the field has been marked as invalid.
29987 * @param {Roo.form.FieldLabel} this
29988 * @param {String} msg The validation message
29993 * Fires after the field has been validated with no errors.
29994 * @param {Roo.form.FieldLabel} this
30000 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30007 invalidClass : 'has-warning',
30008 validClass : 'has-success',
30009 iconTooltip : 'This field is required',
30010 indicatorpos : 'left',
30012 getAutoCreate : function(){
30016 cls : 'roo-bootstrap-field-label ' + this.cls,
30021 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30022 tooltip : this.iconTooltip
30031 if(this.indicatorpos == 'right'){
30034 cls : 'roo-bootstrap-field-label ' + this.cls,
30043 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30044 tooltip : this.iconTooltip
30053 initEvents: function()
30055 Roo.bootstrap.Element.superclass.initEvents.call(this);
30057 this.indicator = this.indicatorEl();
30059 if(this.indicator){
30060 this.indicator.removeClass('visible');
30061 this.indicator.addClass('invisible');
30064 Roo.bootstrap.FieldLabel.register(this);
30067 indicatorEl : function()
30069 var indicator = this.el.select('i.roo-required-indicator',true).first();
30080 * Mark this field as valid
30082 markValid : function()
30084 if(this.indicator){
30085 this.indicator.removeClass('visible');
30086 this.indicator.addClass('invisible');
30089 this.el.removeClass(this.invalidClass);
30091 this.el.addClass(this.validClass);
30093 this.fireEvent('valid', this);
30097 * Mark this field as invalid
30098 * @param {String} msg The validation message
30100 markInvalid : function(msg)
30102 if(this.indicator){
30103 this.indicator.removeClass('invisible');
30104 this.indicator.addClass('visible');
30107 this.el.removeClass(this.validClass);
30109 this.el.addClass(this.invalidClass);
30111 this.fireEvent('invalid', this, msg);
30117 Roo.apply(Roo.bootstrap.FieldLabel, {
30122 * register a FieldLabel Group
30123 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30125 register : function(label)
30127 if(this.groups.hasOwnProperty(label.target)){
30131 this.groups[label.target] = label;
30135 * fetch a FieldLabel Group based on the target
30136 * @param {string} target
30137 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30139 get: function(target) {
30140 if (typeof(this.groups[target]) == 'undefined') {
30144 return this.groups[target] ;
30153 * page DateSplitField.
30159 * @class Roo.bootstrap.DateSplitField
30160 * @extends Roo.bootstrap.Component
30161 * Bootstrap DateSplitField class
30162 * @cfg {string} fieldLabel - the label associated
30163 * @cfg {Number} labelWidth set the width of label (0-12)
30164 * @cfg {String} labelAlign (top|left)
30165 * @cfg {Boolean} dayAllowBlank (true|false) default false
30166 * @cfg {Boolean} monthAllowBlank (true|false) default false
30167 * @cfg {Boolean} yearAllowBlank (true|false) default false
30168 * @cfg {string} dayPlaceholder
30169 * @cfg {string} monthPlaceholder
30170 * @cfg {string} yearPlaceholder
30171 * @cfg {string} dayFormat default 'd'
30172 * @cfg {string} monthFormat default 'm'
30173 * @cfg {string} yearFormat default 'Y'
30174 * @cfg {Number} labellg set the width of label (1-12)
30175 * @cfg {Number} labelmd set the width of label (1-12)
30176 * @cfg {Number} labelsm set the width of label (1-12)
30177 * @cfg {Number} labelxs set the width of label (1-12)
30181 * Create a new DateSplitField
30182 * @param {Object} config The config object
30185 Roo.bootstrap.DateSplitField = function(config){
30186 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30192 * getting the data of years
30193 * @param {Roo.bootstrap.DateSplitField} this
30194 * @param {Object} years
30199 * getting the data of days
30200 * @param {Roo.bootstrap.DateSplitField} this
30201 * @param {Object} days
30206 * Fires after the field has been marked as invalid.
30207 * @param {Roo.form.Field} this
30208 * @param {String} msg The validation message
30213 * Fires after the field has been validated with no errors.
30214 * @param {Roo.form.Field} this
30220 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30223 labelAlign : 'top',
30225 dayAllowBlank : false,
30226 monthAllowBlank : false,
30227 yearAllowBlank : false,
30228 dayPlaceholder : '',
30229 monthPlaceholder : '',
30230 yearPlaceholder : '',
30234 isFormField : true,
30240 getAutoCreate : function()
30244 cls : 'row roo-date-split-field-group',
30249 cls : 'form-hidden-field roo-date-split-field-group-value',
30255 var labelCls = 'col-md-12';
30256 var contentCls = 'col-md-4';
30258 if(this.fieldLabel){
30262 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30266 html : this.fieldLabel
30271 if(this.labelAlign == 'left'){
30273 if(this.labelWidth > 12){
30274 label.style = "width: " + this.labelWidth + 'px';
30277 if(this.labelWidth < 13 && this.labelmd == 0){
30278 this.labelmd = this.labelWidth;
30281 if(this.labellg > 0){
30282 labelCls = ' col-lg-' + this.labellg;
30283 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30286 if(this.labelmd > 0){
30287 labelCls = ' col-md-' + this.labelmd;
30288 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30291 if(this.labelsm > 0){
30292 labelCls = ' col-sm-' + this.labelsm;
30293 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30296 if(this.labelxs > 0){
30297 labelCls = ' col-xs-' + this.labelxs;
30298 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30302 label.cls += ' ' + labelCls;
30304 cfg.cn.push(label);
30307 Roo.each(['day', 'month', 'year'], function(t){
30310 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30317 inputEl: function ()
30319 return this.el.select('.roo-date-split-field-group-value', true).first();
30322 onRender : function(ct, position)
30326 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30328 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30330 this.dayField = new Roo.bootstrap.ComboBox({
30331 allowBlank : this.dayAllowBlank,
30332 alwaysQuery : true,
30333 displayField : 'value',
30336 forceSelection : true,
30338 placeholder : this.dayPlaceholder,
30339 selectOnFocus : true,
30340 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30341 triggerAction : 'all',
30343 valueField : 'value',
30344 store : new Roo.data.SimpleStore({
30345 data : (function() {
30347 _this.fireEvent('days', _this, days);
30350 fields : [ 'value' ]
30353 select : function (_self, record, index)
30355 _this.setValue(_this.getValue());
30360 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30362 this.monthField = new Roo.bootstrap.MonthField({
30363 after : '<i class=\"fa fa-calendar\"></i>',
30364 allowBlank : this.monthAllowBlank,
30365 placeholder : this.monthPlaceholder,
30368 render : function (_self)
30370 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30371 e.preventDefault();
30375 select : function (_self, oldvalue, newvalue)
30377 _this.setValue(_this.getValue());
30382 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30384 this.yearField = new Roo.bootstrap.ComboBox({
30385 allowBlank : this.yearAllowBlank,
30386 alwaysQuery : true,
30387 displayField : 'value',
30390 forceSelection : true,
30392 placeholder : this.yearPlaceholder,
30393 selectOnFocus : true,
30394 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30395 triggerAction : 'all',
30397 valueField : 'value',
30398 store : new Roo.data.SimpleStore({
30399 data : (function() {
30401 _this.fireEvent('years', _this, years);
30404 fields : [ 'value' ]
30407 select : function (_self, record, index)
30409 _this.setValue(_this.getValue());
30414 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30417 setValue : function(v, format)
30419 this.inputEl.dom.value = v;
30421 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30423 var d = Date.parseDate(v, f);
30430 this.setDay(d.format(this.dayFormat));
30431 this.setMonth(d.format(this.monthFormat));
30432 this.setYear(d.format(this.yearFormat));
30439 setDay : function(v)
30441 this.dayField.setValue(v);
30442 this.inputEl.dom.value = this.getValue();
30447 setMonth : function(v)
30449 this.monthField.setValue(v, true);
30450 this.inputEl.dom.value = this.getValue();
30455 setYear : function(v)
30457 this.yearField.setValue(v);
30458 this.inputEl.dom.value = this.getValue();
30463 getDay : function()
30465 return this.dayField.getValue();
30468 getMonth : function()
30470 return this.monthField.getValue();
30473 getYear : function()
30475 return this.yearField.getValue();
30478 getValue : function()
30480 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30482 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30492 this.inputEl.dom.value = '';
30497 validate : function()
30499 var d = this.dayField.validate();
30500 var m = this.monthField.validate();
30501 var y = this.yearField.validate();
30506 (!this.dayAllowBlank && !d) ||
30507 (!this.monthAllowBlank && !m) ||
30508 (!this.yearAllowBlank && !y)
30513 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30522 this.markInvalid();
30527 markValid : function()
30530 var label = this.el.select('label', true).first();
30531 var icon = this.el.select('i.fa-star', true).first();
30537 this.fireEvent('valid', this);
30541 * Mark this field as invalid
30542 * @param {String} msg The validation message
30544 markInvalid : function(msg)
30547 var label = this.el.select('label', true).first();
30548 var icon = this.el.select('i.fa-star', true).first();
30550 if(label && !icon){
30551 this.el.select('.roo-date-split-field-label', true).createChild({
30553 cls : 'text-danger fa fa-lg fa-star',
30554 tooltip : 'This field is required',
30555 style : 'margin-right:5px;'
30559 this.fireEvent('invalid', this, msg);
30562 clearInvalid : function()
30564 var label = this.el.select('label', true).first();
30565 var icon = this.el.select('i.fa-star', true).first();
30571 this.fireEvent('valid', this);
30574 getName: function()
30584 * http://masonry.desandro.com
30586 * The idea is to render all the bricks based on vertical width...
30588 * The original code extends 'outlayer' - we might need to use that....
30594 * @class Roo.bootstrap.LayoutMasonry
30595 * @extends Roo.bootstrap.Component
30596 * Bootstrap Layout Masonry class
30599 * Create a new Element
30600 * @param {Object} config The config object
30603 Roo.bootstrap.LayoutMasonry = function(config){
30605 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30609 Roo.bootstrap.LayoutMasonry.register(this);
30615 * Fire after layout the items
30616 * @param {Roo.bootstrap.LayoutMasonry} this
30617 * @param {Roo.EventObject} e
30624 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30627 * @cfg {Boolean} isLayoutInstant = no animation?
30629 isLayoutInstant : false, // needed?
30632 * @cfg {Number} boxWidth width of the columns
30637 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30642 * @cfg {Number} padWidth padding below box..
30647 * @cfg {Number} gutter gutter width..
30652 * @cfg {Number} maxCols maximum number of columns
30658 * @cfg {Boolean} isAutoInitial defalut true
30660 isAutoInitial : true,
30665 * @cfg {Boolean} isHorizontal defalut false
30667 isHorizontal : false,
30669 currentSize : null,
30675 bricks: null, //CompositeElement
30679 _isLayoutInited : false,
30681 // isAlternative : false, // only use for vertical layout...
30684 * @cfg {Number} alternativePadWidth padding below box..
30686 alternativePadWidth : 50,
30688 selectedBrick : [],
30690 getAutoCreate : function(){
30692 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30696 cls: 'blog-masonary-wrapper ' + this.cls,
30698 cls : 'mas-boxes masonary'
30705 getChildContainer: function( )
30707 if (this.boxesEl) {
30708 return this.boxesEl;
30711 this.boxesEl = this.el.select('.mas-boxes').first();
30713 return this.boxesEl;
30717 initEvents : function()
30721 if(this.isAutoInitial){
30722 Roo.log('hook children rendered');
30723 this.on('childrenrendered', function() {
30724 Roo.log('children rendered');
30730 initial : function()
30732 this.selectedBrick = [];
30734 this.currentSize = this.el.getBox(true);
30736 Roo.EventManager.onWindowResize(this.resize, this);
30738 if(!this.isAutoInitial){
30746 //this.layout.defer(500,this);
30750 resize : function()
30752 var cs = this.el.getBox(true);
30755 this.currentSize.width == cs.width &&
30756 this.currentSize.x == cs.x &&
30757 this.currentSize.height == cs.height &&
30758 this.currentSize.y == cs.y
30760 Roo.log("no change in with or X or Y");
30764 this.currentSize = cs;
30770 layout : function()
30772 this._resetLayout();
30774 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30776 this.layoutItems( isInstant );
30778 this._isLayoutInited = true;
30780 this.fireEvent('layout', this);
30784 _resetLayout : function()
30786 if(this.isHorizontal){
30787 this.horizontalMeasureColumns();
30791 this.verticalMeasureColumns();
30795 verticalMeasureColumns : function()
30797 this.getContainerWidth();
30799 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30800 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30804 var boxWidth = this.boxWidth + this.padWidth;
30806 if(this.containerWidth < this.boxWidth){
30807 boxWidth = this.containerWidth
30810 var containerWidth = this.containerWidth;
30812 var cols = Math.floor(containerWidth / boxWidth);
30814 this.cols = Math.max( cols, 1 );
30816 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30818 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30820 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30822 this.colWidth = boxWidth + avail - this.padWidth;
30824 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30825 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30828 horizontalMeasureColumns : function()
30830 this.getContainerWidth();
30832 var boxWidth = this.boxWidth;
30834 if(this.containerWidth < boxWidth){
30835 boxWidth = this.containerWidth;
30838 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30840 this.el.setHeight(boxWidth);
30844 getContainerWidth : function()
30846 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30849 layoutItems : function( isInstant )
30851 Roo.log(this.bricks);
30853 var items = Roo.apply([], this.bricks);
30855 if(this.isHorizontal){
30856 this._horizontalLayoutItems( items , isInstant );
30860 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30861 // this._verticalAlternativeLayoutItems( items , isInstant );
30865 this._verticalLayoutItems( items , isInstant );
30869 _verticalLayoutItems : function ( items , isInstant)
30871 if ( !items || !items.length ) {
30876 ['xs', 'xs', 'xs', 'tall'],
30877 ['xs', 'xs', 'tall'],
30878 ['xs', 'xs', 'sm'],
30879 ['xs', 'xs', 'xs'],
30885 ['sm', 'xs', 'xs'],
30889 ['tall', 'xs', 'xs', 'xs'],
30890 ['tall', 'xs', 'xs'],
30902 Roo.each(items, function(item, k){
30904 switch (item.size) {
30905 // these layouts take up a full box,
30916 boxes.push([item]);
30939 var filterPattern = function(box, length)
30947 var pattern = box.slice(0, length);
30951 Roo.each(pattern, function(i){
30952 format.push(i.size);
30955 Roo.each(standard, function(s){
30957 if(String(s) != String(format)){
30966 if(!match && length == 1){
30971 filterPattern(box, length - 1);
30975 queue.push(pattern);
30977 box = box.slice(length, box.length);
30979 filterPattern(box, 4);
30985 Roo.each(boxes, function(box, k){
30991 if(box.length == 1){
30996 filterPattern(box, 4);
31000 this._processVerticalLayoutQueue( queue, isInstant );
31004 // _verticalAlternativeLayoutItems : function( items , isInstant )
31006 // if ( !items || !items.length ) {
31010 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31014 _horizontalLayoutItems : function ( items , isInstant)
31016 if ( !items || !items.length || items.length < 3) {
31022 var eItems = items.slice(0, 3);
31024 items = items.slice(3, items.length);
31027 ['xs', 'xs', 'xs', 'wide'],
31028 ['xs', 'xs', 'wide'],
31029 ['xs', 'xs', 'sm'],
31030 ['xs', 'xs', 'xs'],
31036 ['sm', 'xs', 'xs'],
31040 ['wide', 'xs', 'xs', 'xs'],
31041 ['wide', 'xs', 'xs'],
31054 Roo.each(items, function(item, k){
31056 switch (item.size) {
31067 boxes.push([item]);
31091 var filterPattern = function(box, length)
31099 var pattern = box.slice(0, length);
31103 Roo.each(pattern, function(i){
31104 format.push(i.size);
31107 Roo.each(standard, function(s){
31109 if(String(s) != String(format)){
31118 if(!match && length == 1){
31123 filterPattern(box, length - 1);
31127 queue.push(pattern);
31129 box = box.slice(length, box.length);
31131 filterPattern(box, 4);
31137 Roo.each(boxes, function(box, k){
31143 if(box.length == 1){
31148 filterPattern(box, 4);
31155 var pos = this.el.getBox(true);
31159 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31161 var hit_end = false;
31163 Roo.each(queue, function(box){
31167 Roo.each(box, function(b){
31169 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31179 Roo.each(box, function(b){
31181 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31184 mx = Math.max(mx, b.x);
31188 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31192 Roo.each(box, function(b){
31194 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31208 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31211 /** Sets position of item in DOM
31212 * @param {Element} item
31213 * @param {Number} x - horizontal position
31214 * @param {Number} y - vertical position
31215 * @param {Boolean} isInstant - disables transitions
31217 _processVerticalLayoutQueue : function( queue, isInstant )
31219 var pos = this.el.getBox(true);
31224 for (var i = 0; i < this.cols; i++){
31228 Roo.each(queue, function(box, k){
31230 var col = k % this.cols;
31232 Roo.each(box, function(b,kk){
31234 b.el.position('absolute');
31236 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31237 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31239 if(b.size == 'md-left' || b.size == 'md-right'){
31240 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31241 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31244 b.el.setWidth(width);
31245 b.el.setHeight(height);
31247 b.el.select('iframe',true).setSize(width,height);
31251 for (var i = 0; i < this.cols; i++){
31253 if(maxY[i] < maxY[col]){
31258 col = Math.min(col, i);
31262 x = pos.x + col * (this.colWidth + this.padWidth);
31266 var positions = [];
31268 switch (box.length){
31270 positions = this.getVerticalOneBoxColPositions(x, y, box);
31273 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31276 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31279 positions = this.getVerticalFourBoxColPositions(x, y, box);
31285 Roo.each(box, function(b,kk){
31287 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31289 var sz = b.el.getSize();
31291 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31299 for (var i = 0; i < this.cols; i++){
31300 mY = Math.max(mY, maxY[i]);
31303 this.el.setHeight(mY - pos.y);
31307 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31309 // var pos = this.el.getBox(true);
31312 // var maxX = pos.right;
31314 // var maxHeight = 0;
31316 // Roo.each(items, function(item, k){
31320 // item.el.position('absolute');
31322 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31324 // item.el.setWidth(width);
31326 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31328 // item.el.setHeight(height);
31331 // item.el.setXY([x, y], isInstant ? false : true);
31333 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31336 // y = y + height + this.alternativePadWidth;
31338 // maxHeight = maxHeight + height + this.alternativePadWidth;
31342 // this.el.setHeight(maxHeight);
31346 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31348 var pos = this.el.getBox(true);
31353 var maxX = pos.right;
31355 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31357 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31359 Roo.each(queue, function(box, k){
31361 Roo.each(box, function(b, kk){
31363 b.el.position('absolute');
31365 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31366 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31368 if(b.size == 'md-left' || b.size == 'md-right'){
31369 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31370 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31373 b.el.setWidth(width);
31374 b.el.setHeight(height);
31382 var positions = [];
31384 switch (box.length){
31386 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31389 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31392 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31395 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31401 Roo.each(box, function(b,kk){
31403 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31405 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31413 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31415 Roo.each(eItems, function(b,k){
31417 b.size = (k == 0) ? 'sm' : 'xs';
31418 b.x = (k == 0) ? 2 : 1;
31419 b.y = (k == 0) ? 2 : 1;
31421 b.el.position('absolute');
31423 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31425 b.el.setWidth(width);
31427 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31429 b.el.setHeight(height);
31433 var positions = [];
31436 x : maxX - this.unitWidth * 2 - this.gutter,
31441 x : maxX - this.unitWidth,
31442 y : minY + (this.unitWidth + this.gutter) * 2
31446 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31450 Roo.each(eItems, function(b,k){
31452 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31458 getVerticalOneBoxColPositions : function(x, y, box)
31462 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31464 if(box[0].size == 'md-left'){
31468 if(box[0].size == 'md-right'){
31473 x : x + (this.unitWidth + this.gutter) * rand,
31480 getVerticalTwoBoxColPositions : function(x, y, box)
31484 if(box[0].size == 'xs'){
31488 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31492 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31506 x : x + (this.unitWidth + this.gutter) * 2,
31507 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31514 getVerticalThreeBoxColPositions : function(x, y, box)
31518 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31526 x : x + (this.unitWidth + this.gutter) * 1,
31531 x : x + (this.unitWidth + this.gutter) * 2,
31539 if(box[0].size == 'xs' && box[1].size == 'xs'){
31548 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31552 x : x + (this.unitWidth + this.gutter) * 1,
31566 x : x + (this.unitWidth + this.gutter) * 2,
31571 x : x + (this.unitWidth + this.gutter) * 2,
31572 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31579 getVerticalFourBoxColPositions : function(x, y, box)
31583 if(box[0].size == 'xs'){
31592 y : y + (this.unitHeight + this.gutter) * 1
31597 y : y + (this.unitHeight + this.gutter) * 2
31601 x : x + (this.unitWidth + this.gutter) * 1,
31615 x : x + (this.unitWidth + this.gutter) * 2,
31620 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31621 y : y + (this.unitHeight + this.gutter) * 1
31625 x : x + (this.unitWidth + this.gutter) * 2,
31626 y : y + (this.unitWidth + this.gutter) * 2
31633 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31637 if(box[0].size == 'md-left'){
31639 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31646 if(box[0].size == 'md-right'){
31648 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31649 y : minY + (this.unitWidth + this.gutter) * 1
31655 var rand = Math.floor(Math.random() * (4 - box[0].y));
31658 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31659 y : minY + (this.unitWidth + this.gutter) * rand
31666 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31670 if(box[0].size == 'xs'){
31673 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31678 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31679 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31687 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31692 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31693 y : minY + (this.unitWidth + this.gutter) * 2
31700 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31704 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31707 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31712 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31713 y : minY + (this.unitWidth + this.gutter) * 1
31717 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31718 y : minY + (this.unitWidth + this.gutter) * 2
31725 if(box[0].size == 'xs' && box[1].size == 'xs'){
31728 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31733 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31738 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31739 y : minY + (this.unitWidth + this.gutter) * 1
31747 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31752 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31753 y : minY + (this.unitWidth + this.gutter) * 2
31757 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31758 y : minY + (this.unitWidth + this.gutter) * 2
31765 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31769 if(box[0].size == 'xs'){
31772 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31777 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31782 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),
31787 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31788 y : minY + (this.unitWidth + this.gutter) * 1
31796 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31801 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31802 y : minY + (this.unitWidth + this.gutter) * 2
31806 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31807 y : minY + (this.unitWidth + this.gutter) * 2
31811 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),
31812 y : minY + (this.unitWidth + this.gutter) * 2
31820 * remove a Masonry Brick
31821 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31823 removeBrick : function(brick_id)
31829 for (var i = 0; i<this.bricks.length; i++) {
31830 if (this.bricks[i].id == brick_id) {
31831 this.bricks.splice(i,1);
31832 this.el.dom.removeChild(Roo.get(brick_id).dom);
31839 * adds a Masonry Brick
31840 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31842 addBrick : function(cfg)
31844 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31845 //this.register(cn);
31846 cn.parentId = this.id;
31847 cn.onRender(this.el, null);
31852 * register a Masonry Brick
31853 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31856 register : function(brick)
31858 this.bricks.push(brick);
31859 brick.masonryId = this.id;
31863 * clear all the Masonry Brick
31865 clearAll : function()
31868 //this.getChildContainer().dom.innerHTML = "";
31869 this.el.dom.innerHTML = '';
31872 getSelected : function()
31874 if (!this.selectedBrick) {
31878 return this.selectedBrick;
31882 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31886 * register a Masonry Layout
31887 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31890 register : function(layout)
31892 this.groups[layout.id] = layout;
31895 * fetch a Masonry Layout based on the masonry layout ID
31896 * @param {string} the masonry layout to add
31897 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31900 get: function(layout_id) {
31901 if (typeof(this.groups[layout_id]) == 'undefined') {
31904 return this.groups[layout_id] ;
31916 * http://masonry.desandro.com
31918 * The idea is to render all the bricks based on vertical width...
31920 * The original code extends 'outlayer' - we might need to use that....
31926 * @class Roo.bootstrap.LayoutMasonryAuto
31927 * @extends Roo.bootstrap.Component
31928 * Bootstrap Layout Masonry class
31931 * Create a new Element
31932 * @param {Object} config The config object
31935 Roo.bootstrap.LayoutMasonryAuto = function(config){
31936 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31939 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31942 * @cfg {Boolean} isFitWidth - resize the width..
31944 isFitWidth : false, // options..
31946 * @cfg {Boolean} isOriginLeft = left align?
31948 isOriginLeft : true,
31950 * @cfg {Boolean} isOriginTop = top align?
31952 isOriginTop : false,
31954 * @cfg {Boolean} isLayoutInstant = no animation?
31956 isLayoutInstant : false, // needed?
31958 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31960 isResizingContainer : true,
31962 * @cfg {Number} columnWidth width of the columns
31968 * @cfg {Number} maxCols maximum number of columns
31973 * @cfg {Number} padHeight padding below box..
31979 * @cfg {Boolean} isAutoInitial defalut true
31982 isAutoInitial : true,
31988 initialColumnWidth : 0,
31989 currentSize : null,
31991 colYs : null, // array.
31998 bricks: null, //CompositeElement
31999 cols : 0, // array?
32000 // element : null, // wrapped now this.el
32001 _isLayoutInited : null,
32004 getAutoCreate : function(){
32008 cls: 'blog-masonary-wrapper ' + this.cls,
32010 cls : 'mas-boxes masonary'
32017 getChildContainer: function( )
32019 if (this.boxesEl) {
32020 return this.boxesEl;
32023 this.boxesEl = this.el.select('.mas-boxes').first();
32025 return this.boxesEl;
32029 initEvents : function()
32033 if(this.isAutoInitial){
32034 Roo.log('hook children rendered');
32035 this.on('childrenrendered', function() {
32036 Roo.log('children rendered');
32043 initial : function()
32045 this.reloadItems();
32047 this.currentSize = this.el.getBox(true);
32049 /// was window resize... - let's see if this works..
32050 Roo.EventManager.onWindowResize(this.resize, this);
32052 if(!this.isAutoInitial){
32057 this.layout.defer(500,this);
32060 reloadItems: function()
32062 this.bricks = this.el.select('.masonry-brick', true);
32064 this.bricks.each(function(b) {
32065 //Roo.log(b.getSize());
32066 if (!b.attr('originalwidth')) {
32067 b.attr('originalwidth', b.getSize().width);
32072 Roo.log(this.bricks.elements.length);
32075 resize : function()
32078 var cs = this.el.getBox(true);
32080 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32081 Roo.log("no change in with or X");
32084 this.currentSize = cs;
32088 layout : function()
32091 this._resetLayout();
32092 //this._manageStamps();
32094 // don't animate first layout
32095 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32096 this.layoutItems( isInstant );
32098 // flag for initalized
32099 this._isLayoutInited = true;
32102 layoutItems : function( isInstant )
32104 //var items = this._getItemsForLayout( this.items );
32105 // original code supports filtering layout items.. we just ignore it..
32107 this._layoutItems( this.bricks , isInstant );
32109 this._postLayout();
32111 _layoutItems : function ( items , isInstant)
32113 //this.fireEvent( 'layout', this, items );
32116 if ( !items || !items.elements.length ) {
32117 // no items, emit event with empty array
32122 items.each(function(item) {
32123 Roo.log("layout item");
32125 // get x/y object from method
32126 var position = this._getItemLayoutPosition( item );
32128 position.item = item;
32129 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32130 queue.push( position );
32133 this._processLayoutQueue( queue );
32135 /** Sets position of item in DOM
32136 * @param {Element} item
32137 * @param {Number} x - horizontal position
32138 * @param {Number} y - vertical position
32139 * @param {Boolean} isInstant - disables transitions
32141 _processLayoutQueue : function( queue )
32143 for ( var i=0, len = queue.length; i < len; i++ ) {
32144 var obj = queue[i];
32145 obj.item.position('absolute');
32146 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32152 * Any logic you want to do after each layout,
32153 * i.e. size the container
32155 _postLayout : function()
32157 this.resizeContainer();
32160 resizeContainer : function()
32162 if ( !this.isResizingContainer ) {
32165 var size = this._getContainerSize();
32167 this.el.setSize(size.width,size.height);
32168 this.boxesEl.setSize(size.width,size.height);
32174 _resetLayout : function()
32176 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32177 this.colWidth = this.el.getWidth();
32178 //this.gutter = this.el.getWidth();
32180 this.measureColumns();
32186 this.colYs.push( 0 );
32192 measureColumns : function()
32194 this.getContainerWidth();
32195 // if columnWidth is 0, default to outerWidth of first item
32196 if ( !this.columnWidth ) {
32197 var firstItem = this.bricks.first();
32198 Roo.log(firstItem);
32199 this.columnWidth = this.containerWidth;
32200 if (firstItem && firstItem.attr('originalwidth') ) {
32201 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32203 // columnWidth fall back to item of first element
32204 Roo.log("set column width?");
32205 this.initialColumnWidth = this.columnWidth ;
32207 // if first elem has no width, default to size of container
32212 if (this.initialColumnWidth) {
32213 this.columnWidth = this.initialColumnWidth;
32218 // column width is fixed at the top - however if container width get's smaller we should
32221 // this bit calcs how man columns..
32223 var columnWidth = this.columnWidth += this.gutter;
32225 // calculate columns
32226 var containerWidth = this.containerWidth + this.gutter;
32228 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32229 // fix rounding errors, typically with gutters
32230 var excess = columnWidth - containerWidth % columnWidth;
32233 // if overshoot is less than a pixel, round up, otherwise floor it
32234 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32235 cols = Math[ mathMethod ]( cols );
32236 this.cols = Math.max( cols, 1 );
32237 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32239 // padding positioning..
32240 var totalColWidth = this.cols * this.columnWidth;
32241 var padavail = this.containerWidth - totalColWidth;
32242 // so for 2 columns - we need 3 'pads'
32244 var padNeeded = (1+this.cols) * this.padWidth;
32246 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32248 this.columnWidth += padExtra
32249 //this.padWidth = Math.floor(padavail / ( this.cols));
32251 // adjust colum width so that padding is fixed??
32253 // we have 3 columns ... total = width * 3
32254 // we have X left over... that should be used by
32256 //if (this.expandC) {
32264 getContainerWidth : function()
32266 /* // container is parent if fit width
32267 var container = this.isFitWidth ? this.element.parentNode : this.element;
32268 // check that this.size and size are there
32269 // IE8 triggers resize on body size change, so they might not be
32271 var size = getSize( container ); //FIXME
32272 this.containerWidth = size && size.innerWidth; //FIXME
32275 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32279 _getItemLayoutPosition : function( item ) // what is item?
32281 // we resize the item to our columnWidth..
32283 item.setWidth(this.columnWidth);
32284 item.autoBoxAdjust = false;
32286 var sz = item.getSize();
32288 // how many columns does this brick span
32289 var remainder = this.containerWidth % this.columnWidth;
32291 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32292 // round if off by 1 pixel, otherwise use ceil
32293 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32294 colSpan = Math.min( colSpan, this.cols );
32296 // normally this should be '1' as we dont' currently allow multi width columns..
32298 var colGroup = this._getColGroup( colSpan );
32299 // get the minimum Y value from the columns
32300 var minimumY = Math.min.apply( Math, colGroup );
32301 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32303 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32305 // position the brick
32307 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32308 y: this.currentSize.y + minimumY + this.padHeight
32312 // apply setHeight to necessary columns
32313 var setHeight = minimumY + sz.height + this.padHeight;
32314 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32316 var setSpan = this.cols + 1 - colGroup.length;
32317 for ( var i = 0; i < setSpan; i++ ) {
32318 this.colYs[ shortColIndex + i ] = setHeight ;
32325 * @param {Number} colSpan - number of columns the element spans
32326 * @returns {Array} colGroup
32328 _getColGroup : function( colSpan )
32330 if ( colSpan < 2 ) {
32331 // if brick spans only one column, use all the column Ys
32336 // how many different places could this brick fit horizontally
32337 var groupCount = this.cols + 1 - colSpan;
32338 // for each group potential horizontal position
32339 for ( var i = 0; i < groupCount; i++ ) {
32340 // make an array of colY values for that one group
32341 var groupColYs = this.colYs.slice( i, i + colSpan );
32342 // and get the max value of the array
32343 colGroup[i] = Math.max.apply( Math, groupColYs );
32348 _manageStamp : function( stamp )
32350 var stampSize = stamp.getSize();
32351 var offset = stamp.getBox();
32352 // get the columns that this stamp affects
32353 var firstX = this.isOriginLeft ? offset.x : offset.right;
32354 var lastX = firstX + stampSize.width;
32355 var firstCol = Math.floor( firstX / this.columnWidth );
32356 firstCol = Math.max( 0, firstCol );
32358 var lastCol = Math.floor( lastX / this.columnWidth );
32359 // lastCol should not go over if multiple of columnWidth #425
32360 lastCol -= lastX % this.columnWidth ? 0 : 1;
32361 lastCol = Math.min( this.cols - 1, lastCol );
32363 // set colYs to bottom of the stamp
32364 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32367 for ( var i = firstCol; i <= lastCol; i++ ) {
32368 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32373 _getContainerSize : function()
32375 this.maxY = Math.max.apply( Math, this.colYs );
32380 if ( this.isFitWidth ) {
32381 size.width = this._getContainerFitWidth();
32387 _getContainerFitWidth : function()
32389 var unusedCols = 0;
32390 // count unused columns
32393 if ( this.colYs[i] !== 0 ) {
32398 // fit container to columns that have been used
32399 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32402 needsResizeLayout : function()
32404 var previousWidth = this.containerWidth;
32405 this.getContainerWidth();
32406 return previousWidth !== this.containerWidth;
32421 * @class Roo.bootstrap.MasonryBrick
32422 * @extends Roo.bootstrap.Component
32423 * Bootstrap MasonryBrick class
32426 * Create a new MasonryBrick
32427 * @param {Object} config The config object
32430 Roo.bootstrap.MasonryBrick = function(config){
32432 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32434 Roo.bootstrap.MasonryBrick.register(this);
32440 * When a MasonryBrick is clcik
32441 * @param {Roo.bootstrap.MasonryBrick} this
32442 * @param {Roo.EventObject} e
32448 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32451 * @cfg {String} title
32455 * @cfg {String} html
32459 * @cfg {String} bgimage
32463 * @cfg {String} videourl
32467 * @cfg {String} cls
32471 * @cfg {String} href
32475 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32480 * @cfg {String} placetitle (center|bottom)
32485 * @cfg {Boolean} isFitContainer defalut true
32487 isFitContainer : true,
32490 * @cfg {Boolean} preventDefault defalut false
32492 preventDefault : false,
32495 * @cfg {Boolean} inverse defalut false
32497 maskInverse : false,
32499 getAutoCreate : function()
32501 if(!this.isFitContainer){
32502 return this.getSplitAutoCreate();
32505 var cls = 'masonry-brick masonry-brick-full';
32507 if(this.href.length){
32508 cls += ' masonry-brick-link';
32511 if(this.bgimage.length){
32512 cls += ' masonry-brick-image';
32515 if(this.maskInverse){
32516 cls += ' mask-inverse';
32519 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32520 cls += ' enable-mask';
32524 cls += ' masonry-' + this.size + '-brick';
32527 if(this.placetitle.length){
32529 switch (this.placetitle) {
32531 cls += ' masonry-center-title';
32534 cls += ' masonry-bottom-title';
32541 if(!this.html.length && !this.bgimage.length){
32542 cls += ' masonry-center-title';
32545 if(!this.html.length && this.bgimage.length){
32546 cls += ' masonry-bottom-title';
32551 cls += ' ' + this.cls;
32555 tag: (this.href.length) ? 'a' : 'div',
32560 cls: 'masonry-brick-mask'
32564 cls: 'masonry-brick-paragraph',
32570 if(this.href.length){
32571 cfg.href = this.href;
32574 var cn = cfg.cn[1].cn;
32576 if(this.title.length){
32579 cls: 'masonry-brick-title',
32584 if(this.html.length){
32587 cls: 'masonry-brick-text',
32592 if (!this.title.length && !this.html.length) {
32593 cfg.cn[1].cls += ' hide';
32596 if(this.bgimage.length){
32599 cls: 'masonry-brick-image-view',
32604 if(this.videourl.length){
32605 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32606 // youtube support only?
32609 cls: 'masonry-brick-image-view',
32612 allowfullscreen : true
32620 getSplitAutoCreate : function()
32622 var cls = 'masonry-brick masonry-brick-split';
32624 if(this.href.length){
32625 cls += ' masonry-brick-link';
32628 if(this.bgimage.length){
32629 cls += ' masonry-brick-image';
32633 cls += ' masonry-' + this.size + '-brick';
32636 switch (this.placetitle) {
32638 cls += ' masonry-center-title';
32641 cls += ' masonry-bottom-title';
32644 if(!this.bgimage.length){
32645 cls += ' masonry-center-title';
32648 if(this.bgimage.length){
32649 cls += ' masonry-bottom-title';
32655 cls += ' ' + this.cls;
32659 tag: (this.href.length) ? 'a' : 'div',
32664 cls: 'masonry-brick-split-head',
32668 cls: 'masonry-brick-paragraph',
32675 cls: 'masonry-brick-split-body',
32681 if(this.href.length){
32682 cfg.href = this.href;
32685 if(this.title.length){
32686 cfg.cn[0].cn[0].cn.push({
32688 cls: 'masonry-brick-title',
32693 if(this.html.length){
32694 cfg.cn[1].cn.push({
32696 cls: 'masonry-brick-text',
32701 if(this.bgimage.length){
32702 cfg.cn[0].cn.push({
32704 cls: 'masonry-brick-image-view',
32709 if(this.videourl.length){
32710 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32711 // youtube support only?
32712 cfg.cn[0].cn.cn.push({
32714 cls: 'masonry-brick-image-view',
32717 allowfullscreen : true
32724 initEvents: function()
32726 switch (this.size) {
32759 this.el.on('touchstart', this.onTouchStart, this);
32760 this.el.on('touchmove', this.onTouchMove, this);
32761 this.el.on('touchend', this.onTouchEnd, this);
32762 this.el.on('contextmenu', this.onContextMenu, this);
32764 this.el.on('mouseenter' ,this.enter, this);
32765 this.el.on('mouseleave', this.leave, this);
32766 this.el.on('click', this.onClick, this);
32769 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32770 this.parent().bricks.push(this);
32775 onClick: function(e, el)
32777 var time = this.endTimer - this.startTimer;
32778 // Roo.log(e.preventDefault());
32781 e.preventDefault();
32786 if(!this.preventDefault){
32790 e.preventDefault();
32792 if (this.activeClass != '') {
32793 this.selectBrick();
32796 this.fireEvent('click', this, e);
32799 enter: function(e, el)
32801 e.preventDefault();
32803 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32807 if(this.bgimage.length && this.html.length){
32808 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32812 leave: function(e, el)
32814 e.preventDefault();
32816 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32820 if(this.bgimage.length && this.html.length){
32821 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32825 onTouchStart: function(e, el)
32827 // e.preventDefault();
32829 this.touchmoved = false;
32831 if(!this.isFitContainer){
32835 if(!this.bgimage.length || !this.html.length){
32839 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32841 this.timer = new Date().getTime();
32845 onTouchMove: function(e, el)
32847 this.touchmoved = true;
32850 onContextMenu : function(e,el)
32852 e.preventDefault();
32853 e.stopPropagation();
32857 onTouchEnd: function(e, el)
32859 // e.preventDefault();
32861 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32868 if(!this.bgimage.length || !this.html.length){
32870 if(this.href.length){
32871 window.location.href = this.href;
32877 if(!this.isFitContainer){
32881 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32883 window.location.href = this.href;
32886 //selection on single brick only
32887 selectBrick : function() {
32889 if (!this.parentId) {
32893 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32894 var index = m.selectedBrick.indexOf(this.id);
32897 m.selectedBrick.splice(index,1);
32898 this.el.removeClass(this.activeClass);
32902 for(var i = 0; i < m.selectedBrick.length; i++) {
32903 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32904 b.el.removeClass(b.activeClass);
32907 m.selectedBrick = [];
32909 m.selectedBrick.push(this.id);
32910 this.el.addClass(this.activeClass);
32914 isSelected : function(){
32915 return this.el.hasClass(this.activeClass);
32920 Roo.apply(Roo.bootstrap.MasonryBrick, {
32923 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32925 * register a Masonry Brick
32926 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32929 register : function(brick)
32931 //this.groups[brick.id] = brick;
32932 this.groups.add(brick.id, brick);
32935 * fetch a masonry brick based on the masonry brick ID
32936 * @param {string} the masonry brick to add
32937 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32940 get: function(brick_id)
32942 // if (typeof(this.groups[brick_id]) == 'undefined') {
32945 // return this.groups[brick_id] ;
32947 if(this.groups.key(brick_id)) {
32948 return this.groups.key(brick_id);
32966 * @class Roo.bootstrap.Brick
32967 * @extends Roo.bootstrap.Component
32968 * Bootstrap Brick class
32971 * Create a new Brick
32972 * @param {Object} config The config object
32975 Roo.bootstrap.Brick = function(config){
32976 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32982 * When a Brick is click
32983 * @param {Roo.bootstrap.Brick} this
32984 * @param {Roo.EventObject} e
32990 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32993 * @cfg {String} title
32997 * @cfg {String} html
33001 * @cfg {String} bgimage
33005 * @cfg {String} cls
33009 * @cfg {String} href
33013 * @cfg {String} video
33017 * @cfg {Boolean} square
33021 getAutoCreate : function()
33023 var cls = 'roo-brick';
33025 if(this.href.length){
33026 cls += ' roo-brick-link';
33029 if(this.bgimage.length){
33030 cls += ' roo-brick-image';
33033 if(!this.html.length && !this.bgimage.length){
33034 cls += ' roo-brick-center-title';
33037 if(!this.html.length && this.bgimage.length){
33038 cls += ' roo-brick-bottom-title';
33042 cls += ' ' + this.cls;
33046 tag: (this.href.length) ? 'a' : 'div',
33051 cls: 'roo-brick-paragraph',
33057 if(this.href.length){
33058 cfg.href = this.href;
33061 var cn = cfg.cn[0].cn;
33063 if(this.title.length){
33066 cls: 'roo-brick-title',
33071 if(this.html.length){
33074 cls: 'roo-brick-text',
33081 if(this.bgimage.length){
33084 cls: 'roo-brick-image-view',
33092 initEvents: function()
33094 if(this.title.length || this.html.length){
33095 this.el.on('mouseenter' ,this.enter, this);
33096 this.el.on('mouseleave', this.leave, this);
33099 Roo.EventManager.onWindowResize(this.resize, this);
33101 if(this.bgimage.length){
33102 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33103 this.imageEl.on('load', this.onImageLoad, this);
33110 onImageLoad : function()
33115 resize : function()
33117 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33119 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33121 if(this.bgimage.length){
33122 var image = this.el.select('.roo-brick-image-view', true).first();
33124 image.setWidth(paragraph.getWidth());
33127 image.setHeight(paragraph.getWidth());
33130 this.el.setHeight(image.getHeight());
33131 paragraph.setHeight(image.getHeight());
33137 enter: function(e, el)
33139 e.preventDefault();
33141 if(this.bgimage.length){
33142 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33143 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33147 leave: function(e, el)
33149 e.preventDefault();
33151 if(this.bgimage.length){
33152 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33153 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33168 * @class Roo.bootstrap.NumberField
33169 * @extends Roo.bootstrap.Input
33170 * Bootstrap NumberField class
33176 * Create a new NumberField
33177 * @param {Object} config The config object
33180 Roo.bootstrap.NumberField = function(config){
33181 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33184 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33187 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33189 allowDecimals : true,
33191 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33193 decimalSeparator : ".",
33195 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33197 decimalPrecision : 2,
33199 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33201 allowNegative : true,
33204 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33208 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33210 minValue : Number.NEGATIVE_INFINITY,
33212 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33214 maxValue : Number.MAX_VALUE,
33216 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33218 minText : "The minimum value for this field is {0}",
33220 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33222 maxText : "The maximum value for this field is {0}",
33224 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33225 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33227 nanText : "{0} is not a valid number",
33229 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33233 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33235 thousandsDelimiter : false,
33237 * @cfg {String} valueAlign alignment of value
33239 valueAlign : "left",
33241 getAutoCreate : function()
33243 var hiddenInput = {
33247 cls: 'hidden-number-input'
33251 hiddenInput.name = this.name;
33256 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33258 this.name = hiddenInput.name;
33260 if(cfg.cn.length > 0) {
33261 cfg.cn.push(hiddenInput);
33268 initEvents : function()
33270 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33272 var allowed = "0123456789";
33274 if(this.allowDecimals){
33275 allowed += this.decimalSeparator;
33278 if(this.allowNegative){
33282 if(this.thousandsDelimiter) {
33286 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33288 var keyPress = function(e){
33290 var k = e.getKey();
33292 var c = e.getCharCode();
33295 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33296 allowed.indexOf(String.fromCharCode(c)) === -1
33302 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33306 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33311 this.el.on("keypress", keyPress, this);
33314 validateValue : function(value)
33317 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33321 var num = this.parseValue(value);
33324 this.markInvalid(String.format(this.nanText, value));
33328 if(num < this.minValue){
33329 this.markInvalid(String.format(this.minText, this.minValue));
33333 if(num > this.maxValue){
33334 this.markInvalid(String.format(this.maxText, this.maxValue));
33341 getValue : function()
33343 var v = this.hiddenEl().getValue();
33345 return this.fixPrecision(this.parseValue(v));
33348 parseValue : function(value)
33350 if(this.thousandsDelimiter) {
33352 r = new RegExp(",", "g");
33353 value = value.replace(r, "");
33356 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33357 return isNaN(value) ? '' : value;
33360 fixPrecision : function(value)
33362 if(this.thousandsDelimiter) {
33364 r = new RegExp(",", "g");
33365 value = value.replace(r, "");
33368 var nan = isNaN(value);
33370 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33371 return nan ? '' : value;
33373 return parseFloat(value).toFixed(this.decimalPrecision);
33376 setValue : function(v)
33378 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33384 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33386 this.inputEl().dom.value = (v == '') ? '' :
33387 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33389 if(!this.allowZero && v === '0') {
33390 this.hiddenEl().dom.value = '';
33391 this.inputEl().dom.value = '';
33398 decimalPrecisionFcn : function(v)
33400 return Math.floor(v);
33403 beforeBlur : function()
33409 var v = this.parseValue(this.getRawValue());
33416 hiddenEl : function()
33418 return this.el.select('input.hidden-number-input',true).first();
33430 * @class Roo.bootstrap.DocumentSlider
33431 * @extends Roo.bootstrap.Component
33432 * Bootstrap DocumentSlider class
33435 * Create a new DocumentViewer
33436 * @param {Object} config The config object
33439 Roo.bootstrap.DocumentSlider = function(config){
33440 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33447 * Fire after initEvent
33448 * @param {Roo.bootstrap.DocumentSlider} this
33453 * Fire after update
33454 * @param {Roo.bootstrap.DocumentSlider} this
33460 * @param {Roo.bootstrap.DocumentSlider} this
33466 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33472 getAutoCreate : function()
33476 cls : 'roo-document-slider',
33480 cls : 'roo-document-slider-header',
33484 cls : 'roo-document-slider-header-title'
33490 cls : 'roo-document-slider-body',
33494 cls : 'roo-document-slider-prev',
33498 cls : 'fa fa-chevron-left'
33504 cls : 'roo-document-slider-thumb',
33508 cls : 'roo-document-slider-image'
33514 cls : 'roo-document-slider-next',
33518 cls : 'fa fa-chevron-right'
33530 initEvents : function()
33532 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33533 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33535 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33536 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33538 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33539 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33541 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33542 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33544 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33545 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33547 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33548 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33550 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33551 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33553 this.thumbEl.on('click', this.onClick, this);
33555 this.prevIndicator.on('click', this.prev, this);
33557 this.nextIndicator.on('click', this.next, this);
33561 initial : function()
33563 if(this.files.length){
33564 this.indicator = 1;
33568 this.fireEvent('initial', this);
33571 update : function()
33573 this.imageEl.attr('src', this.files[this.indicator - 1]);
33575 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33577 this.prevIndicator.show();
33579 if(this.indicator == 1){
33580 this.prevIndicator.hide();
33583 this.nextIndicator.show();
33585 if(this.indicator == this.files.length){
33586 this.nextIndicator.hide();
33589 this.thumbEl.scrollTo('top');
33591 this.fireEvent('update', this);
33594 onClick : function(e)
33596 e.preventDefault();
33598 this.fireEvent('click', this);
33603 e.preventDefault();
33605 this.indicator = Math.max(1, this.indicator - 1);
33612 e.preventDefault();
33614 this.indicator = Math.min(this.files.length, this.indicator + 1);
33628 * @class Roo.bootstrap.RadioSet
33629 * @extends Roo.bootstrap.Input
33630 * Bootstrap RadioSet class
33631 * @cfg {String} indicatorpos (left|right) default left
33632 * @cfg {Boolean} inline (true|false) inline the element (default true)
33633 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33635 * Create a new RadioSet
33636 * @param {Object} config The config object
33639 Roo.bootstrap.RadioSet = function(config){
33641 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33645 Roo.bootstrap.RadioSet.register(this);
33650 * Fires when the element is checked or unchecked.
33651 * @param {Roo.bootstrap.RadioSet} this This radio
33652 * @param {Roo.bootstrap.Radio} item The checked item
33657 * Fires when the element is click.
33658 * @param {Roo.bootstrap.RadioSet} this This radio set
33659 * @param {Roo.bootstrap.Radio} item The checked item
33660 * @param {Roo.EventObject} e The event object
33667 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33675 indicatorpos : 'left',
33677 getAutoCreate : function()
33681 cls : 'roo-radio-set-label',
33685 html : this.fieldLabel
33690 if(this.indicatorpos == 'left'){
33693 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33694 tooltip : 'This field is required'
33699 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33700 tooltip : 'This field is required'
33706 cls : 'roo-radio-set-items'
33709 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33711 if (align === 'left' && this.fieldLabel.length) {
33714 cls : "roo-radio-set-right",
33720 if(this.labelWidth > 12){
33721 label.style = "width: " + this.labelWidth + 'px';
33724 if(this.labelWidth < 13 && this.labelmd == 0){
33725 this.labelmd = this.labelWidth;
33728 if(this.labellg > 0){
33729 label.cls += ' col-lg-' + this.labellg;
33730 items.cls += ' col-lg-' + (12 - this.labellg);
33733 if(this.labelmd > 0){
33734 label.cls += ' col-md-' + this.labelmd;
33735 items.cls += ' col-md-' + (12 - this.labelmd);
33738 if(this.labelsm > 0){
33739 label.cls += ' col-sm-' + this.labelsm;
33740 items.cls += ' col-sm-' + (12 - this.labelsm);
33743 if(this.labelxs > 0){
33744 label.cls += ' col-xs-' + this.labelxs;
33745 items.cls += ' col-xs-' + (12 - this.labelxs);
33751 cls : 'roo-radio-set',
33755 cls : 'roo-radio-set-input',
33758 value : this.value ? this.value : ''
33765 if(this.weight.length){
33766 cfg.cls += ' roo-radio-' + this.weight;
33770 cfg.cls += ' roo-radio-set-inline';
33774 ['xs','sm','md','lg'].map(function(size){
33775 if (settings[size]) {
33776 cfg.cls += ' col-' + size + '-' + settings[size];
33784 initEvents : function()
33786 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33787 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33789 if(!this.fieldLabel.length){
33790 this.labelEl.hide();
33793 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33794 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33796 this.indicator = this.indicatorEl();
33798 if(this.indicator){
33799 this.indicator.addClass('invisible');
33802 this.originalValue = this.getValue();
33806 inputEl: function ()
33808 return this.el.select('.roo-radio-set-input', true).first();
33811 getChildContainer : function()
33813 return this.itemsEl;
33816 register : function(item)
33818 this.radioes.push(item);
33822 validate : function()
33824 if(this.getVisibilityEl().hasClass('hidden')){
33830 Roo.each(this.radioes, function(i){
33839 if(this.allowBlank) {
33843 if(this.disabled || valid){
33848 this.markInvalid();
33853 markValid : function()
33855 if(this.labelEl.isVisible(true)){
33856 this.indicatorEl().removeClass('visible');
33857 this.indicatorEl().addClass('invisible');
33860 this.el.removeClass([this.invalidClass, this.validClass]);
33861 this.el.addClass(this.validClass);
33863 this.fireEvent('valid', this);
33866 markInvalid : function(msg)
33868 if(this.allowBlank || this.disabled){
33872 if(this.labelEl.isVisible(true)){
33873 this.indicatorEl().removeClass('invisible');
33874 this.indicatorEl().addClass('visible');
33877 this.el.removeClass([this.invalidClass, this.validClass]);
33878 this.el.addClass(this.invalidClass);
33880 this.fireEvent('invalid', this, msg);
33884 setValue : function(v, suppressEvent)
33886 if(this.value === v){
33893 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33896 Roo.each(this.radioes, function(i){
33898 i.el.removeClass('checked');
33901 Roo.each(this.radioes, function(i){
33903 if(i.value === v || i.value.toString() === v.toString()){
33905 i.el.addClass('checked');
33907 if(suppressEvent !== true){
33908 this.fireEvent('check', this, i);
33919 clearInvalid : function(){
33921 if(!this.el || this.preventMark){
33925 this.el.removeClass([this.invalidClass]);
33927 this.fireEvent('valid', this);
33932 Roo.apply(Roo.bootstrap.RadioSet, {
33936 register : function(set)
33938 this.groups[set.name] = set;
33941 get: function(name)
33943 if (typeof(this.groups[name]) == 'undefined') {
33947 return this.groups[name] ;
33953 * Ext JS Library 1.1.1
33954 * Copyright(c) 2006-2007, Ext JS, LLC.
33956 * Originally Released Under LGPL - original licence link has changed is not relivant.
33959 * <script type="text/javascript">
33964 * @class Roo.bootstrap.SplitBar
33965 * @extends Roo.util.Observable
33966 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33970 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33971 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33972 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33973 split.minSize = 100;
33974 split.maxSize = 600;
33975 split.animate = true;
33976 split.on('moved', splitterMoved);
33979 * Create a new SplitBar
33980 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33981 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33982 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33983 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33984 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33985 position of the SplitBar).
33987 Roo.bootstrap.SplitBar = function(cfg){
33992 // dragElement : elm
33993 // resizingElement: el,
33995 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33996 // placement : Roo.bootstrap.SplitBar.LEFT ,
33997 // existingProxy ???
34000 this.el = Roo.get(cfg.dragElement, true);
34001 this.el.dom.unselectable = "on";
34003 this.resizingEl = Roo.get(cfg.resizingElement, true);
34007 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34008 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34011 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34014 * The minimum size of the resizing element. (Defaults to 0)
34020 * The maximum size of the resizing element. (Defaults to 2000)
34023 this.maxSize = 2000;
34026 * Whether to animate the transition to the new size
34029 this.animate = false;
34032 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34035 this.useShim = false;
34040 if(!cfg.existingProxy){
34042 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34044 this.proxy = Roo.get(cfg.existingProxy).dom;
34047 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34050 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34053 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34056 this.dragSpecs = {};
34059 * @private The adapter to use to positon and resize elements
34061 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34062 this.adapter.init(this);
34064 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34066 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34067 this.el.addClass("roo-splitbar-h");
34070 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34071 this.el.addClass("roo-splitbar-v");
34077 * Fires when the splitter is moved (alias for {@link #event-moved})
34078 * @param {Roo.bootstrap.SplitBar} this
34079 * @param {Number} newSize the new width or height
34084 * Fires when the splitter is moved
34085 * @param {Roo.bootstrap.SplitBar} this
34086 * @param {Number} newSize the new width or height
34090 * @event beforeresize
34091 * Fires before the splitter is dragged
34092 * @param {Roo.bootstrap.SplitBar} this
34094 "beforeresize" : true,
34096 "beforeapply" : true
34099 Roo.util.Observable.call(this);
34102 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34103 onStartProxyDrag : function(x, y){
34104 this.fireEvent("beforeresize", this);
34106 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34108 o.enableDisplayMode("block");
34109 // all splitbars share the same overlay
34110 Roo.bootstrap.SplitBar.prototype.overlay = o;
34112 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34113 this.overlay.show();
34114 Roo.get(this.proxy).setDisplayed("block");
34115 var size = this.adapter.getElementSize(this);
34116 this.activeMinSize = this.getMinimumSize();;
34117 this.activeMaxSize = this.getMaximumSize();;
34118 var c1 = size - this.activeMinSize;
34119 var c2 = Math.max(this.activeMaxSize - size, 0);
34120 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34121 this.dd.resetConstraints();
34122 this.dd.setXConstraint(
34123 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34124 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34126 this.dd.setYConstraint(0, 0);
34128 this.dd.resetConstraints();
34129 this.dd.setXConstraint(0, 0);
34130 this.dd.setYConstraint(
34131 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34132 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34135 this.dragSpecs.startSize = size;
34136 this.dragSpecs.startPoint = [x, y];
34137 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34141 * @private Called after the drag operation by the DDProxy
34143 onEndProxyDrag : function(e){
34144 Roo.get(this.proxy).setDisplayed(false);
34145 var endPoint = Roo.lib.Event.getXY(e);
34147 this.overlay.hide();
34150 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34151 newSize = this.dragSpecs.startSize +
34152 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34153 endPoint[0] - this.dragSpecs.startPoint[0] :
34154 this.dragSpecs.startPoint[0] - endPoint[0]
34157 newSize = this.dragSpecs.startSize +
34158 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34159 endPoint[1] - this.dragSpecs.startPoint[1] :
34160 this.dragSpecs.startPoint[1] - endPoint[1]
34163 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34164 if(newSize != this.dragSpecs.startSize){
34165 if(this.fireEvent('beforeapply', this, newSize) !== false){
34166 this.adapter.setElementSize(this, newSize);
34167 this.fireEvent("moved", this, newSize);
34168 this.fireEvent("resize", this, newSize);
34174 * Get the adapter this SplitBar uses
34175 * @return The adapter object
34177 getAdapter : function(){
34178 return this.adapter;
34182 * Set the adapter this SplitBar uses
34183 * @param {Object} adapter A SplitBar adapter object
34185 setAdapter : function(adapter){
34186 this.adapter = adapter;
34187 this.adapter.init(this);
34191 * Gets the minimum size for the resizing element
34192 * @return {Number} The minimum size
34194 getMinimumSize : function(){
34195 return this.minSize;
34199 * Sets the minimum size for the resizing element
34200 * @param {Number} minSize The minimum size
34202 setMinimumSize : function(minSize){
34203 this.minSize = minSize;
34207 * Gets the maximum size for the resizing element
34208 * @return {Number} The maximum size
34210 getMaximumSize : function(){
34211 return this.maxSize;
34215 * Sets the maximum size for the resizing element
34216 * @param {Number} maxSize The maximum size
34218 setMaximumSize : function(maxSize){
34219 this.maxSize = maxSize;
34223 * Sets the initialize size for the resizing element
34224 * @param {Number} size The initial size
34226 setCurrentSize : function(size){
34227 var oldAnimate = this.animate;
34228 this.animate = false;
34229 this.adapter.setElementSize(this, size);
34230 this.animate = oldAnimate;
34234 * Destroy this splitbar.
34235 * @param {Boolean} removeEl True to remove the element
34237 destroy : function(removeEl){
34239 this.shim.remove();
34242 this.proxy.parentNode.removeChild(this.proxy);
34250 * @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.
34252 Roo.bootstrap.SplitBar.createProxy = function(dir){
34253 var proxy = new Roo.Element(document.createElement("div"));
34254 proxy.unselectable();
34255 var cls = 'roo-splitbar-proxy';
34256 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34257 document.body.appendChild(proxy.dom);
34262 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34263 * Default Adapter. It assumes the splitter and resizing element are not positioned
34264 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34266 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34269 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34270 // do nothing for now
34271 init : function(s){
34275 * Called before drag operations to get the current size of the resizing element.
34276 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34278 getElementSize : function(s){
34279 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34280 return s.resizingEl.getWidth();
34282 return s.resizingEl.getHeight();
34287 * Called after drag operations to set the size of the resizing element.
34288 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34289 * @param {Number} newSize The new size to set
34290 * @param {Function} onComplete A function to be invoked when resizing is complete
34292 setElementSize : function(s, newSize, onComplete){
34293 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34295 s.resizingEl.setWidth(newSize);
34297 onComplete(s, newSize);
34300 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34305 s.resizingEl.setHeight(newSize);
34307 onComplete(s, newSize);
34310 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34317 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34318 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34319 * Adapter that moves the splitter element to align with the resized sizing element.
34320 * Used with an absolute positioned SplitBar.
34321 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34322 * document.body, make sure you assign an id to the body element.
34324 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34325 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34326 this.container = Roo.get(container);
34329 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34330 init : function(s){
34331 this.basic.init(s);
34334 getElementSize : function(s){
34335 return this.basic.getElementSize(s);
34338 setElementSize : function(s, newSize, onComplete){
34339 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34342 moveSplitter : function(s){
34343 var yes = Roo.bootstrap.SplitBar;
34344 switch(s.placement){
34346 s.el.setX(s.resizingEl.getRight());
34349 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34352 s.el.setY(s.resizingEl.getBottom());
34355 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34362 * Orientation constant - Create a vertical SplitBar
34366 Roo.bootstrap.SplitBar.VERTICAL = 1;
34369 * Orientation constant - Create a horizontal SplitBar
34373 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34376 * Placement constant - The resizing element is to the left of the splitter element
34380 Roo.bootstrap.SplitBar.LEFT = 1;
34383 * Placement constant - The resizing element is to the right of the splitter element
34387 Roo.bootstrap.SplitBar.RIGHT = 2;
34390 * Placement constant - The resizing element is positioned above the splitter element
34394 Roo.bootstrap.SplitBar.TOP = 3;
34397 * Placement constant - The resizing element is positioned under splitter element
34401 Roo.bootstrap.SplitBar.BOTTOM = 4;
34402 Roo.namespace("Roo.bootstrap.layout");/*
34404 * Ext JS Library 1.1.1
34405 * Copyright(c) 2006-2007, Ext JS, LLC.
34407 * Originally Released Under LGPL - original licence link has changed is not relivant.
34410 * <script type="text/javascript">
34414 * @class Roo.bootstrap.layout.Manager
34415 * @extends Roo.bootstrap.Component
34416 * Base class for layout managers.
34418 Roo.bootstrap.layout.Manager = function(config)
34420 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34426 /** false to disable window resize monitoring @type Boolean */
34427 this.monitorWindowResize = true;
34432 * Fires when a layout is performed.
34433 * @param {Roo.LayoutManager} this
34437 * @event regionresized
34438 * Fires when the user resizes a region.
34439 * @param {Roo.LayoutRegion} region The resized region
34440 * @param {Number} newSize The new size (width for east/west, height for north/south)
34442 "regionresized" : true,
34444 * @event regioncollapsed
34445 * Fires when a region is collapsed.
34446 * @param {Roo.LayoutRegion} region The collapsed region
34448 "regioncollapsed" : true,
34450 * @event regionexpanded
34451 * Fires when a region is expanded.
34452 * @param {Roo.LayoutRegion} region The expanded region
34454 "regionexpanded" : true
34456 this.updating = false;
34459 this.el = Roo.get(config.el);
34465 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34470 monitorWindowResize : true,
34476 onRender : function(ct, position)
34479 this.el = Roo.get(ct);
34482 //this.fireEvent('render',this);
34486 initEvents: function()
34490 // ie scrollbar fix
34491 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34492 document.body.scroll = "no";
34493 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34494 this.el.position('relative');
34496 this.id = this.el.id;
34497 this.el.addClass("roo-layout-container");
34498 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34499 if(this.el.dom != document.body ) {
34500 this.el.on('resize', this.layout,this);
34501 this.el.on('show', this.layout,this);
34507 * Returns true if this layout is currently being updated
34508 * @return {Boolean}
34510 isUpdating : function(){
34511 return this.updating;
34515 * Suspend the LayoutManager from doing auto-layouts while
34516 * making multiple add or remove calls
34518 beginUpdate : function(){
34519 this.updating = true;
34523 * Restore auto-layouts and optionally disable the manager from performing a layout
34524 * @param {Boolean} noLayout true to disable a layout update
34526 endUpdate : function(noLayout){
34527 this.updating = false;
34533 layout: function(){
34537 onRegionResized : function(region, newSize){
34538 this.fireEvent("regionresized", region, newSize);
34542 onRegionCollapsed : function(region){
34543 this.fireEvent("regioncollapsed", region);
34546 onRegionExpanded : function(region){
34547 this.fireEvent("regionexpanded", region);
34551 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34552 * performs box-model adjustments.
34553 * @return {Object} The size as an object {width: (the width), height: (the height)}
34555 getViewSize : function()
34558 if(this.el.dom != document.body){
34559 size = this.el.getSize();
34561 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34563 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34564 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34569 * Returns the Element this layout is bound to.
34570 * @return {Roo.Element}
34572 getEl : function(){
34577 * Returns the specified region.
34578 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34579 * @return {Roo.LayoutRegion}
34581 getRegion : function(target){
34582 return this.regions[target.toLowerCase()];
34585 onWindowResize : function(){
34586 if(this.monitorWindowResize){
34593 * Ext JS Library 1.1.1
34594 * Copyright(c) 2006-2007, Ext JS, LLC.
34596 * Originally Released Under LGPL - original licence link has changed is not relivant.
34599 * <script type="text/javascript">
34602 * @class Roo.bootstrap.layout.Border
34603 * @extends Roo.bootstrap.layout.Manager
34604 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34605 * please see: examples/bootstrap/nested.html<br><br>
34607 <b>The container the layout is rendered into can be either the body element or any other element.
34608 If it is not the body element, the container needs to either be an absolute positioned element,
34609 or you will need to add "position:relative" to the css of the container. You will also need to specify
34610 the container size if it is not the body element.</b>
34613 * Create a new Border
34614 * @param {Object} config Configuration options
34616 Roo.bootstrap.layout.Border = function(config){
34617 config = config || {};
34618 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34622 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34623 if(config[region]){
34624 config[region].region = region;
34625 this.addRegion(config[region]);
34631 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34633 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34635 * Creates and adds a new region if it doesn't already exist.
34636 * @param {String} target The target region key (north, south, east, west or center).
34637 * @param {Object} config The regions config object
34638 * @return {BorderLayoutRegion} The new region
34640 addRegion : function(config)
34642 if(!this.regions[config.region]){
34643 var r = this.factory(config);
34644 this.bindRegion(r);
34646 return this.regions[config.region];
34650 bindRegion : function(r){
34651 this.regions[r.config.region] = r;
34653 r.on("visibilitychange", this.layout, this);
34654 r.on("paneladded", this.layout, this);
34655 r.on("panelremoved", this.layout, this);
34656 r.on("invalidated", this.layout, this);
34657 r.on("resized", this.onRegionResized, this);
34658 r.on("collapsed", this.onRegionCollapsed, this);
34659 r.on("expanded", this.onRegionExpanded, this);
34663 * Performs a layout update.
34665 layout : function()
34667 if(this.updating) {
34671 // render all the rebions if they have not been done alreayd?
34672 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34673 if(this.regions[region] && !this.regions[region].bodyEl){
34674 this.regions[region].onRender(this.el)
34678 var size = this.getViewSize();
34679 var w = size.width;
34680 var h = size.height;
34685 //var x = 0, y = 0;
34687 var rs = this.regions;
34688 var north = rs["north"];
34689 var south = rs["south"];
34690 var west = rs["west"];
34691 var east = rs["east"];
34692 var center = rs["center"];
34693 //if(this.hideOnLayout){ // not supported anymore
34694 //c.el.setStyle("display", "none");
34696 if(north && north.isVisible()){
34697 var b = north.getBox();
34698 var m = north.getMargins();
34699 b.width = w - (m.left+m.right);
34702 centerY = b.height + b.y + m.bottom;
34703 centerH -= centerY;
34704 north.updateBox(this.safeBox(b));
34706 if(south && south.isVisible()){
34707 var b = south.getBox();
34708 var m = south.getMargins();
34709 b.width = w - (m.left+m.right);
34711 var totalHeight = (b.height + m.top + m.bottom);
34712 b.y = h - totalHeight + m.top;
34713 centerH -= totalHeight;
34714 south.updateBox(this.safeBox(b));
34716 if(west && west.isVisible()){
34717 var b = west.getBox();
34718 var m = west.getMargins();
34719 b.height = centerH - (m.top+m.bottom);
34721 b.y = centerY + m.top;
34722 var totalWidth = (b.width + m.left + m.right);
34723 centerX += totalWidth;
34724 centerW -= totalWidth;
34725 west.updateBox(this.safeBox(b));
34727 if(east && east.isVisible()){
34728 var b = east.getBox();
34729 var m = east.getMargins();
34730 b.height = centerH - (m.top+m.bottom);
34731 var totalWidth = (b.width + m.left + m.right);
34732 b.x = w - totalWidth + m.left;
34733 b.y = centerY + m.top;
34734 centerW -= totalWidth;
34735 east.updateBox(this.safeBox(b));
34738 var m = center.getMargins();
34740 x: centerX + m.left,
34741 y: centerY + m.top,
34742 width: centerW - (m.left+m.right),
34743 height: centerH - (m.top+m.bottom)
34745 //if(this.hideOnLayout){
34746 //center.el.setStyle("display", "block");
34748 center.updateBox(this.safeBox(centerBox));
34751 this.fireEvent("layout", this);
34755 safeBox : function(box){
34756 box.width = Math.max(0, box.width);
34757 box.height = Math.max(0, box.height);
34762 * Adds a ContentPanel (or subclass) to this layout.
34763 * @param {String} target The target region key (north, south, east, west or center).
34764 * @param {Roo.ContentPanel} panel The panel to add
34765 * @return {Roo.ContentPanel} The added panel
34767 add : function(target, panel){
34769 target = target.toLowerCase();
34770 return this.regions[target].add(panel);
34774 * Remove a ContentPanel (or subclass) to this layout.
34775 * @param {String} target The target region key (north, south, east, west or center).
34776 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34777 * @return {Roo.ContentPanel} The removed panel
34779 remove : function(target, panel){
34780 target = target.toLowerCase();
34781 return this.regions[target].remove(panel);
34785 * Searches all regions for a panel with the specified id
34786 * @param {String} panelId
34787 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34789 findPanel : function(panelId){
34790 var rs = this.regions;
34791 for(var target in rs){
34792 if(typeof rs[target] != "function"){
34793 var p = rs[target].getPanel(panelId);
34803 * Searches all regions for a panel with the specified id and activates (shows) it.
34804 * @param {String/ContentPanel} panelId The panels id or the panel itself
34805 * @return {Roo.ContentPanel} The shown panel or null
34807 showPanel : function(panelId) {
34808 var rs = this.regions;
34809 for(var target in rs){
34810 var r = rs[target];
34811 if(typeof r != "function"){
34812 if(r.hasPanel(panelId)){
34813 return r.showPanel(panelId);
34821 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34822 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34825 restoreState : function(provider){
34827 provider = Roo.state.Manager;
34829 var sm = new Roo.LayoutStateManager();
34830 sm.init(this, provider);
34836 * Adds a xtype elements to the layout.
34840 xtype : 'ContentPanel',
34847 xtype : 'NestedLayoutPanel',
34853 items : [ ... list of content panels or nested layout panels.. ]
34857 * @param {Object} cfg Xtype definition of item to add.
34859 addxtype : function(cfg)
34861 // basically accepts a pannel...
34862 // can accept a layout region..!?!?
34863 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34866 // theory? children can only be panels??
34868 //if (!cfg.xtype.match(/Panel$/)) {
34873 if (typeof(cfg.region) == 'undefined') {
34874 Roo.log("Failed to add Panel, region was not set");
34878 var region = cfg.region;
34884 xitems = cfg.items;
34891 case 'Content': // ContentPanel (el, cfg)
34892 case 'Scroll': // ContentPanel (el, cfg)
34894 cfg.autoCreate = true;
34895 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34897 // var el = this.el.createChild();
34898 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34901 this.add(region, ret);
34905 case 'TreePanel': // our new panel!
34906 cfg.el = this.el.createChild();
34907 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34908 this.add(region, ret);
34913 // create a new Layout (which is a Border Layout...
34915 var clayout = cfg.layout;
34916 clayout.el = this.el.createChild();
34917 clayout.items = clayout.items || [];
34921 // replace this exitems with the clayout ones..
34922 xitems = clayout.items;
34924 // force background off if it's in center...
34925 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34926 cfg.background = false;
34928 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34931 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34932 //console.log('adding nested layout panel ' + cfg.toSource());
34933 this.add(region, ret);
34934 nb = {}; /// find first...
34939 // needs grid and region
34941 //var el = this.getRegion(region).el.createChild();
34943 *var el = this.el.createChild();
34944 // create the grid first...
34945 cfg.grid.container = el;
34946 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34949 if (region == 'center' && this.active ) {
34950 cfg.background = false;
34953 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34955 this.add(region, ret);
34957 if (cfg.background) {
34958 // render grid on panel activation (if panel background)
34959 ret.on('activate', function(gp) {
34960 if (!gp.grid.rendered) {
34961 // gp.grid.render(el);
34965 // cfg.grid.render(el);
34971 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34972 // it was the old xcomponent building that caused this before.
34973 // espeically if border is the top element in the tree.
34983 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34985 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34986 this.add(region, ret);
34990 throw "Can not add '" + cfg.xtype + "' to Border";
34996 this.beginUpdate();
35000 Roo.each(xitems, function(i) {
35001 region = nb && i.region ? i.region : false;
35003 var add = ret.addxtype(i);
35006 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35007 if (!i.background) {
35008 abn[region] = nb[region] ;
35015 // make the last non-background panel active..
35016 //if (nb) { Roo.log(abn); }
35019 for(var r in abn) {
35020 region = this.getRegion(r);
35022 // tried using nb[r], but it does not work..
35024 region.showPanel(abn[r]);
35035 factory : function(cfg)
35038 var validRegions = Roo.bootstrap.layout.Border.regions;
35040 var target = cfg.region;
35043 var r = Roo.bootstrap.layout;
35047 return new r.North(cfg);
35049 return new r.South(cfg);
35051 return new r.East(cfg);
35053 return new r.West(cfg);
35055 return new r.Center(cfg);
35057 throw 'Layout region "'+target+'" not supported.';
35064 * Ext JS Library 1.1.1
35065 * Copyright(c) 2006-2007, Ext JS, LLC.
35067 * Originally Released Under LGPL - original licence link has changed is not relivant.
35070 * <script type="text/javascript">
35074 * @class Roo.bootstrap.layout.Basic
35075 * @extends Roo.util.Observable
35076 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35077 * and does not have a titlebar, tabs or any other features. All it does is size and position
35078 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35079 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35080 * @cfg {string} region the region that it inhabits..
35081 * @cfg {bool} skipConfig skip config?
35085 Roo.bootstrap.layout.Basic = function(config){
35087 this.mgr = config.mgr;
35089 this.position = config.region;
35091 var skipConfig = config.skipConfig;
35095 * @scope Roo.BasicLayoutRegion
35099 * @event beforeremove
35100 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35101 * @param {Roo.LayoutRegion} this
35102 * @param {Roo.ContentPanel} panel The panel
35103 * @param {Object} e The cancel event object
35105 "beforeremove" : true,
35107 * @event invalidated
35108 * Fires when the layout for this region is changed.
35109 * @param {Roo.LayoutRegion} this
35111 "invalidated" : true,
35113 * @event visibilitychange
35114 * Fires when this region is shown or hidden
35115 * @param {Roo.LayoutRegion} this
35116 * @param {Boolean} visibility true or false
35118 "visibilitychange" : true,
35120 * @event paneladded
35121 * Fires when a panel is added.
35122 * @param {Roo.LayoutRegion} this
35123 * @param {Roo.ContentPanel} panel The panel
35125 "paneladded" : true,
35127 * @event panelremoved
35128 * Fires when a panel is removed.
35129 * @param {Roo.LayoutRegion} this
35130 * @param {Roo.ContentPanel} panel The panel
35132 "panelremoved" : true,
35134 * @event beforecollapse
35135 * Fires when this region before collapse.
35136 * @param {Roo.LayoutRegion} this
35138 "beforecollapse" : true,
35141 * Fires when this region is collapsed.
35142 * @param {Roo.LayoutRegion} this
35144 "collapsed" : true,
35147 * Fires when this region is expanded.
35148 * @param {Roo.LayoutRegion} this
35153 * Fires when this region is slid into view.
35154 * @param {Roo.LayoutRegion} this
35156 "slideshow" : true,
35159 * Fires when this region slides out of view.
35160 * @param {Roo.LayoutRegion} this
35162 "slidehide" : true,
35164 * @event panelactivated
35165 * Fires when a panel is activated.
35166 * @param {Roo.LayoutRegion} this
35167 * @param {Roo.ContentPanel} panel The activated panel
35169 "panelactivated" : true,
35172 * Fires when the user resizes this region.
35173 * @param {Roo.LayoutRegion} this
35174 * @param {Number} newSize The new size (width for east/west, height for north/south)
35178 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35179 this.panels = new Roo.util.MixedCollection();
35180 this.panels.getKey = this.getPanelId.createDelegate(this);
35182 this.activePanel = null;
35183 // ensure listeners are added...
35185 if (config.listeners || config.events) {
35186 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35187 listeners : config.listeners || {},
35188 events : config.events || {}
35192 if(skipConfig !== true){
35193 this.applyConfig(config);
35197 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35199 getPanelId : function(p){
35203 applyConfig : function(config){
35204 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35205 this.config = config;
35210 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35211 * the width, for horizontal (north, south) the height.
35212 * @param {Number} newSize The new width or height
35214 resizeTo : function(newSize){
35215 var el = this.el ? this.el :
35216 (this.activePanel ? this.activePanel.getEl() : null);
35218 switch(this.position){
35221 el.setWidth(newSize);
35222 this.fireEvent("resized", this, newSize);
35226 el.setHeight(newSize);
35227 this.fireEvent("resized", this, newSize);
35233 getBox : function(){
35234 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35237 getMargins : function(){
35238 return this.margins;
35241 updateBox : function(box){
35243 var el = this.activePanel.getEl();
35244 el.dom.style.left = box.x + "px";
35245 el.dom.style.top = box.y + "px";
35246 this.activePanel.setSize(box.width, box.height);
35250 * Returns the container element for this region.
35251 * @return {Roo.Element}
35253 getEl : function(){
35254 return this.activePanel;
35258 * Returns true if this region is currently visible.
35259 * @return {Boolean}
35261 isVisible : function(){
35262 return this.activePanel ? true : false;
35265 setActivePanel : function(panel){
35266 panel = this.getPanel(panel);
35267 if(this.activePanel && this.activePanel != panel){
35268 this.activePanel.setActiveState(false);
35269 this.activePanel.getEl().setLeftTop(-10000,-10000);
35271 this.activePanel = panel;
35272 panel.setActiveState(true);
35274 panel.setSize(this.box.width, this.box.height);
35276 this.fireEvent("panelactivated", this, panel);
35277 this.fireEvent("invalidated");
35281 * Show the specified panel.
35282 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35283 * @return {Roo.ContentPanel} The shown panel or null
35285 showPanel : function(panel){
35286 panel = this.getPanel(panel);
35288 this.setActivePanel(panel);
35294 * Get the active panel for this region.
35295 * @return {Roo.ContentPanel} The active panel or null
35297 getActivePanel : function(){
35298 return this.activePanel;
35302 * Add the passed ContentPanel(s)
35303 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35304 * @return {Roo.ContentPanel} The panel added (if only one was added)
35306 add : function(panel){
35307 if(arguments.length > 1){
35308 for(var i = 0, len = arguments.length; i < len; i++) {
35309 this.add(arguments[i]);
35313 if(this.hasPanel(panel)){
35314 this.showPanel(panel);
35317 var el = panel.getEl();
35318 if(el.dom.parentNode != this.mgr.el.dom){
35319 this.mgr.el.dom.appendChild(el.dom);
35321 if(panel.setRegion){
35322 panel.setRegion(this);
35324 this.panels.add(panel);
35325 el.setStyle("position", "absolute");
35326 if(!panel.background){
35327 this.setActivePanel(panel);
35328 if(this.config.initialSize && this.panels.getCount()==1){
35329 this.resizeTo(this.config.initialSize);
35332 this.fireEvent("paneladded", this, panel);
35337 * Returns true if the panel is in this region.
35338 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35339 * @return {Boolean}
35341 hasPanel : function(panel){
35342 if(typeof panel == "object"){ // must be panel obj
35343 panel = panel.getId();
35345 return this.getPanel(panel) ? true : false;
35349 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35350 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35351 * @param {Boolean} preservePanel Overrides the config preservePanel option
35352 * @return {Roo.ContentPanel} The panel that was removed
35354 remove : function(panel, preservePanel){
35355 panel = this.getPanel(panel);
35360 this.fireEvent("beforeremove", this, panel, e);
35361 if(e.cancel === true){
35364 var panelId = panel.getId();
35365 this.panels.removeKey(panelId);
35370 * Returns the panel specified or null if it's not in this region.
35371 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35372 * @return {Roo.ContentPanel}
35374 getPanel : function(id){
35375 if(typeof id == "object"){ // must be panel obj
35378 return this.panels.get(id);
35382 * Returns this regions position (north/south/east/west/center).
35385 getPosition: function(){
35386 return this.position;
35390 * Ext JS Library 1.1.1
35391 * Copyright(c) 2006-2007, Ext JS, LLC.
35393 * Originally Released Under LGPL - original licence link has changed is not relivant.
35396 * <script type="text/javascript">
35400 * @class Roo.bootstrap.layout.Region
35401 * @extends Roo.bootstrap.layout.Basic
35402 * This class represents a region in a layout manager.
35404 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35405 * @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})
35406 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35407 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35408 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35409 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35410 * @cfg {String} title The title for the region (overrides panel titles)
35411 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35412 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35413 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35414 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35415 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35416 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35417 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35418 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35419 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35420 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35422 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35423 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35424 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35425 * @cfg {Number} width For East/West panels
35426 * @cfg {Number} height For North/South panels
35427 * @cfg {Boolean} split To show the splitter
35428 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35430 * @cfg {string} cls Extra CSS classes to add to region
35432 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35433 * @cfg {string} region the region that it inhabits..
35436 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35437 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35439 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35440 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35441 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35443 Roo.bootstrap.layout.Region = function(config)
35445 this.applyConfig(config);
35447 var mgr = config.mgr;
35448 var pos = config.region;
35449 config.skipConfig = true;
35450 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35453 this.onRender(mgr.el);
35456 this.visible = true;
35457 this.collapsed = false;
35458 this.unrendered_panels = [];
35461 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35463 position: '', // set by wrapper (eg. north/south etc..)
35464 unrendered_panels : null, // unrendered panels.
35465 createBody : function(){
35466 /** This region's body element
35467 * @type Roo.Element */
35468 this.bodyEl = this.el.createChild({
35470 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35474 onRender: function(ctr, pos)
35476 var dh = Roo.DomHelper;
35477 /** This region's container element
35478 * @type Roo.Element */
35479 this.el = dh.append(ctr.dom, {
35481 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35483 /** This region's title element
35484 * @type Roo.Element */
35486 this.titleEl = dh.append(this.el.dom,
35489 unselectable: "on",
35490 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35492 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35493 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35496 this.titleEl.enableDisplayMode();
35497 /** This region's title text element
35498 * @type HTMLElement */
35499 this.titleTextEl = this.titleEl.dom.firstChild;
35500 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35502 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35503 this.closeBtn.enableDisplayMode();
35504 this.closeBtn.on("click", this.closeClicked, this);
35505 this.closeBtn.hide();
35507 this.createBody(this.config);
35508 if(this.config.hideWhenEmpty){
35510 this.on("paneladded", this.validateVisibility, this);
35511 this.on("panelremoved", this.validateVisibility, this);
35513 if(this.autoScroll){
35514 this.bodyEl.setStyle("overflow", "auto");
35516 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35518 //if(c.titlebar !== false){
35519 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35520 this.titleEl.hide();
35522 this.titleEl.show();
35523 if(this.config.title){
35524 this.titleTextEl.innerHTML = this.config.title;
35528 if(this.config.collapsed){
35529 this.collapse(true);
35531 if(this.config.hidden){
35535 if (this.unrendered_panels && this.unrendered_panels.length) {
35536 for (var i =0;i< this.unrendered_panels.length; i++) {
35537 this.add(this.unrendered_panels[i]);
35539 this.unrendered_panels = null;
35545 applyConfig : function(c)
35548 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35549 var dh = Roo.DomHelper;
35550 if(c.titlebar !== false){
35551 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35552 this.collapseBtn.on("click", this.collapse, this);
35553 this.collapseBtn.enableDisplayMode();
35555 if(c.showPin === true || this.showPin){
35556 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35557 this.stickBtn.enableDisplayMode();
35558 this.stickBtn.on("click", this.expand, this);
35559 this.stickBtn.hide();
35564 /** This region's collapsed element
35565 * @type Roo.Element */
35568 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35569 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35572 if(c.floatable !== false){
35573 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35574 this.collapsedEl.on("click", this.collapseClick, this);
35577 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35578 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35579 id: "message", unselectable: "on", style:{"float":"left"}});
35580 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35582 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35583 this.expandBtn.on("click", this.expand, this);
35587 if(this.collapseBtn){
35588 this.collapseBtn.setVisible(c.collapsible == true);
35591 this.cmargins = c.cmargins || this.cmargins ||
35592 (this.position == "west" || this.position == "east" ?
35593 {top: 0, left: 2, right:2, bottom: 0} :
35594 {top: 2, left: 0, right:0, bottom: 2});
35596 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35599 this.bottomTabs = c.tabPosition != "top";
35601 this.autoScroll = c.autoScroll || false;
35606 this.duration = c.duration || .30;
35607 this.slideDuration = c.slideDuration || .45;
35612 * Returns true if this region is currently visible.
35613 * @return {Boolean}
35615 isVisible : function(){
35616 return this.visible;
35620 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35621 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35623 //setCollapsedTitle : function(title){
35624 // title = title || " ";
35625 // if(this.collapsedTitleTextEl){
35626 // this.collapsedTitleTextEl.innerHTML = title;
35630 getBox : function(){
35632 // if(!this.collapsed){
35633 b = this.el.getBox(false, true);
35635 // b = this.collapsedEl.getBox(false, true);
35640 getMargins : function(){
35641 return this.margins;
35642 //return this.collapsed ? this.cmargins : this.margins;
35645 highlight : function(){
35646 this.el.addClass("x-layout-panel-dragover");
35649 unhighlight : function(){
35650 this.el.removeClass("x-layout-panel-dragover");
35653 updateBox : function(box)
35655 if (!this.bodyEl) {
35656 return; // not rendered yet..
35660 if(!this.collapsed){
35661 this.el.dom.style.left = box.x + "px";
35662 this.el.dom.style.top = box.y + "px";
35663 this.updateBody(box.width, box.height);
35665 this.collapsedEl.dom.style.left = box.x + "px";
35666 this.collapsedEl.dom.style.top = box.y + "px";
35667 this.collapsedEl.setSize(box.width, box.height);
35670 this.tabs.autoSizeTabs();
35674 updateBody : function(w, h)
35677 this.el.setWidth(w);
35678 w -= this.el.getBorderWidth("rl");
35679 if(this.config.adjustments){
35680 w += this.config.adjustments[0];
35683 if(h !== null && h > 0){
35684 this.el.setHeight(h);
35685 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35686 h -= this.el.getBorderWidth("tb");
35687 if(this.config.adjustments){
35688 h += this.config.adjustments[1];
35690 this.bodyEl.setHeight(h);
35692 h = this.tabs.syncHeight(h);
35695 if(this.panelSize){
35696 w = w !== null ? w : this.panelSize.width;
35697 h = h !== null ? h : this.panelSize.height;
35699 if(this.activePanel){
35700 var el = this.activePanel.getEl();
35701 w = w !== null ? w : el.getWidth();
35702 h = h !== null ? h : el.getHeight();
35703 this.panelSize = {width: w, height: h};
35704 this.activePanel.setSize(w, h);
35706 if(Roo.isIE && this.tabs){
35707 this.tabs.el.repaint();
35712 * Returns the container element for this region.
35713 * @return {Roo.Element}
35715 getEl : function(){
35720 * Hides this region.
35723 //if(!this.collapsed){
35724 this.el.dom.style.left = "-2000px";
35727 // this.collapsedEl.dom.style.left = "-2000px";
35728 // this.collapsedEl.hide();
35730 this.visible = false;
35731 this.fireEvent("visibilitychange", this, false);
35735 * Shows this region if it was previously hidden.
35738 //if(!this.collapsed){
35741 // this.collapsedEl.show();
35743 this.visible = true;
35744 this.fireEvent("visibilitychange", this, true);
35747 closeClicked : function(){
35748 if(this.activePanel){
35749 this.remove(this.activePanel);
35753 collapseClick : function(e){
35755 e.stopPropagation();
35758 e.stopPropagation();
35764 * Collapses this region.
35765 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35768 collapse : function(skipAnim, skipCheck = false){
35769 if(this.collapsed) {
35773 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35775 this.collapsed = true;
35777 this.split.el.hide();
35779 if(this.config.animate && skipAnim !== true){
35780 this.fireEvent("invalidated", this);
35781 this.animateCollapse();
35783 this.el.setLocation(-20000,-20000);
35785 this.collapsedEl.show();
35786 this.fireEvent("collapsed", this);
35787 this.fireEvent("invalidated", this);
35793 animateCollapse : function(){
35798 * Expands this region if it was previously collapsed.
35799 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35800 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35803 expand : function(e, skipAnim){
35805 e.stopPropagation();
35807 if(!this.collapsed || this.el.hasActiveFx()) {
35811 this.afterSlideIn();
35814 this.collapsed = false;
35815 if(this.config.animate && skipAnim !== true){
35816 this.animateExpand();
35820 this.split.el.show();
35822 this.collapsedEl.setLocation(-2000,-2000);
35823 this.collapsedEl.hide();
35824 this.fireEvent("invalidated", this);
35825 this.fireEvent("expanded", this);
35829 animateExpand : function(){
35833 initTabs : function()
35835 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35837 var ts = new Roo.bootstrap.panel.Tabs({
35838 el: this.bodyEl.dom,
35839 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35840 disableTooltips: this.config.disableTabTips,
35841 toolbar : this.config.toolbar
35844 if(this.config.hideTabs){
35845 ts.stripWrap.setDisplayed(false);
35848 ts.resizeTabs = this.config.resizeTabs === true;
35849 ts.minTabWidth = this.config.minTabWidth || 40;
35850 ts.maxTabWidth = this.config.maxTabWidth || 250;
35851 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35852 ts.monitorResize = false;
35853 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35854 ts.bodyEl.addClass('roo-layout-tabs-body');
35855 this.panels.each(this.initPanelAsTab, this);
35858 initPanelAsTab : function(panel){
35859 var ti = this.tabs.addTab(
35863 this.config.closeOnTab && panel.isClosable(),
35866 if(panel.tabTip !== undefined){
35867 ti.setTooltip(panel.tabTip);
35869 ti.on("activate", function(){
35870 this.setActivePanel(panel);
35873 if(this.config.closeOnTab){
35874 ti.on("beforeclose", function(t, e){
35876 this.remove(panel);
35880 panel.tabItem = ti;
35885 updatePanelTitle : function(panel, title)
35887 if(this.activePanel == panel){
35888 this.updateTitle(title);
35891 var ti = this.tabs.getTab(panel.getEl().id);
35893 if(panel.tabTip !== undefined){
35894 ti.setTooltip(panel.tabTip);
35899 updateTitle : function(title){
35900 if(this.titleTextEl && !this.config.title){
35901 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35905 setActivePanel : function(panel)
35907 panel = this.getPanel(panel);
35908 if(this.activePanel && this.activePanel != panel){
35909 if(this.activePanel.setActiveState(false) === false){
35913 this.activePanel = panel;
35914 panel.setActiveState(true);
35915 if(this.panelSize){
35916 panel.setSize(this.panelSize.width, this.panelSize.height);
35919 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35921 this.updateTitle(panel.getTitle());
35923 this.fireEvent("invalidated", this);
35925 this.fireEvent("panelactivated", this, panel);
35929 * Shows the specified panel.
35930 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35931 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35933 showPanel : function(panel)
35935 panel = this.getPanel(panel);
35938 var tab = this.tabs.getTab(panel.getEl().id);
35939 if(tab.isHidden()){
35940 this.tabs.unhideTab(tab.id);
35944 this.setActivePanel(panel);
35951 * Get the active panel for this region.
35952 * @return {Roo.ContentPanel} The active panel or null
35954 getActivePanel : function(){
35955 return this.activePanel;
35958 validateVisibility : function(){
35959 if(this.panels.getCount() < 1){
35960 this.updateTitle(" ");
35961 this.closeBtn.hide();
35964 if(!this.isVisible()){
35971 * Adds the passed ContentPanel(s) to this region.
35972 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35973 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35975 add : function(panel)
35977 if(arguments.length > 1){
35978 for(var i = 0, len = arguments.length; i < len; i++) {
35979 this.add(arguments[i]);
35984 // if we have not been rendered yet, then we can not really do much of this..
35985 if (!this.bodyEl) {
35986 this.unrendered_panels.push(panel);
35993 if(this.hasPanel(panel)){
35994 this.showPanel(panel);
35997 panel.setRegion(this);
35998 this.panels.add(panel);
35999 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36000 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36001 // and hide them... ???
36002 this.bodyEl.dom.appendChild(panel.getEl().dom);
36003 if(panel.background !== true){
36004 this.setActivePanel(panel);
36006 this.fireEvent("paneladded", this, panel);
36013 this.initPanelAsTab(panel);
36017 if(panel.background !== true){
36018 this.tabs.activate(panel.getEl().id);
36020 this.fireEvent("paneladded", this, panel);
36025 * Hides the tab for the specified panel.
36026 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36028 hidePanel : function(panel){
36029 if(this.tabs && (panel = this.getPanel(panel))){
36030 this.tabs.hideTab(panel.getEl().id);
36035 * Unhides the tab for a previously hidden panel.
36036 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36038 unhidePanel : function(panel){
36039 if(this.tabs && (panel = this.getPanel(panel))){
36040 this.tabs.unhideTab(panel.getEl().id);
36044 clearPanels : function(){
36045 while(this.panels.getCount() > 0){
36046 this.remove(this.panels.first());
36051 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36052 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36053 * @param {Boolean} preservePanel Overrides the config preservePanel option
36054 * @return {Roo.ContentPanel} The panel that was removed
36056 remove : function(panel, preservePanel)
36058 panel = this.getPanel(panel);
36063 this.fireEvent("beforeremove", this, panel, e);
36064 if(e.cancel === true){
36067 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36068 var panelId = panel.getId();
36069 this.panels.removeKey(panelId);
36071 document.body.appendChild(panel.getEl().dom);
36074 this.tabs.removeTab(panel.getEl().id);
36075 }else if (!preservePanel){
36076 this.bodyEl.dom.removeChild(panel.getEl().dom);
36078 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36079 var p = this.panels.first();
36080 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36081 tempEl.appendChild(p.getEl().dom);
36082 this.bodyEl.update("");
36083 this.bodyEl.dom.appendChild(p.getEl().dom);
36085 this.updateTitle(p.getTitle());
36087 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36088 this.setActivePanel(p);
36090 panel.setRegion(null);
36091 if(this.activePanel == panel){
36092 this.activePanel = null;
36094 if(this.config.autoDestroy !== false && preservePanel !== true){
36095 try{panel.destroy();}catch(e){}
36097 this.fireEvent("panelremoved", this, panel);
36102 * Returns the TabPanel component used by this region
36103 * @return {Roo.TabPanel}
36105 getTabs : function(){
36109 createTool : function(parentEl, className){
36110 var btn = Roo.DomHelper.append(parentEl, {
36112 cls: "x-layout-tools-button",
36115 cls: "roo-layout-tools-button-inner " + className,
36119 btn.addClassOnOver("roo-layout-tools-button-over");
36124 * Ext JS Library 1.1.1
36125 * Copyright(c) 2006-2007, Ext JS, LLC.
36127 * Originally Released Under LGPL - original licence link has changed is not relivant.
36130 * <script type="text/javascript">
36136 * @class Roo.SplitLayoutRegion
36137 * @extends Roo.LayoutRegion
36138 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36140 Roo.bootstrap.layout.Split = function(config){
36141 this.cursor = config.cursor;
36142 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36145 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36147 splitTip : "Drag to resize.",
36148 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36149 useSplitTips : false,
36151 applyConfig : function(config){
36152 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36155 onRender : function(ctr,pos) {
36157 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36158 if(!this.config.split){
36163 var splitEl = Roo.DomHelper.append(ctr.dom, {
36165 id: this.el.id + "-split",
36166 cls: "roo-layout-split roo-layout-split-"+this.position,
36169 /** The SplitBar for this region
36170 * @type Roo.SplitBar */
36171 // does not exist yet...
36172 Roo.log([this.position, this.orientation]);
36174 this.split = new Roo.bootstrap.SplitBar({
36175 dragElement : splitEl,
36176 resizingElement: this.el,
36177 orientation : this.orientation
36180 this.split.on("moved", this.onSplitMove, this);
36181 this.split.useShim = this.config.useShim === true;
36182 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36183 if(this.useSplitTips){
36184 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36186 //if(config.collapsible){
36187 // this.split.el.on("dblclick", this.collapse, this);
36190 if(typeof this.config.minSize != "undefined"){
36191 this.split.minSize = this.config.minSize;
36193 if(typeof this.config.maxSize != "undefined"){
36194 this.split.maxSize = this.config.maxSize;
36196 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36197 this.hideSplitter();
36202 getHMaxSize : function(){
36203 var cmax = this.config.maxSize || 10000;
36204 var center = this.mgr.getRegion("center");
36205 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36208 getVMaxSize : function(){
36209 var cmax = this.config.maxSize || 10000;
36210 var center = this.mgr.getRegion("center");
36211 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36214 onSplitMove : function(split, newSize){
36215 this.fireEvent("resized", this, newSize);
36219 * Returns the {@link Roo.SplitBar} for this region.
36220 * @return {Roo.SplitBar}
36222 getSplitBar : function(){
36227 this.hideSplitter();
36228 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36231 hideSplitter : function(){
36233 this.split.el.setLocation(-2000,-2000);
36234 this.split.el.hide();
36240 this.split.el.show();
36242 Roo.bootstrap.layout.Split.superclass.show.call(this);
36245 beforeSlide: function(){
36246 if(Roo.isGecko){// firefox overflow auto bug workaround
36247 this.bodyEl.clip();
36249 this.tabs.bodyEl.clip();
36251 if(this.activePanel){
36252 this.activePanel.getEl().clip();
36254 if(this.activePanel.beforeSlide){
36255 this.activePanel.beforeSlide();
36261 afterSlide : function(){
36262 if(Roo.isGecko){// firefox overflow auto bug workaround
36263 this.bodyEl.unclip();
36265 this.tabs.bodyEl.unclip();
36267 if(this.activePanel){
36268 this.activePanel.getEl().unclip();
36269 if(this.activePanel.afterSlide){
36270 this.activePanel.afterSlide();
36276 initAutoHide : function(){
36277 if(this.autoHide !== false){
36278 if(!this.autoHideHd){
36279 var st = new Roo.util.DelayedTask(this.slideIn, this);
36280 this.autoHideHd = {
36281 "mouseout": function(e){
36282 if(!e.within(this.el, true)){
36286 "mouseover" : function(e){
36292 this.el.on(this.autoHideHd);
36296 clearAutoHide : function(){
36297 if(this.autoHide !== false){
36298 this.el.un("mouseout", this.autoHideHd.mouseout);
36299 this.el.un("mouseover", this.autoHideHd.mouseover);
36303 clearMonitor : function(){
36304 Roo.get(document).un("click", this.slideInIf, this);
36307 // these names are backwards but not changed for compat
36308 slideOut : function(){
36309 if(this.isSlid || this.el.hasActiveFx()){
36312 this.isSlid = true;
36313 if(this.collapseBtn){
36314 this.collapseBtn.hide();
36316 this.closeBtnState = this.closeBtn.getStyle('display');
36317 this.closeBtn.hide();
36319 this.stickBtn.show();
36322 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36323 this.beforeSlide();
36324 this.el.setStyle("z-index", 10001);
36325 this.el.slideIn(this.getSlideAnchor(), {
36326 callback: function(){
36328 this.initAutoHide();
36329 Roo.get(document).on("click", this.slideInIf, this);
36330 this.fireEvent("slideshow", this);
36337 afterSlideIn : function(){
36338 this.clearAutoHide();
36339 this.isSlid = false;
36340 this.clearMonitor();
36341 this.el.setStyle("z-index", "");
36342 if(this.collapseBtn){
36343 this.collapseBtn.show();
36345 this.closeBtn.setStyle('display', this.closeBtnState);
36347 this.stickBtn.hide();
36349 this.fireEvent("slidehide", this);
36352 slideIn : function(cb){
36353 if(!this.isSlid || this.el.hasActiveFx()){
36357 this.isSlid = false;
36358 this.beforeSlide();
36359 this.el.slideOut(this.getSlideAnchor(), {
36360 callback: function(){
36361 this.el.setLeftTop(-10000, -10000);
36363 this.afterSlideIn();
36371 slideInIf : function(e){
36372 if(!e.within(this.el)){
36377 animateCollapse : function(){
36378 this.beforeSlide();
36379 this.el.setStyle("z-index", 20000);
36380 var anchor = this.getSlideAnchor();
36381 this.el.slideOut(anchor, {
36382 callback : function(){
36383 this.el.setStyle("z-index", "");
36384 this.collapsedEl.slideIn(anchor, {duration:.3});
36386 this.el.setLocation(-10000,-10000);
36388 this.fireEvent("collapsed", this);
36395 animateExpand : function(){
36396 this.beforeSlide();
36397 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36398 this.el.setStyle("z-index", 20000);
36399 this.collapsedEl.hide({
36402 this.el.slideIn(this.getSlideAnchor(), {
36403 callback : function(){
36404 this.el.setStyle("z-index", "");
36407 this.split.el.show();
36409 this.fireEvent("invalidated", this);
36410 this.fireEvent("expanded", this);
36438 getAnchor : function(){
36439 return this.anchors[this.position];
36442 getCollapseAnchor : function(){
36443 return this.canchors[this.position];
36446 getSlideAnchor : function(){
36447 return this.sanchors[this.position];
36450 getAlignAdj : function(){
36451 var cm = this.cmargins;
36452 switch(this.position){
36468 getExpandAdj : function(){
36469 var c = this.collapsedEl, cm = this.cmargins;
36470 switch(this.position){
36472 return [-(cm.right+c.getWidth()+cm.left), 0];
36475 return [cm.right+c.getWidth()+cm.left, 0];
36478 return [0, -(cm.top+cm.bottom+c.getHeight())];
36481 return [0, cm.top+cm.bottom+c.getHeight()];
36487 * Ext JS Library 1.1.1
36488 * Copyright(c) 2006-2007, Ext JS, LLC.
36490 * Originally Released Under LGPL - original licence link has changed is not relivant.
36493 * <script type="text/javascript">
36496 * These classes are private internal classes
36498 Roo.bootstrap.layout.Center = function(config){
36499 config.region = "center";
36500 Roo.bootstrap.layout.Region.call(this, config);
36501 this.visible = true;
36502 this.minWidth = config.minWidth || 20;
36503 this.minHeight = config.minHeight || 20;
36506 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36508 // center panel can't be hidden
36512 // center panel can't be hidden
36515 getMinWidth: function(){
36516 return this.minWidth;
36519 getMinHeight: function(){
36520 return this.minHeight;
36533 Roo.bootstrap.layout.North = function(config)
36535 config.region = 'north';
36536 config.cursor = 'n-resize';
36538 Roo.bootstrap.layout.Split.call(this, config);
36542 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36543 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36544 this.split.el.addClass("roo-layout-split-v");
36546 var size = config.initialSize || config.height;
36547 if(typeof size != "undefined"){
36548 this.el.setHeight(size);
36551 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36553 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36557 getBox : function(){
36558 if(this.collapsed){
36559 return this.collapsedEl.getBox();
36561 var box = this.el.getBox();
36563 box.height += this.split.el.getHeight();
36568 updateBox : function(box){
36569 if(this.split && !this.collapsed){
36570 box.height -= this.split.el.getHeight();
36571 this.split.el.setLeft(box.x);
36572 this.split.el.setTop(box.y+box.height);
36573 this.split.el.setWidth(box.width);
36575 if(this.collapsed){
36576 this.updateBody(box.width, null);
36578 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36586 Roo.bootstrap.layout.South = function(config){
36587 config.region = 'south';
36588 config.cursor = 's-resize';
36589 Roo.bootstrap.layout.Split.call(this, config);
36591 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36592 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36593 this.split.el.addClass("roo-layout-split-v");
36595 var size = config.initialSize || config.height;
36596 if(typeof size != "undefined"){
36597 this.el.setHeight(size);
36601 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36602 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36603 getBox : function(){
36604 if(this.collapsed){
36605 return this.collapsedEl.getBox();
36607 var box = this.el.getBox();
36609 var sh = this.split.el.getHeight();
36616 updateBox : function(box){
36617 if(this.split && !this.collapsed){
36618 var sh = this.split.el.getHeight();
36621 this.split.el.setLeft(box.x);
36622 this.split.el.setTop(box.y-sh);
36623 this.split.el.setWidth(box.width);
36625 if(this.collapsed){
36626 this.updateBody(box.width, null);
36628 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36632 Roo.bootstrap.layout.East = function(config){
36633 config.region = "east";
36634 config.cursor = "e-resize";
36635 Roo.bootstrap.layout.Split.call(this, config);
36637 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36638 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36639 this.split.el.addClass("roo-layout-split-h");
36641 var size = config.initialSize || config.width;
36642 if(typeof size != "undefined"){
36643 this.el.setWidth(size);
36646 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36647 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36648 getBox : function(){
36649 if(this.collapsed){
36650 return this.collapsedEl.getBox();
36652 var box = this.el.getBox();
36654 var sw = this.split.el.getWidth();
36661 updateBox : function(box){
36662 if(this.split && !this.collapsed){
36663 var sw = this.split.el.getWidth();
36665 this.split.el.setLeft(box.x);
36666 this.split.el.setTop(box.y);
36667 this.split.el.setHeight(box.height);
36670 if(this.collapsed){
36671 this.updateBody(null, box.height);
36673 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36677 Roo.bootstrap.layout.West = function(config){
36678 config.region = "west";
36679 config.cursor = "w-resize";
36681 Roo.bootstrap.layout.Split.call(this, config);
36683 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36684 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36685 this.split.el.addClass("roo-layout-split-h");
36689 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36690 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36692 onRender: function(ctr, pos)
36694 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36695 var size = this.config.initialSize || this.config.width;
36696 if(typeof size != "undefined"){
36697 this.el.setWidth(size);
36701 getBox : function(){
36702 if(this.collapsed){
36703 return this.collapsedEl.getBox();
36705 var box = this.el.getBox();
36707 box.width += this.split.el.getWidth();
36712 updateBox : function(box){
36713 if(this.split && !this.collapsed){
36714 var sw = this.split.el.getWidth();
36716 this.split.el.setLeft(box.x+box.width);
36717 this.split.el.setTop(box.y);
36718 this.split.el.setHeight(box.height);
36720 if(this.collapsed){
36721 this.updateBody(null, box.height);
36723 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36726 Roo.namespace("Roo.bootstrap.panel");/*
36728 * Ext JS Library 1.1.1
36729 * Copyright(c) 2006-2007, Ext JS, LLC.
36731 * Originally Released Under LGPL - original licence link has changed is not relivant.
36734 * <script type="text/javascript">
36737 * @class Roo.ContentPanel
36738 * @extends Roo.util.Observable
36739 * A basic ContentPanel element.
36740 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36741 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36742 * @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
36743 * @cfg {Boolean} closable True if the panel can be closed/removed
36744 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36745 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36746 * @cfg {Toolbar} toolbar A toolbar for this panel
36747 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36748 * @cfg {String} title The title for this panel
36749 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36750 * @cfg {String} url Calls {@link #setUrl} with this value
36751 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36752 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36753 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36754 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36755 * @cfg {Boolean} badges render the badges
36758 * Create a new ContentPanel.
36759 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36760 * @param {String/Object} config A string to set only the title or a config object
36761 * @param {String} content (optional) Set the HTML content for this panel
36762 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36764 Roo.bootstrap.panel.Content = function( config){
36766 this.tpl = config.tpl || false;
36768 var el = config.el;
36769 var content = config.content;
36771 if(config.autoCreate){ // xtype is available if this is called from factory
36774 this.el = Roo.get(el);
36775 if(!this.el && config && config.autoCreate){
36776 if(typeof config.autoCreate == "object"){
36777 if(!config.autoCreate.id){
36778 config.autoCreate.id = config.id||el;
36780 this.el = Roo.DomHelper.append(document.body,
36781 config.autoCreate, true);
36783 var elcfg = { tag: "div",
36784 cls: "roo-layout-inactive-content",
36788 elcfg.html = config.html;
36792 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36795 this.closable = false;
36796 this.loaded = false;
36797 this.active = false;
36800 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36802 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36804 this.wrapEl = this.el; //this.el.wrap();
36806 if (config.toolbar.items) {
36807 ti = config.toolbar.items ;
36808 delete config.toolbar.items ;
36812 this.toolbar.render(this.wrapEl, 'before');
36813 for(var i =0;i < ti.length;i++) {
36814 // Roo.log(['add child', items[i]]);
36815 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36817 this.toolbar.items = nitems;
36818 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36819 delete config.toolbar;
36823 // xtype created footer. - not sure if will work as we normally have to render first..
36824 if (this.footer && !this.footer.el && this.footer.xtype) {
36825 if (!this.wrapEl) {
36826 this.wrapEl = this.el.wrap();
36829 this.footer.container = this.wrapEl.createChild();
36831 this.footer = Roo.factory(this.footer, Roo);
36836 if(typeof config == "string"){
36837 this.title = config;
36839 Roo.apply(this, config);
36843 this.resizeEl = Roo.get(this.resizeEl, true);
36845 this.resizeEl = this.el;
36847 // handle view.xtype
36855 * Fires when this panel is activated.
36856 * @param {Roo.ContentPanel} this
36860 * @event deactivate
36861 * Fires when this panel is activated.
36862 * @param {Roo.ContentPanel} this
36864 "deactivate" : true,
36868 * Fires when this panel is resized if fitToFrame is true.
36869 * @param {Roo.ContentPanel} this
36870 * @param {Number} width The width after any component adjustments
36871 * @param {Number} height The height after any component adjustments
36877 * Fires when this tab is created
36878 * @param {Roo.ContentPanel} this
36889 if(this.autoScroll){
36890 this.resizeEl.setStyle("overflow", "auto");
36892 // fix randome scrolling
36893 //this.el.on('scroll', function() {
36894 // Roo.log('fix random scolling');
36895 // this.scrollTo('top',0);
36898 content = content || this.content;
36900 this.setContent(content);
36902 if(config && config.url){
36903 this.setUrl(this.url, this.params, this.loadOnce);
36908 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36910 if (this.view && typeof(this.view.xtype) != 'undefined') {
36911 this.view.el = this.el.appendChild(document.createElement("div"));
36912 this.view = Roo.factory(this.view);
36913 this.view.render && this.view.render(false, '');
36917 this.fireEvent('render', this);
36920 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36924 setRegion : function(region){
36925 this.region = region;
36926 this.setActiveClass(region && !this.background);
36930 setActiveClass: function(state)
36933 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36934 this.el.setStyle('position','relative');
36936 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36937 this.el.setStyle('position', 'absolute');
36942 * Returns the toolbar for this Panel if one was configured.
36943 * @return {Roo.Toolbar}
36945 getToolbar : function(){
36946 return this.toolbar;
36949 setActiveState : function(active)
36951 this.active = active;
36952 this.setActiveClass(active);
36954 if(this.fireEvent("deactivate", this) === false){
36959 this.fireEvent("activate", this);
36963 * Updates this panel's element
36964 * @param {String} content The new content
36965 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36967 setContent : function(content, loadScripts){
36968 this.el.update(content, loadScripts);
36971 ignoreResize : function(w, h){
36972 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36975 this.lastSize = {width: w, height: h};
36980 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36981 * @return {Roo.UpdateManager} The UpdateManager
36983 getUpdateManager : function(){
36984 return this.el.getUpdateManager();
36987 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36988 * @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:
36991 url: "your-url.php",
36992 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36993 callback: yourFunction,
36994 scope: yourObject, //(optional scope)
36997 text: "Loading...",
37002 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37003 * 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.
37004 * @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}
37005 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37006 * @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.
37007 * @return {Roo.ContentPanel} this
37010 var um = this.el.getUpdateManager();
37011 um.update.apply(um, arguments);
37017 * 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.
37018 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37019 * @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)
37020 * @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)
37021 * @return {Roo.UpdateManager} The UpdateManager
37023 setUrl : function(url, params, loadOnce){
37024 if(this.refreshDelegate){
37025 this.removeListener("activate", this.refreshDelegate);
37027 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37028 this.on("activate", this.refreshDelegate);
37029 return this.el.getUpdateManager();
37032 _handleRefresh : function(url, params, loadOnce){
37033 if(!loadOnce || !this.loaded){
37034 var updater = this.el.getUpdateManager();
37035 updater.update(url, params, this._setLoaded.createDelegate(this));
37039 _setLoaded : function(){
37040 this.loaded = true;
37044 * Returns this panel's id
37047 getId : function(){
37052 * Returns this panel's element - used by regiosn to add.
37053 * @return {Roo.Element}
37055 getEl : function(){
37056 return this.wrapEl || this.el;
37061 adjustForComponents : function(width, height)
37063 //Roo.log('adjustForComponents ');
37064 if(this.resizeEl != this.el){
37065 width -= this.el.getFrameWidth('lr');
37066 height -= this.el.getFrameWidth('tb');
37069 var te = this.toolbar.getEl();
37070 te.setWidth(width);
37071 height -= te.getHeight();
37074 var te = this.footer.getEl();
37075 te.setWidth(width);
37076 height -= te.getHeight();
37080 if(this.adjustments){
37081 width += this.adjustments[0];
37082 height += this.adjustments[1];
37084 return {"width": width, "height": height};
37087 setSize : function(width, height){
37088 if(this.fitToFrame && !this.ignoreResize(width, height)){
37089 if(this.fitContainer && this.resizeEl != this.el){
37090 this.el.setSize(width, height);
37092 var size = this.adjustForComponents(width, height);
37093 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37094 this.fireEvent('resize', this, size.width, size.height);
37099 * Returns this panel's title
37102 getTitle : function(){
37104 if (typeof(this.title) != 'object') {
37109 for (var k in this.title) {
37110 if (!this.title.hasOwnProperty(k)) {
37114 if (k.indexOf('-') >= 0) {
37115 var s = k.split('-');
37116 for (var i = 0; i<s.length; i++) {
37117 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37120 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37127 * Set this panel's title
37128 * @param {String} title
37130 setTitle : function(title){
37131 this.title = title;
37133 this.region.updatePanelTitle(this, title);
37138 * Returns true is this panel was configured to be closable
37139 * @return {Boolean}
37141 isClosable : function(){
37142 return this.closable;
37145 beforeSlide : function(){
37147 this.resizeEl.clip();
37150 afterSlide : function(){
37152 this.resizeEl.unclip();
37156 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37157 * Will fail silently if the {@link #setUrl} method has not been called.
37158 * This does not activate the panel, just updates its content.
37160 refresh : function(){
37161 if(this.refreshDelegate){
37162 this.loaded = false;
37163 this.refreshDelegate();
37168 * Destroys this panel
37170 destroy : function(){
37171 this.el.removeAllListeners();
37172 var tempEl = document.createElement("span");
37173 tempEl.appendChild(this.el.dom);
37174 tempEl.innerHTML = "";
37180 * form - if the content panel contains a form - this is a reference to it.
37181 * @type {Roo.form.Form}
37185 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37186 * This contains a reference to it.
37192 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37202 * @param {Object} cfg Xtype definition of item to add.
37206 getChildContainer: function () {
37207 return this.getEl();
37212 var ret = new Roo.factory(cfg);
37217 if (cfg.xtype.match(/^Form$/)) {
37220 //if (this.footer) {
37221 // el = this.footer.container.insertSibling(false, 'before');
37223 el = this.el.createChild();
37226 this.form = new Roo.form.Form(cfg);
37229 if ( this.form.allItems.length) {
37230 this.form.render(el.dom);
37234 // should only have one of theses..
37235 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37236 // views.. should not be just added - used named prop 'view''
37238 cfg.el = this.el.appendChild(document.createElement("div"));
37241 var ret = new Roo.factory(cfg);
37243 ret.render && ret.render(false, ''); // render blank..
37253 * @class Roo.bootstrap.panel.Grid
37254 * @extends Roo.bootstrap.panel.Content
37256 * Create a new GridPanel.
37257 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37258 * @param {Object} config A the config object
37264 Roo.bootstrap.panel.Grid = function(config)
37268 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37269 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37271 config.el = this.wrapper;
37272 //this.el = this.wrapper;
37274 if (config.container) {
37275 // ctor'ed from a Border/panel.grid
37278 this.wrapper.setStyle("overflow", "hidden");
37279 this.wrapper.addClass('roo-grid-container');
37284 if(config.toolbar){
37285 var tool_el = this.wrapper.createChild();
37286 this.toolbar = Roo.factory(config.toolbar);
37288 if (config.toolbar.items) {
37289 ti = config.toolbar.items ;
37290 delete config.toolbar.items ;
37294 this.toolbar.render(tool_el);
37295 for(var i =0;i < ti.length;i++) {
37296 // Roo.log(['add child', items[i]]);
37297 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37299 this.toolbar.items = nitems;
37301 delete config.toolbar;
37304 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37305 config.grid.scrollBody = true;;
37306 config.grid.monitorWindowResize = false; // turn off autosizing
37307 config.grid.autoHeight = false;
37308 config.grid.autoWidth = false;
37310 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37312 if (config.background) {
37313 // render grid on panel activation (if panel background)
37314 this.on('activate', function(gp) {
37315 if (!gp.grid.rendered) {
37316 gp.grid.render(this.wrapper);
37317 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37322 this.grid.render(this.wrapper);
37323 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37326 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37327 // ??? needed ??? config.el = this.wrapper;
37332 // xtype created footer. - not sure if will work as we normally have to render first..
37333 if (this.footer && !this.footer.el && this.footer.xtype) {
37335 var ctr = this.grid.getView().getFooterPanel(true);
37336 this.footer.dataSource = this.grid.dataSource;
37337 this.footer = Roo.factory(this.footer, Roo);
37338 this.footer.render(ctr);
37348 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37349 getId : function(){
37350 return this.grid.id;
37354 * Returns the grid for this panel
37355 * @return {Roo.bootstrap.Table}
37357 getGrid : function(){
37361 setSize : function(width, height){
37362 if(!this.ignoreResize(width, height)){
37363 var grid = this.grid;
37364 var size = this.adjustForComponents(width, height);
37365 var gridel = grid.getGridEl();
37366 gridel.setSize(size.width, size.height);
37368 var thd = grid.getGridEl().select('thead',true).first();
37369 var tbd = grid.getGridEl().select('tbody', true).first();
37371 tbd.setSize(width, height - thd.getHeight());
37380 beforeSlide : function(){
37381 this.grid.getView().scroller.clip();
37384 afterSlide : function(){
37385 this.grid.getView().scroller.unclip();
37388 destroy : function(){
37389 this.grid.destroy();
37391 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37396 * @class Roo.bootstrap.panel.Nest
37397 * @extends Roo.bootstrap.panel.Content
37399 * Create a new Panel, that can contain a layout.Border.
37402 * @param {Roo.BorderLayout} layout The layout for this panel
37403 * @param {String/Object} config A string to set only the title or a config object
37405 Roo.bootstrap.panel.Nest = function(config)
37407 // construct with only one argument..
37408 /* FIXME - implement nicer consturctors
37409 if (layout.layout) {
37411 layout = config.layout;
37412 delete config.layout;
37414 if (layout.xtype && !layout.getEl) {
37415 // then layout needs constructing..
37416 layout = Roo.factory(layout, Roo);
37420 config.el = config.layout.getEl();
37422 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37424 config.layout.monitorWindowResize = false; // turn off autosizing
37425 this.layout = config.layout;
37426 this.layout.getEl().addClass("roo-layout-nested-layout");
37433 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37435 setSize : function(width, height){
37436 if(!this.ignoreResize(width, height)){
37437 var size = this.adjustForComponents(width, height);
37438 var el = this.layout.getEl();
37439 if (size.height < 1) {
37440 el.setWidth(size.width);
37442 el.setSize(size.width, size.height);
37444 var touch = el.dom.offsetWidth;
37445 this.layout.layout();
37446 // ie requires a double layout on the first pass
37447 if(Roo.isIE && !this.initialized){
37448 this.initialized = true;
37449 this.layout.layout();
37454 // activate all subpanels if not currently active..
37456 setActiveState : function(active){
37457 this.active = active;
37458 this.setActiveClass(active);
37461 this.fireEvent("deactivate", this);
37465 this.fireEvent("activate", this);
37466 // not sure if this should happen before or after..
37467 if (!this.layout) {
37468 return; // should not happen..
37471 for (var r in this.layout.regions) {
37472 reg = this.layout.getRegion(r);
37473 if (reg.getActivePanel()) {
37474 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37475 reg.setActivePanel(reg.getActivePanel());
37478 if (!reg.panels.length) {
37481 reg.showPanel(reg.getPanel(0));
37490 * Returns the nested BorderLayout for this panel
37491 * @return {Roo.BorderLayout}
37493 getLayout : function(){
37494 return this.layout;
37498 * Adds a xtype elements to the layout of the nested panel
37502 xtype : 'ContentPanel',
37509 xtype : 'NestedLayoutPanel',
37515 items : [ ... list of content panels or nested layout panels.. ]
37519 * @param {Object} cfg Xtype definition of item to add.
37521 addxtype : function(cfg) {
37522 return this.layout.addxtype(cfg);
37527 * Ext JS Library 1.1.1
37528 * Copyright(c) 2006-2007, Ext JS, LLC.
37530 * Originally Released Under LGPL - original licence link has changed is not relivant.
37533 * <script type="text/javascript">
37536 * @class Roo.TabPanel
37537 * @extends Roo.util.Observable
37538 * A lightweight tab container.
37542 // basic tabs 1, built from existing content
37543 var tabs = new Roo.TabPanel("tabs1");
37544 tabs.addTab("script", "View Script");
37545 tabs.addTab("markup", "View Markup");
37546 tabs.activate("script");
37548 // more advanced tabs, built from javascript
37549 var jtabs = new Roo.TabPanel("jtabs");
37550 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37552 // set up the UpdateManager
37553 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37554 var updater = tab2.getUpdateManager();
37555 updater.setDefaultUrl("ajax1.htm");
37556 tab2.on('activate', updater.refresh, updater, true);
37558 // Use setUrl for Ajax loading
37559 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37560 tab3.setUrl("ajax2.htm", null, true);
37563 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37566 jtabs.activate("jtabs-1");
37569 * Create a new TabPanel.
37570 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37571 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37573 Roo.bootstrap.panel.Tabs = function(config){
37575 * The container element for this TabPanel.
37576 * @type Roo.Element
37578 this.el = Roo.get(config.el);
37581 if(typeof config == "boolean"){
37582 this.tabPosition = config ? "bottom" : "top";
37584 Roo.apply(this, config);
37588 if(this.tabPosition == "bottom"){
37589 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37590 this.el.addClass("roo-tabs-bottom");
37592 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37593 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37594 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37596 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37598 if(this.tabPosition != "bottom"){
37599 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37600 * @type Roo.Element
37602 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37603 this.el.addClass("roo-tabs-top");
37607 this.bodyEl.setStyle("position", "relative");
37609 this.active = null;
37610 this.activateDelegate = this.activate.createDelegate(this);
37615 * Fires when the active tab changes
37616 * @param {Roo.TabPanel} this
37617 * @param {Roo.TabPanelItem} activePanel The new active tab
37621 * @event beforetabchange
37622 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37623 * @param {Roo.TabPanel} this
37624 * @param {Object} e Set cancel to true on this object to cancel the tab change
37625 * @param {Roo.TabPanelItem} tab The tab being changed to
37627 "beforetabchange" : true
37630 Roo.EventManager.onWindowResize(this.onResize, this);
37631 this.cpad = this.el.getPadding("lr");
37632 this.hiddenCount = 0;
37635 // toolbar on the tabbar support...
37636 if (this.toolbar) {
37637 alert("no toolbar support yet");
37638 this.toolbar = false;
37640 var tcfg = this.toolbar;
37641 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37642 this.toolbar = new Roo.Toolbar(tcfg);
37643 if (Roo.isSafari) {
37644 var tbl = tcfg.container.child('table', true);
37645 tbl.setAttribute('width', '100%');
37653 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37656 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37658 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37660 tabPosition : "top",
37662 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37664 currentTabWidth : 0,
37666 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37670 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37674 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37676 preferredTabWidth : 175,
37678 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37680 resizeTabs : false,
37682 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37684 monitorResize : true,
37686 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37691 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37692 * @param {String} id The id of the div to use <b>or create</b>
37693 * @param {String} text The text for the tab
37694 * @param {String} content (optional) Content to put in the TabPanelItem body
37695 * @param {Boolean} closable (optional) True to create a close icon on the tab
37696 * @return {Roo.TabPanelItem} The created TabPanelItem
37698 addTab : function(id, text, content, closable, tpl)
37700 var item = new Roo.bootstrap.panel.TabItem({
37704 closable : closable,
37707 this.addTabItem(item);
37709 item.setContent(content);
37715 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37716 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37717 * @return {Roo.TabPanelItem}
37719 getTab : function(id){
37720 return this.items[id];
37724 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37725 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37727 hideTab : function(id){
37728 var t = this.items[id];
37731 this.hiddenCount++;
37732 this.autoSizeTabs();
37737 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37738 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37740 unhideTab : function(id){
37741 var t = this.items[id];
37743 t.setHidden(false);
37744 this.hiddenCount--;
37745 this.autoSizeTabs();
37750 * Adds an existing {@link Roo.TabPanelItem}.
37751 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37753 addTabItem : function(item){
37754 this.items[item.id] = item;
37755 this.items.push(item);
37756 // if(this.resizeTabs){
37757 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37758 // this.autoSizeTabs();
37760 // item.autoSize();
37765 * Removes a {@link Roo.TabPanelItem}.
37766 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37768 removeTab : function(id){
37769 var items = this.items;
37770 var tab = items[id];
37771 if(!tab) { return; }
37772 var index = items.indexOf(tab);
37773 if(this.active == tab && items.length > 1){
37774 var newTab = this.getNextAvailable(index);
37779 this.stripEl.dom.removeChild(tab.pnode.dom);
37780 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37781 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37783 items.splice(index, 1);
37784 delete this.items[tab.id];
37785 tab.fireEvent("close", tab);
37786 tab.purgeListeners();
37787 this.autoSizeTabs();
37790 getNextAvailable : function(start){
37791 var items = this.items;
37793 // look for a next tab that will slide over to
37794 // replace the one being removed
37795 while(index < items.length){
37796 var item = items[++index];
37797 if(item && !item.isHidden()){
37801 // if one isn't found select the previous tab (on the left)
37804 var item = items[--index];
37805 if(item && !item.isHidden()){
37813 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37814 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37816 disableTab : function(id){
37817 var tab = this.items[id];
37818 if(tab && this.active != tab){
37824 * Enables a {@link Roo.TabPanelItem} that is disabled.
37825 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37827 enableTab : function(id){
37828 var tab = this.items[id];
37833 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37834 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37835 * @return {Roo.TabPanelItem} The TabPanelItem.
37837 activate : function(id){
37838 var tab = this.items[id];
37842 if(tab == this.active || tab.disabled){
37846 this.fireEvent("beforetabchange", this, e, tab);
37847 if(e.cancel !== true && !tab.disabled){
37849 this.active.hide();
37851 this.active = this.items[id];
37852 this.active.show();
37853 this.fireEvent("tabchange", this, this.active);
37859 * Gets the active {@link Roo.TabPanelItem}.
37860 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37862 getActiveTab : function(){
37863 return this.active;
37867 * Updates the tab body element to fit the height of the container element
37868 * for overflow scrolling
37869 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37871 syncHeight : function(targetHeight){
37872 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37873 var bm = this.bodyEl.getMargins();
37874 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37875 this.bodyEl.setHeight(newHeight);
37879 onResize : function(){
37880 if(this.monitorResize){
37881 this.autoSizeTabs();
37886 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37888 beginUpdate : function(){
37889 this.updating = true;
37893 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37895 endUpdate : function(){
37896 this.updating = false;
37897 this.autoSizeTabs();
37901 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37903 autoSizeTabs : function(){
37904 var count = this.items.length;
37905 var vcount = count - this.hiddenCount;
37906 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37909 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37910 var availWidth = Math.floor(w / vcount);
37911 var b = this.stripBody;
37912 if(b.getWidth() > w){
37913 var tabs = this.items;
37914 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37915 if(availWidth < this.minTabWidth){
37916 /*if(!this.sleft){ // incomplete scrolling code
37917 this.createScrollButtons();
37920 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37923 if(this.currentTabWidth < this.preferredTabWidth){
37924 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37930 * Returns the number of tabs in this TabPanel.
37933 getCount : function(){
37934 return this.items.length;
37938 * Resizes all the tabs to the passed width
37939 * @param {Number} The new width
37941 setTabWidth : function(width){
37942 this.currentTabWidth = width;
37943 for(var i = 0, len = this.items.length; i < len; i++) {
37944 if(!this.items[i].isHidden()) {
37945 this.items[i].setWidth(width);
37951 * Destroys this TabPanel
37952 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37954 destroy : function(removeEl){
37955 Roo.EventManager.removeResizeListener(this.onResize, this);
37956 for(var i = 0, len = this.items.length; i < len; i++){
37957 this.items[i].purgeListeners();
37959 if(removeEl === true){
37960 this.el.update("");
37965 createStrip : function(container)
37967 var strip = document.createElement("nav");
37968 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37969 container.appendChild(strip);
37973 createStripList : function(strip)
37975 // div wrapper for retard IE
37976 // returns the "tr" element.
37977 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37978 //'<div class="x-tabs-strip-wrap">'+
37979 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37980 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37981 return strip.firstChild; //.firstChild.firstChild.firstChild;
37983 createBody : function(container)
37985 var body = document.createElement("div");
37986 Roo.id(body, "tab-body");
37987 //Roo.fly(body).addClass("x-tabs-body");
37988 Roo.fly(body).addClass("tab-content");
37989 container.appendChild(body);
37992 createItemBody :function(bodyEl, id){
37993 var body = Roo.getDom(id);
37995 body = document.createElement("div");
37998 //Roo.fly(body).addClass("x-tabs-item-body");
37999 Roo.fly(body).addClass("tab-pane");
38000 bodyEl.insertBefore(body, bodyEl.firstChild);
38004 createStripElements : function(stripEl, text, closable, tpl)
38006 var td = document.createElement("li"); // was td..
38009 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38012 stripEl.appendChild(td);
38014 td.className = "x-tabs-closable";
38015 if(!this.closeTpl){
38016 this.closeTpl = new Roo.Template(
38017 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38018 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38019 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38022 var el = this.closeTpl.overwrite(td, {"text": text});
38023 var close = el.getElementsByTagName("div")[0];
38024 var inner = el.getElementsByTagName("em")[0];
38025 return {"el": el, "close": close, "inner": inner};
38028 // not sure what this is..
38029 // if(!this.tabTpl){
38030 //this.tabTpl = new Roo.Template(
38031 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38032 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38034 // this.tabTpl = new Roo.Template(
38035 // '<a href="#">' +
38036 // '<span unselectable="on"' +
38037 // (this.disableTooltips ? '' : ' title="{text}"') +
38038 // ' >{text}</span></a>'
38044 var template = tpl || this.tabTpl || false;
38048 template = new Roo.Template(
38050 '<span unselectable="on"' +
38051 (this.disableTooltips ? '' : ' title="{text}"') +
38052 ' >{text}</span></a>'
38056 switch (typeof(template)) {
38060 template = new Roo.Template(template);
38066 var el = template.overwrite(td, {"text": text});
38068 var inner = el.getElementsByTagName("span")[0];
38070 return {"el": el, "inner": inner};
38078 * @class Roo.TabPanelItem
38079 * @extends Roo.util.Observable
38080 * Represents an individual item (tab plus body) in a TabPanel.
38081 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38082 * @param {String} id The id of this TabPanelItem
38083 * @param {String} text The text for the tab of this TabPanelItem
38084 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38086 Roo.bootstrap.panel.TabItem = function(config){
38088 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38089 * @type Roo.TabPanel
38091 this.tabPanel = config.panel;
38093 * The id for this TabPanelItem
38096 this.id = config.id;
38098 this.disabled = false;
38100 this.text = config.text;
38102 this.loaded = false;
38103 this.closable = config.closable;
38106 * The body element for this TabPanelItem.
38107 * @type Roo.Element
38109 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38110 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38111 this.bodyEl.setStyle("display", "block");
38112 this.bodyEl.setStyle("zoom", "1");
38113 //this.hideAction();
38115 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38117 this.el = Roo.get(els.el);
38118 this.inner = Roo.get(els.inner, true);
38119 this.textEl = Roo.get(this.el.dom.firstChild, true);
38120 this.pnode = Roo.get(els.el.parentNode, true);
38121 // this.el.on("mousedown", this.onTabMouseDown, this);
38122 this.el.on("click", this.onTabClick, this);
38124 if(config.closable){
38125 var c = Roo.get(els.close, true);
38126 c.dom.title = this.closeText;
38127 c.addClassOnOver("close-over");
38128 c.on("click", this.closeClick, this);
38134 * Fires when this tab becomes the active tab.
38135 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38136 * @param {Roo.TabPanelItem} this
38140 * @event beforeclose
38141 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38142 * @param {Roo.TabPanelItem} this
38143 * @param {Object} e Set cancel to true on this object to cancel the close.
38145 "beforeclose": true,
38148 * Fires when this tab is closed.
38149 * @param {Roo.TabPanelItem} this
38153 * @event deactivate
38154 * Fires when this tab is no longer the active tab.
38155 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38156 * @param {Roo.TabPanelItem} this
38158 "deactivate" : true
38160 this.hidden = false;
38162 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38165 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38167 purgeListeners : function(){
38168 Roo.util.Observable.prototype.purgeListeners.call(this);
38169 this.el.removeAllListeners();
38172 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38175 this.pnode.addClass("active");
38178 this.tabPanel.stripWrap.repaint();
38180 this.fireEvent("activate", this.tabPanel, this);
38184 * Returns true if this tab is the active tab.
38185 * @return {Boolean}
38187 isActive : function(){
38188 return this.tabPanel.getActiveTab() == this;
38192 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38195 this.pnode.removeClass("active");
38197 this.fireEvent("deactivate", this.tabPanel, this);
38200 hideAction : function(){
38201 this.bodyEl.hide();
38202 this.bodyEl.setStyle("position", "absolute");
38203 this.bodyEl.setLeft("-20000px");
38204 this.bodyEl.setTop("-20000px");
38207 showAction : function(){
38208 this.bodyEl.setStyle("position", "relative");
38209 this.bodyEl.setTop("");
38210 this.bodyEl.setLeft("");
38211 this.bodyEl.show();
38215 * Set the tooltip for the tab.
38216 * @param {String} tooltip The tab's tooltip
38218 setTooltip : function(text){
38219 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38220 this.textEl.dom.qtip = text;
38221 this.textEl.dom.removeAttribute('title');
38223 this.textEl.dom.title = text;
38227 onTabClick : function(e){
38228 e.preventDefault();
38229 this.tabPanel.activate(this.id);
38232 onTabMouseDown : function(e){
38233 e.preventDefault();
38234 this.tabPanel.activate(this.id);
38237 getWidth : function(){
38238 return this.inner.getWidth();
38241 setWidth : function(width){
38242 var iwidth = width - this.pnode.getPadding("lr");
38243 this.inner.setWidth(iwidth);
38244 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38245 this.pnode.setWidth(width);
38249 * Show or hide the tab
38250 * @param {Boolean} hidden True to hide or false to show.
38252 setHidden : function(hidden){
38253 this.hidden = hidden;
38254 this.pnode.setStyle("display", hidden ? "none" : "");
38258 * Returns true if this tab is "hidden"
38259 * @return {Boolean}
38261 isHidden : function(){
38262 return this.hidden;
38266 * Returns the text for this tab
38269 getText : function(){
38273 autoSize : function(){
38274 //this.el.beginMeasure();
38275 this.textEl.setWidth(1);
38277 * #2804 [new] Tabs in Roojs
38278 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38280 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38281 //this.el.endMeasure();
38285 * Sets the text for the tab (Note: this also sets the tooltip text)
38286 * @param {String} text The tab's text and tooltip
38288 setText : function(text){
38290 this.textEl.update(text);
38291 this.setTooltip(text);
38292 //if(!this.tabPanel.resizeTabs){
38293 // this.autoSize();
38297 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38299 activate : function(){
38300 this.tabPanel.activate(this.id);
38304 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38306 disable : function(){
38307 if(this.tabPanel.active != this){
38308 this.disabled = true;
38309 this.pnode.addClass("disabled");
38314 * Enables this TabPanelItem if it was previously disabled.
38316 enable : function(){
38317 this.disabled = false;
38318 this.pnode.removeClass("disabled");
38322 * Sets the content for this TabPanelItem.
38323 * @param {String} content The content
38324 * @param {Boolean} loadScripts true to look for and load scripts
38326 setContent : function(content, loadScripts){
38327 this.bodyEl.update(content, loadScripts);
38331 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38332 * @return {Roo.UpdateManager} The UpdateManager
38334 getUpdateManager : function(){
38335 return this.bodyEl.getUpdateManager();
38339 * Set a URL to be used to load the content for this TabPanelItem.
38340 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38341 * @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)
38342 * @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)
38343 * @return {Roo.UpdateManager} The UpdateManager
38345 setUrl : function(url, params, loadOnce){
38346 if(this.refreshDelegate){
38347 this.un('activate', this.refreshDelegate);
38349 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38350 this.on("activate", this.refreshDelegate);
38351 return this.bodyEl.getUpdateManager();
38355 _handleRefresh : function(url, params, loadOnce){
38356 if(!loadOnce || !this.loaded){
38357 var updater = this.bodyEl.getUpdateManager();
38358 updater.update(url, params, this._setLoaded.createDelegate(this));
38363 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38364 * Will fail silently if the setUrl method has not been called.
38365 * This does not activate the panel, just updates its content.
38367 refresh : function(){
38368 if(this.refreshDelegate){
38369 this.loaded = false;
38370 this.refreshDelegate();
38375 _setLoaded : function(){
38376 this.loaded = true;
38380 closeClick : function(e){
38383 this.fireEvent("beforeclose", this, o);
38384 if(o.cancel !== true){
38385 this.tabPanel.removeTab(this.id);
38389 * The text displayed in the tooltip for the close icon.
38392 closeText : "Close this tab"
38395 * This script refer to:
38396 * Title: International Telephone Input
38397 * Author: Jack O'Connor
38398 * Code version: v12.1.12
38399 * Availability: https://github.com/jackocnr/intl-tel-input.git
38402 Roo.bootstrap.PhoneInputData = function() {
38405 "Afghanistan (افغانستان)",
38410 "Albania (Shqipëri)",
38415 "Algeria (الجزائر)",
38440 "Antigua and Barbuda",
38450 "Armenia (Հայաստան)",
38466 "Austria (Österreich)",
38471 "Azerbaijan (Azərbaycan)",
38481 "Bahrain (البحرين)",
38486 "Bangladesh (বাংলাদেশ)",
38496 "Belarus (Беларусь)",
38501 "Belgium (België)",
38531 "Bosnia and Herzegovina (Босна и Херцеговина)",
38546 "British Indian Ocean Territory",
38551 "British Virgin Islands",
38561 "Bulgaria (България)",
38571 "Burundi (Uburundi)",
38576 "Cambodia (កម្ពុជា)",
38581 "Cameroon (Cameroun)",
38590 ["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"]
38593 "Cape Verde (Kabu Verdi)",
38598 "Caribbean Netherlands",
38609 "Central African Republic (République centrafricaine)",
38629 "Christmas Island",
38635 "Cocos (Keeling) Islands",
38646 "Comoros (جزر القمر)",
38651 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38656 "Congo (Republic) (Congo-Brazzaville)",
38676 "Croatia (Hrvatska)",
38697 "Czech Republic (Česká republika)",
38702 "Denmark (Danmark)",
38717 "Dominican Republic (República Dominicana)",
38721 ["809", "829", "849"]
38739 "Equatorial Guinea (Guinea Ecuatorial)",
38759 "Falkland Islands (Islas Malvinas)",
38764 "Faroe Islands (Føroyar)",
38785 "French Guiana (Guyane française)",
38790 "French Polynesia (Polynésie française)",
38805 "Georgia (საქართველო)",
38810 "Germany (Deutschland)",
38830 "Greenland (Kalaallit Nunaat)",
38867 "Guinea-Bissau (Guiné Bissau)",
38892 "Hungary (Magyarország)",
38897 "Iceland (Ísland)",
38917 "Iraq (العراق)",
38933 "Israel (ישראל)",
38960 "Jordan (الأردن)",
38965 "Kazakhstan (Казахстан)",
38986 "Kuwait (الكويت)",
38991 "Kyrgyzstan (Кыргызстан)",
39001 "Latvia (Latvija)",
39006 "Lebanon (لبنان)",
39021 "Libya (ليبيا)",
39031 "Lithuania (Lietuva)",
39046 "Macedonia (FYROM) (Македонија)",
39051 "Madagascar (Madagasikara)",
39081 "Marshall Islands",
39091 "Mauritania (موريتانيا)",
39096 "Mauritius (Moris)",
39117 "Moldova (Republica Moldova)",
39127 "Mongolia (Монгол)",
39132 "Montenegro (Crna Gora)",
39142 "Morocco (المغرب)",
39148 "Mozambique (Moçambique)",
39153 "Myanmar (Burma) (မြန်မာ)",
39158 "Namibia (Namibië)",
39173 "Netherlands (Nederland)",
39178 "New Caledonia (Nouvelle-Calédonie)",
39213 "North Korea (조선 민주주의 인민 공화국)",
39218 "Northern Mariana Islands",
39234 "Pakistan (پاکستان)",
39244 "Palestine (فلسطين)",
39254 "Papua New Guinea",
39296 "Réunion (La Réunion)",
39302 "Romania (România)",
39318 "Saint Barthélemy",
39329 "Saint Kitts and Nevis",
39339 "Saint Martin (Saint-Martin (partie française))",
39345 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39350 "Saint Vincent and the Grenadines",
39365 "São Tomé and Príncipe (São Tomé e Príncipe)",
39370 "Saudi Arabia (المملكة العربية السعودية)",
39375 "Senegal (Sénégal)",
39405 "Slovakia (Slovensko)",
39410 "Slovenia (Slovenija)",
39420 "Somalia (Soomaaliya)",
39430 "South Korea (대한민국)",
39435 "South Sudan (جنوب السودان)",
39445 "Sri Lanka (ශ්රී ලංකාව)",
39450 "Sudan (السودان)",
39460 "Svalbard and Jan Mayen",
39471 "Sweden (Sverige)",
39476 "Switzerland (Schweiz)",
39481 "Syria (سوريا)",
39526 "Trinidad and Tobago",
39531 "Tunisia (تونس)",
39536 "Turkey (Türkiye)",
39546 "Turks and Caicos Islands",
39556 "U.S. Virgin Islands",
39566 "Ukraine (Україна)",
39571 "United Arab Emirates (الإمارات العربية المتحدة)",
39593 "Uzbekistan (Oʻzbekiston)",
39603 "Vatican City (Città del Vaticano)",
39614 "Vietnam (Việt Nam)",
39619 "Wallis and Futuna (Wallis-et-Futuna)",
39624 "Western Sahara (الصحراء الغربية)",
39630 "Yemen (اليمن)",
39654 * This script refer to:
39655 * Title: International Telephone Input
39656 * Author: Jack O'Connor
39657 * Code version: v12.1.12
39658 * Availability: https://github.com/jackocnr/intl-tel-input.git
39662 * @class Roo.bootstrap.PhoneInput
39663 * @extends Roo.bootstrap.TriggerField
39664 * An input with International dial-code selection
39666 * @cfg {String} defaultDialCode default '+852'
39667 * @cfg {Array} preferedCountries default []
39670 * Create a new PhoneInput.
39671 * @param {Object} config Configuration options
39674 Roo.bootstrap.PhoneInput = function(config) {
39675 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39678 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39680 listWidth: undefined,
39682 selectedClass: 'active',
39684 invalidClass : "has-warning",
39686 validClass: 'has-success',
39688 allowed: '0123456789',
39691 * @cfg {String} defaultDialCode The default dial code when initializing the input
39693 defaultDialCode: '+852',
39696 * @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
39698 preferedCountries: false,
39700 getAutoCreate : function()
39702 var data = Roo.bootstrap.PhoneInputData();
39703 var align = this.labelAlign || this.parentLabelAlign();
39706 this.allCountries = [];
39707 this.dialCodeMapping = [];
39709 for (var i = 0; i < data.length; i++) {
39711 this.allCountries[i] = {
39715 priority: c[3] || 0,
39716 areaCodes: c[4] || null
39718 this.dialCodeMapping[c[2]] = {
39721 priority: c[3] || 0,
39722 areaCodes: c[4] || null
39734 cls : 'form-control tel-input',
39735 autocomplete: 'new-password'
39738 var hiddenInput = {
39741 cls: 'hidden-tel-input'
39745 hiddenInput.name = this.name;
39748 if (this.disabled) {
39749 input.disabled = true;
39752 var flag_container = {
39769 cls: this.hasFeedback ? 'has-feedback' : '',
39775 cls: 'dial-code-holder',
39782 cls: 'roo-select2-container input-group',
39789 if (this.fieldLabel.length) {
39792 tooltip: 'This field is required'
39798 cls: 'control-label',
39804 html: this.fieldLabel
39807 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39813 if(this.indicatorpos == 'right') {
39814 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39821 if(align == 'left') {
39829 if(this.labelWidth > 12){
39830 label.style = "width: " + this.labelWidth + 'px';
39832 if(this.labelWidth < 13 && this.labelmd == 0){
39833 this.labelmd = this.labelWidth;
39835 if(this.labellg > 0){
39836 label.cls += ' col-lg-' + this.labellg;
39837 input.cls += ' col-lg-' + (12 - this.labellg);
39839 if(this.labelmd > 0){
39840 label.cls += ' col-md-' + this.labelmd;
39841 container.cls += ' col-md-' + (12 - this.labelmd);
39843 if(this.labelsm > 0){
39844 label.cls += ' col-sm-' + this.labelsm;
39845 container.cls += ' col-sm-' + (12 - this.labelsm);
39847 if(this.labelxs > 0){
39848 label.cls += ' col-xs-' + this.labelxs;
39849 container.cls += ' col-xs-' + (12 - this.labelxs);
39859 var settings = this;
39861 ['xs','sm','md','lg'].map(function(size){
39862 if (settings[size]) {
39863 cfg.cls += ' col-' + size + '-' + settings[size];
39867 this.store = new Roo.data.Store({
39868 proxy : new Roo.data.MemoryProxy({}),
39869 reader : new Roo.data.JsonReader({
39880 'name' : 'dialCode',
39884 'name' : 'priority',
39888 'name' : 'areaCodes',
39895 if(!this.preferedCountries) {
39896 this.preferedCountries = [
39903 var p = this.preferedCountries.reverse();
39906 for (var i = 0; i < p.length; i++) {
39907 for (var j = 0; j < this.allCountries.length; j++) {
39908 if(this.allCountries[j].iso2 == p[i]) {
39909 var t = this.allCountries[j];
39910 this.allCountries.splice(j,1);
39911 this.allCountries.unshift(t);
39917 this.store.proxy.data = {
39919 data: this.allCountries
39925 initEvents : function()
39928 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39930 this.indicator = this.indicatorEl();
39931 this.flag = this.flagEl();
39932 this.dialCodeHolder = this.dialCodeHolderEl();
39934 this.trigger = this.el.select('div.flag-box',true).first();
39935 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39940 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39941 _this.list.setWidth(lw);
39944 this.list.on('mouseover', this.onViewOver, this);
39945 this.list.on('mousemove', this.onViewMove, this);
39946 this.inputEl().on("keyup", this.onKeyUp, this);
39948 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39950 this.view = new Roo.View(this.list, this.tpl, {
39951 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39954 this.view.on('click', this.onViewClick, this);
39955 this.setValue(this.defaultDialCode);
39958 onTriggerClick : function(e)
39960 Roo.log('trigger click');
39965 if(this.isExpanded()){
39967 this.hasFocus = false;
39969 this.store.load({});
39970 this.hasFocus = true;
39975 isExpanded : function()
39977 return this.list.isVisible();
39980 collapse : function()
39982 if(!this.isExpanded()){
39986 Roo.get(document).un('mousedown', this.collapseIf, this);
39987 Roo.get(document).un('mousewheel', this.collapseIf, this);
39988 this.fireEvent('collapse', this);
39992 expand : function()
39996 if(this.isExpanded() || !this.hasFocus){
40000 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40001 this.list.setWidth(lw);
40004 this.restrictHeight();
40006 Roo.get(document).on('mousedown', this.collapseIf, this);
40007 Roo.get(document).on('mousewheel', this.collapseIf, this);
40009 this.fireEvent('expand', this);
40012 restrictHeight : function()
40014 this.list.alignTo(this.inputEl(), this.listAlign);
40015 this.list.alignTo(this.inputEl(), this.listAlign);
40018 onViewOver : function(e, t)
40020 if(this.inKeyMode){
40023 var item = this.view.findItemFromChild(t);
40026 var index = this.view.indexOf(item);
40027 this.select(index, false);
40032 onViewClick : function(view, doFocus, el, e)
40034 var index = this.view.getSelectedIndexes()[0];
40036 var r = this.store.getAt(index);
40039 this.onSelect(r, index);
40041 if(doFocus !== false && !this.blockFocus){
40042 this.inputEl().focus();
40046 onViewMove : function(e, t)
40048 this.inKeyMode = false;
40051 select : function(index, scrollIntoView)
40053 this.selectedIndex = index;
40054 this.view.select(index);
40055 if(scrollIntoView !== false){
40056 var el = this.view.getNode(index);
40058 this.list.scrollChildIntoView(el, false);
40063 createList : function()
40065 this.list = Roo.get(document.body).createChild({
40067 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40068 style: 'display:none'
40071 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40074 collapseIf : function(e)
40076 var in_combo = e.within(this.el);
40077 var in_list = e.within(this.list);
40078 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40080 if (in_combo || in_list || is_list) {
40086 onSelect : function(record, index)
40088 if(this.fireEvent('beforeselect', this, record, index) !== false){
40090 this.setFlagClass(record.data.iso2);
40091 this.setDialCode(record.data.dialCode);
40092 this.hasFocus = false;
40094 this.fireEvent('select', this, record, index);
40098 flagEl : function()
40100 var flag = this.el.select('div.flag',true).first();
40107 dialCodeHolderEl : function()
40109 var d = this.el.select('input.dial-code-holder',true).first();
40116 setDialCode : function(v)
40118 this.dialCodeHolder.dom.value = '+'+v;
40121 setFlagClass : function(n)
40123 this.flag.dom.className = 'flag '+n;
40126 getValue : function()
40128 var v = this.inputEl().getValue();
40129 if(this.dialCodeHolder) {
40130 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40135 setValue : function(v)
40137 var d = this.getDialCode(v);
40139 //invalid dial code
40140 if(v.length == 0 || !d || d.length == 0) {
40142 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40143 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40149 this.setFlagClass(this.dialCodeMapping[d].iso2);
40150 this.setDialCode(d);
40151 this.inputEl().dom.value = v.replace('+'+d,'');
40152 this.hiddenEl().dom.value = this.getValue();
40157 getDialCode : function(v)
40161 if (v.length == 0) {
40162 return this.dialCodeHolder.dom.value;
40166 if (v.charAt(0) != "+") {
40169 var numericChars = "";
40170 for (var i = 1; i < v.length; i++) {
40171 var c = v.charAt(i);
40174 if (this.dialCodeMapping[numericChars]) {
40175 dialCode = v.substr(1, i);
40177 if (numericChars.length == 4) {
40187 this.setValue(this.defaultDialCode);
40191 hiddenEl : function()
40193 return this.el.select('input.hidden-tel-input',true).first();
40196 onKeyUp : function(e){
40198 var k = e.getKey();
40199 var c = e.getCharCode();
40202 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40203 this.allowed.indexOf(String.fromCharCode(c)) === -1
40208 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40211 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40215 this.setValue(this.getValue());
40220 * @class Roo.bootstrap.MoneyField
40221 * @extends Roo.bootstrap.ComboBox
40222 * Bootstrap MoneyField class
40225 * Create a new MoneyField.
40226 * @param {Object} config Configuration options
40229 Roo.bootstrap.MoneyField = function(config) {
40231 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40235 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40238 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40240 allowDecimals : true,
40242 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40244 decimalSeparator : ".",
40246 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40248 decimalPrecision : 0,
40250 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40252 allowNegative : true,
40254 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40258 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40260 minValue : Number.NEGATIVE_INFINITY,
40262 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40264 maxValue : Number.MAX_VALUE,
40266 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40268 minText : "The minimum value for this field is {0}",
40270 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40272 maxText : "The maximum value for this field is {0}",
40274 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40275 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40277 nanText : "{0} is not a valid number",
40279 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40283 * @cfg {String} defaults currency of the MoneyField
40284 * value should be in lkey
40286 defaultCurrency : false,
40288 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40290 thousandsDelimiter : false,
40300 getAutoCreate : function()
40302 var align = this.labelAlign || this.parentLabelAlign();
40314 cls : 'form-control roo-money-amount-input',
40315 autocomplete: 'new-password'
40318 var hiddenInput = {
40322 cls: 'hidden-number-input'
40326 hiddenInput.name = this.name;
40329 if (this.disabled) {
40330 input.disabled = true;
40333 var clg = 12 - this.inputlg;
40334 var cmd = 12 - this.inputmd;
40335 var csm = 12 - this.inputsm;
40336 var cxs = 12 - this.inputxs;
40340 cls : 'row roo-money-field',
40344 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40348 cls: 'roo-select2-container input-group',
40352 cls : 'form-control roo-money-currency-input',
40353 autocomplete: 'new-password',
40355 name : this.currencyName
40359 cls : 'input-group-addon',
40373 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40377 cls: this.hasFeedback ? 'has-feedback' : '',
40388 if (this.fieldLabel.length) {
40391 tooltip: 'This field is required'
40397 cls: 'control-label',
40403 html: this.fieldLabel
40406 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40412 if(this.indicatorpos == 'right') {
40413 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40420 if(align == 'left') {
40428 if(this.labelWidth > 12){
40429 label.style = "width: " + this.labelWidth + 'px';
40431 if(this.labelWidth < 13 && this.labelmd == 0){
40432 this.labelmd = this.labelWidth;
40434 if(this.labellg > 0){
40435 label.cls += ' col-lg-' + this.labellg;
40436 input.cls += ' col-lg-' + (12 - this.labellg);
40438 if(this.labelmd > 0){
40439 label.cls += ' col-md-' + this.labelmd;
40440 container.cls += ' col-md-' + (12 - this.labelmd);
40442 if(this.labelsm > 0){
40443 label.cls += ' col-sm-' + this.labelsm;
40444 container.cls += ' col-sm-' + (12 - this.labelsm);
40446 if(this.labelxs > 0){
40447 label.cls += ' col-xs-' + this.labelxs;
40448 container.cls += ' col-xs-' + (12 - this.labelxs);
40459 var settings = this;
40461 ['xs','sm','md','lg'].map(function(size){
40462 if (settings[size]) {
40463 cfg.cls += ' col-' + size + '-' + settings[size];
40470 initEvents : function()
40472 this.indicator = this.indicatorEl();
40474 this.initCurrencyEvent();
40476 this.initNumberEvent();
40479 initCurrencyEvent : function()
40482 throw "can not find store for combo";
40485 this.store = Roo.factory(this.store, Roo.data);
40486 this.store.parent = this;
40490 this.triggerEl = this.el.select('.input-group-addon', true).first();
40492 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40497 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40498 _this.list.setWidth(lw);
40501 this.list.on('mouseover', this.onViewOver, this);
40502 this.list.on('mousemove', this.onViewMove, this);
40503 this.list.on('scroll', this.onViewScroll, this);
40506 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40509 this.view = new Roo.View(this.list, this.tpl, {
40510 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40513 this.view.on('click', this.onViewClick, this);
40515 this.store.on('beforeload', this.onBeforeLoad, this);
40516 this.store.on('load', this.onLoad, this);
40517 this.store.on('loadexception', this.onLoadException, this);
40519 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40520 "up" : function(e){
40521 this.inKeyMode = true;
40525 "down" : function(e){
40526 if(!this.isExpanded()){
40527 this.onTriggerClick();
40529 this.inKeyMode = true;
40534 "enter" : function(e){
40537 if(this.fireEvent("specialkey", this, e)){
40538 this.onViewClick(false);
40544 "esc" : function(e){
40548 "tab" : function(e){
40551 if(this.fireEvent("specialkey", this, e)){
40552 this.onViewClick(false);
40560 doRelay : function(foo, bar, hname){
40561 if(hname == 'down' || this.scope.isExpanded()){
40562 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40570 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40574 initNumberEvent : function(e)
40576 this.inputEl().on("keydown" , this.fireKey, this);
40577 this.inputEl().on("focus", this.onFocus, this);
40578 this.inputEl().on("blur", this.onBlur, this);
40580 this.inputEl().relayEvent('keyup', this);
40582 if(this.indicator){
40583 this.indicator.addClass('invisible');
40586 this.originalValue = this.getValue();
40588 if(this.validationEvent == 'keyup'){
40589 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40590 this.inputEl().on('keyup', this.filterValidation, this);
40592 else if(this.validationEvent !== false){
40593 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40596 if(this.selectOnFocus){
40597 this.on("focus", this.preFocus, this);
40600 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40601 this.inputEl().on("keypress", this.filterKeys, this);
40603 this.inputEl().relayEvent('keypress', this);
40606 var allowed = "0123456789";
40608 if(this.allowDecimals){
40609 allowed += this.decimalSeparator;
40612 if(this.allowNegative){
40616 if(this.thousandsDelimiter) {
40620 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40622 var keyPress = function(e){
40624 var k = e.getKey();
40626 var c = e.getCharCode();
40629 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40630 allowed.indexOf(String.fromCharCode(c)) === -1
40636 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40640 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40645 this.inputEl().on("keypress", keyPress, this);
40649 onTriggerClick : function(e)
40656 this.loadNext = false;
40658 if(this.isExpanded()){
40663 this.hasFocus = true;
40665 if(this.triggerAction == 'all') {
40666 this.doQuery(this.allQuery, true);
40670 this.doQuery(this.getRawValue());
40673 getCurrency : function()
40675 var v = this.currencyEl().getValue();
40680 restrictHeight : function()
40682 this.list.alignTo(this.currencyEl(), this.listAlign);
40683 this.list.alignTo(this.currencyEl(), this.listAlign);
40686 onViewClick : function(view, doFocus, el, e)
40688 var index = this.view.getSelectedIndexes()[0];
40690 var r = this.store.getAt(index);
40693 this.onSelect(r, index);
40697 onSelect : function(record, index){
40699 if(this.fireEvent('beforeselect', this, record, index) !== false){
40701 this.setFromCurrencyData(index > -1 ? record.data : false);
40705 this.fireEvent('select', this, record, index);
40709 setFromCurrencyData : function(o)
40713 this.lastCurrency = o;
40715 if (this.currencyField) {
40716 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40718 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40721 this.lastSelectionText = currency;
40723 //setting default currency
40724 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40725 this.setCurrency(this.defaultCurrency);
40729 this.setCurrency(currency);
40732 setFromData : function(o)
40736 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40738 this.setFromCurrencyData(c);
40743 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40745 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40748 this.setValue(value);
40752 setCurrency : function(v)
40754 this.currencyValue = v;
40757 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40762 setValue : function(v)
40764 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40770 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40772 this.inputEl().dom.value = (v == '') ? '' :
40773 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40775 if(!this.allowZero && v === '0') {
40776 this.hiddenEl().dom.value = '';
40777 this.inputEl().dom.value = '';
40784 getRawValue : function()
40786 var v = this.inputEl().getValue();
40791 getValue : function()
40793 return this.fixPrecision(this.parseValue(this.getRawValue()));
40796 parseValue : function(value)
40798 if(this.thousandsDelimiter) {
40800 r = new RegExp(",", "g");
40801 value = value.replace(r, "");
40804 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40805 return isNaN(value) ? '' : value;
40809 fixPrecision : function(value)
40811 if(this.thousandsDelimiter) {
40813 r = new RegExp(",", "g");
40814 value = value.replace(r, "");
40817 var nan = isNaN(value);
40819 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40820 return nan ? '' : value;
40822 return parseFloat(value).toFixed(this.decimalPrecision);
40825 decimalPrecisionFcn : function(v)
40827 return Math.floor(v);
40830 validateValue : function(value)
40832 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40836 var num = this.parseValue(value);
40839 this.markInvalid(String.format(this.nanText, value));
40843 if(num < this.minValue){
40844 this.markInvalid(String.format(this.minText, this.minValue));
40848 if(num > this.maxValue){
40849 this.markInvalid(String.format(this.maxText, this.maxValue));
40856 validate : function()
40858 if(this.disabled || this.allowBlank){
40863 var currency = this.getCurrency();
40865 if(this.validateValue(this.getRawValue()) && currency.length){
40870 this.markInvalid();
40874 getName: function()
40879 beforeBlur : function()
40885 var v = this.parseValue(this.getRawValue());
40892 onBlur : function()
40896 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40897 //this.el.removeClass(this.focusClass);
40900 this.hasFocus = false;
40902 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40906 var v = this.getValue();
40908 if(String(v) !== String(this.startValue)){
40909 this.fireEvent('change', this, v, this.startValue);
40912 this.fireEvent("blur", this);
40915 inputEl : function()
40917 return this.el.select('.roo-money-amount-input', true).first();
40920 currencyEl : function()
40922 return this.el.select('.roo-money-currency-input', true).first();
40925 hiddenEl : function()
40927 return this.el.select('input.hidden-number-input',true).first();