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);
2227 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2230 * Displays this menu at a specific xy position
2231 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2232 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2234 showAt : function(xy, parentMenu, /* private: */_e){
2235 this.parentMenu = parentMenu;
2240 this.fireEvent("beforeshow", this);
2241 // xy = this.el.adjustForConstraints(xy);
2244 xy = this.el.adjustForConstraints(xy);
2247 this.hideMenuItems();
2248 this.hidden = false;
2249 this.triggerEl.addClass('open');
2251 // xy = this.el.getAlignToXY(this.triggerEl, '?');
2253 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2254 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2257 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2262 this.fireEvent("show", this);
2268 this.doFocus.defer(50, this);
2272 doFocus : function(){
2274 this.focusEl.focus();
2279 * Hides this menu and optionally all parent menus
2280 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2282 hide : function(deep)
2285 this.hideMenuItems();
2286 if(this.el && this.isVisible()){
2287 this.fireEvent("beforehide", this);
2288 if(this.activeItem){
2289 this.activeItem.deactivate();
2290 this.activeItem = null;
2292 this.triggerEl.removeClass('open');;
2294 this.fireEvent("hide", this);
2296 if(deep === true && this.parentMenu){
2297 this.parentMenu.hide(true);
2301 onTriggerClick : function(e)
2303 Roo.log('trigger click');
2305 var target = e.getTarget();
2307 Roo.log(target.nodeName.toLowerCase());
2309 if(target.nodeName.toLowerCase() === 'i'){
2315 onTriggerPress : function(e)
2317 Roo.log('trigger press');
2318 //Roo.log(e.getTarget());
2319 // Roo.log(this.triggerEl.dom);
2321 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2322 var pel = Roo.get(e.getTarget());
2323 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2324 Roo.log('is treeview or dropdown?');
2328 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2332 if (this.isVisible()) {
2337 this.show(this.triggerEl, false, false);
2340 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2347 hideMenuItems : function()
2349 Roo.log("hide Menu Items");
2353 //$(backdrop).remove()
2354 this.el.select('.open',true).each(function(aa) {
2356 aa.removeClass('open');
2357 //var parent = getParent($(this))
2358 //var relatedTarget = { relatedTarget: this }
2360 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2361 //if (e.isDefaultPrevented()) return
2362 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2365 addxtypeChild : function (tree, cntr) {
2366 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2368 this.menuitems.add(comp);
2380 this.getEl().dom.innerHTML = '';
2381 this.menuitems.clear();
2395 * @class Roo.bootstrap.MenuItem
2396 * @extends Roo.bootstrap.Component
2397 * Bootstrap MenuItem class
2398 * @cfg {String} html the menu label
2399 * @cfg {String} href the link
2400 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2401 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2402 * @cfg {Boolean} active used on sidebars to highlight active itesm
2403 * @cfg {String} fa favicon to show on left of menu item.
2404 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2408 * Create a new MenuItem
2409 * @param {Object} config The config object
2413 Roo.bootstrap.MenuItem = function(config){
2414 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2419 * The raw click event for the entire grid.
2420 * @param {Roo.bootstrap.MenuItem} this
2421 * @param {Roo.EventObject} e
2427 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2431 preventDefault: false,
2432 isContainer : false,
2436 getAutoCreate : function(){
2438 if(this.isContainer){
2441 cls: 'dropdown-menu-item'
2455 if (this.fa !== false) {
2458 cls : 'fa fa-' + this.fa
2467 cls: 'dropdown-menu-item',
2470 if (this.parent().type == 'treeview') {
2471 cfg.cls = 'treeview-menu';
2474 cfg.cls += ' active';
2479 anc.href = this.href || cfg.cn[0].href ;
2480 ctag.html = this.html || cfg.cn[0].html ;
2484 initEvents: function()
2486 if (this.parent().type == 'treeview') {
2487 this.el.select('a').on('click', this.onClick, this);
2491 this.menu.parentType = this.xtype;
2492 this.menu.triggerEl = this.el;
2493 this.menu = this.addxtype(Roo.apply({}, this.menu));
2497 onClick : function(e)
2499 Roo.log('item on click ');
2501 if(this.preventDefault){
2504 //this.parent().hideMenuItems();
2506 this.fireEvent('click', this, e);
2525 * @class Roo.bootstrap.MenuSeparator
2526 * @extends Roo.bootstrap.Component
2527 * Bootstrap MenuSeparator class
2530 * Create a new MenuItem
2531 * @param {Object} config The config object
2535 Roo.bootstrap.MenuSeparator = function(config){
2536 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2539 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2541 getAutoCreate : function(){
2560 * @class Roo.bootstrap.Modal
2561 * @extends Roo.bootstrap.Component
2562 * Bootstrap Modal class
2563 * @cfg {String} title Title of dialog
2564 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2565 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2566 * @cfg {Boolean} specificTitle default false
2567 * @cfg {Array} buttons Array of buttons or standard button set..
2568 * @cfg {String} buttonPosition (left|right|center) default right
2569 * @cfg {Boolean} animate default true
2570 * @cfg {Boolean} allow_close default true
2571 * @cfg {Boolean} fitwindow default false
2572 * @cfg {String} size (sm|lg) default empty
2576 * Create a new Modal Dialog
2577 * @param {Object} config The config object
2580 Roo.bootstrap.Modal = function(config){
2581 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2586 * The raw btnclick event for the button
2587 * @param {Roo.EventObject} e
2592 * Fire when dialog resize
2593 * @param {Roo.bootstrap.Modal} this
2594 * @param {Roo.EventObject} e
2598 this.buttons = this.buttons || [];
2601 this.tmpl = Roo.factory(this.tmpl);
2606 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2608 title : 'test dialog',
2618 specificTitle: false,
2620 buttonPosition: 'right',
2639 onRender : function(ct, position)
2641 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2644 var cfg = Roo.apply({}, this.getAutoCreate());
2647 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2649 //if (!cfg.name.length) {
2653 cfg.cls += ' ' + this.cls;
2656 cfg.style = this.style;
2658 this.el = Roo.get(document.body).createChild(cfg, position);
2660 //var type = this.el.dom.type;
2663 if(this.tabIndex !== undefined){
2664 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2667 this.dialogEl = this.el.select('.modal-dialog',true).first();
2668 this.bodyEl = this.el.select('.modal-body',true).first();
2669 this.closeEl = this.el.select('.modal-header .close', true).first();
2670 this.headerEl = this.el.select('.modal-header',true).first();
2671 this.titleEl = this.el.select('.modal-title',true).first();
2672 this.footerEl = this.el.select('.modal-footer',true).first();
2674 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2676 //this.el.addClass("x-dlg-modal");
2678 if (this.buttons.length) {
2679 Roo.each(this.buttons, function(bb) {
2680 var b = Roo.apply({}, bb);
2681 b.xns = b.xns || Roo.bootstrap;
2682 b.xtype = b.xtype || 'Button';
2683 if (typeof(b.listeners) == 'undefined') {
2684 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2687 var btn = Roo.factory(b);
2689 btn.render(this.el.select('.modal-footer div').first());
2693 // render the children.
2696 if(typeof(this.items) != 'undefined'){
2697 var items = this.items;
2700 for(var i =0;i < items.length;i++) {
2701 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2705 this.items = nitems;
2707 // where are these used - they used to be body/close/footer
2711 //this.el.addClass([this.fieldClass, this.cls]);
2715 getAutoCreate : function(){
2720 html : this.html || ''
2725 cls : 'modal-title',
2729 if(this.specificTitle){
2735 if (this.allow_close) {
2747 if(this.size.length){
2748 size = 'modal-' + this.size;
2755 cls: "modal-dialog " + size,
2758 cls : "modal-content",
2761 cls : 'modal-header',
2766 cls : 'modal-footer',
2770 cls: 'btn-' + this.buttonPosition
2787 modal.cls += ' fade';
2793 getChildContainer : function() {
2798 getButtonContainer : function() {
2799 return this.el.select('.modal-footer div',true).first();
2802 initEvents : function()
2804 if (this.allow_close) {
2805 this.closeEl.on('click', this.hide, this);
2807 Roo.EventManager.onWindowResize(this.resize, this, true);
2814 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2815 if (this.fitwindow) {
2816 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2817 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2822 setSize : function(w,h)
2832 if (!this.rendered) {
2836 //this.el.setStyle('display', 'block');
2837 this.el.removeClass('hideing');
2838 this.el.addClass('show');
2840 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2843 this.el.addClass('in');
2846 this.el.addClass('in');
2850 // not sure how we can show data in here..
2852 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2855 Roo.get(document.body).addClass("x-body-masked");
2857 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2858 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2859 this.maskEl.addClass('show');
2863 this.fireEvent('show', this);
2865 // set zindex here - otherwise it appears to be ignored...
2866 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2869 this.items.forEach( function(e) {
2870 e.layout ? e.layout() : false;
2878 if(this.fireEvent("beforehide", this) !== false){
2879 this.maskEl.removeClass('show');
2880 Roo.get(document.body).removeClass("x-body-masked");
2881 this.el.removeClass('in');
2882 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2884 if(this.animate){ // why
2885 this.el.addClass('hideing');
2887 if (!this.el.hasClass('hideing')) {
2888 return; // it's been shown again...
2890 this.el.removeClass('show');
2891 this.el.removeClass('hideing');
2895 this.el.removeClass('show');
2897 this.fireEvent('hide', this);
2900 isVisible : function()
2903 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2907 addButton : function(str, cb)
2911 var b = Roo.apply({}, { html : str } );
2912 b.xns = b.xns || Roo.bootstrap;
2913 b.xtype = b.xtype || 'Button';
2914 if (typeof(b.listeners) == 'undefined') {
2915 b.listeners = { click : cb.createDelegate(this) };
2918 var btn = Roo.factory(b);
2920 btn.render(this.el.select('.modal-footer div').first());
2926 setDefaultButton : function(btn)
2928 //this.el.select('.modal-footer').()
2932 resizeTo: function(w,h)
2936 this.dialogEl.setWidth(w);
2937 if (this.diff === false) {
2938 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2941 this.bodyEl.setHeight(h-this.diff);
2943 this.fireEvent('resize', this);
2946 setContentSize : function(w, h)
2950 onButtonClick: function(btn,e)
2953 this.fireEvent('btnclick', btn.name, e);
2956 * Set the title of the Dialog
2957 * @param {String} str new Title
2959 setTitle: function(str) {
2960 this.titleEl.dom.innerHTML = str;
2963 * Set the body of the Dialog
2964 * @param {String} str new Title
2966 setBody: function(str) {
2967 this.bodyEl.dom.innerHTML = str;
2970 * Set the body of the Dialog using the template
2971 * @param {Obj} data - apply this data to the template and replace the body contents.
2973 applyBody: function(obj)
2976 Roo.log("Error - using apply Body without a template");
2979 this.tmpl.overwrite(this.bodyEl, obj);
2985 Roo.apply(Roo.bootstrap.Modal, {
2987 * Button config that displays a single OK button
2996 * Button config that displays Yes and No buttons
3012 * Button config that displays OK and Cancel buttons
3027 * Button config that displays Yes, No and Cancel buttons
3051 * messagebox - can be used as a replace
3055 * @class Roo.MessageBox
3056 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3060 Roo.Msg.alert('Status', 'Changes saved successfully.');
3062 // Prompt for user data:
3063 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3065 // process text value...
3069 // Show a dialog using config options:
3071 title:'Save Changes?',
3072 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3073 buttons: Roo.Msg.YESNOCANCEL,
3080 Roo.bootstrap.MessageBox = function(){
3081 var dlg, opt, mask, waitTimer;
3082 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3083 var buttons, activeTextEl, bwidth;
3087 var handleButton = function(button){
3089 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3093 var handleHide = function(){
3095 dlg.el.removeClass(opt.cls);
3098 // Roo.TaskMgr.stop(waitTimer);
3099 // waitTimer = null;
3104 var updateButtons = function(b){
3107 buttons["ok"].hide();
3108 buttons["cancel"].hide();
3109 buttons["yes"].hide();
3110 buttons["no"].hide();
3111 //dlg.footer.dom.style.display = 'none';
3114 dlg.footerEl.dom.style.display = '';
3115 for(var k in buttons){
3116 if(typeof buttons[k] != "function"){
3119 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3120 width += buttons[k].el.getWidth()+15;
3130 var handleEsc = function(d, k, e){
3131 if(opt && opt.closable !== false){
3141 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3142 * @return {Roo.BasicDialog} The BasicDialog element
3144 getDialog : function(){
3146 dlg = new Roo.bootstrap.Modal( {
3149 //constraintoviewport:false,
3151 //collapsible : false,
3156 //buttonAlign:"center",
3157 closeClick : function(){
3158 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3161 handleButton("cancel");
3166 dlg.on("hide", handleHide);
3168 //dlg.addKeyListener(27, handleEsc);
3170 this.buttons = buttons;
3171 var bt = this.buttonText;
3172 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3173 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3174 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3175 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3177 bodyEl = dlg.bodyEl.createChild({
3179 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3180 '<textarea class="roo-mb-textarea"></textarea>' +
3181 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3183 msgEl = bodyEl.dom.firstChild;
3184 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3185 textboxEl.enableDisplayMode();
3186 textboxEl.addKeyListener([10,13], function(){
3187 if(dlg.isVisible() && opt && opt.buttons){
3190 }else if(opt.buttons.yes){
3191 handleButton("yes");
3195 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3196 textareaEl.enableDisplayMode();
3197 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3198 progressEl.enableDisplayMode();
3200 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3201 var pf = progressEl.dom.firstChild;
3203 pp = Roo.get(pf.firstChild);
3204 pp.setHeight(pf.offsetHeight);
3212 * Updates the message box body text
3213 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3214 * the XHTML-compliant non-breaking space character '&#160;')
3215 * @return {Roo.MessageBox} This message box
3217 updateText : function(text)
3219 if(!dlg.isVisible() && !opt.width){
3220 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3221 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3223 msgEl.innerHTML = text || ' ';
3225 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3226 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3228 Math.min(opt.width || cw , this.maxWidth),
3229 Math.max(opt.minWidth || this.minWidth, bwidth)
3232 activeTextEl.setWidth(w);
3234 if(dlg.isVisible()){
3235 dlg.fixedcenter = false;
3237 // to big, make it scroll. = But as usual stupid IE does not support
3240 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3241 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3242 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3244 bodyEl.dom.style.height = '';
3245 bodyEl.dom.style.overflowY = '';
3248 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3250 bodyEl.dom.style.overflowX = '';
3253 dlg.setContentSize(w, bodyEl.getHeight());
3254 if(dlg.isVisible()){
3255 dlg.fixedcenter = true;
3261 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3262 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3263 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3264 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3265 * @return {Roo.MessageBox} This message box
3267 updateProgress : function(value, text){
3269 this.updateText(text);
3272 if (pp) { // weird bug on my firefox - for some reason this is not defined
3273 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3274 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3280 * Returns true if the message box is currently displayed
3281 * @return {Boolean} True if the message box is visible, else false
3283 isVisible : function(){
3284 return dlg && dlg.isVisible();
3288 * Hides the message box if it is displayed
3291 if(this.isVisible()){
3297 * Displays a new message box, or reinitializes an existing message box, based on the config options
3298 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3299 * The following config object properties are supported:
3301 Property Type Description
3302 ---------- --------------- ------------------------------------------------------------------------------------
3303 animEl String/Element An id or Element from which the message box should animate as it opens and
3304 closes (defaults to undefined)
3305 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3306 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3307 closable Boolean False to hide the top-right close button (defaults to true). Note that
3308 progress and wait dialogs will ignore this property and always hide the
3309 close button as they can only be closed programmatically.
3310 cls String A custom CSS class to apply to the message box element
3311 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3312 displayed (defaults to 75)
3313 fn Function A callback function to execute after closing the dialog. The arguments to the
3314 function will be btn (the name of the button that was clicked, if applicable,
3315 e.g. "ok"), and text (the value of the active text field, if applicable).
3316 Progress and wait dialogs will ignore this option since they do not respond to
3317 user actions and can only be closed programmatically, so any required function
3318 should be called by the same code after it closes the dialog.
3319 icon String A CSS class that provides a background image to be used as an icon for
3320 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3321 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3322 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3323 modal Boolean False to allow user interaction with the page while the message box is
3324 displayed (defaults to true)
3325 msg String A string that will replace the existing message box body text (defaults
3326 to the XHTML-compliant non-breaking space character ' ')
3327 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3328 progress Boolean True to display a progress bar (defaults to false)
3329 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3330 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3331 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3332 title String The title text
3333 value String The string value to set into the active textbox element if displayed
3334 wait Boolean True to display a progress bar (defaults to false)
3335 width Number The width of the dialog in pixels
3342 msg: 'Please enter your address:',
3344 buttons: Roo.MessageBox.OKCANCEL,
3347 animEl: 'addAddressBtn'
3350 * @param {Object} config Configuration options
3351 * @return {Roo.MessageBox} This message box
3353 show : function(options)
3356 // this causes nightmares if you show one dialog after another
3357 // especially on callbacks..
3359 if(this.isVisible()){
3362 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3363 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3364 Roo.log("New Dialog Message:" + options.msg )
3365 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3366 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3369 var d = this.getDialog();
3371 d.setTitle(opt.title || " ");
3372 d.closeEl.setDisplayed(opt.closable !== false);
3373 activeTextEl = textboxEl;
3374 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3379 textareaEl.setHeight(typeof opt.multiline == "number" ?
3380 opt.multiline : this.defaultTextHeight);
3381 activeTextEl = textareaEl;
3390 progressEl.setDisplayed(opt.progress === true);
3391 this.updateProgress(0);
3392 activeTextEl.dom.value = opt.value || "";
3394 dlg.setDefaultButton(activeTextEl);
3396 var bs = opt.buttons;
3400 }else if(bs && bs.yes){
3401 db = buttons["yes"];
3403 dlg.setDefaultButton(db);
3405 bwidth = updateButtons(opt.buttons);
3406 this.updateText(opt.msg);
3408 d.el.addClass(opt.cls);
3410 d.proxyDrag = opt.proxyDrag === true;
3411 d.modal = opt.modal !== false;
3412 d.mask = opt.modal !== false ? mask : false;
3414 // force it to the end of the z-index stack so it gets a cursor in FF
3415 document.body.appendChild(dlg.el.dom);
3416 d.animateTarget = null;
3417 d.show(options.animEl);
3423 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3424 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3425 * and closing the message box when the process is complete.
3426 * @param {String} title The title bar text
3427 * @param {String} msg The message box body text
3428 * @return {Roo.MessageBox} This message box
3430 progress : function(title, msg){
3437 minWidth: this.minProgressWidth,
3444 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3445 * If a callback function is passed it will be called after the user clicks the button, and the
3446 * id of the button that was clicked will be passed as the only parameter to the callback
3447 * (could also be the top-right close button).
3448 * @param {String} title The title bar text
3449 * @param {String} msg The message box body text
3450 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3451 * @param {Object} scope (optional) The scope of the callback function
3452 * @return {Roo.MessageBox} This message box
3454 alert : function(title, msg, fn, scope)
3469 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3470 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3471 * You are responsible for closing the message box when the process is complete.
3472 * @param {String} msg The message box body text
3473 * @param {String} title (optional) The title bar text
3474 * @return {Roo.MessageBox} This message box
3476 wait : function(msg, title){
3487 waitTimer = Roo.TaskMgr.start({
3489 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3497 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3498 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3499 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3500 * @param {String} title The title bar text
3501 * @param {String} msg The message box body text
3502 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3503 * @param {Object} scope (optional) The scope of the callback function
3504 * @return {Roo.MessageBox} This message box
3506 confirm : function(title, msg, fn, scope){
3510 buttons: this.YESNO,
3519 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3520 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3521 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3522 * (could also be the top-right close button) and the text that was entered will be passed as the two
3523 * parameters to the callback.
3524 * @param {String} title The title bar text
3525 * @param {String} msg The message box body text
3526 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3527 * @param {Object} scope (optional) The scope of the callback function
3528 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3529 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3530 * @return {Roo.MessageBox} This message box
3532 prompt : function(title, msg, fn, scope, multiline){
3536 buttons: this.OKCANCEL,
3541 multiline: multiline,
3548 * Button config that displays a single OK button
3553 * Button config that displays Yes and No buttons
3556 YESNO : {yes:true, no:true},
3558 * Button config that displays OK and Cancel buttons
3561 OKCANCEL : {ok:true, cancel:true},
3563 * Button config that displays Yes, No and Cancel buttons
3566 YESNOCANCEL : {yes:true, no:true, cancel:true},
3569 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3572 defaultTextHeight : 75,
3574 * The maximum width in pixels of the message box (defaults to 600)
3579 * The minimum width in pixels of the message box (defaults to 100)
3584 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3585 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3588 minProgressWidth : 250,
3590 * An object containing the default button text strings that can be overriden for localized language support.
3591 * Supported properties are: ok, cancel, yes and no.
3592 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3605 * Shorthand for {@link Roo.MessageBox}
3607 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3608 Roo.Msg = Roo.Msg || Roo.MessageBox;
3617 * @class Roo.bootstrap.Navbar
3618 * @extends Roo.bootstrap.Component
3619 * Bootstrap Navbar class
3622 * Create a new Navbar
3623 * @param {Object} config The config object
3627 Roo.bootstrap.Navbar = function(config){
3628 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3632 * @event beforetoggle
3633 * Fire before toggle the menu
3634 * @param {Roo.EventObject} e
3636 "beforetoggle" : true
3640 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3649 getAutoCreate : function(){
3652 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3656 initEvents :function ()
3658 //Roo.log(this.el.select('.navbar-toggle',true));
3659 this.el.select('.navbar-toggle',true).on('click', function() {
3660 if(this.fireEvent('beforetoggle', this) !== false){
3661 this.el.select('.navbar-collapse',true).toggleClass('in');
3671 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3673 var size = this.el.getSize();
3674 this.maskEl.setSize(size.width, size.height);
3675 this.maskEl.enableDisplayMode("block");
3684 getChildContainer : function()
3686 if (this.el.select('.collapse').getCount()) {
3687 return this.el.select('.collapse',true).first();
3720 * @class Roo.bootstrap.NavSimplebar
3721 * @extends Roo.bootstrap.Navbar
3722 * Bootstrap Sidebar class
3724 * @cfg {Boolean} inverse is inverted color
3726 * @cfg {String} type (nav | pills | tabs)
3727 * @cfg {Boolean} arrangement stacked | justified
3728 * @cfg {String} align (left | right) alignment
3730 * @cfg {Boolean} main (true|false) main nav bar? default false
3731 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3733 * @cfg {String} tag (header|footer|nav|div) default is nav
3739 * Create a new Sidebar
3740 * @param {Object} config The config object
3744 Roo.bootstrap.NavSimplebar = function(config){
3745 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3748 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3764 getAutoCreate : function(){
3768 tag : this.tag || 'div',
3781 this.type = this.type || 'nav';
3782 if (['tabs','pills'].indexOf(this.type)!==-1) {
3783 cfg.cn[0].cls += ' nav-' + this.type
3787 if (this.type!=='nav') {
3788 Roo.log('nav type must be nav/tabs/pills')
3790 cfg.cn[0].cls += ' navbar-nav'
3796 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3797 cfg.cn[0].cls += ' nav-' + this.arrangement;
3801 if (this.align === 'right') {
3802 cfg.cn[0].cls += ' navbar-right';
3806 cfg.cls += ' navbar-inverse';
3833 * @class Roo.bootstrap.NavHeaderbar
3834 * @extends Roo.bootstrap.NavSimplebar
3835 * Bootstrap Sidebar class
3837 * @cfg {String} brand what is brand
3838 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3839 * @cfg {String} brand_href href of the brand
3840 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3841 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3842 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3843 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3846 * Create a new Sidebar
3847 * @param {Object} config The config object
3851 Roo.bootstrap.NavHeaderbar = function(config){
3852 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3856 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3863 desktopCenter : false,
3866 getAutoCreate : function(){
3869 tag: this.nav || 'nav',
3876 if (this.desktopCenter) {
3877 cn.push({cls : 'container', cn : []});
3884 cls: 'navbar-header',
3889 cls: 'navbar-toggle',
3890 'data-toggle': 'collapse',
3895 html: 'Toggle navigation'
3917 cls: 'collapse navbar-collapse',
3921 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3923 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3924 cfg.cls += ' navbar-' + this.position;
3926 // tag can override this..
3928 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3931 if (this.brand !== '') {
3934 href: this.brand_href ? this.brand_href : '#',
3935 cls: 'navbar-brand',
3943 cfg.cls += ' main-nav';
3951 getHeaderChildContainer : function()
3953 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3954 return this.el.select('.navbar-header',true).first();
3957 return this.getChildContainer();
3961 initEvents : function()
3963 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3965 if (this.autohide) {
3970 Roo.get(document).on('scroll',function(e) {
3971 var ns = Roo.get(document).getScroll().top;
3972 var os = prevScroll;
3976 ft.removeClass('slideDown');
3977 ft.addClass('slideUp');
3980 ft.removeClass('slideUp');
3981 ft.addClass('slideDown');
4002 * @class Roo.bootstrap.NavSidebar
4003 * @extends Roo.bootstrap.Navbar
4004 * Bootstrap Sidebar class
4007 * Create a new Sidebar
4008 * @param {Object} config The config object
4012 Roo.bootstrap.NavSidebar = function(config){
4013 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4016 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4018 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4020 getAutoCreate : function(){
4025 cls: 'sidebar sidebar-nav'
4047 * @class Roo.bootstrap.NavGroup
4048 * @extends Roo.bootstrap.Component
4049 * Bootstrap NavGroup class
4050 * @cfg {String} align (left|right)
4051 * @cfg {Boolean} inverse
4052 * @cfg {String} type (nav|pills|tab) default nav
4053 * @cfg {String} navId - reference Id for navbar.
4057 * Create a new nav group
4058 * @param {Object} config The config object
4061 Roo.bootstrap.NavGroup = function(config){
4062 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4065 Roo.bootstrap.NavGroup.register(this);
4069 * Fires when the active item changes
4070 * @param {Roo.bootstrap.NavGroup} this
4071 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4072 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4079 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4090 getAutoCreate : function()
4092 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4099 if (['tabs','pills'].indexOf(this.type)!==-1) {
4100 cfg.cls += ' nav-' + this.type
4102 if (this.type!=='nav') {
4103 Roo.log('nav type must be nav/tabs/pills')
4105 cfg.cls += ' navbar-nav'
4108 if (this.parent() && this.parent().sidebar) {
4111 cls: 'dashboard-menu sidebar-menu'
4117 if (this.form === true) {
4123 if (this.align === 'right') {
4124 cfg.cls += ' navbar-right';
4126 cfg.cls += ' navbar-left';
4130 if (this.align === 'right') {
4131 cfg.cls += ' navbar-right';
4135 cfg.cls += ' navbar-inverse';
4143 * sets the active Navigation item
4144 * @param {Roo.bootstrap.NavItem} the new current navitem
4146 setActiveItem : function(item)
4149 Roo.each(this.navItems, function(v){
4154 v.setActive(false, true);
4161 item.setActive(true, true);
4162 this.fireEvent('changed', this, item, prev);
4167 * gets the active Navigation item
4168 * @return {Roo.bootstrap.NavItem} the current navitem
4170 getActive : function()
4174 Roo.each(this.navItems, function(v){
4185 indexOfNav : function()
4189 Roo.each(this.navItems, function(v,i){
4200 * adds a Navigation item
4201 * @param {Roo.bootstrap.NavItem} the navitem to add
4203 addItem : function(cfg)
4205 var cn = new Roo.bootstrap.NavItem(cfg);
4207 cn.parentId = this.id;
4208 cn.onRender(this.el, null);
4212 * register a Navigation item
4213 * @param {Roo.bootstrap.NavItem} the navitem to add
4215 register : function(item)
4217 this.navItems.push( item);
4218 item.navId = this.navId;
4223 * clear all the Navigation item
4226 clearAll : function()
4229 this.el.dom.innerHTML = '';
4232 getNavItem: function(tabId)
4235 Roo.each(this.navItems, function(e) {
4236 if (e.tabId == tabId) {
4246 setActiveNext : function()
4248 var i = this.indexOfNav(this.getActive());
4249 if (i > this.navItems.length) {
4252 this.setActiveItem(this.navItems[i+1]);
4254 setActivePrev : function()
4256 var i = this.indexOfNav(this.getActive());
4260 this.setActiveItem(this.navItems[i-1]);
4262 clearWasActive : function(except) {
4263 Roo.each(this.navItems, function(e) {
4264 if (e.tabId != except.tabId && e.was_active) {
4265 e.was_active = false;
4272 getWasActive : function ()
4275 Roo.each(this.navItems, function(e) {
4290 Roo.apply(Roo.bootstrap.NavGroup, {
4294 * register a Navigation Group
4295 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4297 register : function(navgrp)
4299 this.groups[navgrp.navId] = navgrp;
4303 * fetch a Navigation Group based on the navigation ID
4304 * @param {string} the navgroup to add
4305 * @returns {Roo.bootstrap.NavGroup} the navgroup
4307 get: function(navId) {
4308 if (typeof(this.groups[navId]) == 'undefined') {
4310 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4312 return this.groups[navId] ;
4327 * @class Roo.bootstrap.NavItem
4328 * @extends Roo.bootstrap.Component
4329 * Bootstrap Navbar.NavItem class
4330 * @cfg {String} href link to
4331 * @cfg {String} html content of button
4332 * @cfg {String} badge text inside badge
4333 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4334 * @cfg {String} glyphicon name of glyphicon
4335 * @cfg {String} icon name of font awesome icon
4336 * @cfg {Boolean} active Is item active
4337 * @cfg {Boolean} disabled Is item disabled
4339 * @cfg {Boolean} preventDefault (true | false) default false
4340 * @cfg {String} tabId the tab that this item activates.
4341 * @cfg {String} tagtype (a|span) render as a href or span?
4342 * @cfg {Boolean} animateRef (true|false) link to element default false
4345 * Create a new Navbar Item
4346 * @param {Object} config The config object
4348 Roo.bootstrap.NavItem = function(config){
4349 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4354 * The raw click event for the entire grid.
4355 * @param {Roo.EventObject} e
4360 * Fires when the active item active state changes
4361 * @param {Roo.bootstrap.NavItem} this
4362 * @param {boolean} state the new state
4368 * Fires when scroll to element
4369 * @param {Roo.bootstrap.NavItem} this
4370 * @param {Object} options
4371 * @param {Roo.EventObject} e
4379 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4387 preventDefault : false,
4394 getAutoCreate : function(){
4403 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4405 if (this.disabled) {
4406 cfg.cls += ' disabled';
4409 if (this.href || this.html || this.glyphicon || this.icon) {
4413 href : this.href || "#",
4414 html: this.html || ''
4419 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4422 if(this.glyphicon) {
4423 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4428 cfg.cn[0].html += " <span class='caret'></span>";
4432 if (this.badge !== '') {
4434 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4442 initEvents: function()
4444 if (typeof (this.menu) != 'undefined') {
4445 this.menu.parentType = this.xtype;
4446 this.menu.triggerEl = this.el;
4447 this.menu = this.addxtype(Roo.apply({}, this.menu));
4450 this.el.select('a',true).on('click', this.onClick, this);
4452 if(this.tagtype == 'span'){
4453 this.el.select('span',true).on('click', this.onClick, this);
4456 // at this point parent should be available..
4457 this.parent().register(this);
4460 onClick : function(e)
4462 if (e.getTarget('.dropdown-menu-item')) {
4463 // did you click on a menu itemm.... - then don't trigger onclick..
4468 this.preventDefault ||
4471 Roo.log("NavItem - prevent Default?");
4475 if (this.disabled) {
4479 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4480 if (tg && tg.transition) {
4481 Roo.log("waiting for the transitionend");
4487 //Roo.log("fire event clicked");
4488 if(this.fireEvent('click', this, e) === false){
4492 if(this.tagtype == 'span'){
4496 //Roo.log(this.href);
4497 var ael = this.el.select('a',true).first();
4500 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4501 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4502 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4503 return; // ignore... - it's a 'hash' to another page.
4505 Roo.log("NavItem - prevent Default?");
4507 this.scrollToElement(e);
4511 var p = this.parent();
4513 if (['tabs','pills'].indexOf(p.type)!==-1) {
4514 if (typeof(p.setActiveItem) !== 'undefined') {
4515 p.setActiveItem(this);
4519 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4520 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4521 // remove the collapsed menu expand...
4522 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4526 isActive: function () {
4529 setActive : function(state, fire, is_was_active)
4531 if (this.active && !state && this.navId) {
4532 this.was_active = true;
4533 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4535 nv.clearWasActive(this);
4539 this.active = state;
4542 this.el.removeClass('active');
4543 } else if (!this.el.hasClass('active')) {
4544 this.el.addClass('active');
4547 this.fireEvent('changed', this, state);
4550 // show a panel if it's registered and related..
4552 if (!this.navId || !this.tabId || !state || is_was_active) {
4556 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4560 var pan = tg.getPanelByName(this.tabId);
4564 // if we can not flip to new panel - go back to old nav highlight..
4565 if (false == tg.showPanel(pan)) {
4566 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4568 var onav = nv.getWasActive();
4570 onav.setActive(true, false, true);
4579 // this should not be here...
4580 setDisabled : function(state)
4582 this.disabled = state;
4584 this.el.removeClass('disabled');
4585 } else if (!this.el.hasClass('disabled')) {
4586 this.el.addClass('disabled');
4592 * Fetch the element to display the tooltip on.
4593 * @return {Roo.Element} defaults to this.el
4595 tooltipEl : function()
4597 return this.el.select('' + this.tagtype + '', true).first();
4600 scrollToElement : function(e)
4602 var c = document.body;
4605 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4607 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4608 c = document.documentElement;
4611 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4617 var o = target.calcOffsetsTo(c);
4624 this.fireEvent('scrollto', this, options, e);
4626 Roo.get(c).scrollTo('top', options.value, true);
4639 * <span> icon </span>
4640 * <span> text </span>
4641 * <span>badge </span>
4645 * @class Roo.bootstrap.NavSidebarItem
4646 * @extends Roo.bootstrap.NavItem
4647 * Bootstrap Navbar.NavSidebarItem class
4648 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4649 * {Boolean} open is the menu open
4650 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4651 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4652 * {String} buttonSize (sm|md|lg)the extra classes for the button
4653 * {Boolean} showArrow show arrow next to the text (default true)
4655 * Create a new Navbar Button
4656 * @param {Object} config The config object
4658 Roo.bootstrap.NavSidebarItem = function(config){
4659 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4664 * The raw click event for the entire grid.
4665 * @param {Roo.EventObject} e
4670 * Fires when the active item active state changes
4671 * @param {Roo.bootstrap.NavSidebarItem} this
4672 * @param {boolean} state the new state
4680 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4682 badgeWeight : 'default',
4688 buttonWeight : 'default',
4694 getAutoCreate : function(){
4699 href : this.href || '#',
4705 if(this.buttonView){
4708 href : this.href || '#',
4709 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4722 cfg.cls += ' active';
4725 if (this.disabled) {
4726 cfg.cls += ' disabled';
4729 cfg.cls += ' open x-open';
4732 if (this.glyphicon || this.icon) {
4733 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4734 a.cn.push({ tag : 'i', cls : c }) ;
4737 if(!this.buttonView){
4740 html : this.html || ''
4747 if (this.badge !== '') {
4748 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4754 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4757 a.cls += ' dropdown-toggle treeview' ;
4763 initEvents : function()
4765 if (typeof (this.menu) != 'undefined') {
4766 this.menu.parentType = this.xtype;
4767 this.menu.triggerEl = this.el;
4768 this.menu = this.addxtype(Roo.apply({}, this.menu));
4771 this.el.on('click', this.onClick, this);
4773 if(this.badge !== ''){
4774 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4779 onClick : function(e)
4786 if(this.preventDefault){
4790 this.fireEvent('click', this);
4793 disable : function()
4795 this.setDisabled(true);
4800 this.setDisabled(false);
4803 setDisabled : function(state)
4805 if(this.disabled == state){
4809 this.disabled = state;
4812 this.el.addClass('disabled');
4816 this.el.removeClass('disabled');
4821 setActive : function(state)
4823 if(this.active == state){
4827 this.active = state;
4830 this.el.addClass('active');
4834 this.el.removeClass('active');
4839 isActive: function ()
4844 setBadge : function(str)
4850 this.badgeEl.dom.innerHTML = str;
4867 * @class Roo.bootstrap.Row
4868 * @extends Roo.bootstrap.Component
4869 * Bootstrap Row class (contains columns...)
4873 * @param {Object} config The config object
4876 Roo.bootstrap.Row = function(config){
4877 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4880 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4882 getAutoCreate : function(){
4901 * @class Roo.bootstrap.Element
4902 * @extends Roo.bootstrap.Component
4903 * Bootstrap Element class
4904 * @cfg {String} html contents of the element
4905 * @cfg {String} tag tag of the element
4906 * @cfg {String} cls class of the element
4907 * @cfg {Boolean} preventDefault (true|false) default false
4908 * @cfg {Boolean} clickable (true|false) default false
4911 * Create a new Element
4912 * @param {Object} config The config object
4915 Roo.bootstrap.Element = function(config){
4916 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4922 * When a element is chick
4923 * @param {Roo.bootstrap.Element} this
4924 * @param {Roo.EventObject} e
4930 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4935 preventDefault: false,
4938 getAutoCreate : function(){
4942 // cls: this.cls, double assign in parent class Component.js :: onRender
4949 initEvents: function()
4951 Roo.bootstrap.Element.superclass.initEvents.call(this);
4954 this.el.on('click', this.onClick, this);
4959 onClick : function(e)
4961 if(this.preventDefault){
4965 this.fireEvent('click', this, e);
4968 getValue : function()
4970 return this.el.dom.innerHTML;
4973 setValue : function(value)
4975 this.el.dom.innerHTML = value;
4990 * @class Roo.bootstrap.Pagination
4991 * @extends Roo.bootstrap.Component
4992 * Bootstrap Pagination class
4993 * @cfg {String} size xs | sm | md | lg
4994 * @cfg {Boolean} inverse false | true
4997 * Create a new Pagination
4998 * @param {Object} config The config object
5001 Roo.bootstrap.Pagination = function(config){
5002 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5005 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5011 getAutoCreate : function(){
5017 cfg.cls += ' inverse';
5023 cfg.cls += " " + this.cls;
5041 * @class Roo.bootstrap.PaginationItem
5042 * @extends Roo.bootstrap.Component
5043 * Bootstrap PaginationItem class
5044 * @cfg {String} html text
5045 * @cfg {String} href the link
5046 * @cfg {Boolean} preventDefault (true | false) default true
5047 * @cfg {Boolean} active (true | false) default false
5048 * @cfg {Boolean} disabled default false
5052 * Create a new PaginationItem
5053 * @param {Object} config The config object
5057 Roo.bootstrap.PaginationItem = function(config){
5058 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5063 * The raw click event for the entire grid.
5064 * @param {Roo.EventObject} e
5070 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5074 preventDefault: true,
5079 getAutoCreate : function(){
5085 href : this.href ? this.href : '#',
5086 html : this.html ? this.html : ''
5096 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5100 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5106 initEvents: function() {
5108 this.el.on('click', this.onClick, this);
5111 onClick : function(e)
5113 Roo.log('PaginationItem on click ');
5114 if(this.preventDefault){
5122 this.fireEvent('click', this, e);
5138 * @class Roo.bootstrap.Slider
5139 * @extends Roo.bootstrap.Component
5140 * Bootstrap Slider class
5143 * Create a new Slider
5144 * @param {Object} config The config object
5147 Roo.bootstrap.Slider = function(config){
5148 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5151 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5153 getAutoCreate : function(){
5157 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5161 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5173 * Ext JS Library 1.1.1
5174 * Copyright(c) 2006-2007, Ext JS, LLC.
5176 * Originally Released Under LGPL - original licence link has changed is not relivant.
5179 * <script type="text/javascript">
5184 * @class Roo.grid.ColumnModel
5185 * @extends Roo.util.Observable
5186 * This is the default implementation of a ColumnModel used by the Grid. It defines
5187 * the columns in the grid.
5190 var colModel = new Roo.grid.ColumnModel([
5191 {header: "Ticker", width: 60, sortable: true, locked: true},
5192 {header: "Company Name", width: 150, sortable: true},
5193 {header: "Market Cap.", width: 100, sortable: true},
5194 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5195 {header: "Employees", width: 100, sortable: true, resizable: false}
5200 * The config options listed for this class are options which may appear in each
5201 * individual column definition.
5202 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5204 * @param {Object} config An Array of column config objects. See this class's
5205 * config objects for details.
5207 Roo.grid.ColumnModel = function(config){
5209 * The config passed into the constructor
5211 this.config = config;
5214 // if no id, create one
5215 // if the column does not have a dataIndex mapping,
5216 // map it to the order it is in the config
5217 for(var i = 0, len = config.length; i < len; i++){
5219 if(typeof c.dataIndex == "undefined"){
5222 if(typeof c.renderer == "string"){
5223 c.renderer = Roo.util.Format[c.renderer];
5225 if(typeof c.id == "undefined"){
5228 if(c.editor && c.editor.xtype){
5229 c.editor = Roo.factory(c.editor, Roo.grid);
5231 if(c.editor && c.editor.isFormField){
5232 c.editor = new Roo.grid.GridEditor(c.editor);
5234 this.lookup[c.id] = c;
5238 * The width of columns which have no width specified (defaults to 100)
5241 this.defaultWidth = 100;
5244 * Default sortable of columns which have no sortable specified (defaults to false)
5247 this.defaultSortable = false;
5251 * @event widthchange
5252 * Fires when the width of a column changes.
5253 * @param {ColumnModel} this
5254 * @param {Number} columnIndex The column index
5255 * @param {Number} newWidth The new width
5257 "widthchange": true,
5259 * @event headerchange
5260 * Fires when the text of a header changes.
5261 * @param {ColumnModel} this
5262 * @param {Number} columnIndex The column index
5263 * @param {Number} newText The new header text
5265 "headerchange": true,
5267 * @event hiddenchange
5268 * Fires when a column is hidden or "unhidden".
5269 * @param {ColumnModel} this
5270 * @param {Number} columnIndex The column index
5271 * @param {Boolean} hidden true if hidden, false otherwise
5273 "hiddenchange": true,
5275 * @event columnmoved
5276 * Fires when a column is moved.
5277 * @param {ColumnModel} this
5278 * @param {Number} oldIndex
5279 * @param {Number} newIndex
5281 "columnmoved" : true,
5283 * @event columlockchange
5284 * Fires when a column's locked state is changed
5285 * @param {ColumnModel} this
5286 * @param {Number} colIndex
5287 * @param {Boolean} locked true if locked
5289 "columnlockchange" : true
5291 Roo.grid.ColumnModel.superclass.constructor.call(this);
5293 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5295 * @cfg {String} header The header text to display in the Grid view.
5298 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5299 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5300 * specified, the column's index is used as an index into the Record's data Array.
5303 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5304 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5307 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5308 * Defaults to the value of the {@link #defaultSortable} property.
5309 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5312 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5315 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5318 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5321 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5324 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5325 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5326 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5327 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5330 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5333 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5336 * @cfg {String} cursor (Optional)
5339 * @cfg {String} tooltip (Optional)
5342 * @cfg {Number} xs (Optional)
5345 * @cfg {Number} sm (Optional)
5348 * @cfg {Number} md (Optional)
5351 * @cfg {Number} lg (Optional)
5354 * Returns the id of the column at the specified index.
5355 * @param {Number} index The column index
5356 * @return {String} the id
5358 getColumnId : function(index){
5359 return this.config[index].id;
5363 * Returns the column for a specified id.
5364 * @param {String} id The column id
5365 * @return {Object} the column
5367 getColumnById : function(id){
5368 return this.lookup[id];
5373 * Returns the column for a specified dataIndex.
5374 * @param {String} dataIndex The column dataIndex
5375 * @return {Object|Boolean} the column or false if not found
5377 getColumnByDataIndex: function(dataIndex){
5378 var index = this.findColumnIndex(dataIndex);
5379 return index > -1 ? this.config[index] : false;
5383 * Returns the index for a specified column id.
5384 * @param {String} id The column id
5385 * @return {Number} the index, or -1 if not found
5387 getIndexById : function(id){
5388 for(var i = 0, len = this.config.length; i < len; i++){
5389 if(this.config[i].id == id){
5397 * Returns the index for a specified column dataIndex.
5398 * @param {String} dataIndex The column dataIndex
5399 * @return {Number} the index, or -1 if not found
5402 findColumnIndex : function(dataIndex){
5403 for(var i = 0, len = this.config.length; i < len; i++){
5404 if(this.config[i].dataIndex == dataIndex){
5412 moveColumn : function(oldIndex, newIndex){
5413 var c = this.config[oldIndex];
5414 this.config.splice(oldIndex, 1);
5415 this.config.splice(newIndex, 0, c);
5416 this.dataMap = null;
5417 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5420 isLocked : function(colIndex){
5421 return this.config[colIndex].locked === true;
5424 setLocked : function(colIndex, value, suppressEvent){
5425 if(this.isLocked(colIndex) == value){
5428 this.config[colIndex].locked = value;
5430 this.fireEvent("columnlockchange", this, colIndex, value);
5434 getTotalLockedWidth : function(){
5436 for(var i = 0; i < this.config.length; i++){
5437 if(this.isLocked(i) && !this.isHidden(i)){
5438 this.totalWidth += this.getColumnWidth(i);
5444 getLockedCount : function(){
5445 for(var i = 0, len = this.config.length; i < len; i++){
5446 if(!this.isLocked(i)){
5451 return this.config.length;
5455 * Returns the number of columns.
5458 getColumnCount : function(visibleOnly){
5459 if(visibleOnly === true){
5461 for(var i = 0, len = this.config.length; i < len; i++){
5462 if(!this.isHidden(i)){
5468 return this.config.length;
5472 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5473 * @param {Function} fn
5474 * @param {Object} scope (optional)
5475 * @return {Array} result
5477 getColumnsBy : function(fn, scope){
5479 for(var i = 0, len = this.config.length; i < len; i++){
5480 var c = this.config[i];
5481 if(fn.call(scope||this, c, i) === true){
5489 * Returns true if the specified column is sortable.
5490 * @param {Number} col The column index
5493 isSortable : function(col){
5494 if(typeof this.config[col].sortable == "undefined"){
5495 return this.defaultSortable;
5497 return this.config[col].sortable;
5501 * Returns the rendering (formatting) function defined for the column.
5502 * @param {Number} col The column index.
5503 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5505 getRenderer : function(col){
5506 if(!this.config[col].renderer){
5507 return Roo.grid.ColumnModel.defaultRenderer;
5509 return this.config[col].renderer;
5513 * Sets the rendering (formatting) function for a column.
5514 * @param {Number} col The column index
5515 * @param {Function} fn The function to use to process the cell's raw data
5516 * to return HTML markup for the grid view. The render function is called with
5517 * the following parameters:<ul>
5518 * <li>Data value.</li>
5519 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5520 * <li>css A CSS style string to apply to the table cell.</li>
5521 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5522 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5523 * <li>Row index</li>
5524 * <li>Column index</li>
5525 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5527 setRenderer : function(col, fn){
5528 this.config[col].renderer = fn;
5532 * Returns the width for the specified column.
5533 * @param {Number} col The column index
5536 getColumnWidth : function(col){
5537 return this.config[col].width * 1 || this.defaultWidth;
5541 * Sets the width for a column.
5542 * @param {Number} col The column index
5543 * @param {Number} width The new width
5545 setColumnWidth : function(col, width, suppressEvent){
5546 this.config[col].width = width;
5547 this.totalWidth = null;
5549 this.fireEvent("widthchange", this, col, width);
5554 * Returns the total width of all columns.
5555 * @param {Boolean} includeHidden True to include hidden column widths
5558 getTotalWidth : function(includeHidden){
5559 if(!this.totalWidth){
5560 this.totalWidth = 0;
5561 for(var i = 0, len = this.config.length; i < len; i++){
5562 if(includeHidden || !this.isHidden(i)){
5563 this.totalWidth += this.getColumnWidth(i);
5567 return this.totalWidth;
5571 * Returns the header for the specified column.
5572 * @param {Number} col The column index
5575 getColumnHeader : function(col){
5576 return this.config[col].header;
5580 * Sets the header for a column.
5581 * @param {Number} col The column index
5582 * @param {String} header The new header
5584 setColumnHeader : function(col, header){
5585 this.config[col].header = header;
5586 this.fireEvent("headerchange", this, col, header);
5590 * Returns the tooltip for the specified column.
5591 * @param {Number} col The column index
5594 getColumnTooltip : function(col){
5595 return this.config[col].tooltip;
5598 * Sets the tooltip for a column.
5599 * @param {Number} col The column index
5600 * @param {String} tooltip The new tooltip
5602 setColumnTooltip : function(col, tooltip){
5603 this.config[col].tooltip = tooltip;
5607 * Returns the dataIndex for the specified column.
5608 * @param {Number} col The column index
5611 getDataIndex : function(col){
5612 return this.config[col].dataIndex;
5616 * Sets the dataIndex for a column.
5617 * @param {Number} col The column index
5618 * @param {Number} dataIndex The new dataIndex
5620 setDataIndex : function(col, dataIndex){
5621 this.config[col].dataIndex = dataIndex;
5627 * Returns true if the cell is editable.
5628 * @param {Number} colIndex The column index
5629 * @param {Number} rowIndex The row index - this is nto actually used..?
5632 isCellEditable : function(colIndex, rowIndex){
5633 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5637 * Returns the editor defined for the cell/column.
5638 * return false or null to disable editing.
5639 * @param {Number} colIndex The column index
5640 * @param {Number} rowIndex The row index
5643 getCellEditor : function(colIndex, rowIndex){
5644 return this.config[colIndex].editor;
5648 * Sets if a column is editable.
5649 * @param {Number} col The column index
5650 * @param {Boolean} editable True if the column is editable
5652 setEditable : function(col, editable){
5653 this.config[col].editable = editable;
5658 * Returns true if the column is hidden.
5659 * @param {Number} colIndex The column index
5662 isHidden : function(colIndex){
5663 return this.config[colIndex].hidden;
5668 * Returns true if the column width cannot be changed
5670 isFixed : function(colIndex){
5671 return this.config[colIndex].fixed;
5675 * Returns true if the column can be resized
5678 isResizable : function(colIndex){
5679 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5682 * Sets if a column is hidden.
5683 * @param {Number} colIndex The column index
5684 * @param {Boolean} hidden True if the column is hidden
5686 setHidden : function(colIndex, hidden){
5687 this.config[colIndex].hidden = hidden;
5688 this.totalWidth = null;
5689 this.fireEvent("hiddenchange", this, colIndex, hidden);
5693 * Sets the editor for a column.
5694 * @param {Number} col The column index
5695 * @param {Object} editor The editor object
5697 setEditor : function(col, editor){
5698 this.config[col].editor = editor;
5702 Roo.grid.ColumnModel.defaultRenderer = function(value)
5704 if(typeof value == "object") {
5707 if(typeof value == "string" && value.length < 1){
5711 return String.format("{0}", value);
5714 // Alias for backwards compatibility
5715 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5718 * Ext JS Library 1.1.1
5719 * Copyright(c) 2006-2007, Ext JS, LLC.
5721 * Originally Released Under LGPL - original licence link has changed is not relivant.
5724 * <script type="text/javascript">
5728 * @class Roo.LoadMask
5729 * A simple utility class for generically masking elements while loading data. If the element being masked has
5730 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5731 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5732 * element's UpdateManager load indicator and will be destroyed after the initial load.
5734 * Create a new LoadMask
5735 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5736 * @param {Object} config The config object
5738 Roo.LoadMask = function(el, config){
5739 this.el = Roo.get(el);
5740 Roo.apply(this, config);
5742 this.store.on('beforeload', this.onBeforeLoad, this);
5743 this.store.on('load', this.onLoad, this);
5744 this.store.on('loadexception', this.onLoadException, this);
5745 this.removeMask = false;
5747 var um = this.el.getUpdateManager();
5748 um.showLoadIndicator = false; // disable the default indicator
5749 um.on('beforeupdate', this.onBeforeLoad, this);
5750 um.on('update', this.onLoad, this);
5751 um.on('failure', this.onLoad, this);
5752 this.removeMask = true;
5756 Roo.LoadMask.prototype = {
5758 * @cfg {Boolean} removeMask
5759 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5760 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5764 * The text to display in a centered loading message box (defaults to 'Loading...')
5768 * @cfg {String} msgCls
5769 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5771 msgCls : 'x-mask-loading',
5774 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5780 * Disables the mask to prevent it from being displayed
5782 disable : function(){
5783 this.disabled = true;
5787 * Enables the mask so that it can be displayed
5789 enable : function(){
5790 this.disabled = false;
5793 onLoadException : function()
5797 if (typeof(arguments[3]) != 'undefined') {
5798 Roo.MessageBox.alert("Error loading",arguments[3]);
5802 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5803 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5810 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5815 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5819 onBeforeLoad : function(){
5821 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5826 destroy : function(){
5828 this.store.un('beforeload', this.onBeforeLoad, this);
5829 this.store.un('load', this.onLoad, this);
5830 this.store.un('loadexception', this.onLoadException, this);
5832 var um = this.el.getUpdateManager();
5833 um.un('beforeupdate', this.onBeforeLoad, this);
5834 um.un('update', this.onLoad, this);
5835 um.un('failure', this.onLoad, this);
5846 * @class Roo.bootstrap.Table
5847 * @extends Roo.bootstrap.Component
5848 * Bootstrap Table class
5849 * @cfg {String} cls table class
5850 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5851 * @cfg {String} bgcolor Specifies the background color for a table
5852 * @cfg {Number} border Specifies whether the table cells should have borders or not
5853 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5854 * @cfg {Number} cellspacing Specifies the space between cells
5855 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5856 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5857 * @cfg {String} sortable Specifies that the table should be sortable
5858 * @cfg {String} summary Specifies a summary of the content of a table
5859 * @cfg {Number} width Specifies the width of a table
5860 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5862 * @cfg {boolean} striped Should the rows be alternative striped
5863 * @cfg {boolean} bordered Add borders to the table
5864 * @cfg {boolean} hover Add hover highlighting
5865 * @cfg {boolean} condensed Format condensed
5866 * @cfg {boolean} responsive Format condensed
5867 * @cfg {Boolean} loadMask (true|false) default false
5868 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5869 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5870 * @cfg {Boolean} rowSelection (true|false) default false
5871 * @cfg {Boolean} cellSelection (true|false) default false
5872 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5873 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5874 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5878 * Create a new Table
5879 * @param {Object} config The config object
5882 Roo.bootstrap.Table = function(config){
5883 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5888 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5889 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5890 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5891 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5893 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5895 this.sm.grid = this;
5896 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5897 this.sm = this.selModel;
5898 this.sm.xmodule = this.xmodule || false;
5901 if (this.cm && typeof(this.cm.config) == 'undefined') {
5902 this.colModel = new Roo.grid.ColumnModel(this.cm);
5903 this.cm = this.colModel;
5904 this.cm.xmodule = this.xmodule || false;
5907 this.store= Roo.factory(this.store, Roo.data);
5908 this.ds = this.store;
5909 this.ds.xmodule = this.xmodule || false;
5912 if (this.footer && this.store) {
5913 this.footer.dataSource = this.ds;
5914 this.footer = Roo.factory(this.footer);
5921 * Fires when a cell is clicked
5922 * @param {Roo.bootstrap.Table} this
5923 * @param {Roo.Element} el
5924 * @param {Number} rowIndex
5925 * @param {Number} columnIndex
5926 * @param {Roo.EventObject} e
5930 * @event celldblclick
5931 * Fires when a cell is double clicked
5932 * @param {Roo.bootstrap.Table} this
5933 * @param {Roo.Element} el
5934 * @param {Number} rowIndex
5935 * @param {Number} columnIndex
5936 * @param {Roo.EventObject} e
5938 "celldblclick" : true,
5941 * Fires when a row is clicked
5942 * @param {Roo.bootstrap.Table} this
5943 * @param {Roo.Element} el
5944 * @param {Number} rowIndex
5945 * @param {Roo.EventObject} e
5949 * @event rowdblclick
5950 * Fires when a row is double clicked
5951 * @param {Roo.bootstrap.Table} this
5952 * @param {Roo.Element} el
5953 * @param {Number} rowIndex
5954 * @param {Roo.EventObject} e
5956 "rowdblclick" : true,
5959 * Fires when a mouseover occur
5960 * @param {Roo.bootstrap.Table} this
5961 * @param {Roo.Element} el
5962 * @param {Number} rowIndex
5963 * @param {Number} columnIndex
5964 * @param {Roo.EventObject} e
5969 * Fires when a mouseout occur
5970 * @param {Roo.bootstrap.Table} this
5971 * @param {Roo.Element} el
5972 * @param {Number} rowIndex
5973 * @param {Number} columnIndex
5974 * @param {Roo.EventObject} e
5979 * Fires when a row is rendered, so you can change add a style to it.
5980 * @param {Roo.bootstrap.Table} this
5981 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5985 * @event rowsrendered
5986 * Fires when all the rows have been rendered
5987 * @param {Roo.bootstrap.Table} this
5989 'rowsrendered' : true,
5991 * @event contextmenu
5992 * The raw contextmenu event for the entire grid.
5993 * @param {Roo.EventObject} e
5995 "contextmenu" : true,
5997 * @event rowcontextmenu
5998 * Fires when a row is right clicked
5999 * @param {Roo.bootstrap.Table} this
6000 * @param {Number} rowIndex
6001 * @param {Roo.EventObject} e
6003 "rowcontextmenu" : true,
6005 * @event cellcontextmenu
6006 * Fires when a cell is right clicked
6007 * @param {Roo.bootstrap.Table} this
6008 * @param {Number} rowIndex
6009 * @param {Number} cellIndex
6010 * @param {Roo.EventObject} e
6012 "cellcontextmenu" : true,
6014 * @event headercontextmenu
6015 * Fires when a header is right clicked
6016 * @param {Roo.bootstrap.Table} this
6017 * @param {Number} columnIndex
6018 * @param {Roo.EventObject} e
6020 "headercontextmenu" : true
6024 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6050 rowSelection : false,
6051 cellSelection : false,
6054 // Roo.Element - the tbody
6056 // Roo.Element - thead element
6059 container: false, // used by gridpanel...
6065 getAutoCreate : function()
6067 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6074 if (this.scrollBody) {
6075 cfg.cls += ' table-body-fixed';
6078 cfg.cls += ' table-striped';
6082 cfg.cls += ' table-hover';
6084 if (this.bordered) {
6085 cfg.cls += ' table-bordered';
6087 if (this.condensed) {
6088 cfg.cls += ' table-condensed';
6090 if (this.responsive) {
6091 cfg.cls += ' table-responsive';
6095 cfg.cls+= ' ' +this.cls;
6098 // this lot should be simplifed...
6101 cfg.align=this.align;
6104 cfg.bgcolor=this.bgcolor;
6107 cfg.border=this.border;
6109 if (this.cellpadding) {
6110 cfg.cellpadding=this.cellpadding;
6112 if (this.cellspacing) {
6113 cfg.cellspacing=this.cellspacing;
6116 cfg.frame=this.frame;
6119 cfg.rules=this.rules;
6121 if (this.sortable) {
6122 cfg.sortable=this.sortable;
6125 cfg.summary=this.summary;
6128 cfg.width=this.width;
6131 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6134 if(this.store || this.cm){
6135 if(this.headerShow){
6136 cfg.cn.push(this.renderHeader());
6139 cfg.cn.push(this.renderBody());
6141 if(this.footerShow){
6142 cfg.cn.push(this.renderFooter());
6144 // where does this come from?
6145 //cfg.cls+= ' TableGrid';
6148 return { cn : [ cfg ] };
6151 initEvents : function()
6153 if(!this.store || !this.cm){
6156 if (this.selModel) {
6157 this.selModel.initEvents();
6161 //Roo.log('initEvents with ds!!!!');
6163 this.mainBody = this.el.select('tbody', true).first();
6164 this.mainHead = this.el.select('thead', true).first();
6171 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6172 e.on('click', _this.sort, _this);
6175 this.mainBody.on("click", this.onClick, this);
6176 this.mainBody.on("dblclick", this.onDblClick, this);
6178 // why is this done????? = it breaks dialogs??
6179 //this.parent().el.setStyle('position', 'relative');
6183 this.footer.parentId = this.id;
6184 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6187 this.el.select('tfoot tr td').first().addClass('hide');
6191 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6193 this.store.on('load', this.onLoad, this);
6194 this.store.on('beforeload', this.onBeforeLoad, this);
6195 this.store.on('update', this.onUpdate, this);
6196 this.store.on('add', this.onAdd, this);
6197 this.store.on("clear", this.clear, this);
6199 this.el.on("contextmenu", this.onContextMenu, this);
6201 this.mainBody.on('scroll', this.onBodyScroll, this);
6203 this.cm.on("headerchange", this.onHeaderChange, this);
6205 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6209 onContextMenu : function(e, t)
6211 this.processEvent("contextmenu", e);
6214 processEvent : function(name, e)
6216 if (name != 'touchstart' ) {
6217 this.fireEvent(name, e);
6220 var t = e.getTarget();
6222 var cell = Roo.get(t);
6228 if(cell.findParent('tfoot', false, true)){
6232 if(cell.findParent('thead', false, true)){
6234 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6235 cell = Roo.get(t).findParent('th', false, true);
6237 Roo.log("failed to find th in thead?");
6238 Roo.log(e.getTarget());
6243 var cellIndex = cell.dom.cellIndex;
6245 var ename = name == 'touchstart' ? 'click' : name;
6246 this.fireEvent("header" + ename, this, cellIndex, e);
6251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6252 cell = Roo.get(t).findParent('td', false, true);
6254 Roo.log("failed to find th in tbody?");
6255 Roo.log(e.getTarget());
6260 var row = cell.findParent('tr', false, true);
6261 var cellIndex = cell.dom.cellIndex;
6262 var rowIndex = row.dom.rowIndex - 1;
6266 this.fireEvent("row" + name, this, rowIndex, e);
6270 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6276 onMouseover : function(e, el)
6278 var cell = Roo.get(el);
6284 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6285 cell = cell.findParent('td', false, true);
6288 var row = cell.findParent('tr', false, true);
6289 var cellIndex = cell.dom.cellIndex;
6290 var rowIndex = row.dom.rowIndex - 1; // start from 0
6292 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6296 onMouseout : function(e, el)
6298 var cell = Roo.get(el);
6304 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6305 cell = cell.findParent('td', false, true);
6308 var row = cell.findParent('tr', false, true);
6309 var cellIndex = cell.dom.cellIndex;
6310 var rowIndex = row.dom.rowIndex - 1; // start from 0
6312 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6316 onClick : function(e, el)
6318 var cell = Roo.get(el);
6320 if(!cell || (!this.cellSelection && !this.rowSelection)){
6324 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6325 cell = cell.findParent('td', false, true);
6328 if(!cell || typeof(cell) == 'undefined'){
6332 var row = cell.findParent('tr', false, true);
6334 if(!row || typeof(row) == 'undefined'){
6338 var cellIndex = cell.dom.cellIndex;
6339 var rowIndex = this.getRowIndex(row);
6341 // why??? - should these not be based on SelectionModel?
6342 if(this.cellSelection){
6343 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6346 if(this.rowSelection){
6347 this.fireEvent('rowclick', this, row, rowIndex, e);
6353 onDblClick : function(e,el)
6355 var cell = Roo.get(el);
6357 if(!cell || (!this.cellSelection && !this.rowSelection)){
6361 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6362 cell = cell.findParent('td', false, true);
6365 if(!cell || typeof(cell) == 'undefined'){
6369 var row = cell.findParent('tr', false, true);
6371 if(!row || typeof(row) == 'undefined'){
6375 var cellIndex = cell.dom.cellIndex;
6376 var rowIndex = this.getRowIndex(row);
6378 if(this.cellSelection){
6379 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6382 if(this.rowSelection){
6383 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6387 sort : function(e,el)
6389 var col = Roo.get(el);
6391 if(!col.hasClass('sortable')){
6395 var sort = col.attr('sort');
6398 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6402 this.store.sortInfo = {field : sort, direction : dir};
6405 Roo.log("calling footer first");
6406 this.footer.onClick('first');
6409 this.store.load({ params : { start : 0 } });
6413 renderHeader : function()
6421 this.totalWidth = 0;
6423 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6425 var config = cm.config[i];
6429 cls : 'x-hcol-' + i,
6431 html: cm.getColumnHeader(i)
6436 if(typeof(config.sortable) != 'undefined' && config.sortable){
6438 c.html = '<i class="glyphicon"></i>' + c.html;
6441 if(typeof(config.lgHeader) != 'undefined'){
6442 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6445 if(typeof(config.mdHeader) != 'undefined'){
6446 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6449 if(typeof(config.smHeader) != 'undefined'){
6450 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6453 if(typeof(config.xsHeader) != 'undefined'){
6454 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6461 if(typeof(config.tooltip) != 'undefined'){
6462 c.tooltip = config.tooltip;
6465 if(typeof(config.colspan) != 'undefined'){
6466 c.colspan = config.colspan;
6469 if(typeof(config.hidden) != 'undefined' && config.hidden){
6470 c.style += ' display:none;';
6473 if(typeof(config.dataIndex) != 'undefined'){
6474 c.sort = config.dataIndex;
6479 if(typeof(config.align) != 'undefined' && config.align.length){
6480 c.style += ' text-align:' + config.align + ';';
6483 if(typeof(config.width) != 'undefined'){
6484 c.style += ' width:' + config.width + 'px;';
6485 this.totalWidth += config.width;
6487 this.totalWidth += 100; // assume minimum of 100 per column?
6490 if(typeof(config.cls) != 'undefined'){
6491 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6494 ['xs','sm','md','lg'].map(function(size){
6496 if(typeof(config[size]) == 'undefined'){
6500 if (!config[size]) { // 0 = hidden
6501 c.cls += ' hidden-' + size;
6505 c.cls += ' col-' + size + '-' + config[size];
6515 renderBody : function()
6525 colspan : this.cm.getColumnCount()
6535 renderFooter : function()
6545 colspan : this.cm.getColumnCount()
6559 // Roo.log('ds onload');
6564 var ds = this.store;
6566 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6567 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6568 if (_this.store.sortInfo) {
6570 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6571 e.select('i', true).addClass(['glyphicon-arrow-up']);
6574 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6575 e.select('i', true).addClass(['glyphicon-arrow-down']);
6580 var tbody = this.mainBody;
6582 if(ds.getCount() > 0){
6583 ds.data.each(function(d,rowIndex){
6584 var row = this.renderRow(cm, ds, rowIndex);
6586 tbody.createChild(row);
6590 if(row.cellObjects.length){
6591 Roo.each(row.cellObjects, function(r){
6592 _this.renderCellObject(r);
6599 Roo.each(this.el.select('tbody td', true).elements, function(e){
6600 e.on('mouseover', _this.onMouseover, _this);
6603 Roo.each(this.el.select('tbody td', true).elements, function(e){
6604 e.on('mouseout', _this.onMouseout, _this);
6606 this.fireEvent('rowsrendered', this);
6607 //if(this.loadMask){
6608 // this.maskEl.hide();
6615 onUpdate : function(ds,record)
6617 this.refreshRow(record);
6621 onRemove : function(ds, record, index, isUpdate){
6622 if(isUpdate !== true){
6623 this.fireEvent("beforerowremoved", this, index, record);
6625 var bt = this.mainBody.dom;
6627 var rows = this.el.select('tbody > tr', true).elements;
6629 if(typeof(rows[index]) != 'undefined'){
6630 bt.removeChild(rows[index].dom);
6633 // if(bt.rows[index]){
6634 // bt.removeChild(bt.rows[index]);
6637 if(isUpdate !== true){
6638 //this.stripeRows(index);
6639 //this.syncRowHeights(index, index);
6641 this.fireEvent("rowremoved", this, index, record);
6645 onAdd : function(ds, records, rowIndex)
6647 //Roo.log('on Add called');
6648 // - note this does not handle multiple adding very well..
6649 var bt = this.mainBody.dom;
6650 for (var i =0 ; i < records.length;i++) {
6651 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6652 //Roo.log(records[i]);
6653 //Roo.log(this.store.getAt(rowIndex+i));
6654 this.insertRow(this.store, rowIndex + i, false);
6661 refreshRow : function(record){
6662 var ds = this.store, index;
6663 if(typeof record == 'number'){
6665 record = ds.getAt(index);
6667 index = ds.indexOf(record);
6669 this.insertRow(ds, index, true);
6671 this.onRemove(ds, record, index+1, true);
6673 //this.syncRowHeights(index, index);
6675 this.fireEvent("rowupdated", this, index, record);
6678 insertRow : function(dm, rowIndex, isUpdate){
6681 this.fireEvent("beforerowsinserted", this, rowIndex);
6683 //var s = this.getScrollState();
6684 var row = this.renderRow(this.cm, this.store, rowIndex);
6685 // insert before rowIndex..
6686 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6690 if(row.cellObjects.length){
6691 Roo.each(row.cellObjects, function(r){
6692 _this.renderCellObject(r);
6697 this.fireEvent("rowsinserted", this, rowIndex);
6698 //this.syncRowHeights(firstRow, lastRow);
6699 //this.stripeRows(firstRow);
6706 getRowDom : function(rowIndex)
6708 var rows = this.el.select('tbody > tr', true).elements;
6710 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6713 // returns the object tree for a tr..
6716 renderRow : function(cm, ds, rowIndex)
6718 var d = ds.getAt(rowIndex);
6722 cls : 'x-row-' + rowIndex,
6726 var cellObjects = [];
6728 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6729 var config = cm.config[i];
6731 var renderer = cm.getRenderer(i);
6735 if(typeof(renderer) !== 'undefined'){
6736 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6738 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6739 // and are rendered into the cells after the row is rendered - using the id for the element.
6741 if(typeof(value) === 'object'){
6751 rowIndex : rowIndex,
6756 this.fireEvent('rowclass', this, rowcfg);
6760 cls : rowcfg.rowClass + ' x-col-' + i,
6762 html: (typeof(value) === 'object') ? '' : value
6769 if(typeof(config.colspan) != 'undefined'){
6770 td.colspan = config.colspan;
6773 if(typeof(config.hidden) != 'undefined' && config.hidden){
6774 td.style += ' display:none;';
6777 if(typeof(config.align) != 'undefined' && config.align.length){
6778 td.style += ' text-align:' + config.align + ';';
6781 if(typeof(config.width) != 'undefined'){
6782 td.style += ' width:' + config.width + 'px;';
6785 if(typeof(config.cursor) != 'undefined'){
6786 td.style += ' cursor:' + config.cursor + ';';
6789 if(typeof(config.cls) != 'undefined'){
6790 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6793 ['xs','sm','md','lg'].map(function(size){
6795 if(typeof(config[size]) == 'undefined'){
6799 if (!config[size]) { // 0 = hidden
6800 td.cls += ' hidden-' + size;
6804 td.cls += ' col-' + size + '-' + config[size];
6812 row.cellObjects = cellObjects;
6820 onBeforeLoad : function()
6822 //Roo.log('ds onBeforeLoad');
6826 //if(this.loadMask){
6827 // this.maskEl.show();
6835 this.el.select('tbody', true).first().dom.innerHTML = '';
6838 * Show or hide a row.
6839 * @param {Number} rowIndex to show or hide
6840 * @param {Boolean} state hide
6842 setRowVisibility : function(rowIndex, state)
6844 var bt = this.mainBody.dom;
6846 var rows = this.el.select('tbody > tr', true).elements;
6848 if(typeof(rows[rowIndex]) == 'undefined'){
6851 rows[rowIndex].dom.style.display = state ? '' : 'none';
6855 getSelectionModel : function(){
6857 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6859 return this.selModel;
6862 * Render the Roo.bootstrap object from renderder
6864 renderCellObject : function(r)
6868 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6870 var t = r.cfg.render(r.container);
6873 Roo.each(r.cfg.cn, function(c){
6875 container: t.getChildContainer(),
6878 _this.renderCellObject(child);
6883 getRowIndex : function(row)
6887 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6898 * Returns the grid's underlying element = used by panel.Grid
6899 * @return {Element} The element
6901 getGridEl : function(){
6905 * Forces a resize - used by panel.Grid
6906 * @return {Element} The element
6908 autoSize : function()
6910 //var ctr = Roo.get(this.container.dom.parentElement);
6911 var ctr = Roo.get(this.el.dom);
6913 var thd = this.getGridEl().select('thead',true).first();
6914 var tbd = this.getGridEl().select('tbody', true).first();
6915 var tfd = this.getGridEl().select('tfoot', true).first();
6917 var cw = ctr.getWidth();
6921 tbd.setSize(ctr.getWidth(),
6922 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6924 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6927 cw = Math.max(cw, this.totalWidth);
6928 this.getGridEl().select('tr',true).setWidth(cw);
6929 // resize 'expandable coloumn?
6931 return; // we doe not have a view in this design..
6934 onBodyScroll: function()
6936 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6938 this.mainHead.setStyle({
6939 'position' : 'relative',
6940 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6946 var scrollHeight = this.mainBody.dom.scrollHeight;
6948 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6950 var height = this.mainBody.getHeight();
6952 if(scrollHeight - height == scrollTop) {
6954 var total = this.ds.getTotalCount();
6956 if(this.footer.cursor + this.footer.pageSize < total){
6958 this.footer.ds.load({
6960 start : this.footer.cursor + this.footer.pageSize,
6961 limit : this.footer.pageSize
6971 onHeaderChange : function()
6973 var header = this.renderHeader();
6974 var table = this.el.select('table', true).first();
6976 this.mainHead.remove();
6977 this.mainHead = table.createChild(header, this.mainBody, false);
6980 onHiddenChange : function(colModel, colIndex, hidden)
6982 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6983 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6985 this.CSS.updateRule(thSelector, "display", "");
6986 this.CSS.updateRule(tdSelector, "display", "");
6989 this.CSS.updateRule(thSelector, "display", "none");
6990 this.CSS.updateRule(tdSelector, "display", "none");
6993 this.onHeaderChange();
7010 * @class Roo.bootstrap.TableCell
7011 * @extends Roo.bootstrap.Component
7012 * Bootstrap TableCell class
7013 * @cfg {String} html cell contain text
7014 * @cfg {String} cls cell class
7015 * @cfg {String} tag cell tag (td|th) default td
7016 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7017 * @cfg {String} align Aligns the content in a cell
7018 * @cfg {String} axis Categorizes cells
7019 * @cfg {String} bgcolor Specifies the background color of a cell
7020 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7021 * @cfg {Number} colspan Specifies the number of columns a cell should span
7022 * @cfg {String} headers Specifies one or more header cells a cell is related to
7023 * @cfg {Number} height Sets the height of a cell
7024 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7025 * @cfg {Number} rowspan Sets the number of rows a cell should span
7026 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7027 * @cfg {String} valign Vertical aligns the content in a cell
7028 * @cfg {Number} width Specifies the width of a cell
7031 * Create a new TableCell
7032 * @param {Object} config The config object
7035 Roo.bootstrap.TableCell = function(config){
7036 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7039 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7059 getAutoCreate : function(){
7060 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7080 cfg.align=this.align
7086 cfg.bgcolor=this.bgcolor
7089 cfg.charoff=this.charoff
7092 cfg.colspan=this.colspan
7095 cfg.headers=this.headers
7098 cfg.height=this.height
7101 cfg.nowrap=this.nowrap
7104 cfg.rowspan=this.rowspan
7107 cfg.scope=this.scope
7110 cfg.valign=this.valign
7113 cfg.width=this.width
7132 * @class Roo.bootstrap.TableRow
7133 * @extends Roo.bootstrap.Component
7134 * Bootstrap TableRow class
7135 * @cfg {String} cls row class
7136 * @cfg {String} align Aligns the content in a table row
7137 * @cfg {String} bgcolor Specifies a background color for a table row
7138 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7139 * @cfg {String} valign Vertical aligns the content in a table row
7142 * Create a new TableRow
7143 * @param {Object} config The config object
7146 Roo.bootstrap.TableRow = function(config){
7147 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7150 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7158 getAutoCreate : function(){
7159 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7169 cfg.align = this.align;
7172 cfg.bgcolor = this.bgcolor;
7175 cfg.charoff = this.charoff;
7178 cfg.valign = this.valign;
7196 * @class Roo.bootstrap.TableBody
7197 * @extends Roo.bootstrap.Component
7198 * Bootstrap TableBody class
7199 * @cfg {String} cls element class
7200 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7201 * @cfg {String} align Aligns the content inside the element
7202 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7203 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7206 * Create a new TableBody
7207 * @param {Object} config The config object
7210 Roo.bootstrap.TableBody = function(config){
7211 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7214 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7222 getAutoCreate : function(){
7223 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7237 cfg.align = this.align;
7240 cfg.charoff = this.charoff;
7243 cfg.valign = this.valign;
7250 // initEvents : function()
7257 // this.store = Roo.factory(this.store, Roo.data);
7258 // this.store.on('load', this.onLoad, this);
7260 // this.store.load();
7264 // onLoad: function ()
7266 // this.fireEvent('load', this);
7276 * Ext JS Library 1.1.1
7277 * Copyright(c) 2006-2007, Ext JS, LLC.
7279 * Originally Released Under LGPL - original licence link has changed is not relivant.
7282 * <script type="text/javascript">
7285 // as we use this in bootstrap.
7286 Roo.namespace('Roo.form');
7288 * @class Roo.form.Action
7289 * Internal Class used to handle form actions
7291 * @param {Roo.form.BasicForm} el The form element or its id
7292 * @param {Object} config Configuration options
7297 // define the action interface
7298 Roo.form.Action = function(form, options){
7300 this.options = options || {};
7303 * Client Validation Failed
7306 Roo.form.Action.CLIENT_INVALID = 'client';
7308 * Server Validation Failed
7311 Roo.form.Action.SERVER_INVALID = 'server';
7313 * Connect to Server Failed
7316 Roo.form.Action.CONNECT_FAILURE = 'connect';
7318 * Reading Data from Server Failed
7321 Roo.form.Action.LOAD_FAILURE = 'load';
7323 Roo.form.Action.prototype = {
7325 failureType : undefined,
7326 response : undefined,
7330 run : function(options){
7335 success : function(response){
7340 handleResponse : function(response){
7344 // default connection failure
7345 failure : function(response){
7347 this.response = response;
7348 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7349 this.form.afterAction(this, false);
7352 processResponse : function(response){
7353 this.response = response;
7354 if(!response.responseText){
7357 this.result = this.handleResponse(response);
7361 // utility functions used internally
7362 getUrl : function(appendParams){
7363 var url = this.options.url || this.form.url || this.form.el.dom.action;
7365 var p = this.getParams();
7367 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7373 getMethod : function(){
7374 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7377 getParams : function(){
7378 var bp = this.form.baseParams;
7379 var p = this.options.params;
7381 if(typeof p == "object"){
7382 p = Roo.urlEncode(Roo.applyIf(p, bp));
7383 }else if(typeof p == 'string' && bp){
7384 p += '&' + Roo.urlEncode(bp);
7387 p = Roo.urlEncode(bp);
7392 createCallback : function(){
7394 success: this.success,
7395 failure: this.failure,
7397 timeout: (this.form.timeout*1000),
7398 upload: this.form.fileUpload ? this.success : undefined
7403 Roo.form.Action.Submit = function(form, options){
7404 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7407 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7410 haveProgress : false,
7411 uploadComplete : false,
7413 // uploadProgress indicator.
7414 uploadProgress : function()
7416 if (!this.form.progressUrl) {
7420 if (!this.haveProgress) {
7421 Roo.MessageBox.progress("Uploading", "Uploading");
7423 if (this.uploadComplete) {
7424 Roo.MessageBox.hide();
7428 this.haveProgress = true;
7430 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7432 var c = new Roo.data.Connection();
7434 url : this.form.progressUrl,
7439 success : function(req){
7440 //console.log(data);
7444 rdata = Roo.decode(req.responseText)
7446 Roo.log("Invalid data from server..");
7450 if (!rdata || !rdata.success) {
7452 Roo.MessageBox.alert(Roo.encode(rdata));
7455 var data = rdata.data;
7457 if (this.uploadComplete) {
7458 Roo.MessageBox.hide();
7463 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7464 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7467 this.uploadProgress.defer(2000,this);
7470 failure: function(data) {
7471 Roo.log('progress url failed ');
7482 // run get Values on the form, so it syncs any secondary forms.
7483 this.form.getValues();
7485 var o = this.options;
7486 var method = this.getMethod();
7487 var isPost = method == 'POST';
7488 if(o.clientValidation === false || this.form.isValid()){
7490 if (this.form.progressUrl) {
7491 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7492 (new Date() * 1) + '' + Math.random());
7497 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7498 form:this.form.el.dom,
7499 url:this.getUrl(!isPost),
7501 params:isPost ? this.getParams() : null,
7502 isUpload: this.form.fileUpload
7505 this.uploadProgress();
7507 }else if (o.clientValidation !== false){ // client validation failed
7508 this.failureType = Roo.form.Action.CLIENT_INVALID;
7509 this.form.afterAction(this, false);
7513 success : function(response)
7515 this.uploadComplete= true;
7516 if (this.haveProgress) {
7517 Roo.MessageBox.hide();
7521 var result = this.processResponse(response);
7522 if(result === true || result.success){
7523 this.form.afterAction(this, true);
7527 this.form.markInvalid(result.errors);
7528 this.failureType = Roo.form.Action.SERVER_INVALID;
7530 this.form.afterAction(this, false);
7532 failure : function(response)
7534 this.uploadComplete= true;
7535 if (this.haveProgress) {
7536 Roo.MessageBox.hide();
7539 this.response = response;
7540 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7541 this.form.afterAction(this, false);
7544 handleResponse : function(response){
7545 if(this.form.errorReader){
7546 var rs = this.form.errorReader.read(response);
7549 for(var i = 0, len = rs.records.length; i < len; i++) {
7550 var r = rs.records[i];
7554 if(errors.length < 1){
7558 success : rs.success,
7564 ret = Roo.decode(response.responseText);
7568 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7578 Roo.form.Action.Load = function(form, options){
7579 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7580 this.reader = this.form.reader;
7583 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7588 Roo.Ajax.request(Roo.apply(
7589 this.createCallback(), {
7590 method:this.getMethod(),
7591 url:this.getUrl(false),
7592 params:this.getParams()
7596 success : function(response){
7598 var result = this.processResponse(response);
7599 if(result === true || !result.success || !result.data){
7600 this.failureType = Roo.form.Action.LOAD_FAILURE;
7601 this.form.afterAction(this, false);
7604 this.form.clearInvalid();
7605 this.form.setValues(result.data);
7606 this.form.afterAction(this, true);
7609 handleResponse : function(response){
7610 if(this.form.reader){
7611 var rs = this.form.reader.read(response);
7612 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7614 success : rs.success,
7618 return Roo.decode(response.responseText);
7622 Roo.form.Action.ACTION_TYPES = {
7623 'load' : Roo.form.Action.Load,
7624 'submit' : Roo.form.Action.Submit
7633 * @class Roo.bootstrap.Form
7634 * @extends Roo.bootstrap.Component
7635 * Bootstrap Form class
7636 * @cfg {String} method GET | POST (default POST)
7637 * @cfg {String} labelAlign top | left (default top)
7638 * @cfg {String} align left | right - for navbars
7639 * @cfg {Boolean} loadMask load mask when submit (default true)
7644 * @param {Object} config The config object
7648 Roo.bootstrap.Form = function(config){
7650 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7652 Roo.bootstrap.Form.popover.apply();
7656 * @event clientvalidation
7657 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7658 * @param {Form} this
7659 * @param {Boolean} valid true if the form has passed client-side validation
7661 clientvalidation: true,
7663 * @event beforeaction
7664 * Fires before any action is performed. Return false to cancel the action.
7665 * @param {Form} this
7666 * @param {Action} action The action to be performed
7670 * @event actionfailed
7671 * Fires when an action fails.
7672 * @param {Form} this
7673 * @param {Action} action The action that failed
7675 actionfailed : true,
7677 * @event actioncomplete
7678 * Fires when an action is completed.
7679 * @param {Form} this
7680 * @param {Action} action The action that completed
7682 actioncomplete : true
7686 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7689 * @cfg {String} method
7690 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7695 * The URL to use for form actions if one isn't supplied in the action options.
7698 * @cfg {Boolean} fileUpload
7699 * Set to true if this form is a file upload.
7703 * @cfg {Object} baseParams
7704 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7708 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7712 * @cfg {Sting} align (left|right) for navbar forms
7717 activeAction : null,
7720 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7721 * element by passing it or its id or mask the form itself by passing in true.
7724 waitMsgTarget : false,
7729 * @cfg {Boolean} errorMask (true|false) default false
7734 * @cfg {Number} maskOffset Default 100
7739 * @cfg {Boolean} maskBody
7743 getAutoCreate : function(){
7747 method : this.method || 'POST',
7748 id : this.id || Roo.id(),
7751 if (this.parent().xtype.match(/^Nav/)) {
7752 cfg.cls = 'navbar-form navbar-' + this.align;
7756 if (this.labelAlign == 'left' ) {
7757 cfg.cls += ' form-horizontal';
7763 initEvents : function()
7765 this.el.on('submit', this.onSubmit, this);
7766 // this was added as random key presses on the form where triggering form submit.
7767 this.el.on('keypress', function(e) {
7768 if (e.getCharCode() != 13) {
7771 // we might need to allow it for textareas.. and some other items.
7772 // check e.getTarget().
7774 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7778 Roo.log("keypress blocked");
7786 onSubmit : function(e){
7791 * Returns true if client-side validation on the form is successful.
7794 isValid : function(){
7795 var items = this.getItems();
7799 items.each(function(f){
7806 if(!target && f.el.isVisible(true)){
7812 if(this.errorMask && !valid){
7813 Roo.bootstrap.Form.popover.mask(this, target);
7820 * Returns true if any fields in this form have changed since their original load.
7823 isDirty : function(){
7825 var items = this.getItems();
7826 items.each(function(f){
7836 * Performs a predefined action (submit or load) or custom actions you define on this form.
7837 * @param {String} actionName The name of the action type
7838 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7839 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7840 * accept other config options):
7842 Property Type Description
7843 ---------------- --------------- ----------------------------------------------------------------------------------
7844 url String The url for the action (defaults to the form's url)
7845 method String The form method to use (defaults to the form's method, or POST if not defined)
7846 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7847 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7848 validate the form on the client (defaults to false)
7850 * @return {BasicForm} this
7852 doAction : function(action, options){
7853 if(typeof action == 'string'){
7854 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7856 if(this.fireEvent('beforeaction', this, action) !== false){
7857 this.beforeAction(action);
7858 action.run.defer(100, action);
7864 beforeAction : function(action){
7865 var o = action.options;
7870 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7872 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7875 // not really supported yet.. ??
7877 //if(this.waitMsgTarget === true){
7878 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7879 //}else if(this.waitMsgTarget){
7880 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7881 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7883 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7889 afterAction : function(action, success){
7890 this.activeAction = null;
7891 var o = action.options;
7896 Roo.get(document.body).unmask();
7902 //if(this.waitMsgTarget === true){
7903 // this.el.unmask();
7904 //}else if(this.waitMsgTarget){
7905 // this.waitMsgTarget.unmask();
7907 // Roo.MessageBox.updateProgress(1);
7908 // Roo.MessageBox.hide();
7915 Roo.callback(o.success, o.scope, [this, action]);
7916 this.fireEvent('actioncomplete', this, action);
7920 // failure condition..
7921 // we have a scenario where updates need confirming.
7922 // eg. if a locking scenario exists..
7923 // we look for { errors : { needs_confirm : true }} in the response.
7925 (typeof(action.result) != 'undefined') &&
7926 (typeof(action.result.errors) != 'undefined') &&
7927 (typeof(action.result.errors.needs_confirm) != 'undefined')
7930 Roo.log("not supported yet");
7933 Roo.MessageBox.confirm(
7934 "Change requires confirmation",
7935 action.result.errorMsg,
7940 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7950 Roo.callback(o.failure, o.scope, [this, action]);
7951 // show an error message if no failed handler is set..
7952 if (!this.hasListener('actionfailed')) {
7953 Roo.log("need to add dialog support");
7955 Roo.MessageBox.alert("Error",
7956 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7957 action.result.errorMsg :
7958 "Saving Failed, please check your entries or try again"
7963 this.fireEvent('actionfailed', this, action);
7968 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7969 * @param {String} id The value to search for
7972 findField : function(id){
7973 var items = this.getItems();
7974 var field = items.get(id);
7976 items.each(function(f){
7977 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7984 return field || null;
7987 * Mark fields in this form invalid in bulk.
7988 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7989 * @return {BasicForm} this
7991 markInvalid : function(errors){
7992 if(errors instanceof Array){
7993 for(var i = 0, len = errors.length; i < len; i++){
7994 var fieldError = errors[i];
7995 var f = this.findField(fieldError.id);
7997 f.markInvalid(fieldError.msg);
8003 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8004 field.markInvalid(errors[id]);
8008 //Roo.each(this.childForms || [], function (f) {
8009 // f.markInvalid(errors);
8016 * Set values for fields in this form in bulk.
8017 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8018 * @return {BasicForm} this
8020 setValues : function(values){
8021 if(values instanceof Array){ // array of objects
8022 for(var i = 0, len = values.length; i < len; i++){
8024 var f = this.findField(v.id);
8026 f.setValue(v.value);
8027 if(this.trackResetOnLoad){
8028 f.originalValue = f.getValue();
8032 }else{ // object hash
8035 if(typeof values[id] != 'function' && (field = this.findField(id))){
8037 if (field.setFromData &&
8039 field.displayField &&
8040 // combos' with local stores can
8041 // be queried via setValue()
8042 // to set their value..
8043 (field.store && !field.store.isLocal)
8047 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8048 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8049 field.setFromData(sd);
8051 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8053 field.setFromData(values);
8056 field.setValue(values[id]);
8060 if(this.trackResetOnLoad){
8061 field.originalValue = field.getValue();
8067 //Roo.each(this.childForms || [], function (f) {
8068 // f.setValues(values);
8075 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8076 * they are returned as an array.
8077 * @param {Boolean} asString
8080 getValues : function(asString){
8081 //if (this.childForms) {
8082 // copy values from the child forms
8083 // Roo.each(this.childForms, function (f) {
8084 // this.setValues(f.getValues());
8090 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8091 if(asString === true){
8094 return Roo.urlDecode(fs);
8098 * Returns the fields in this form as an object with key/value pairs.
8099 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8102 getFieldValues : function(with_hidden)
8104 var items = this.getItems();
8106 items.each(function(f){
8112 var v = f.getValue();
8114 if (f.inputType =='radio') {
8115 if (typeof(ret[f.getName()]) == 'undefined') {
8116 ret[f.getName()] = ''; // empty..
8119 if (!f.el.dom.checked) {
8127 if(f.xtype == 'MoneyField'){
8128 ret[f.currencyName] = f.getCurrency();
8131 // not sure if this supported any more..
8132 if ((typeof(v) == 'object') && f.getRawValue) {
8133 v = f.getRawValue() ; // dates..
8135 // combo boxes where name != hiddenName...
8136 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8137 ret[f.name] = f.getRawValue();
8139 ret[f.getName()] = v;
8146 * Clears all invalid messages in this form.
8147 * @return {BasicForm} this
8149 clearInvalid : function(){
8150 var items = this.getItems();
8152 items.each(function(f){
8161 * @return {BasicForm} this
8164 var items = this.getItems();
8165 items.each(function(f){
8169 Roo.each(this.childForms || [], function (f) {
8177 getItems : function()
8179 var r=new Roo.util.MixedCollection(false, function(o){
8180 return o.id || (o.id = Roo.id());
8182 var iter = function(el) {
8189 Roo.each(el.items,function(e) {
8198 hideFields : function(items)
8200 Roo.each(items, function(i){
8202 var f = this.findField(i);
8208 if(f.xtype == 'DateField'){
8209 f.setVisible(false);
8218 showFields : function(items)
8220 Roo.each(items, function(i){
8222 var f = this.findField(i);
8228 if(f.xtype == 'DateField'){
8240 Roo.apply(Roo.bootstrap.Form, {
8267 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8268 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8269 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8270 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8273 this.maskEl.top.enableDisplayMode("block");
8274 this.maskEl.left.enableDisplayMode("block");
8275 this.maskEl.bottom.enableDisplayMode("block");
8276 this.maskEl.right.enableDisplayMode("block");
8278 this.toolTip = new Roo.bootstrap.Tooltip({
8279 cls : 'roo-form-error-popover',
8281 'left' : ['r-l', [-2,0], 'right'],
8282 'right' : ['l-r', [2,0], 'left'],
8283 'bottom' : ['tl-bl', [0,2], 'top'],
8284 'top' : [ 'bl-tl', [0,-2], 'bottom']
8288 this.toolTip.render(Roo.get(document.body));
8290 this.toolTip.el.enableDisplayMode("block");
8292 Roo.get(document.body).on('click', function(){
8296 Roo.get(document.body).on('touchstart', function(){
8300 this.isApplied = true
8303 mask : function(form, target)
8307 this.target = target;
8309 if(!this.form.errorMask || !target.el){
8313 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8315 Roo.log(scrollable);
8317 var ot = this.target.el.calcOffsetsTo(scrollable);
8319 var scrollTo = ot[1] - this.form.maskOffset;
8321 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8323 scrollable.scrollTo('top', scrollTo);
8325 var box = this.target.el.getBox();
8327 var zIndex = Roo.bootstrap.Modal.zIndex++;
8330 this.maskEl.top.setStyle('position', 'absolute');
8331 this.maskEl.top.setStyle('z-index', zIndex);
8332 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8333 this.maskEl.top.setLeft(0);
8334 this.maskEl.top.setTop(0);
8335 this.maskEl.top.show();
8337 this.maskEl.left.setStyle('position', 'absolute');
8338 this.maskEl.left.setStyle('z-index', zIndex);
8339 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8340 this.maskEl.left.setLeft(0);
8341 this.maskEl.left.setTop(box.y - this.padding);
8342 this.maskEl.left.show();
8344 this.maskEl.bottom.setStyle('position', 'absolute');
8345 this.maskEl.bottom.setStyle('z-index', zIndex);
8346 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8347 this.maskEl.bottom.setLeft(0);
8348 this.maskEl.bottom.setTop(box.bottom + this.padding);
8349 this.maskEl.bottom.show();
8351 this.maskEl.right.setStyle('position', 'absolute');
8352 this.maskEl.right.setStyle('z-index', zIndex);
8353 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8354 this.maskEl.right.setLeft(box.right + this.padding);
8355 this.maskEl.right.setTop(box.y - this.padding);
8356 this.maskEl.right.show();
8358 this.toolTip.bindEl = this.target.el;
8360 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8362 var tip = this.target.blankText;
8364 if(this.target.getValue() !== '' ) {
8366 if (this.target.invalidText.length) {
8367 tip = this.target.invalidText;
8368 } else if (this.target.regexText.length){
8369 tip = this.target.regexText;
8373 this.toolTip.show(tip);
8375 this.intervalID = window.setInterval(function() {
8376 Roo.bootstrap.Form.popover.unmask();
8379 window.onwheel = function(){ return false;};
8381 (function(){ this.isMasked = true; }).defer(500, this);
8387 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8391 this.maskEl.top.setStyle('position', 'absolute');
8392 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8393 this.maskEl.top.hide();
8395 this.maskEl.left.setStyle('position', 'absolute');
8396 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8397 this.maskEl.left.hide();
8399 this.maskEl.bottom.setStyle('position', 'absolute');
8400 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8401 this.maskEl.bottom.hide();
8403 this.maskEl.right.setStyle('position', 'absolute');
8404 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8405 this.maskEl.right.hide();
8407 this.toolTip.hide();
8409 this.toolTip.el.hide();
8411 window.onwheel = function(){ return true;};
8413 if(this.intervalID){
8414 window.clearInterval(this.intervalID);
8415 this.intervalID = false;
8418 this.isMasked = false;
8428 * Ext JS Library 1.1.1
8429 * Copyright(c) 2006-2007, Ext JS, LLC.
8431 * Originally Released Under LGPL - original licence link has changed is not relivant.
8434 * <script type="text/javascript">
8437 * @class Roo.form.VTypes
8438 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8441 Roo.form.VTypes = function(){
8442 // closure these in so they are only created once.
8443 var alpha = /^[a-zA-Z_]+$/;
8444 var alphanum = /^[a-zA-Z0-9_]+$/;
8445 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8446 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8448 // All these messages and functions are configurable
8451 * The function used to validate email addresses
8452 * @param {String} value The email address
8454 'email' : function(v){
8455 return email.test(v);
8458 * The error text to display when the email validation function returns false
8461 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8463 * The keystroke filter mask to be applied on email input
8466 'emailMask' : /[a-z0-9_\.\-@]/i,
8469 * The function used to validate URLs
8470 * @param {String} value The URL
8472 'url' : function(v){
8476 * The error text to display when the url validation function returns false
8479 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8482 * The function used to validate alpha values
8483 * @param {String} value The value
8485 'alpha' : function(v){
8486 return alpha.test(v);
8489 * The error text to display when the alpha validation function returns false
8492 'alphaText' : 'This field should only contain letters and _',
8494 * The keystroke filter mask to be applied on alpha input
8497 'alphaMask' : /[a-z_]/i,
8500 * The function used to validate alphanumeric values
8501 * @param {String} value The value
8503 'alphanum' : function(v){
8504 return alphanum.test(v);
8507 * The error text to display when the alphanumeric validation function returns false
8510 'alphanumText' : 'This field should only contain letters, numbers and _',
8512 * The keystroke filter mask to be applied on alphanumeric input
8515 'alphanumMask' : /[a-z0-9_]/i
8525 * @class Roo.bootstrap.Input
8526 * @extends Roo.bootstrap.Component
8527 * Bootstrap Input class
8528 * @cfg {Boolean} disabled is it disabled
8529 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8530 * @cfg {String} name name of the input
8531 * @cfg {string} fieldLabel - the label associated
8532 * @cfg {string} placeholder - placeholder to put in text.
8533 * @cfg {string} before - input group add on before
8534 * @cfg {string} after - input group add on after
8535 * @cfg {string} size - (lg|sm) or leave empty..
8536 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8537 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8538 * @cfg {Number} md colspan out of 12 for computer-sized screens
8539 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8540 * @cfg {string} value default value of the input
8541 * @cfg {Number} labelWidth set the width of label
8542 * @cfg {Number} labellg set the width of label (1-12)
8543 * @cfg {Number} labelmd set the width of label (1-12)
8544 * @cfg {Number} labelsm set the width of label (1-12)
8545 * @cfg {Number} labelxs set the width of label (1-12)
8546 * @cfg {String} labelAlign (top|left)
8547 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8548 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8549 * @cfg {String} indicatorpos (left|right) default left
8550 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8551 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8553 * @cfg {String} align (left|center|right) Default left
8554 * @cfg {Boolean} forceFeedback (true|false) Default false
8557 * Create a new Input
8558 * @param {Object} config The config object
8561 Roo.bootstrap.Input = function(config){
8563 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8568 * Fires when this field receives input focus.
8569 * @param {Roo.form.Field} this
8574 * Fires when this field loses input focus.
8575 * @param {Roo.form.Field} this
8580 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8581 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8582 * @param {Roo.form.Field} this
8583 * @param {Roo.EventObject} e The event object
8588 * Fires just before the field blurs if the field value has changed.
8589 * @param {Roo.form.Field} this
8590 * @param {Mixed} newValue The new value
8591 * @param {Mixed} oldValue The original value
8596 * Fires after the field has been marked as invalid.
8597 * @param {Roo.form.Field} this
8598 * @param {String} msg The validation message
8603 * Fires after the field has been validated with no errors.
8604 * @param {Roo.form.Field} this
8609 * Fires after the key up
8610 * @param {Roo.form.Field} this
8611 * @param {Roo.EventObject} e The event Object
8617 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8619 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8620 automatic validation (defaults to "keyup").
8622 validationEvent : "keyup",
8624 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8626 validateOnBlur : true,
8628 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8630 validationDelay : 250,
8632 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8634 focusClass : "x-form-focus", // not needed???
8638 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8640 invalidClass : "has-warning",
8643 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8645 validClass : "has-success",
8648 * @cfg {Boolean} hasFeedback (true|false) default true
8653 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8655 invalidFeedbackClass : "glyphicon-warning-sign",
8658 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8660 validFeedbackClass : "glyphicon-ok",
8663 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8665 selectOnFocus : false,
8668 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8672 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8677 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8679 disableKeyFilter : false,
8682 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8686 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8690 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8692 blankText : "Please complete this mandatory field",
8695 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8699 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8701 maxLength : Number.MAX_VALUE,
8703 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8705 minLengthText : "The minimum length for this field is {0}",
8707 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8709 maxLengthText : "The maximum length for this field is {0}",
8713 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8714 * If available, this function will be called only after the basic validators all return true, and will be passed the
8715 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8719 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8720 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8721 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8725 * @cfg {String} regexText -- Depricated - use Invalid Text
8730 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8736 autocomplete: false,
8755 formatedValue : false,
8756 forceFeedback : false,
8758 indicatorpos : 'left',
8768 parentLabelAlign : function()
8771 while (parent.parent()) {
8772 parent = parent.parent();
8773 if (typeof(parent.labelAlign) !='undefined') {
8774 return parent.labelAlign;
8781 getAutoCreate : function()
8783 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8789 if(this.inputType != 'hidden'){
8790 cfg.cls = 'form-group' //input-group
8796 type : this.inputType,
8798 cls : 'form-control',
8799 placeholder : this.placeholder || '',
8800 autocomplete : this.autocomplete || 'new-password'
8803 if(this.capture.length){
8804 input.capture = this.capture;
8807 if(this.accept.length){
8808 input.accept = this.accept + "/*";
8812 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8815 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8816 input.maxLength = this.maxLength;
8819 if (this.disabled) {
8820 input.disabled=true;
8823 if (this.readOnly) {
8824 input.readonly=true;
8828 input.name = this.name;
8832 input.cls += ' input-' + this.size;
8836 ['xs','sm','md','lg'].map(function(size){
8837 if (settings[size]) {
8838 cfg.cls += ' col-' + size + '-' + settings[size];
8842 var inputblock = input;
8846 cls: 'glyphicon form-control-feedback'
8849 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8852 cls : 'has-feedback',
8860 if (this.before || this.after) {
8863 cls : 'input-group',
8867 if (this.before && typeof(this.before) == 'string') {
8869 inputblock.cn.push({
8871 cls : 'roo-input-before input-group-addon',
8875 if (this.before && typeof(this.before) == 'object') {
8876 this.before = Roo.factory(this.before);
8878 inputblock.cn.push({
8880 cls : 'roo-input-before input-group-' +
8881 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8885 inputblock.cn.push(input);
8887 if (this.after && typeof(this.after) == 'string') {
8888 inputblock.cn.push({
8890 cls : 'roo-input-after input-group-addon',
8894 if (this.after && typeof(this.after) == 'object') {
8895 this.after = Roo.factory(this.after);
8897 inputblock.cn.push({
8899 cls : 'roo-input-after input-group-' +
8900 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8905 inputblock.cls += ' has-feedback';
8906 inputblock.cn.push(feedback);
8910 if (align ==='left' && this.fieldLabel.length) {
8912 cfg.cls += ' roo-form-group-label-left';
8917 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8918 tooltip : 'This field is required'
8923 cls : 'control-label',
8924 html : this.fieldLabel
8935 var labelCfg = cfg.cn[1];
8936 var contentCfg = cfg.cn[2];
8938 if(this.indicatorpos == 'right'){
8943 cls : 'control-label',
8947 html : this.fieldLabel
8951 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8952 tooltip : 'This field is required'
8965 labelCfg = cfg.cn[0];
8966 contentCfg = cfg.cn[1];
8970 if(this.labelWidth > 12){
8971 labelCfg.style = "width: " + this.labelWidth + 'px';
8974 if(this.labelWidth < 13 && this.labelmd == 0){
8975 this.labelmd = this.labelWidth;
8978 if(this.labellg > 0){
8979 labelCfg.cls += ' col-lg-' + this.labellg;
8980 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8983 if(this.labelmd > 0){
8984 labelCfg.cls += ' col-md-' + this.labelmd;
8985 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8988 if(this.labelsm > 0){
8989 labelCfg.cls += ' col-sm-' + this.labelsm;
8990 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8993 if(this.labelxs > 0){
8994 labelCfg.cls += ' col-xs-' + this.labelxs;
8995 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8999 } else if ( this.fieldLabel.length) {
9004 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9005 tooltip : 'This field is required'
9009 //cls : 'input-group-addon',
9010 html : this.fieldLabel
9018 if(this.indicatorpos == 'right'){
9023 //cls : 'input-group-addon',
9024 html : this.fieldLabel
9029 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9030 tooltip : 'This field is required'
9050 if (this.parentType === 'Navbar' && this.parent().bar) {
9051 cfg.cls += ' navbar-form';
9054 if (this.parentType === 'NavGroup') {
9055 cfg.cls += ' navbar-form';
9063 * return the real input element.
9065 inputEl: function ()
9067 return this.el.select('input.form-control',true).first();
9070 tooltipEl : function()
9072 return this.inputEl();
9075 indicatorEl : function()
9077 var indicator = this.el.select('i.roo-required-indicator',true).first();
9087 setDisabled : function(v)
9089 var i = this.inputEl().dom;
9091 i.removeAttribute('disabled');
9095 i.setAttribute('disabled','true');
9097 initEvents : function()
9100 this.inputEl().on("keydown" , this.fireKey, this);
9101 this.inputEl().on("focus", this.onFocus, this);
9102 this.inputEl().on("blur", this.onBlur, this);
9104 this.inputEl().relayEvent('keyup', this);
9106 this.indicator = this.indicatorEl();
9109 this.indicator.addClass('invisible');
9112 // reference to original value for reset
9113 this.originalValue = this.getValue();
9114 //Roo.form.TextField.superclass.initEvents.call(this);
9115 if(this.validationEvent == 'keyup'){
9116 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9117 this.inputEl().on('keyup', this.filterValidation, this);
9119 else if(this.validationEvent !== false){
9120 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9123 if(this.selectOnFocus){
9124 this.on("focus", this.preFocus, this);
9127 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9128 this.inputEl().on("keypress", this.filterKeys, this);
9130 this.inputEl().relayEvent('keypress', this);
9133 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9134 this.el.on("click", this.autoSize, this);
9137 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9138 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9141 if (typeof(this.before) == 'object') {
9142 this.before.render(this.el.select('.roo-input-before',true).first());
9144 if (typeof(this.after) == 'object') {
9145 this.after.render(this.el.select('.roo-input-after',true).first());
9148 this.inputEl().on('change', this.onChange, this);
9151 filterValidation : function(e){
9152 if(!e.isNavKeyPress()){
9153 this.validationTask.delay(this.validationDelay);
9157 * Validates the field value
9158 * @return {Boolean} True if the value is valid, else false
9160 validate : function(){
9161 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9162 if(this.disabled || this.validateValue(this.getRawValue())){
9173 * Validates a value according to the field's validation rules and marks the field as invalid
9174 * if the validation fails
9175 * @param {Mixed} value The value to validate
9176 * @return {Boolean} True if the value is valid, else false
9178 validateValue : function(value)
9180 if(this.getVisibilityEl().hasClass('hidden')){
9184 if(value.length < 1) { // if it's blank
9185 if(this.allowBlank){
9191 if(value.length < this.minLength){
9194 if(value.length > this.maxLength){
9198 var vt = Roo.form.VTypes;
9199 if(!vt[this.vtype](value, this)){
9203 if(typeof this.validator == "function"){
9204 var msg = this.validator(value);
9208 if (typeof(msg) == 'string') {
9209 this.invalidText = msg;
9213 if(this.regex && !this.regex.test(value)){
9221 fireKey : function(e){
9222 //Roo.log('field ' + e.getKey());
9223 if(e.isNavKeyPress()){
9224 this.fireEvent("specialkey", this, e);
9227 focus : function (selectText){
9229 this.inputEl().focus();
9230 if(selectText === true){
9231 this.inputEl().dom.select();
9237 onFocus : function(){
9238 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9239 // this.el.addClass(this.focusClass);
9242 this.hasFocus = true;
9243 this.startValue = this.getValue();
9244 this.fireEvent("focus", this);
9248 beforeBlur : Roo.emptyFn,
9252 onBlur : function(){
9254 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9255 //this.el.removeClass(this.focusClass);
9257 this.hasFocus = false;
9258 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9261 var v = this.getValue();
9262 if(String(v) !== String(this.startValue)){
9263 this.fireEvent('change', this, v, this.startValue);
9265 this.fireEvent("blur", this);
9268 onChange : function(e)
9270 var v = this.getValue();
9271 if(String(v) !== String(this.startValue)){
9272 this.fireEvent('change', this, v, this.startValue);
9278 * Resets the current field value to the originally loaded value and clears any validation messages
9281 this.setValue(this.originalValue);
9285 * Returns the name of the field
9286 * @return {Mixed} name The name field
9288 getName: function(){
9292 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9293 * @return {Mixed} value The field value
9295 getValue : function(){
9297 var v = this.inputEl().getValue();
9302 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9303 * @return {Mixed} value The field value
9305 getRawValue : function(){
9306 var v = this.inputEl().getValue();
9312 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9313 * @param {Mixed} value The value to set
9315 setRawValue : function(v){
9316 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9319 selectText : function(start, end){
9320 var v = this.getRawValue();
9322 start = start === undefined ? 0 : start;
9323 end = end === undefined ? v.length : end;
9324 var d = this.inputEl().dom;
9325 if(d.setSelectionRange){
9326 d.setSelectionRange(start, end);
9327 }else if(d.createTextRange){
9328 var range = d.createTextRange();
9329 range.moveStart("character", start);
9330 range.moveEnd("character", v.length-end);
9337 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9338 * @param {Mixed} value The value to set
9340 setValue : function(v){
9343 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9349 processValue : function(value){
9350 if(this.stripCharsRe){
9351 var newValue = value.replace(this.stripCharsRe, '');
9352 if(newValue !== value){
9353 this.setRawValue(newValue);
9360 preFocus : function(){
9362 if(this.selectOnFocus){
9363 this.inputEl().dom.select();
9366 filterKeys : function(e){
9368 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9371 var c = e.getCharCode(), cc = String.fromCharCode(c);
9372 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9375 if(!this.maskRe.test(cc)){
9380 * Clear any invalid styles/messages for this field
9382 clearInvalid : function(){
9384 if(!this.el || this.preventMark){ // not rendered
9389 this.el.removeClass(this.invalidClass);
9391 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9393 var feedback = this.el.select('.form-control-feedback', true).first();
9396 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9401 this.fireEvent('valid', this);
9405 * Mark this field as valid
9407 markValid : function()
9409 if(!this.el || this.preventMark){ // not rendered...
9413 this.el.removeClass([this.invalidClass, this.validClass]);
9415 var feedback = this.el.select('.form-control-feedback', true).first();
9418 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9422 this.indicator.removeClass('visible');
9423 this.indicator.addClass('invisible');
9430 if(this.allowBlank && !this.getRawValue().length){
9434 this.el.addClass(this.validClass);
9436 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9438 var feedback = this.el.select('.form-control-feedback', true).first();
9441 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9442 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9447 this.fireEvent('valid', this);
9451 * Mark this field as invalid
9452 * @param {String} msg The validation message
9454 markInvalid : function(msg)
9456 if(!this.el || this.preventMark){ // not rendered
9460 this.el.removeClass([this.invalidClass, this.validClass]);
9462 var feedback = this.el.select('.form-control-feedback', true).first();
9465 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9472 if(this.allowBlank && !this.getRawValue().length){
9477 this.indicator.removeClass('invisible');
9478 this.indicator.addClass('visible');
9481 this.el.addClass(this.invalidClass);
9483 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9485 var feedback = this.el.select('.form-control-feedback', true).first();
9488 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9490 if(this.getValue().length || this.forceFeedback){
9491 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9498 this.fireEvent('invalid', this, msg);
9501 SafariOnKeyDown : function(event)
9503 // this is a workaround for a password hang bug on chrome/ webkit.
9504 if (this.inputEl().dom.type != 'password') {
9508 var isSelectAll = false;
9510 if(this.inputEl().dom.selectionEnd > 0){
9511 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9513 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9514 event.preventDefault();
9519 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9521 event.preventDefault();
9522 // this is very hacky as keydown always get's upper case.
9524 var cc = String.fromCharCode(event.getCharCode());
9525 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9529 adjustWidth : function(tag, w){
9530 tag = tag.toLowerCase();
9531 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9532 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9536 if(tag == 'textarea'){
9539 }else if(Roo.isOpera){
9543 if(tag == 'textarea'){
9551 setFieldLabel : function(v)
9558 var ar = this.el.select('label > span',true);
9560 if (ar.elements.length) {
9561 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9562 this.fieldLabel = v;
9566 var br = this.el.select('label',true);
9568 if(br.elements.length) {
9569 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9570 this.fieldLabel = v;
9574 Roo.log('Cannot Found any of label > span || label in input');
9578 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9579 this.fieldLabel = v;
9594 * @class Roo.bootstrap.TextArea
9595 * @extends Roo.bootstrap.Input
9596 * Bootstrap TextArea class
9597 * @cfg {Number} cols Specifies the visible width of a text area
9598 * @cfg {Number} rows Specifies the visible number of lines in a text area
9599 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9600 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9601 * @cfg {string} html text
9604 * Create a new TextArea
9605 * @param {Object} config The config object
9608 Roo.bootstrap.TextArea = function(config){
9609 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9613 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9623 getAutoCreate : function(){
9625 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9631 if(this.inputType != 'hidden'){
9632 cfg.cls = 'form-group' //input-group
9640 value : this.value || '',
9641 html: this.html || '',
9642 cls : 'form-control',
9643 placeholder : this.placeholder || ''
9647 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9648 input.maxLength = this.maxLength;
9652 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9656 input.cols = this.cols;
9659 if (this.readOnly) {
9660 input.readonly = true;
9664 input.name = this.name;
9668 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9672 ['xs','sm','md','lg'].map(function(size){
9673 if (settings[size]) {
9674 cfg.cls += ' col-' + size + '-' + settings[size];
9678 var inputblock = input;
9680 if(this.hasFeedback && !this.allowBlank){
9684 cls: 'glyphicon form-control-feedback'
9688 cls : 'has-feedback',
9697 if (this.before || this.after) {
9700 cls : 'input-group',
9704 inputblock.cn.push({
9706 cls : 'input-group-addon',
9711 inputblock.cn.push(input);
9713 if(this.hasFeedback && !this.allowBlank){
9714 inputblock.cls += ' has-feedback';
9715 inputblock.cn.push(feedback);
9719 inputblock.cn.push({
9721 cls : 'input-group-addon',
9728 if (align ==='left' && this.fieldLabel.length) {
9733 cls : 'control-label',
9734 html : this.fieldLabel
9745 if(this.labelWidth > 12){
9746 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9749 if(this.labelWidth < 13 && this.labelmd == 0){
9750 this.labelmd = this.labelWidth;
9753 if(this.labellg > 0){
9754 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9755 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9758 if(this.labelmd > 0){
9759 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9760 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9763 if(this.labelsm > 0){
9764 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9765 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9768 if(this.labelxs > 0){
9769 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9770 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9773 } else if ( this.fieldLabel.length) {
9778 //cls : 'input-group-addon',
9779 html : this.fieldLabel
9797 if (this.disabled) {
9798 input.disabled=true;
9805 * return the real textarea element.
9807 inputEl: function ()
9809 return this.el.select('textarea.form-control',true).first();
9813 * Clear any invalid styles/messages for this field
9815 clearInvalid : function()
9818 if(!this.el || this.preventMark){ // not rendered
9822 var label = this.el.select('label', true).first();
9823 var icon = this.el.select('i.fa-star', true).first();
9829 this.el.removeClass(this.invalidClass);
9831 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9833 var feedback = this.el.select('.form-control-feedback', true).first();
9836 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9841 this.fireEvent('valid', this);
9845 * Mark this field as valid
9847 markValid : function()
9849 if(!this.el || this.preventMark){ // not rendered
9853 this.el.removeClass([this.invalidClass, this.validClass]);
9855 var feedback = this.el.select('.form-control-feedback', true).first();
9858 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9861 if(this.disabled || this.allowBlank){
9865 var label = this.el.select('label', true).first();
9866 var icon = this.el.select('i.fa-star', true).first();
9872 this.el.addClass(this.validClass);
9874 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9876 var feedback = this.el.select('.form-control-feedback', true).first();
9879 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9880 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9885 this.fireEvent('valid', this);
9889 * Mark this field as invalid
9890 * @param {String} msg The validation message
9892 markInvalid : function(msg)
9894 if(!this.el || this.preventMark){ // not rendered
9898 this.el.removeClass([this.invalidClass, this.validClass]);
9900 var feedback = this.el.select('.form-control-feedback', true).first();
9903 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9906 if(this.disabled || this.allowBlank){
9910 var label = this.el.select('label', true).first();
9911 var icon = this.el.select('i.fa-star', true).first();
9913 if(!this.getValue().length && label && !icon){
9914 this.el.createChild({
9916 cls : 'text-danger fa fa-lg fa-star',
9917 tooltip : 'This field is required',
9918 style : 'margin-right:5px;'
9922 this.el.addClass(this.invalidClass);
9924 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9926 var feedback = this.el.select('.form-control-feedback', true).first();
9929 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9931 if(this.getValue().length || this.forceFeedback){
9932 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9939 this.fireEvent('invalid', this, msg);
9947 * trigger field - base class for combo..
9952 * @class Roo.bootstrap.TriggerField
9953 * @extends Roo.bootstrap.Input
9954 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9955 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9956 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9957 * for which you can provide a custom implementation. For example:
9959 var trigger = new Roo.bootstrap.TriggerField();
9960 trigger.onTriggerClick = myTriggerFn;
9961 trigger.applyTo('my-field');
9964 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9965 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9966 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9967 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9968 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9971 * Create a new TriggerField.
9972 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9973 * to the base TextField)
9975 Roo.bootstrap.TriggerField = function(config){
9976 this.mimicing = false;
9977 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9980 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9982 * @cfg {String} triggerClass A CSS class to apply to the trigger
9985 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9990 * @cfg {Boolean} removable (true|false) special filter default false
9994 /** @cfg {Boolean} grow @hide */
9995 /** @cfg {Number} growMin @hide */
9996 /** @cfg {Number} growMax @hide */
10002 autoSize: Roo.emptyFn,
10006 deferHeight : true,
10009 actionMode : 'wrap',
10014 getAutoCreate : function(){
10016 var align = this.labelAlign || this.parentLabelAlign();
10021 cls: 'form-group' //input-group
10028 type : this.inputType,
10029 cls : 'form-control',
10030 autocomplete: 'new-password',
10031 placeholder : this.placeholder || ''
10035 input.name = this.name;
10038 input.cls += ' input-' + this.size;
10041 if (this.disabled) {
10042 input.disabled=true;
10045 var inputblock = input;
10047 if(this.hasFeedback && !this.allowBlank){
10051 cls: 'glyphicon form-control-feedback'
10054 if(this.removable && !this.editable && !this.tickable){
10056 cls : 'has-feedback',
10062 cls : 'roo-combo-removable-btn close'
10069 cls : 'has-feedback',
10078 if(this.removable && !this.editable && !this.tickable){
10080 cls : 'roo-removable',
10086 cls : 'roo-combo-removable-btn close'
10093 if (this.before || this.after) {
10096 cls : 'input-group',
10100 inputblock.cn.push({
10102 cls : 'input-group-addon',
10107 inputblock.cn.push(input);
10109 if(this.hasFeedback && !this.allowBlank){
10110 inputblock.cls += ' has-feedback';
10111 inputblock.cn.push(feedback);
10115 inputblock.cn.push({
10117 cls : 'input-group-addon',
10130 cls: 'form-hidden-field'
10144 cls: 'form-hidden-field'
10148 cls: 'roo-select2-choices',
10152 cls: 'roo-select2-search-field',
10165 cls: 'roo-select2-container input-group',
10170 // cls: 'typeahead typeahead-long dropdown-menu',
10171 // style: 'display:none'
10176 if(!this.multiple && this.showToggleBtn){
10182 if (this.caret != false) {
10185 cls: 'fa fa-' + this.caret
10192 cls : 'input-group-addon btn dropdown-toggle',
10197 cls: 'combobox-clear',
10211 combobox.cls += ' roo-select2-container-multi';
10214 if (align ==='left' && this.fieldLabel.length) {
10216 cfg.cls += ' roo-form-group-label-left';
10221 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10222 tooltip : 'This field is required'
10227 cls : 'control-label',
10228 html : this.fieldLabel
10240 var labelCfg = cfg.cn[1];
10241 var contentCfg = cfg.cn[2];
10243 if(this.indicatorpos == 'right'){
10248 cls : 'control-label',
10252 html : this.fieldLabel
10256 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10257 tooltip : 'This field is required'
10270 labelCfg = cfg.cn[0];
10271 contentCfg = cfg.cn[1];
10274 if(this.labelWidth > 12){
10275 labelCfg.style = "width: " + this.labelWidth + 'px';
10278 if(this.labelWidth < 13 && this.labelmd == 0){
10279 this.labelmd = this.labelWidth;
10282 if(this.labellg > 0){
10283 labelCfg.cls += ' col-lg-' + this.labellg;
10284 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10287 if(this.labelmd > 0){
10288 labelCfg.cls += ' col-md-' + this.labelmd;
10289 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10292 if(this.labelsm > 0){
10293 labelCfg.cls += ' col-sm-' + this.labelsm;
10294 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10297 if(this.labelxs > 0){
10298 labelCfg.cls += ' col-xs-' + this.labelxs;
10299 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10302 } else if ( this.fieldLabel.length) {
10303 // Roo.log(" label");
10307 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10308 tooltip : 'This field is required'
10312 //cls : 'input-group-addon',
10313 html : this.fieldLabel
10321 if(this.indicatorpos == 'right'){
10329 html : this.fieldLabel
10333 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10334 tooltip : 'This field is required'
10347 // Roo.log(" no label && no align");
10354 ['xs','sm','md','lg'].map(function(size){
10355 if (settings[size]) {
10356 cfg.cls += ' col-' + size + '-' + settings[size];
10367 onResize : function(w, h){
10368 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10369 // if(typeof w == 'number'){
10370 // var x = w - this.trigger.getWidth();
10371 // this.inputEl().setWidth(this.adjustWidth('input', x));
10372 // this.trigger.setStyle('left', x+'px');
10377 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10380 getResizeEl : function(){
10381 return this.inputEl();
10385 getPositionEl : function(){
10386 return this.inputEl();
10390 alignErrorIcon : function(){
10391 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10395 initEvents : function(){
10399 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10400 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10401 if(!this.multiple && this.showToggleBtn){
10402 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10403 if(this.hideTrigger){
10404 this.trigger.setDisplayed(false);
10406 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10410 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10413 if(this.removable && !this.editable && !this.tickable){
10414 var close = this.closeTriggerEl();
10417 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10418 close.on('click', this.removeBtnClick, this, close);
10422 //this.trigger.addClassOnOver('x-form-trigger-over');
10423 //this.trigger.addClassOnClick('x-form-trigger-click');
10426 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10430 closeTriggerEl : function()
10432 var close = this.el.select('.roo-combo-removable-btn', true).first();
10433 return close ? close : false;
10436 removeBtnClick : function(e, h, el)
10438 e.preventDefault();
10440 if(this.fireEvent("remove", this) !== false){
10442 this.fireEvent("afterremove", this)
10446 createList : function()
10448 this.list = Roo.get(document.body).createChild({
10450 cls: 'typeahead typeahead-long dropdown-menu',
10451 style: 'display:none'
10454 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10459 initTrigger : function(){
10464 onDestroy : function(){
10466 this.trigger.removeAllListeners();
10467 // this.trigger.remove();
10470 // this.wrap.remove();
10472 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10476 onFocus : function(){
10477 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10479 if(!this.mimicing){
10480 this.wrap.addClass('x-trigger-wrap-focus');
10481 this.mimicing = true;
10482 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10483 if(this.monitorTab){
10484 this.el.on("keydown", this.checkTab, this);
10491 checkTab : function(e){
10492 if(e.getKey() == e.TAB){
10493 this.triggerBlur();
10498 onBlur : function(){
10503 mimicBlur : function(e, t){
10505 if(!this.wrap.contains(t) && this.validateBlur()){
10506 this.triggerBlur();
10512 triggerBlur : function(){
10513 this.mimicing = false;
10514 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10515 if(this.monitorTab){
10516 this.el.un("keydown", this.checkTab, this);
10518 //this.wrap.removeClass('x-trigger-wrap-focus');
10519 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10523 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10524 validateBlur : function(e, t){
10529 onDisable : function(){
10530 this.inputEl().dom.disabled = true;
10531 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10533 // this.wrap.addClass('x-item-disabled');
10538 onEnable : function(){
10539 this.inputEl().dom.disabled = false;
10540 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10542 // this.el.removeClass('x-item-disabled');
10547 onShow : function(){
10548 var ae = this.getActionEl();
10551 ae.dom.style.display = '';
10552 ae.dom.style.visibility = 'visible';
10558 onHide : function(){
10559 var ae = this.getActionEl();
10560 ae.dom.style.display = 'none';
10564 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10565 * by an implementing function.
10567 * @param {EventObject} e
10569 onTriggerClick : Roo.emptyFn
10573 * Ext JS Library 1.1.1
10574 * Copyright(c) 2006-2007, Ext JS, LLC.
10576 * Originally Released Under LGPL - original licence link has changed is not relivant.
10579 * <script type="text/javascript">
10584 * @class Roo.data.SortTypes
10586 * Defines the default sorting (casting?) comparison functions used when sorting data.
10588 Roo.data.SortTypes = {
10590 * Default sort that does nothing
10591 * @param {Mixed} s The value being converted
10592 * @return {Mixed} The comparison value
10594 none : function(s){
10599 * The regular expression used to strip tags
10603 stripTagsRE : /<\/?[^>]+>/gi,
10606 * Strips all HTML tags to sort on text only
10607 * @param {Mixed} s The value being converted
10608 * @return {String} The comparison value
10610 asText : function(s){
10611 return String(s).replace(this.stripTagsRE, "");
10615 * Strips all HTML tags to sort on text only - Case insensitive
10616 * @param {Mixed} s The value being converted
10617 * @return {String} The comparison value
10619 asUCText : function(s){
10620 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10624 * Case insensitive string
10625 * @param {Mixed} s The value being converted
10626 * @return {String} The comparison value
10628 asUCString : function(s) {
10629 return String(s).toUpperCase();
10634 * @param {Mixed} s The value being converted
10635 * @return {Number} The comparison value
10637 asDate : function(s) {
10641 if(s instanceof Date){
10642 return s.getTime();
10644 return Date.parse(String(s));
10649 * @param {Mixed} s The value being converted
10650 * @return {Float} The comparison value
10652 asFloat : function(s) {
10653 var val = parseFloat(String(s).replace(/,/g, ""));
10662 * @param {Mixed} s The value being converted
10663 * @return {Number} The comparison value
10665 asInt : function(s) {
10666 var val = parseInt(String(s).replace(/,/g, ""));
10674 * Ext JS Library 1.1.1
10675 * Copyright(c) 2006-2007, Ext JS, LLC.
10677 * Originally Released Under LGPL - original licence link has changed is not relivant.
10680 * <script type="text/javascript">
10684 * @class Roo.data.Record
10685 * Instances of this class encapsulate both record <em>definition</em> information, and record
10686 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10687 * to access Records cached in an {@link Roo.data.Store} object.<br>
10689 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10690 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10693 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10695 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10696 * {@link #create}. The parameters are the same.
10697 * @param {Array} data An associative Array of data values keyed by the field name.
10698 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10699 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10700 * not specified an integer id is generated.
10702 Roo.data.Record = function(data, id){
10703 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10708 * Generate a constructor for a specific record layout.
10709 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10710 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10711 * Each field definition object may contain the following properties: <ul>
10712 * <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,
10713 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10714 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10715 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10716 * is being used, then this is a string containing the javascript expression to reference the data relative to
10717 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10718 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10719 * this may be omitted.</p></li>
10720 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10721 * <ul><li>auto (Default, implies no conversion)</li>
10726 * <li>date</li></ul></p></li>
10727 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10728 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10729 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10730 * by the Reader into an object that will be stored in the Record. It is passed the
10731 * following parameters:<ul>
10732 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10734 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10736 * <br>usage:<br><pre><code>
10737 var TopicRecord = Roo.data.Record.create(
10738 {name: 'title', mapping: 'topic_title'},
10739 {name: 'author', mapping: 'username'},
10740 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10741 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10742 {name: 'lastPoster', mapping: 'user2'},
10743 {name: 'excerpt', mapping: 'post_text'}
10746 var myNewRecord = new TopicRecord({
10747 title: 'Do my job please',
10750 lastPost: new Date(),
10751 lastPoster: 'Animal',
10752 excerpt: 'No way dude!'
10754 myStore.add(myNewRecord);
10759 Roo.data.Record.create = function(o){
10760 var f = function(){
10761 f.superclass.constructor.apply(this, arguments);
10763 Roo.extend(f, Roo.data.Record);
10764 var p = f.prototype;
10765 p.fields = new Roo.util.MixedCollection(false, function(field){
10768 for(var i = 0, len = o.length; i < len; i++){
10769 p.fields.add(new Roo.data.Field(o[i]));
10771 f.getField = function(name){
10772 return p.fields.get(name);
10777 Roo.data.Record.AUTO_ID = 1000;
10778 Roo.data.Record.EDIT = 'edit';
10779 Roo.data.Record.REJECT = 'reject';
10780 Roo.data.Record.COMMIT = 'commit';
10782 Roo.data.Record.prototype = {
10784 * Readonly flag - true if this record has been modified.
10793 join : function(store){
10794 this.store = store;
10798 * Set the named field to the specified value.
10799 * @param {String} name The name of the field to set.
10800 * @param {Object} value The value to set the field to.
10802 set : function(name, value){
10803 if(this.data[name] == value){
10807 if(!this.modified){
10808 this.modified = {};
10810 if(typeof this.modified[name] == 'undefined'){
10811 this.modified[name] = this.data[name];
10813 this.data[name] = value;
10814 if(!this.editing && this.store){
10815 this.store.afterEdit(this);
10820 * Get the value of the named field.
10821 * @param {String} name The name of the field to get the value of.
10822 * @return {Object} The value of the field.
10824 get : function(name){
10825 return this.data[name];
10829 beginEdit : function(){
10830 this.editing = true;
10831 this.modified = {};
10835 cancelEdit : function(){
10836 this.editing = false;
10837 delete this.modified;
10841 endEdit : function(){
10842 this.editing = false;
10843 if(this.dirty && this.store){
10844 this.store.afterEdit(this);
10849 * Usually called by the {@link Roo.data.Store} which owns the Record.
10850 * Rejects all changes made to the Record since either creation, or the last commit operation.
10851 * Modified fields are reverted to their original values.
10853 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10854 * of reject operations.
10856 reject : function(){
10857 var m = this.modified;
10859 if(typeof m[n] != "function"){
10860 this.data[n] = m[n];
10863 this.dirty = false;
10864 delete this.modified;
10865 this.editing = false;
10867 this.store.afterReject(this);
10872 * Usually called by the {@link Roo.data.Store} which owns the Record.
10873 * Commits all changes made to the Record since either creation, or the last commit operation.
10875 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10876 * of commit operations.
10878 commit : function(){
10879 this.dirty = false;
10880 delete this.modified;
10881 this.editing = false;
10883 this.store.afterCommit(this);
10888 hasError : function(){
10889 return this.error != null;
10893 clearError : function(){
10898 * Creates a copy of this record.
10899 * @param {String} id (optional) A new record id if you don't want to use this record's id
10902 copy : function(newId) {
10903 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10907 * Ext JS Library 1.1.1
10908 * Copyright(c) 2006-2007, Ext JS, LLC.
10910 * Originally Released Under LGPL - original licence link has changed is not relivant.
10913 * <script type="text/javascript">
10919 * @class Roo.data.Store
10920 * @extends Roo.util.Observable
10921 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10922 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10924 * 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
10925 * has no knowledge of the format of the data returned by the Proxy.<br>
10927 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10928 * instances from the data object. These records are cached and made available through accessor functions.
10930 * Creates a new Store.
10931 * @param {Object} config A config object containing the objects needed for the Store to access data,
10932 * and read the data into Records.
10934 Roo.data.Store = function(config){
10935 this.data = new Roo.util.MixedCollection(false);
10936 this.data.getKey = function(o){
10939 this.baseParams = {};
10941 this.paramNames = {
10946 "multisort" : "_multisort"
10949 if(config && config.data){
10950 this.inlineData = config.data;
10951 delete config.data;
10954 Roo.apply(this, config);
10956 if(this.reader){ // reader passed
10957 this.reader = Roo.factory(this.reader, Roo.data);
10958 this.reader.xmodule = this.xmodule || false;
10959 if(!this.recordType){
10960 this.recordType = this.reader.recordType;
10962 if(this.reader.onMetaChange){
10963 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10967 if(this.recordType){
10968 this.fields = this.recordType.prototype.fields;
10970 this.modified = [];
10974 * @event datachanged
10975 * Fires when the data cache has changed, and a widget which is using this Store
10976 * as a Record cache should refresh its view.
10977 * @param {Store} this
10979 datachanged : true,
10981 * @event metachange
10982 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10983 * @param {Store} this
10984 * @param {Object} meta The JSON metadata
10989 * Fires when Records have been added to the Store
10990 * @param {Store} this
10991 * @param {Roo.data.Record[]} records The array of Records added
10992 * @param {Number} index The index at which the record(s) were added
10997 * Fires when a Record has been removed from the Store
10998 * @param {Store} this
10999 * @param {Roo.data.Record} record The Record that was removed
11000 * @param {Number} index The index at which the record was removed
11005 * Fires when a Record has been updated
11006 * @param {Store} this
11007 * @param {Roo.data.Record} record The Record that was updated
11008 * @param {String} operation The update operation being performed. Value may be one of:
11010 Roo.data.Record.EDIT
11011 Roo.data.Record.REJECT
11012 Roo.data.Record.COMMIT
11018 * Fires when the data cache has been cleared.
11019 * @param {Store} this
11023 * @event beforeload
11024 * Fires before a request is made for a new data object. If the beforeload handler returns false
11025 * the load action will be canceled.
11026 * @param {Store} this
11027 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11031 * @event beforeloadadd
11032 * Fires after a new set of Records has been loaded.
11033 * @param {Store} this
11034 * @param {Roo.data.Record[]} records The Records that were loaded
11035 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11037 beforeloadadd : true,
11040 * Fires after a new set of Records has been loaded, before they are added to the store.
11041 * @param {Store} this
11042 * @param {Roo.data.Record[]} records The Records that were loaded
11043 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11044 * @params {Object} return from reader
11048 * @event loadexception
11049 * Fires if an exception occurs in the Proxy during loading.
11050 * Called with the signature of the Proxy's "loadexception" event.
11051 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11054 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11055 * @param {Object} load options
11056 * @param {Object} jsonData from your request (normally this contains the Exception)
11058 loadexception : true
11062 this.proxy = Roo.factory(this.proxy, Roo.data);
11063 this.proxy.xmodule = this.xmodule || false;
11064 this.relayEvents(this.proxy, ["loadexception"]);
11066 this.sortToggle = {};
11067 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11069 Roo.data.Store.superclass.constructor.call(this);
11071 if(this.inlineData){
11072 this.loadData(this.inlineData);
11073 delete this.inlineData;
11077 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11079 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11080 * without a remote query - used by combo/forms at present.
11084 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11087 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11090 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11091 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11094 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11095 * on any HTTP request
11098 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11101 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11105 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11106 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11108 remoteSort : false,
11111 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11112 * loaded or when a record is removed. (defaults to false).
11114 pruneModifiedRecords : false,
11117 lastOptions : null,
11120 * Add Records to the Store and fires the add event.
11121 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11123 add : function(records){
11124 records = [].concat(records);
11125 for(var i = 0, len = records.length; i < len; i++){
11126 records[i].join(this);
11128 var index = this.data.length;
11129 this.data.addAll(records);
11130 this.fireEvent("add", this, records, index);
11134 * Remove a Record from the Store and fires the remove event.
11135 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11137 remove : function(record){
11138 var index = this.data.indexOf(record);
11139 this.data.removeAt(index);
11141 if(this.pruneModifiedRecords){
11142 this.modified.remove(record);
11144 this.fireEvent("remove", this, record, index);
11148 * Remove all Records from the Store and fires the clear event.
11150 removeAll : function(){
11152 if(this.pruneModifiedRecords){
11153 this.modified = [];
11155 this.fireEvent("clear", this);
11159 * Inserts Records to the Store at the given index and fires the add event.
11160 * @param {Number} index The start index at which to insert the passed Records.
11161 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11163 insert : function(index, records){
11164 records = [].concat(records);
11165 for(var i = 0, len = records.length; i < len; i++){
11166 this.data.insert(index, records[i]);
11167 records[i].join(this);
11169 this.fireEvent("add", this, records, index);
11173 * Get the index within the cache of the passed Record.
11174 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11175 * @return {Number} The index of the passed Record. Returns -1 if not found.
11177 indexOf : function(record){
11178 return this.data.indexOf(record);
11182 * Get the index within the cache of the Record with the passed id.
11183 * @param {String} id The id of the Record to find.
11184 * @return {Number} The index of the Record. Returns -1 if not found.
11186 indexOfId : function(id){
11187 return this.data.indexOfKey(id);
11191 * Get the Record with the specified id.
11192 * @param {String} id The id of the Record to find.
11193 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11195 getById : function(id){
11196 return this.data.key(id);
11200 * Get the Record at the specified index.
11201 * @param {Number} index The index of the Record to find.
11202 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11204 getAt : function(index){
11205 return this.data.itemAt(index);
11209 * Returns a range of Records between specified indices.
11210 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11211 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11212 * @return {Roo.data.Record[]} An array of Records
11214 getRange : function(start, end){
11215 return this.data.getRange(start, end);
11219 storeOptions : function(o){
11220 o = Roo.apply({}, o);
11223 this.lastOptions = o;
11227 * Loads the Record cache from the configured Proxy using the configured Reader.
11229 * If using remote paging, then the first load call must specify the <em>start</em>
11230 * and <em>limit</em> properties in the options.params property to establish the initial
11231 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11233 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11234 * and this call will return before the new data has been loaded. Perform any post-processing
11235 * in a callback function, or in a "load" event handler.</strong>
11237 * @param {Object} options An object containing properties which control loading options:<ul>
11238 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11239 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11240 * passed the following arguments:<ul>
11241 * <li>r : Roo.data.Record[]</li>
11242 * <li>options: Options object from the load call</li>
11243 * <li>success: Boolean success indicator</li></ul></li>
11244 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11245 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11248 load : function(options){
11249 options = options || {};
11250 if(this.fireEvent("beforeload", this, options) !== false){
11251 this.storeOptions(options);
11252 var p = Roo.apply(options.params || {}, this.baseParams);
11253 // if meta was not loaded from remote source.. try requesting it.
11254 if (!this.reader.metaFromRemote) {
11255 p._requestMeta = 1;
11257 if(this.sortInfo && this.remoteSort){
11258 var pn = this.paramNames;
11259 p[pn["sort"]] = this.sortInfo.field;
11260 p[pn["dir"]] = this.sortInfo.direction;
11262 if (this.multiSort) {
11263 var pn = this.paramNames;
11264 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11267 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11272 * Reloads the Record cache from the configured Proxy using the configured Reader and
11273 * the options from the last load operation performed.
11274 * @param {Object} options (optional) An object containing properties which may override the options
11275 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11276 * the most recently used options are reused).
11278 reload : function(options){
11279 this.load(Roo.applyIf(options||{}, this.lastOptions));
11283 // Called as a callback by the Reader during a load operation.
11284 loadRecords : function(o, options, success){
11285 if(!o || success === false){
11286 if(success !== false){
11287 this.fireEvent("load", this, [], options, o);
11289 if(options.callback){
11290 options.callback.call(options.scope || this, [], options, false);
11294 // if data returned failure - throw an exception.
11295 if (o.success === false) {
11296 // show a message if no listener is registered.
11297 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11298 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11300 // loadmask wil be hooked into this..
11301 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11304 var r = o.records, t = o.totalRecords || r.length;
11306 this.fireEvent("beforeloadadd", this, r, options, o);
11308 if(!options || options.add !== true){
11309 if(this.pruneModifiedRecords){
11310 this.modified = [];
11312 for(var i = 0, len = r.length; i < len; i++){
11316 this.data = this.snapshot;
11317 delete this.snapshot;
11320 this.data.addAll(r);
11321 this.totalLength = t;
11323 this.fireEvent("datachanged", this);
11325 this.totalLength = Math.max(t, this.data.length+r.length);
11329 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11331 var e = new Roo.data.Record({});
11333 e.set(this.parent.displayField, this.parent.emptyTitle);
11334 e.set(this.parent.valueField, '');
11339 this.fireEvent("load", this, r, options, o);
11340 if(options.callback){
11341 options.callback.call(options.scope || this, r, options, true);
11347 * Loads data from a passed data block. A Reader which understands the format of the data
11348 * must have been configured in the constructor.
11349 * @param {Object} data The data block from which to read the Records. The format of the data expected
11350 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11351 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11353 loadData : function(o, append){
11354 var r = this.reader.readRecords(o);
11355 this.loadRecords(r, {add: append}, true);
11359 * Gets the number of cached records.
11361 * <em>If using paging, this may not be the total size of the dataset. If the data object
11362 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11363 * the data set size</em>
11365 getCount : function(){
11366 return this.data.length || 0;
11370 * Gets the total number of records in the dataset as returned by the server.
11372 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11373 * the dataset size</em>
11375 getTotalCount : function(){
11376 return this.totalLength || 0;
11380 * Returns the sort state of the Store as an object with two properties:
11382 field {String} The name of the field by which the Records are sorted
11383 direction {String} The sort order, "ASC" or "DESC"
11386 getSortState : function(){
11387 return this.sortInfo;
11391 applySort : function(){
11392 if(this.sortInfo && !this.remoteSort){
11393 var s = this.sortInfo, f = s.field;
11394 var st = this.fields.get(f).sortType;
11395 var fn = function(r1, r2){
11396 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11397 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11399 this.data.sort(s.direction, fn);
11400 if(this.snapshot && this.snapshot != this.data){
11401 this.snapshot.sort(s.direction, fn);
11407 * Sets the default sort column and order to be used by the next load operation.
11408 * @param {String} fieldName The name of the field to sort by.
11409 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11411 setDefaultSort : function(field, dir){
11412 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11416 * Sort the Records.
11417 * If remote sorting is used, the sort is performed on the server, and the cache is
11418 * reloaded. If local sorting is used, the cache is sorted internally.
11419 * @param {String} fieldName The name of the field to sort by.
11420 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11422 sort : function(fieldName, dir){
11423 var f = this.fields.get(fieldName);
11425 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11427 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11428 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11433 this.sortToggle[f.name] = dir;
11434 this.sortInfo = {field: f.name, direction: dir};
11435 if(!this.remoteSort){
11437 this.fireEvent("datachanged", this);
11439 this.load(this.lastOptions);
11444 * Calls the specified function for each of the Records in the cache.
11445 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11446 * Returning <em>false</em> aborts and exits the iteration.
11447 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11449 each : function(fn, scope){
11450 this.data.each(fn, scope);
11454 * Gets all records modified since the last commit. Modified records are persisted across load operations
11455 * (e.g., during paging).
11456 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11458 getModifiedRecords : function(){
11459 return this.modified;
11463 createFilterFn : function(property, value, anyMatch){
11464 if(!value.exec){ // not a regex
11465 value = String(value);
11466 if(value.length == 0){
11469 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11471 return function(r){
11472 return value.test(r.data[property]);
11477 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11478 * @param {String} property A field on your records
11479 * @param {Number} start The record index to start at (defaults to 0)
11480 * @param {Number} end The last record index to include (defaults to length - 1)
11481 * @return {Number} The sum
11483 sum : function(property, start, end){
11484 var rs = this.data.items, v = 0;
11485 start = start || 0;
11486 end = (end || end === 0) ? end : rs.length-1;
11488 for(var i = start; i <= end; i++){
11489 v += (rs[i].data[property] || 0);
11495 * Filter the records by a specified property.
11496 * @param {String} field A field on your records
11497 * @param {String/RegExp} value Either a string that the field
11498 * should start with or a RegExp to test against the field
11499 * @param {Boolean} anyMatch True to match any part not just the beginning
11501 filter : function(property, value, anyMatch){
11502 var fn = this.createFilterFn(property, value, anyMatch);
11503 return fn ? this.filterBy(fn) : this.clearFilter();
11507 * Filter by a function. The specified function will be called with each
11508 * record in this data source. If the function returns true the record is included,
11509 * otherwise it is filtered.
11510 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11511 * @param {Object} scope (optional) The scope of the function (defaults to this)
11513 filterBy : function(fn, scope){
11514 this.snapshot = this.snapshot || this.data;
11515 this.data = this.queryBy(fn, scope||this);
11516 this.fireEvent("datachanged", this);
11520 * Query the records by a specified property.
11521 * @param {String} field A field on your records
11522 * @param {String/RegExp} value Either a string that the field
11523 * should start with or a RegExp to test against the field
11524 * @param {Boolean} anyMatch True to match any part not just the beginning
11525 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11527 query : function(property, value, anyMatch){
11528 var fn = this.createFilterFn(property, value, anyMatch);
11529 return fn ? this.queryBy(fn) : this.data.clone();
11533 * Query by a function. The specified function will be called with each
11534 * record in this data source. If the function returns true the record is included
11536 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11537 * @param {Object} scope (optional) The scope of the function (defaults to this)
11538 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11540 queryBy : function(fn, scope){
11541 var data = this.snapshot || this.data;
11542 return data.filterBy(fn, scope||this);
11546 * Collects unique values for a particular dataIndex from this store.
11547 * @param {String} dataIndex The property to collect
11548 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11549 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11550 * @return {Array} An array of the unique values
11552 collect : function(dataIndex, allowNull, bypassFilter){
11553 var d = (bypassFilter === true && this.snapshot) ?
11554 this.snapshot.items : this.data.items;
11555 var v, sv, r = [], l = {};
11556 for(var i = 0, len = d.length; i < len; i++){
11557 v = d[i].data[dataIndex];
11559 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11568 * Revert to a view of the Record cache with no filtering applied.
11569 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11571 clearFilter : function(suppressEvent){
11572 if(this.snapshot && this.snapshot != this.data){
11573 this.data = this.snapshot;
11574 delete this.snapshot;
11575 if(suppressEvent !== true){
11576 this.fireEvent("datachanged", this);
11582 afterEdit : function(record){
11583 if(this.modified.indexOf(record) == -1){
11584 this.modified.push(record);
11586 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11590 afterReject : function(record){
11591 this.modified.remove(record);
11592 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11596 afterCommit : function(record){
11597 this.modified.remove(record);
11598 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11602 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11603 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11605 commitChanges : function(){
11606 var m = this.modified.slice(0);
11607 this.modified = [];
11608 for(var i = 0, len = m.length; i < len; i++){
11614 * Cancel outstanding changes on all changed records.
11616 rejectChanges : function(){
11617 var m = this.modified.slice(0);
11618 this.modified = [];
11619 for(var i = 0, len = m.length; i < len; i++){
11624 onMetaChange : function(meta, rtype, o){
11625 this.recordType = rtype;
11626 this.fields = rtype.prototype.fields;
11627 delete this.snapshot;
11628 this.sortInfo = meta.sortInfo || this.sortInfo;
11629 this.modified = [];
11630 this.fireEvent('metachange', this, this.reader.meta);
11633 moveIndex : function(data, type)
11635 var index = this.indexOf(data);
11637 var newIndex = index + type;
11641 this.insert(newIndex, data);
11646 * Ext JS Library 1.1.1
11647 * Copyright(c) 2006-2007, Ext JS, LLC.
11649 * Originally Released Under LGPL - original licence link has changed is not relivant.
11652 * <script type="text/javascript">
11656 * @class Roo.data.SimpleStore
11657 * @extends Roo.data.Store
11658 * Small helper class to make creating Stores from Array data easier.
11659 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11660 * @cfg {Array} fields An array of field definition objects, or field name strings.
11661 * @cfg {Array} data The multi-dimensional array of data
11663 * @param {Object} config
11665 Roo.data.SimpleStore = function(config){
11666 Roo.data.SimpleStore.superclass.constructor.call(this, {
11668 reader: new Roo.data.ArrayReader({
11671 Roo.data.Record.create(config.fields)
11673 proxy : new Roo.data.MemoryProxy(config.data)
11677 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11679 * Ext JS Library 1.1.1
11680 * Copyright(c) 2006-2007, Ext JS, LLC.
11682 * Originally Released Under LGPL - original licence link has changed is not relivant.
11685 * <script type="text/javascript">
11690 * @extends Roo.data.Store
11691 * @class Roo.data.JsonStore
11692 * Small helper class to make creating Stores for JSON data easier. <br/>
11694 var store = new Roo.data.JsonStore({
11695 url: 'get-images.php',
11697 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11700 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11701 * JsonReader and HttpProxy (unless inline data is provided).</b>
11702 * @cfg {Array} fields An array of field definition objects, or field name strings.
11704 * @param {Object} config
11706 Roo.data.JsonStore = function(c){
11707 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11708 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11709 reader: new Roo.data.JsonReader(c, c.fields)
11712 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11714 * Ext JS Library 1.1.1
11715 * Copyright(c) 2006-2007, Ext JS, LLC.
11717 * Originally Released Under LGPL - original licence link has changed is not relivant.
11720 * <script type="text/javascript">
11724 Roo.data.Field = function(config){
11725 if(typeof config == "string"){
11726 config = {name: config};
11728 Roo.apply(this, config);
11731 this.type = "auto";
11734 var st = Roo.data.SortTypes;
11735 // named sortTypes are supported, here we look them up
11736 if(typeof this.sortType == "string"){
11737 this.sortType = st[this.sortType];
11740 // set default sortType for strings and dates
11741 if(!this.sortType){
11744 this.sortType = st.asUCString;
11747 this.sortType = st.asDate;
11750 this.sortType = st.none;
11755 var stripRe = /[\$,%]/g;
11757 // prebuilt conversion function for this field, instead of
11758 // switching every time we're reading a value
11760 var cv, dateFormat = this.dateFormat;
11765 cv = function(v){ return v; };
11768 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11772 return v !== undefined && v !== null && v !== '' ?
11773 parseInt(String(v).replace(stripRe, ""), 10) : '';
11778 return v !== undefined && v !== null && v !== '' ?
11779 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11784 cv = function(v){ return v === true || v === "true" || v == 1; };
11791 if(v instanceof Date){
11795 if(dateFormat == "timestamp"){
11796 return new Date(v*1000);
11798 return Date.parseDate(v, dateFormat);
11800 var parsed = Date.parse(v);
11801 return parsed ? new Date(parsed) : null;
11810 Roo.data.Field.prototype = {
11818 * Ext JS Library 1.1.1
11819 * Copyright(c) 2006-2007, Ext JS, LLC.
11821 * Originally Released Under LGPL - original licence link has changed is not relivant.
11824 * <script type="text/javascript">
11827 // Base class for reading structured data from a data source. This class is intended to be
11828 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11831 * @class Roo.data.DataReader
11832 * Base class for reading structured data from a data source. This class is intended to be
11833 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11836 Roo.data.DataReader = function(meta, recordType){
11840 this.recordType = recordType instanceof Array ?
11841 Roo.data.Record.create(recordType) : recordType;
11844 Roo.data.DataReader.prototype = {
11846 * Create an empty record
11847 * @param {Object} data (optional) - overlay some values
11848 * @return {Roo.data.Record} record created.
11850 newRow : function(d) {
11852 this.recordType.prototype.fields.each(function(c) {
11854 case 'int' : da[c.name] = 0; break;
11855 case 'date' : da[c.name] = new Date(); break;
11856 case 'float' : da[c.name] = 0.0; break;
11857 case 'boolean' : da[c.name] = false; break;
11858 default : da[c.name] = ""; break;
11862 return new this.recordType(Roo.apply(da, d));
11867 * Ext JS Library 1.1.1
11868 * Copyright(c) 2006-2007, Ext JS, LLC.
11870 * Originally Released Under LGPL - original licence link has changed is not relivant.
11873 * <script type="text/javascript">
11877 * @class Roo.data.DataProxy
11878 * @extends Roo.data.Observable
11879 * This class is an abstract base class for implementations which provide retrieval of
11880 * unformatted data objects.<br>
11882 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11883 * (of the appropriate type which knows how to parse the data object) to provide a block of
11884 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11886 * Custom implementations must implement the load method as described in
11887 * {@link Roo.data.HttpProxy#load}.
11889 Roo.data.DataProxy = function(){
11892 * @event beforeload
11893 * Fires before a network request is made to retrieve a data object.
11894 * @param {Object} This DataProxy object.
11895 * @param {Object} params The params parameter to the load function.
11900 * Fires before the load method's callback is called.
11901 * @param {Object} This DataProxy object.
11902 * @param {Object} o The data object.
11903 * @param {Object} arg The callback argument object passed to the load function.
11907 * @event loadexception
11908 * Fires if an Exception occurs during data retrieval.
11909 * @param {Object} This DataProxy object.
11910 * @param {Object} o The data object.
11911 * @param {Object} arg The callback argument object passed to the load function.
11912 * @param {Object} e The Exception.
11914 loadexception : true
11916 Roo.data.DataProxy.superclass.constructor.call(this);
11919 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11922 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11926 * Ext JS Library 1.1.1
11927 * Copyright(c) 2006-2007, Ext JS, LLC.
11929 * Originally Released Under LGPL - original licence link has changed is not relivant.
11932 * <script type="text/javascript">
11935 * @class Roo.data.MemoryProxy
11936 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11937 * to the Reader when its load method is called.
11939 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11941 Roo.data.MemoryProxy = function(data){
11945 Roo.data.MemoryProxy.superclass.constructor.call(this);
11949 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11952 * Load data from the requested source (in this case an in-memory
11953 * data object passed to the constructor), read the data object into
11954 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11955 * process that block using the passed callback.
11956 * @param {Object} params This parameter is not used by the MemoryProxy class.
11957 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11958 * object into a block of Roo.data.Records.
11959 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11960 * The function must be passed <ul>
11961 * <li>The Record block object</li>
11962 * <li>The "arg" argument from the load function</li>
11963 * <li>A boolean success indicator</li>
11965 * @param {Object} scope The scope in which to call the callback
11966 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11968 load : function(params, reader, callback, scope, arg){
11969 params = params || {};
11972 result = reader.readRecords(this.data);
11974 this.fireEvent("loadexception", this, arg, null, e);
11975 callback.call(scope, null, arg, false);
11978 callback.call(scope, result, arg, true);
11982 update : function(params, records){
11987 * Ext JS Library 1.1.1
11988 * Copyright(c) 2006-2007, Ext JS, LLC.
11990 * Originally Released Under LGPL - original licence link has changed is not relivant.
11993 * <script type="text/javascript">
11996 * @class Roo.data.HttpProxy
11997 * @extends Roo.data.DataProxy
11998 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11999 * configured to reference a certain URL.<br><br>
12001 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12002 * from which the running page was served.<br><br>
12004 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12006 * Be aware that to enable the browser to parse an XML document, the server must set
12007 * the Content-Type header in the HTTP response to "text/xml".
12009 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12010 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12011 * will be used to make the request.
12013 Roo.data.HttpProxy = function(conn){
12014 Roo.data.HttpProxy.superclass.constructor.call(this);
12015 // is conn a conn config or a real conn?
12017 this.useAjax = !conn || !conn.events;
12021 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12022 // thse are take from connection...
12025 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12028 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12029 * extra parameters to each request made by this object. (defaults to undefined)
12032 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12033 * to each request made by this object. (defaults to undefined)
12036 * @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)
12039 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12042 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12048 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12052 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12053 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12054 * a finer-grained basis than the DataProxy events.
12056 getConnection : function(){
12057 return this.useAjax ? Roo.Ajax : this.conn;
12061 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12062 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12063 * process that block using the passed callback.
12064 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12065 * for the request to the remote server.
12066 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12067 * object into a block of Roo.data.Records.
12068 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12069 * The function must be passed <ul>
12070 * <li>The Record block object</li>
12071 * <li>The "arg" argument from the load function</li>
12072 * <li>A boolean success indicator</li>
12074 * @param {Object} scope The scope in which to call the callback
12075 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12077 load : function(params, reader, callback, scope, arg){
12078 if(this.fireEvent("beforeload", this, params) !== false){
12080 params : params || {},
12082 callback : callback,
12087 callback : this.loadResponse,
12091 Roo.applyIf(o, this.conn);
12092 if(this.activeRequest){
12093 Roo.Ajax.abort(this.activeRequest);
12095 this.activeRequest = Roo.Ajax.request(o);
12097 this.conn.request(o);
12100 callback.call(scope||this, null, arg, false);
12105 loadResponse : function(o, success, response){
12106 delete this.activeRequest;
12108 this.fireEvent("loadexception", this, o, response);
12109 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12114 result = o.reader.read(response);
12116 this.fireEvent("loadexception", this, o, response, e);
12117 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12121 this.fireEvent("load", this, o, o.request.arg);
12122 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12126 update : function(dataSet){
12131 updateResponse : function(dataSet){
12136 * Ext JS Library 1.1.1
12137 * Copyright(c) 2006-2007, Ext JS, LLC.
12139 * Originally Released Under LGPL - original licence link has changed is not relivant.
12142 * <script type="text/javascript">
12146 * @class Roo.data.ScriptTagProxy
12147 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12148 * other than the originating domain of the running page.<br><br>
12150 * <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
12151 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12153 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12154 * source code that is used as the source inside a <script> tag.<br><br>
12156 * In order for the browser to process the returned data, the server must wrap the data object
12157 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12158 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12159 * depending on whether the callback name was passed:
12162 boolean scriptTag = false;
12163 String cb = request.getParameter("callback");
12166 response.setContentType("text/javascript");
12168 response.setContentType("application/x-json");
12170 Writer out = response.getWriter();
12172 out.write(cb + "(");
12174 out.print(dataBlock.toJsonString());
12181 * @param {Object} config A configuration object.
12183 Roo.data.ScriptTagProxy = function(config){
12184 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12185 Roo.apply(this, config);
12186 this.head = document.getElementsByTagName("head")[0];
12189 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12191 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12193 * @cfg {String} url The URL from which to request the data object.
12196 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12200 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12201 * the server the name of the callback function set up by the load call to process the returned data object.
12202 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12203 * javascript output which calls this named function passing the data object as its only parameter.
12205 callbackParam : "callback",
12207 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12208 * name to the request.
12213 * Load data from the configured URL, read the data object into
12214 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12215 * process that block using the passed callback.
12216 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12217 * for the request to the remote server.
12218 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12219 * object into a block of Roo.data.Records.
12220 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12221 * The function must be passed <ul>
12222 * <li>The Record block object</li>
12223 * <li>The "arg" argument from the load function</li>
12224 * <li>A boolean success indicator</li>
12226 * @param {Object} scope The scope in which to call the callback
12227 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12229 load : function(params, reader, callback, scope, arg){
12230 if(this.fireEvent("beforeload", this, params) !== false){
12232 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12234 var url = this.url;
12235 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12237 url += "&_dc=" + (new Date().getTime());
12239 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12242 cb : "stcCallback"+transId,
12243 scriptId : "stcScript"+transId,
12247 callback : callback,
12253 window[trans.cb] = function(o){
12254 conn.handleResponse(o, trans);
12257 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12259 if(this.autoAbort !== false){
12263 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12265 var script = document.createElement("script");
12266 script.setAttribute("src", url);
12267 script.setAttribute("type", "text/javascript");
12268 script.setAttribute("id", trans.scriptId);
12269 this.head.appendChild(script);
12271 this.trans = trans;
12273 callback.call(scope||this, null, arg, false);
12278 isLoading : function(){
12279 return this.trans ? true : false;
12283 * Abort the current server request.
12285 abort : function(){
12286 if(this.isLoading()){
12287 this.destroyTrans(this.trans);
12292 destroyTrans : function(trans, isLoaded){
12293 this.head.removeChild(document.getElementById(trans.scriptId));
12294 clearTimeout(trans.timeoutId);
12296 window[trans.cb] = undefined;
12298 delete window[trans.cb];
12301 // if hasn't been loaded, wait for load to remove it to prevent script error
12302 window[trans.cb] = function(){
12303 window[trans.cb] = undefined;
12305 delete window[trans.cb];
12312 handleResponse : function(o, trans){
12313 this.trans = false;
12314 this.destroyTrans(trans, true);
12317 result = trans.reader.readRecords(o);
12319 this.fireEvent("loadexception", this, o, trans.arg, e);
12320 trans.callback.call(trans.scope||window, null, trans.arg, false);
12323 this.fireEvent("load", this, o, trans.arg);
12324 trans.callback.call(trans.scope||window, result, trans.arg, true);
12328 handleFailure : function(trans){
12329 this.trans = false;
12330 this.destroyTrans(trans, false);
12331 this.fireEvent("loadexception", this, null, trans.arg);
12332 trans.callback.call(trans.scope||window, null, trans.arg, false);
12336 * Ext JS Library 1.1.1
12337 * Copyright(c) 2006-2007, Ext JS, LLC.
12339 * Originally Released Under LGPL - original licence link has changed is not relivant.
12342 * <script type="text/javascript">
12346 * @class Roo.data.JsonReader
12347 * @extends Roo.data.DataReader
12348 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12349 * based on mappings in a provided Roo.data.Record constructor.
12351 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12352 * in the reply previously.
12357 var RecordDef = Roo.data.Record.create([
12358 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12359 {name: 'occupation'} // This field will use "occupation" as the mapping.
12361 var myReader = new Roo.data.JsonReader({
12362 totalProperty: "results", // The property which contains the total dataset size (optional)
12363 root: "rows", // The property which contains an Array of row objects
12364 id: "id" // The property within each row object that provides an ID for the record (optional)
12368 * This would consume a JSON file like this:
12370 { 'results': 2, 'rows': [
12371 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12372 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12375 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12376 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12377 * paged from the remote server.
12378 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12379 * @cfg {String} root name of the property which contains the Array of row objects.
12380 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12381 * @cfg {Array} fields Array of field definition objects
12383 * Create a new JsonReader
12384 * @param {Object} meta Metadata configuration options
12385 * @param {Object} recordType Either an Array of field definition objects,
12386 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12388 Roo.data.JsonReader = function(meta, recordType){
12391 // set some defaults:
12392 Roo.applyIf(meta, {
12393 totalProperty: 'total',
12394 successProperty : 'success',
12399 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12401 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12404 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12405 * Used by Store query builder to append _requestMeta to params.
12408 metaFromRemote : false,
12410 * This method is only used by a DataProxy which has retrieved data from a remote server.
12411 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12412 * @return {Object} data A data block which is used by an Roo.data.Store object as
12413 * a cache of Roo.data.Records.
12415 read : function(response){
12416 var json = response.responseText;
12418 var o = /* eval:var:o */ eval("("+json+")");
12420 throw {message: "JsonReader.read: Json object not found"};
12426 this.metaFromRemote = true;
12427 this.meta = o.metaData;
12428 this.recordType = Roo.data.Record.create(o.metaData.fields);
12429 this.onMetaChange(this.meta, this.recordType, o);
12431 return this.readRecords(o);
12434 // private function a store will implement
12435 onMetaChange : function(meta, recordType, o){
12442 simpleAccess: function(obj, subsc) {
12449 getJsonAccessor: function(){
12451 return function(expr) {
12453 return(re.test(expr))
12454 ? new Function("obj", "return obj." + expr)
12459 return Roo.emptyFn;
12464 * Create a data block containing Roo.data.Records from an XML document.
12465 * @param {Object} o An object which contains an Array of row objects in the property specified
12466 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12467 * which contains the total size of the dataset.
12468 * @return {Object} data A data block which is used by an Roo.data.Store object as
12469 * a cache of Roo.data.Records.
12471 readRecords : function(o){
12473 * After any data loads, the raw JSON data is available for further custom processing.
12477 var s = this.meta, Record = this.recordType,
12478 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12480 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12482 if(s.totalProperty) {
12483 this.getTotal = this.getJsonAccessor(s.totalProperty);
12485 if(s.successProperty) {
12486 this.getSuccess = this.getJsonAccessor(s.successProperty);
12488 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12490 var g = this.getJsonAccessor(s.id);
12491 this.getId = function(rec) {
12493 return (r === undefined || r === "") ? null : r;
12496 this.getId = function(){return null;};
12499 for(var jj = 0; jj < fl; jj++){
12501 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12502 this.ef[jj] = this.getJsonAccessor(map);
12506 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12507 if(s.totalProperty){
12508 var vt = parseInt(this.getTotal(o), 10);
12513 if(s.successProperty){
12514 var vs = this.getSuccess(o);
12515 if(vs === false || vs === 'false'){
12520 for(var i = 0; i < c; i++){
12523 var id = this.getId(n);
12524 for(var j = 0; j < fl; j++){
12526 var v = this.ef[j](n);
12528 Roo.log('missing convert for ' + f.name);
12532 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12534 var record = new Record(values, id);
12536 records[i] = record;
12542 totalRecords : totalRecords
12547 * Ext JS Library 1.1.1
12548 * Copyright(c) 2006-2007, Ext JS, LLC.
12550 * Originally Released Under LGPL - original licence link has changed is not relivant.
12553 * <script type="text/javascript">
12557 * @class Roo.data.ArrayReader
12558 * @extends Roo.data.DataReader
12559 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12560 * Each element of that Array represents a row of data fields. The
12561 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12562 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12566 var RecordDef = Roo.data.Record.create([
12567 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12568 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12570 var myReader = new Roo.data.ArrayReader({
12571 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12575 * This would consume an Array like this:
12577 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12579 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12581 * Create a new JsonReader
12582 * @param {Object} meta Metadata configuration options.
12583 * @param {Object} recordType Either an Array of field definition objects
12584 * as specified to {@link Roo.data.Record#create},
12585 * or an {@link Roo.data.Record} object
12586 * created using {@link Roo.data.Record#create}.
12588 Roo.data.ArrayReader = function(meta, recordType){
12589 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12592 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12594 * Create a data block containing Roo.data.Records from an XML document.
12595 * @param {Object} o An Array of row objects which represents the dataset.
12596 * @return {Object} data A data block which is used by an Roo.data.Store object as
12597 * a cache of Roo.data.Records.
12599 readRecords : function(o){
12600 var sid = this.meta ? this.meta.id : null;
12601 var recordType = this.recordType, fields = recordType.prototype.fields;
12604 for(var i = 0; i < root.length; i++){
12607 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12608 for(var j = 0, jlen = fields.length; j < jlen; j++){
12609 var f = fields.items[j];
12610 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12611 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12613 values[f.name] = v;
12615 var record = new recordType(values, id);
12617 records[records.length] = record;
12621 totalRecords : records.length
12630 * @class Roo.bootstrap.ComboBox
12631 * @extends Roo.bootstrap.TriggerField
12632 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12633 * @cfg {Boolean} append (true|false) default false
12634 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12635 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12636 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12637 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12638 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12639 * @cfg {Boolean} animate default true
12640 * @cfg {Boolean} emptyResultText only for touch device
12641 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12642 * @cfg {String} emptyTitle default ''
12644 * Create a new ComboBox.
12645 * @param {Object} config Configuration options
12647 Roo.bootstrap.ComboBox = function(config){
12648 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12652 * Fires when the dropdown list is expanded
12653 * @param {Roo.bootstrap.ComboBox} combo This combo box
12658 * Fires when the dropdown list is collapsed
12659 * @param {Roo.bootstrap.ComboBox} combo This combo box
12663 * @event beforeselect
12664 * Fires before a list item is selected. Return false to cancel the selection.
12665 * @param {Roo.bootstrap.ComboBox} combo This combo box
12666 * @param {Roo.data.Record} record The data record returned from the underlying store
12667 * @param {Number} index The index of the selected item in the dropdown list
12669 'beforeselect' : true,
12672 * Fires when a list item is selected
12673 * @param {Roo.bootstrap.ComboBox} combo This combo box
12674 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12675 * @param {Number} index The index of the selected item in the dropdown list
12679 * @event beforequery
12680 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12681 * The event object passed has these properties:
12682 * @param {Roo.bootstrap.ComboBox} combo This combo box
12683 * @param {String} query The query
12684 * @param {Boolean} forceAll true to force "all" query
12685 * @param {Boolean} cancel true to cancel the query
12686 * @param {Object} e The query event object
12688 'beforequery': true,
12691 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12692 * @param {Roo.bootstrap.ComboBox} combo This combo box
12697 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12698 * @param {Roo.bootstrap.ComboBox} combo This combo box
12699 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12704 * Fires when the remove value from the combobox array
12705 * @param {Roo.bootstrap.ComboBox} combo This combo box
12709 * @event afterremove
12710 * Fires when the remove value from the combobox array
12711 * @param {Roo.bootstrap.ComboBox} combo This combo box
12713 'afterremove' : true,
12715 * @event specialfilter
12716 * Fires when specialfilter
12717 * @param {Roo.bootstrap.ComboBox} combo This combo box
12719 'specialfilter' : true,
12722 * Fires when tick the element
12723 * @param {Roo.bootstrap.ComboBox} combo This combo box
12727 * @event touchviewdisplay
12728 * Fires when touch view require special display (default is using displayField)
12729 * @param {Roo.bootstrap.ComboBox} combo This combo box
12730 * @param {Object} cfg set html .
12732 'touchviewdisplay' : true
12737 this.tickItems = [];
12739 this.selectedIndex = -1;
12740 if(this.mode == 'local'){
12741 if(config.queryDelay === undefined){
12742 this.queryDelay = 10;
12744 if(config.minChars === undefined){
12750 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12753 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12754 * rendering into an Roo.Editor, defaults to false)
12757 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12758 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12761 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12764 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12765 * the dropdown list (defaults to undefined, with no header element)
12769 * @cfg {String/Roo.Template} tpl The template to use to render the output
12773 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12775 listWidth: undefined,
12777 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12778 * mode = 'remote' or 'text' if mode = 'local')
12780 displayField: undefined,
12783 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12784 * mode = 'remote' or 'value' if mode = 'local').
12785 * Note: use of a valueField requires the user make a selection
12786 * in order for a value to be mapped.
12788 valueField: undefined,
12790 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12795 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12796 * field's data value (defaults to the underlying DOM element's name)
12798 hiddenName: undefined,
12800 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12804 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12806 selectedClass: 'active',
12809 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12813 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12814 * anchor positions (defaults to 'tl-bl')
12816 listAlign: 'tl-bl?',
12818 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12822 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12823 * query specified by the allQuery config option (defaults to 'query')
12825 triggerAction: 'query',
12827 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12828 * (defaults to 4, does not apply if editable = false)
12832 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12833 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12837 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12838 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12842 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12843 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12847 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12848 * when editable = true (defaults to false)
12850 selectOnFocus:false,
12852 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12854 queryParam: 'query',
12856 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12857 * when mode = 'remote' (defaults to 'Loading...')
12859 loadingText: 'Loading...',
12861 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12865 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12869 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12870 * traditional select (defaults to true)
12874 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12878 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12882 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12883 * listWidth has a higher value)
12887 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12888 * allow the user to set arbitrary text into the field (defaults to false)
12890 forceSelection:false,
12892 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12893 * if typeAhead = true (defaults to 250)
12895 typeAheadDelay : 250,
12897 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12898 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12900 valueNotFoundText : undefined,
12902 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12904 blockFocus : false,
12907 * @cfg {Boolean} disableClear Disable showing of clear button.
12909 disableClear : false,
12911 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12913 alwaysQuery : false,
12916 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12921 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12923 invalidClass : "has-warning",
12926 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12928 validClass : "has-success",
12931 * @cfg {Boolean} specialFilter (true|false) special filter default false
12933 specialFilter : false,
12936 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12938 mobileTouchView : true,
12941 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12943 useNativeIOS : false,
12945 ios_options : false,
12957 btnPosition : 'right',
12958 triggerList : true,
12959 showToggleBtn : true,
12961 emptyResultText: 'Empty',
12962 triggerText : 'Select',
12965 // element that contains real text value.. (when hidden is used..)
12967 getAutoCreate : function()
12972 * Render classic select for iso
12975 if(Roo.isIOS && this.useNativeIOS){
12976 cfg = this.getAutoCreateNativeIOS();
12984 if(Roo.isTouch && this.mobileTouchView){
12985 cfg = this.getAutoCreateTouchView();
12992 if(!this.tickable){
12993 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12998 * ComboBox with tickable selections
13001 var align = this.labelAlign || this.parentLabelAlign();
13004 cls : 'form-group roo-combobox-tickable' //input-group
13007 var btn_text_select = '';
13008 var btn_text_done = '';
13009 var btn_text_cancel = '';
13011 if (this.btn_text_show) {
13012 btn_text_select = 'Select';
13013 btn_text_done = 'Done';
13014 btn_text_cancel = 'Cancel';
13019 cls : 'tickable-buttons',
13024 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13025 //html : this.triggerText
13026 html: btn_text_select
13032 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13034 html: btn_text_done
13040 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13042 html: btn_text_cancel
13048 buttons.cn.unshift({
13050 cls: 'roo-select2-search-field-input'
13056 Roo.each(buttons.cn, function(c){
13058 c.cls += ' btn-' + _this.size;
13061 if (_this.disabled) {
13072 cls: 'form-hidden-field'
13076 cls: 'roo-select2-choices',
13080 cls: 'roo-select2-search-field',
13091 cls: 'roo-select2-container input-group roo-select2-container-multi',
13096 // cls: 'typeahead typeahead-long dropdown-menu',
13097 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13102 if(this.hasFeedback && !this.allowBlank){
13106 cls: 'glyphicon form-control-feedback'
13109 combobox.cn.push(feedback);
13113 if (align ==='left' && this.fieldLabel.length) {
13115 cfg.cls += ' roo-form-group-label-left';
13120 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13121 tooltip : 'This field is required'
13126 cls : 'control-label',
13127 html : this.fieldLabel
13139 var labelCfg = cfg.cn[1];
13140 var contentCfg = cfg.cn[2];
13143 if(this.indicatorpos == 'right'){
13149 cls : 'control-label',
13153 html : this.fieldLabel
13157 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13158 tooltip : 'This field is required'
13173 labelCfg = cfg.cn[0];
13174 contentCfg = cfg.cn[1];
13178 if(this.labelWidth > 12){
13179 labelCfg.style = "width: " + this.labelWidth + 'px';
13182 if(this.labelWidth < 13 && this.labelmd == 0){
13183 this.labelmd = this.labelWidth;
13186 if(this.labellg > 0){
13187 labelCfg.cls += ' col-lg-' + this.labellg;
13188 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13191 if(this.labelmd > 0){
13192 labelCfg.cls += ' col-md-' + this.labelmd;
13193 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13196 if(this.labelsm > 0){
13197 labelCfg.cls += ' col-sm-' + this.labelsm;
13198 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13201 if(this.labelxs > 0){
13202 labelCfg.cls += ' col-xs-' + this.labelxs;
13203 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13207 } else if ( this.fieldLabel.length) {
13208 // Roo.log(" label");
13212 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13213 tooltip : 'This field is required'
13217 //cls : 'input-group-addon',
13218 html : this.fieldLabel
13223 if(this.indicatorpos == 'right'){
13227 //cls : 'input-group-addon',
13228 html : this.fieldLabel
13232 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13233 tooltip : 'This field is required'
13242 // Roo.log(" no label && no align");
13249 ['xs','sm','md','lg'].map(function(size){
13250 if (settings[size]) {
13251 cfg.cls += ' col-' + size + '-' + settings[size];
13259 _initEventsCalled : false,
13262 initEvents: function()
13264 if (this._initEventsCalled) { // as we call render... prevent looping...
13267 this._initEventsCalled = true;
13270 throw "can not find store for combo";
13273 this.indicator = this.indicatorEl();
13275 this.store = Roo.factory(this.store, Roo.data);
13276 this.store.parent = this;
13278 // if we are building from html. then this element is so complex, that we can not really
13279 // use the rendered HTML.
13280 // so we have to trash and replace the previous code.
13281 if (Roo.XComponent.build_from_html) {
13282 // remove this element....
13283 var e = this.el.dom, k=0;
13284 while (e ) { e = e.previousSibling; ++k;}
13289 this.rendered = false;
13291 this.render(this.parent().getChildContainer(true), k);
13294 if(Roo.isIOS && this.useNativeIOS){
13295 this.initIOSView();
13303 if(Roo.isTouch && this.mobileTouchView){
13304 this.initTouchView();
13309 this.initTickableEvents();
13313 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13315 if(this.hiddenName){
13317 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13319 this.hiddenField.dom.value =
13320 this.hiddenValue !== undefined ? this.hiddenValue :
13321 this.value !== undefined ? this.value : '';
13323 // prevent input submission
13324 this.el.dom.removeAttribute('name');
13325 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13330 // this.el.dom.setAttribute('autocomplete', 'off');
13333 var cls = 'x-combo-list';
13335 //this.list = new Roo.Layer({
13336 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13342 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13343 _this.list.setWidth(lw);
13346 this.list.on('mouseover', this.onViewOver, this);
13347 this.list.on('mousemove', this.onViewMove, this);
13348 this.list.on('scroll', this.onViewScroll, this);
13351 this.list.swallowEvent('mousewheel');
13352 this.assetHeight = 0;
13355 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13356 this.assetHeight += this.header.getHeight();
13359 this.innerList = this.list.createChild({cls:cls+'-inner'});
13360 this.innerList.on('mouseover', this.onViewOver, this);
13361 this.innerList.on('mousemove', this.onViewMove, this);
13362 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13364 if(this.allowBlank && !this.pageSize && !this.disableClear){
13365 this.footer = this.list.createChild({cls:cls+'-ft'});
13366 this.pageTb = new Roo.Toolbar(this.footer);
13370 this.footer = this.list.createChild({cls:cls+'-ft'});
13371 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13372 {pageSize: this.pageSize});
13376 if (this.pageTb && this.allowBlank && !this.disableClear) {
13378 this.pageTb.add(new Roo.Toolbar.Fill(), {
13379 cls: 'x-btn-icon x-btn-clear',
13381 handler: function()
13384 _this.clearValue();
13385 _this.onSelect(false, -1);
13390 this.assetHeight += this.footer.getHeight();
13395 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13398 this.view = new Roo.View(this.list, this.tpl, {
13399 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13401 //this.view.wrapEl.setDisplayed(false);
13402 this.view.on('click', this.onViewClick, this);
13405 this.store.on('beforeload', this.onBeforeLoad, this);
13406 this.store.on('load', this.onLoad, this);
13407 this.store.on('loadexception', this.onLoadException, this);
13409 if(this.resizable){
13410 this.resizer = new Roo.Resizable(this.list, {
13411 pinned:true, handles:'se'
13413 this.resizer.on('resize', function(r, w, h){
13414 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13415 this.listWidth = w;
13416 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13417 this.restrictHeight();
13419 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13422 if(!this.editable){
13423 this.editable = true;
13424 this.setEditable(false);
13429 if (typeof(this.events.add.listeners) != 'undefined') {
13431 this.addicon = this.wrap.createChild(
13432 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13434 this.addicon.on('click', function(e) {
13435 this.fireEvent('add', this);
13438 if (typeof(this.events.edit.listeners) != 'undefined') {
13440 this.editicon = this.wrap.createChild(
13441 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13442 if (this.addicon) {
13443 this.editicon.setStyle('margin-left', '40px');
13445 this.editicon.on('click', function(e) {
13447 // we fire even if inothing is selected..
13448 this.fireEvent('edit', this, this.lastData );
13454 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13455 "up" : function(e){
13456 this.inKeyMode = true;
13460 "down" : function(e){
13461 if(!this.isExpanded()){
13462 this.onTriggerClick();
13464 this.inKeyMode = true;
13469 "enter" : function(e){
13470 // this.onViewClick();
13474 if(this.fireEvent("specialkey", this, e)){
13475 this.onViewClick(false);
13481 "esc" : function(e){
13485 "tab" : function(e){
13488 if(this.fireEvent("specialkey", this, e)){
13489 this.onViewClick(false);
13497 doRelay : function(foo, bar, hname){
13498 if(hname == 'down' || this.scope.isExpanded()){
13499 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13508 this.queryDelay = Math.max(this.queryDelay || 10,
13509 this.mode == 'local' ? 10 : 250);
13512 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13514 if(this.typeAhead){
13515 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13517 if(this.editable !== false){
13518 this.inputEl().on("keyup", this.onKeyUp, this);
13520 if(this.forceSelection){
13521 this.inputEl().on('blur', this.doForce, this);
13525 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13526 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13530 initTickableEvents: function()
13534 if(this.hiddenName){
13536 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13538 this.hiddenField.dom.value =
13539 this.hiddenValue !== undefined ? this.hiddenValue :
13540 this.value !== undefined ? this.value : '';
13542 // prevent input submission
13543 this.el.dom.removeAttribute('name');
13544 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13549 // this.list = this.el.select('ul.dropdown-menu',true).first();
13551 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13552 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13553 if(this.triggerList){
13554 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13557 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13558 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13560 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13561 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13563 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13564 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13566 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13567 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13568 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13571 this.cancelBtn.hide();
13576 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13577 _this.list.setWidth(lw);
13580 this.list.on('mouseover', this.onViewOver, this);
13581 this.list.on('mousemove', this.onViewMove, this);
13583 this.list.on('scroll', this.onViewScroll, this);
13586 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>';
13589 this.view = new Roo.View(this.list, this.tpl, {
13590 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13593 //this.view.wrapEl.setDisplayed(false);
13594 this.view.on('click', this.onViewClick, this);
13598 this.store.on('beforeload', this.onBeforeLoad, this);
13599 this.store.on('load', this.onLoad, this);
13600 this.store.on('loadexception', this.onLoadException, this);
13603 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13604 "up" : function(e){
13605 this.inKeyMode = true;
13609 "down" : function(e){
13610 this.inKeyMode = true;
13614 "enter" : function(e){
13615 if(this.fireEvent("specialkey", this, e)){
13616 this.onViewClick(false);
13622 "esc" : function(e){
13623 this.onTickableFooterButtonClick(e, false, false);
13626 "tab" : function(e){
13627 this.fireEvent("specialkey", this, e);
13629 this.onTickableFooterButtonClick(e, false, false);
13636 doRelay : function(e, fn, key){
13637 if(this.scope.isExpanded()){
13638 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13647 this.queryDelay = Math.max(this.queryDelay || 10,
13648 this.mode == 'local' ? 10 : 250);
13651 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13653 if(this.typeAhead){
13654 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13657 if(this.editable !== false){
13658 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13661 this.indicator = this.indicatorEl();
13663 if(this.indicator){
13664 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13665 this.indicator.hide();
13670 onDestroy : function(){
13672 this.view.setStore(null);
13673 this.view.el.removeAllListeners();
13674 this.view.el.remove();
13675 this.view.purgeListeners();
13678 this.list.dom.innerHTML = '';
13682 this.store.un('beforeload', this.onBeforeLoad, this);
13683 this.store.un('load', this.onLoad, this);
13684 this.store.un('loadexception', this.onLoadException, this);
13686 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13690 fireKey : function(e){
13691 if(e.isNavKeyPress() && !this.list.isVisible()){
13692 this.fireEvent("specialkey", this, e);
13697 onResize: function(w, h){
13698 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13700 // if(typeof w != 'number'){
13701 // // we do not handle it!?!?
13704 // var tw = this.trigger.getWidth();
13705 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13706 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13708 // this.inputEl().setWidth( this.adjustWidth('input', x));
13710 // //this.trigger.setStyle('left', x+'px');
13712 // if(this.list && this.listWidth === undefined){
13713 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13714 // this.list.setWidth(lw);
13715 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13723 * Allow or prevent the user from directly editing the field text. If false is passed,
13724 * the user will only be able to select from the items defined in the dropdown list. This method
13725 * is the runtime equivalent of setting the 'editable' config option at config time.
13726 * @param {Boolean} value True to allow the user to directly edit the field text
13728 setEditable : function(value){
13729 if(value == this.editable){
13732 this.editable = value;
13734 this.inputEl().dom.setAttribute('readOnly', true);
13735 this.inputEl().on('mousedown', this.onTriggerClick, this);
13736 this.inputEl().addClass('x-combo-noedit');
13738 this.inputEl().dom.setAttribute('readOnly', false);
13739 this.inputEl().un('mousedown', this.onTriggerClick, this);
13740 this.inputEl().removeClass('x-combo-noedit');
13746 onBeforeLoad : function(combo,opts){
13747 if(!this.hasFocus){
13751 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13753 this.restrictHeight();
13754 this.selectedIndex = -1;
13758 onLoad : function(){
13760 this.hasQuery = false;
13762 if(!this.hasFocus){
13766 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13767 this.loading.hide();
13770 if(this.store.getCount() > 0){
13773 this.restrictHeight();
13774 if(this.lastQuery == this.allQuery){
13775 if(this.editable && !this.tickable){
13776 this.inputEl().dom.select();
13780 !this.selectByValue(this.value, true) &&
13783 !this.store.lastOptions ||
13784 typeof(this.store.lastOptions.add) == 'undefined' ||
13785 this.store.lastOptions.add != true
13788 this.select(0, true);
13791 if(this.autoFocus){
13794 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13795 this.taTask.delay(this.typeAheadDelay);
13799 this.onEmptyResults();
13805 onLoadException : function()
13807 this.hasQuery = false;
13809 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13810 this.loading.hide();
13813 if(this.tickable && this.editable){
13818 // only causes errors at present
13819 //Roo.log(this.store.reader.jsonData);
13820 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13822 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13828 onTypeAhead : function(){
13829 if(this.store.getCount() > 0){
13830 var r = this.store.getAt(0);
13831 var newValue = r.data[this.displayField];
13832 var len = newValue.length;
13833 var selStart = this.getRawValue().length;
13835 if(selStart != len){
13836 this.setRawValue(newValue);
13837 this.selectText(selStart, newValue.length);
13843 onSelect : function(record, index){
13845 if(this.fireEvent('beforeselect', this, record, index) !== false){
13847 this.setFromData(index > -1 ? record.data : false);
13850 this.fireEvent('select', this, record, index);
13855 * Returns the currently selected field value or empty string if no value is set.
13856 * @return {String} value The selected value
13858 getValue : function()
13860 if(Roo.isIOS && this.useNativeIOS){
13861 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13865 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13868 if(this.valueField){
13869 return typeof this.value != 'undefined' ? this.value : '';
13871 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13875 getRawValue : function()
13877 if(Roo.isIOS && this.useNativeIOS){
13878 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13881 var v = this.inputEl().getValue();
13887 * Clears any text/value currently set in the field
13889 clearValue : function(){
13891 if(this.hiddenField){
13892 this.hiddenField.dom.value = '';
13895 this.setRawValue('');
13896 this.lastSelectionText = '';
13897 this.lastData = false;
13899 var close = this.closeTriggerEl();
13910 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13911 * will be displayed in the field. If the value does not match the data value of an existing item,
13912 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13913 * Otherwise the field will be blank (although the value will still be set).
13914 * @param {String} value The value to match
13916 setValue : function(v)
13918 if(Roo.isIOS && this.useNativeIOS){
13919 this.setIOSValue(v);
13929 if(this.valueField){
13930 var r = this.findRecord(this.valueField, v);
13932 text = r.data[this.displayField];
13933 }else if(this.valueNotFoundText !== undefined){
13934 text = this.valueNotFoundText;
13937 this.lastSelectionText = text;
13938 if(this.hiddenField){
13939 this.hiddenField.dom.value = v;
13941 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13944 var close = this.closeTriggerEl();
13947 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13953 * @property {Object} the last set data for the element
13958 * Sets the value of the field based on a object which is related to the record format for the store.
13959 * @param {Object} value the value to set as. or false on reset?
13961 setFromData : function(o){
13968 var dv = ''; // display value
13969 var vv = ''; // value value..
13971 if (this.displayField) {
13972 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13974 // this is an error condition!!!
13975 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13978 if(this.valueField){
13979 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13982 var close = this.closeTriggerEl();
13985 if(dv.length || vv * 1 > 0){
13987 this.blockFocus=true;
13993 if(this.hiddenField){
13994 this.hiddenField.dom.value = vv;
13996 this.lastSelectionText = dv;
13997 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14001 // no hidden field.. - we store the value in 'value', but still display
14002 // display field!!!!
14003 this.lastSelectionText = dv;
14004 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14011 reset : function(){
14012 // overridden so that last data is reset..
14019 this.setValue(this.originalValue);
14020 //this.clearInvalid();
14021 this.lastData = false;
14023 this.view.clearSelections();
14029 findRecord : function(prop, value){
14031 if(this.store.getCount() > 0){
14032 this.store.each(function(r){
14033 if(r.data[prop] == value){
14043 getName: function()
14045 // returns hidden if it's set..
14046 if (!this.rendered) {return ''};
14047 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14051 onViewMove : function(e, t){
14052 this.inKeyMode = false;
14056 onViewOver : function(e, t){
14057 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14060 var item = this.view.findItemFromChild(t);
14063 var index = this.view.indexOf(item);
14064 this.select(index, false);
14069 onViewClick : function(view, doFocus, el, e)
14071 var index = this.view.getSelectedIndexes()[0];
14073 var r = this.store.getAt(index);
14077 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14084 Roo.each(this.tickItems, function(v,k){
14086 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14088 _this.tickItems.splice(k, 1);
14090 if(typeof(e) == 'undefined' && view == false){
14091 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14103 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14104 this.tickItems.push(r.data);
14107 if(typeof(e) == 'undefined' && view == false){
14108 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14115 this.onSelect(r, index);
14117 if(doFocus !== false && !this.blockFocus){
14118 this.inputEl().focus();
14123 restrictHeight : function(){
14124 //this.innerList.dom.style.height = '';
14125 //var inner = this.innerList.dom;
14126 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14127 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14128 //this.list.beginUpdate();
14129 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14130 this.list.alignTo(this.inputEl(), this.listAlign);
14131 this.list.alignTo(this.inputEl(), this.listAlign);
14132 //this.list.endUpdate();
14136 onEmptyResults : function(){
14138 if(this.tickable && this.editable){
14139 this.hasFocus = false;
14140 this.restrictHeight();
14148 * Returns true if the dropdown list is expanded, else false.
14150 isExpanded : function(){
14151 return this.list.isVisible();
14155 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14156 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14157 * @param {String} value The data value of the item to select
14158 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14159 * selected item if it is not currently in view (defaults to true)
14160 * @return {Boolean} True if the value matched an item in the list, else false
14162 selectByValue : function(v, scrollIntoView){
14163 if(v !== undefined && v !== null){
14164 var r = this.findRecord(this.valueField || this.displayField, v);
14166 this.select(this.store.indexOf(r), scrollIntoView);
14174 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14175 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14176 * @param {Number} index The zero-based index of the list item to select
14177 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14178 * selected item if it is not currently in view (defaults to true)
14180 select : function(index, scrollIntoView){
14181 this.selectedIndex = index;
14182 this.view.select(index);
14183 if(scrollIntoView !== false){
14184 var el = this.view.getNode(index);
14186 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14189 this.list.scrollChildIntoView(el, false);
14195 selectNext : function(){
14196 var ct = this.store.getCount();
14198 if(this.selectedIndex == -1){
14200 }else if(this.selectedIndex < ct-1){
14201 this.select(this.selectedIndex+1);
14207 selectPrev : function(){
14208 var ct = this.store.getCount();
14210 if(this.selectedIndex == -1){
14212 }else if(this.selectedIndex != 0){
14213 this.select(this.selectedIndex-1);
14219 onKeyUp : function(e){
14220 if(this.editable !== false && !e.isSpecialKey()){
14221 this.lastKey = e.getKey();
14222 this.dqTask.delay(this.queryDelay);
14227 validateBlur : function(){
14228 return !this.list || !this.list.isVisible();
14232 initQuery : function(){
14234 var v = this.getRawValue();
14236 if(this.tickable && this.editable){
14237 v = this.tickableInputEl().getValue();
14244 doForce : function(){
14245 if(this.inputEl().dom.value.length > 0){
14246 this.inputEl().dom.value =
14247 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14253 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14254 * query allowing the query action to be canceled if needed.
14255 * @param {String} query The SQL query to execute
14256 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14257 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14258 * saved in the current store (defaults to false)
14260 doQuery : function(q, forceAll){
14262 if(q === undefined || q === null){
14267 forceAll: forceAll,
14271 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14276 forceAll = qe.forceAll;
14277 if(forceAll === true || (q.length >= this.minChars)){
14279 this.hasQuery = true;
14281 if(this.lastQuery != q || this.alwaysQuery){
14282 this.lastQuery = q;
14283 if(this.mode == 'local'){
14284 this.selectedIndex = -1;
14286 this.store.clearFilter();
14289 if(this.specialFilter){
14290 this.fireEvent('specialfilter', this);
14295 this.store.filter(this.displayField, q);
14298 this.store.fireEvent("datachanged", this.store);
14305 this.store.baseParams[this.queryParam] = q;
14307 var options = {params : this.getParams(q)};
14310 options.add = true;
14311 options.params.start = this.page * this.pageSize;
14314 this.store.load(options);
14317 * this code will make the page width larger, at the beginning, the list not align correctly,
14318 * we should expand the list on onLoad
14319 * so command out it
14324 this.selectedIndex = -1;
14329 this.loadNext = false;
14333 getParams : function(q){
14335 //p[this.queryParam] = q;
14339 p.limit = this.pageSize;
14345 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14347 collapse : function(){
14348 if(!this.isExpanded()){
14354 this.hasFocus = false;
14358 this.cancelBtn.hide();
14359 this.trigger.show();
14362 this.tickableInputEl().dom.value = '';
14363 this.tickableInputEl().blur();
14368 Roo.get(document).un('mousedown', this.collapseIf, this);
14369 Roo.get(document).un('mousewheel', this.collapseIf, this);
14370 if (!this.editable) {
14371 Roo.get(document).un('keydown', this.listKeyPress, this);
14373 this.fireEvent('collapse', this);
14379 collapseIf : function(e){
14380 var in_combo = e.within(this.el);
14381 var in_list = e.within(this.list);
14382 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14384 if (in_combo || in_list || is_list) {
14385 //e.stopPropagation();
14390 this.onTickableFooterButtonClick(e, false, false);
14398 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14400 expand : function(){
14402 if(this.isExpanded() || !this.hasFocus){
14406 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14407 this.list.setWidth(lw);
14413 this.restrictHeight();
14417 this.tickItems = Roo.apply([], this.item);
14420 this.cancelBtn.show();
14421 this.trigger.hide();
14424 this.tickableInputEl().focus();
14429 Roo.get(document).on('mousedown', this.collapseIf, this);
14430 Roo.get(document).on('mousewheel', this.collapseIf, this);
14431 if (!this.editable) {
14432 Roo.get(document).on('keydown', this.listKeyPress, this);
14435 this.fireEvent('expand', this);
14439 // Implements the default empty TriggerField.onTriggerClick function
14440 onTriggerClick : function(e)
14442 Roo.log('trigger click');
14444 if(this.disabled || !this.triggerList){
14449 this.loadNext = false;
14451 if(this.isExpanded()){
14453 if (!this.blockFocus) {
14454 this.inputEl().focus();
14458 this.hasFocus = true;
14459 if(this.triggerAction == 'all') {
14460 this.doQuery(this.allQuery, true);
14462 this.doQuery(this.getRawValue());
14464 if (!this.blockFocus) {
14465 this.inputEl().focus();
14470 onTickableTriggerClick : function(e)
14477 this.loadNext = false;
14478 this.hasFocus = true;
14480 if(this.triggerAction == 'all') {
14481 this.doQuery(this.allQuery, true);
14483 this.doQuery(this.getRawValue());
14487 onSearchFieldClick : function(e)
14489 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14490 this.onTickableFooterButtonClick(e, false, false);
14494 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14499 this.loadNext = false;
14500 this.hasFocus = true;
14502 if(this.triggerAction == 'all') {
14503 this.doQuery(this.allQuery, true);
14505 this.doQuery(this.getRawValue());
14509 listKeyPress : function(e)
14511 //Roo.log('listkeypress');
14512 // scroll to first matching element based on key pres..
14513 if (e.isSpecialKey()) {
14516 var k = String.fromCharCode(e.getKey()).toUpperCase();
14519 var csel = this.view.getSelectedNodes();
14520 var cselitem = false;
14522 var ix = this.view.indexOf(csel[0]);
14523 cselitem = this.store.getAt(ix);
14524 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14530 this.store.each(function(v) {
14532 // start at existing selection.
14533 if (cselitem.id == v.id) {
14539 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14540 match = this.store.indexOf(v);
14546 if (match === false) {
14547 return true; // no more action?
14550 this.view.select(match);
14551 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14552 sn.scrollIntoView(sn.dom.parentNode, false);
14555 onViewScroll : function(e, t){
14557 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){
14561 this.hasQuery = true;
14563 this.loading = this.list.select('.loading', true).first();
14565 if(this.loading === null){
14566 this.list.createChild({
14568 cls: 'loading roo-select2-more-results roo-select2-active',
14569 html: 'Loading more results...'
14572 this.loading = this.list.select('.loading', true).first();
14574 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14576 this.loading.hide();
14579 this.loading.show();
14584 this.loadNext = true;
14586 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14591 addItem : function(o)
14593 var dv = ''; // display value
14595 if (this.displayField) {
14596 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14598 // this is an error condition!!!
14599 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14606 var choice = this.choices.createChild({
14608 cls: 'roo-select2-search-choice',
14617 cls: 'roo-select2-search-choice-close fa fa-times',
14622 }, this.searchField);
14624 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14626 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14634 this.inputEl().dom.value = '';
14639 onRemoveItem : function(e, _self, o)
14641 e.preventDefault();
14643 this.lastItem = Roo.apply([], this.item);
14645 var index = this.item.indexOf(o.data) * 1;
14648 Roo.log('not this item?!');
14652 this.item.splice(index, 1);
14657 this.fireEvent('remove', this, e);
14663 syncValue : function()
14665 if(!this.item.length){
14672 Roo.each(this.item, function(i){
14673 if(_this.valueField){
14674 value.push(i[_this.valueField]);
14681 this.value = value.join(',');
14683 if(this.hiddenField){
14684 this.hiddenField.dom.value = this.value;
14687 this.store.fireEvent("datachanged", this.store);
14692 clearItem : function()
14694 if(!this.multiple){
14700 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14708 if(this.tickable && !Roo.isTouch){
14709 this.view.refresh();
14713 inputEl: function ()
14715 if(Roo.isIOS && this.useNativeIOS){
14716 return this.el.select('select.roo-ios-select', true).first();
14719 if(Roo.isTouch && this.mobileTouchView){
14720 return this.el.select('input.form-control',true).first();
14724 return this.searchField;
14727 return this.el.select('input.form-control',true).first();
14730 onTickableFooterButtonClick : function(e, btn, el)
14732 e.preventDefault();
14734 this.lastItem = Roo.apply([], this.item);
14736 if(btn && btn.name == 'cancel'){
14737 this.tickItems = Roo.apply([], this.item);
14746 Roo.each(this.tickItems, function(o){
14754 validate : function()
14756 if(this.getVisibilityEl().hasClass('hidden')){
14760 var v = this.getRawValue();
14763 v = this.getValue();
14766 if(this.disabled || this.allowBlank || v.length){
14771 this.markInvalid();
14775 tickableInputEl : function()
14777 if(!this.tickable || !this.editable){
14778 return this.inputEl();
14781 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14785 getAutoCreateTouchView : function()
14790 cls: 'form-group' //input-group
14796 type : this.inputType,
14797 cls : 'form-control x-combo-noedit',
14798 autocomplete: 'new-password',
14799 placeholder : this.placeholder || '',
14804 input.name = this.name;
14808 input.cls += ' input-' + this.size;
14811 if (this.disabled) {
14812 input.disabled = true;
14823 inputblock.cls += ' input-group';
14825 inputblock.cn.unshift({
14827 cls : 'input-group-addon',
14832 if(this.removable && !this.multiple){
14833 inputblock.cls += ' roo-removable';
14835 inputblock.cn.push({
14838 cls : 'roo-combo-removable-btn close'
14842 if(this.hasFeedback && !this.allowBlank){
14844 inputblock.cls += ' has-feedback';
14846 inputblock.cn.push({
14848 cls: 'glyphicon form-control-feedback'
14855 inputblock.cls += (this.before) ? '' : ' input-group';
14857 inputblock.cn.push({
14859 cls : 'input-group-addon',
14870 cls: 'form-hidden-field'
14884 cls: 'form-hidden-field'
14888 cls: 'roo-select2-choices',
14892 cls: 'roo-select2-search-field',
14905 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14911 if(!this.multiple && this.showToggleBtn){
14918 if (this.caret != false) {
14921 cls: 'fa fa-' + this.caret
14928 cls : 'input-group-addon btn dropdown-toggle',
14933 cls: 'combobox-clear',
14947 combobox.cls += ' roo-select2-container-multi';
14950 var align = this.labelAlign || this.parentLabelAlign();
14952 if (align ==='left' && this.fieldLabel.length) {
14957 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14958 tooltip : 'This field is required'
14962 cls : 'control-label',
14963 html : this.fieldLabel
14974 var labelCfg = cfg.cn[1];
14975 var contentCfg = cfg.cn[2];
14978 if(this.indicatorpos == 'right'){
14983 cls : 'control-label',
14987 html : this.fieldLabel
14991 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14992 tooltip : 'This field is required'
15005 labelCfg = cfg.cn[0];
15006 contentCfg = cfg.cn[1];
15011 if(this.labelWidth > 12){
15012 labelCfg.style = "width: " + this.labelWidth + 'px';
15015 if(this.labelWidth < 13 && this.labelmd == 0){
15016 this.labelmd = this.labelWidth;
15019 if(this.labellg > 0){
15020 labelCfg.cls += ' col-lg-' + this.labellg;
15021 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15024 if(this.labelmd > 0){
15025 labelCfg.cls += ' col-md-' + this.labelmd;
15026 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15029 if(this.labelsm > 0){
15030 labelCfg.cls += ' col-sm-' + this.labelsm;
15031 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15034 if(this.labelxs > 0){
15035 labelCfg.cls += ' col-xs-' + this.labelxs;
15036 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15040 } else if ( this.fieldLabel.length) {
15044 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15045 tooltip : 'This field is required'
15049 cls : 'control-label',
15050 html : this.fieldLabel
15061 if(this.indicatorpos == 'right'){
15065 cls : 'control-label',
15066 html : this.fieldLabel,
15070 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15071 tooltip : 'This field is required'
15088 var settings = this;
15090 ['xs','sm','md','lg'].map(function(size){
15091 if (settings[size]) {
15092 cfg.cls += ' col-' + size + '-' + settings[size];
15099 initTouchView : function()
15101 this.renderTouchView();
15103 this.touchViewEl.on('scroll', function(){
15104 this.el.dom.scrollTop = 0;
15107 this.originalValue = this.getValue();
15109 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15111 this.inputEl().on("click", this.showTouchView, this);
15112 if (this.triggerEl) {
15113 this.triggerEl.on("click", this.showTouchView, this);
15117 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15118 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15120 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15122 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15123 this.store.on('load', this.onTouchViewLoad, this);
15124 this.store.on('loadexception', this.onTouchViewLoadException, this);
15126 if(this.hiddenName){
15128 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15130 this.hiddenField.dom.value =
15131 this.hiddenValue !== undefined ? this.hiddenValue :
15132 this.value !== undefined ? this.value : '';
15134 this.el.dom.removeAttribute('name');
15135 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15139 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15140 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15143 if(this.removable && !this.multiple){
15144 var close = this.closeTriggerEl();
15146 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15147 close.on('click', this.removeBtnClick, this, close);
15151 * fix the bug in Safari iOS8
15153 this.inputEl().on("focus", function(e){
15154 document.activeElement.blur();
15162 renderTouchView : function()
15164 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15165 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15167 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15168 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15170 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15171 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15172 this.touchViewBodyEl.setStyle('overflow', 'auto');
15174 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15175 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15177 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15178 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15182 showTouchView : function()
15188 this.touchViewHeaderEl.hide();
15190 if(this.modalTitle.length){
15191 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15192 this.touchViewHeaderEl.show();
15195 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15196 this.touchViewEl.show();
15198 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15200 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15201 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15203 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15205 if(this.modalTitle.length){
15206 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15209 this.touchViewBodyEl.setHeight(bodyHeight);
15213 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15215 this.touchViewEl.addClass('in');
15218 this.doTouchViewQuery();
15222 hideTouchView : function()
15224 this.touchViewEl.removeClass('in');
15228 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15230 this.touchViewEl.setStyle('display', 'none');
15235 setTouchViewValue : function()
15242 Roo.each(this.tickItems, function(o){
15247 this.hideTouchView();
15250 doTouchViewQuery : function()
15259 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15263 if(!this.alwaysQuery || this.mode == 'local'){
15264 this.onTouchViewLoad();
15271 onTouchViewBeforeLoad : function(combo,opts)
15277 onTouchViewLoad : function()
15279 if(this.store.getCount() < 1){
15280 this.onTouchViewEmptyResults();
15284 this.clearTouchView();
15286 var rawValue = this.getRawValue();
15288 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15290 this.tickItems = [];
15292 this.store.data.each(function(d, rowIndex){
15293 var row = this.touchViewListGroup.createChild(template);
15295 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15296 row.addClass(d.data.cls);
15299 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15302 html : d.data[this.displayField]
15305 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15306 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15309 row.removeClass('selected');
15310 if(!this.multiple && this.valueField &&
15311 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15314 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15315 row.addClass('selected');
15318 if(this.multiple && this.valueField &&
15319 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15323 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15324 this.tickItems.push(d.data);
15327 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15331 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15333 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15335 if(this.modalTitle.length){
15336 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15339 var listHeight = this.touchViewListGroup.getHeight();
15343 if(firstChecked && listHeight > bodyHeight){
15344 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15349 onTouchViewLoadException : function()
15351 this.hideTouchView();
15354 onTouchViewEmptyResults : function()
15356 this.clearTouchView();
15358 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15360 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15364 clearTouchView : function()
15366 this.touchViewListGroup.dom.innerHTML = '';
15369 onTouchViewClick : function(e, el, o)
15371 e.preventDefault();
15374 var rowIndex = o.rowIndex;
15376 var r = this.store.getAt(rowIndex);
15378 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15380 if(!this.multiple){
15381 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15382 c.dom.removeAttribute('checked');
15385 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15387 this.setFromData(r.data);
15389 var close = this.closeTriggerEl();
15395 this.hideTouchView();
15397 this.fireEvent('select', this, r, rowIndex);
15402 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15403 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15404 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15408 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15409 this.addItem(r.data);
15410 this.tickItems.push(r.data);
15414 getAutoCreateNativeIOS : function()
15417 cls: 'form-group' //input-group,
15422 cls : 'roo-ios-select'
15426 combobox.name = this.name;
15429 if (this.disabled) {
15430 combobox.disabled = true;
15433 var settings = this;
15435 ['xs','sm','md','lg'].map(function(size){
15436 if (settings[size]) {
15437 cfg.cls += ' col-' + size + '-' + settings[size];
15447 initIOSView : function()
15449 this.store.on('load', this.onIOSViewLoad, this);
15454 onIOSViewLoad : function()
15456 if(this.store.getCount() < 1){
15460 this.clearIOSView();
15462 if(this.allowBlank) {
15464 var default_text = '-- SELECT --';
15466 if(this.placeholder.length){
15467 default_text = this.placeholder;
15470 if(this.emptyTitle.length){
15471 default_text += ' - ' + this.emptyTitle + ' -';
15474 var opt = this.inputEl().createChild({
15477 html : default_text
15481 o[this.valueField] = 0;
15482 o[this.displayField] = default_text;
15484 this.ios_options.push({
15491 this.store.data.each(function(d, rowIndex){
15495 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15496 html = d.data[this.displayField];
15501 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15502 value = d.data[this.valueField];
15511 if(this.value == d.data[this.valueField]){
15512 option['selected'] = true;
15515 var opt = this.inputEl().createChild(option);
15517 this.ios_options.push({
15524 this.inputEl().on('change', function(){
15525 this.fireEvent('select', this);
15530 clearIOSView: function()
15532 this.inputEl().dom.innerHTML = '';
15534 this.ios_options = [];
15537 setIOSValue: function(v)
15541 if(!this.ios_options){
15545 Roo.each(this.ios_options, function(opts){
15547 opts.el.dom.removeAttribute('selected');
15549 if(opts.data[this.valueField] != v){
15553 opts.el.dom.setAttribute('selected', true);
15559 * @cfg {Boolean} grow
15563 * @cfg {Number} growMin
15567 * @cfg {Number} growMax
15576 Roo.apply(Roo.bootstrap.ComboBox, {
15580 cls: 'modal-header',
15602 cls: 'list-group-item',
15606 cls: 'roo-combobox-list-group-item-value'
15610 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15624 listItemCheckbox : {
15626 cls: 'list-group-item',
15630 cls: 'roo-combobox-list-group-item-value'
15634 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15650 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15655 cls: 'modal-footer',
15663 cls: 'col-xs-6 text-left',
15666 cls: 'btn btn-danger roo-touch-view-cancel',
15672 cls: 'col-xs-6 text-right',
15675 cls: 'btn btn-success roo-touch-view-ok',
15686 Roo.apply(Roo.bootstrap.ComboBox, {
15688 touchViewTemplate : {
15690 cls: 'modal fade roo-combobox-touch-view',
15694 cls: 'modal-dialog',
15695 style : 'position:fixed', // we have to fix position....
15699 cls: 'modal-content',
15701 Roo.bootstrap.ComboBox.header,
15702 Roo.bootstrap.ComboBox.body,
15703 Roo.bootstrap.ComboBox.footer
15712 * Ext JS Library 1.1.1
15713 * Copyright(c) 2006-2007, Ext JS, LLC.
15715 * Originally Released Under LGPL - original licence link has changed is not relivant.
15718 * <script type="text/javascript">
15723 * @extends Roo.util.Observable
15724 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15725 * This class also supports single and multi selection modes. <br>
15726 * Create a data model bound view:
15728 var store = new Roo.data.Store(...);
15730 var view = new Roo.View({
15732 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15734 singleSelect: true,
15735 selectedClass: "ydataview-selected",
15739 // listen for node click?
15740 view.on("click", function(vw, index, node, e){
15741 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15745 dataModel.load("foobar.xml");
15747 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15749 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15750 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15752 * Note: old style constructor is still suported (container, template, config)
15755 * Create a new View
15756 * @param {Object} config The config object
15759 Roo.View = function(config, depreciated_tpl, depreciated_config){
15761 this.parent = false;
15763 if (typeof(depreciated_tpl) == 'undefined') {
15764 // new way.. - universal constructor.
15765 Roo.apply(this, config);
15766 this.el = Roo.get(this.el);
15769 this.el = Roo.get(config);
15770 this.tpl = depreciated_tpl;
15771 Roo.apply(this, depreciated_config);
15773 this.wrapEl = this.el.wrap().wrap();
15774 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15777 if(typeof(this.tpl) == "string"){
15778 this.tpl = new Roo.Template(this.tpl);
15780 // support xtype ctors..
15781 this.tpl = new Roo.factory(this.tpl, Roo);
15785 this.tpl.compile();
15790 * @event beforeclick
15791 * Fires before a click is processed. Returns false to cancel the default action.
15792 * @param {Roo.View} this
15793 * @param {Number} index The index of the target node
15794 * @param {HTMLElement} node The target node
15795 * @param {Roo.EventObject} e The raw event object
15797 "beforeclick" : true,
15800 * Fires when a template node is clicked.
15801 * @param {Roo.View} this
15802 * @param {Number} index The index of the target node
15803 * @param {HTMLElement} node The target node
15804 * @param {Roo.EventObject} e The raw event object
15809 * Fires when a template node is double clicked.
15810 * @param {Roo.View} this
15811 * @param {Number} index The index of the target node
15812 * @param {HTMLElement} node The target node
15813 * @param {Roo.EventObject} e The raw event object
15817 * @event contextmenu
15818 * Fires when a template node is right clicked.
15819 * @param {Roo.View} this
15820 * @param {Number} index The index of the target node
15821 * @param {HTMLElement} node The target node
15822 * @param {Roo.EventObject} e The raw event object
15824 "contextmenu" : true,
15826 * @event selectionchange
15827 * Fires when the selected nodes change.
15828 * @param {Roo.View} this
15829 * @param {Array} selections Array of the selected nodes
15831 "selectionchange" : true,
15834 * @event beforeselect
15835 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15836 * @param {Roo.View} this
15837 * @param {HTMLElement} node The node to be selected
15838 * @param {Array} selections Array of currently selected nodes
15840 "beforeselect" : true,
15842 * @event preparedata
15843 * Fires on every row to render, to allow you to change the data.
15844 * @param {Roo.View} this
15845 * @param {Object} data to be rendered (change this)
15847 "preparedata" : true
15855 "click": this.onClick,
15856 "dblclick": this.onDblClick,
15857 "contextmenu": this.onContextMenu,
15861 this.selections = [];
15863 this.cmp = new Roo.CompositeElementLite([]);
15865 this.store = Roo.factory(this.store, Roo.data);
15866 this.setStore(this.store, true);
15869 if ( this.footer && this.footer.xtype) {
15871 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15873 this.footer.dataSource = this.store;
15874 this.footer.container = fctr;
15875 this.footer = Roo.factory(this.footer, Roo);
15876 fctr.insertFirst(this.el);
15878 // this is a bit insane - as the paging toolbar seems to detach the el..
15879 // dom.parentNode.parentNode.parentNode
15880 // they get detached?
15884 Roo.View.superclass.constructor.call(this);
15889 Roo.extend(Roo.View, Roo.util.Observable, {
15892 * @cfg {Roo.data.Store} store Data store to load data from.
15897 * @cfg {String|Roo.Element} el The container element.
15902 * @cfg {String|Roo.Template} tpl The template used by this View
15906 * @cfg {String} dataName the named area of the template to use as the data area
15907 * Works with domtemplates roo-name="name"
15911 * @cfg {String} selectedClass The css class to add to selected nodes
15913 selectedClass : "x-view-selected",
15915 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15920 * @cfg {String} text to display on mask (default Loading)
15924 * @cfg {Boolean} multiSelect Allow multiple selection
15926 multiSelect : false,
15928 * @cfg {Boolean} singleSelect Allow single selection
15930 singleSelect: false,
15933 * @cfg {Boolean} toggleSelect - selecting
15935 toggleSelect : false,
15938 * @cfg {Boolean} tickable - selecting
15943 * Returns the element this view is bound to.
15944 * @return {Roo.Element}
15946 getEl : function(){
15947 return this.wrapEl;
15953 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15955 refresh : function(){
15956 //Roo.log('refresh');
15959 // if we are using something like 'domtemplate', then
15960 // the what gets used is:
15961 // t.applySubtemplate(NAME, data, wrapping data..)
15962 // the outer template then get' applied with
15963 // the store 'extra data'
15964 // and the body get's added to the
15965 // roo-name="data" node?
15966 // <span class='roo-tpl-{name}'></span> ?????
15970 this.clearSelections();
15971 this.el.update("");
15973 var records = this.store.getRange();
15974 if(records.length < 1) {
15976 // is this valid?? = should it render a template??
15978 this.el.update(this.emptyText);
15982 if (this.dataName) {
15983 this.el.update(t.apply(this.store.meta)); //????
15984 el = this.el.child('.roo-tpl-' + this.dataName);
15987 for(var i = 0, len = records.length; i < len; i++){
15988 var data = this.prepareData(records[i].data, i, records[i]);
15989 this.fireEvent("preparedata", this, data, i, records[i]);
15991 var d = Roo.apply({}, data);
15994 Roo.apply(d, {'roo-id' : Roo.id()});
15998 Roo.each(this.parent.item, function(item){
15999 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16002 Roo.apply(d, {'roo-data-checked' : 'checked'});
16006 html[html.length] = Roo.util.Format.trim(
16008 t.applySubtemplate(this.dataName, d, this.store.meta) :
16015 el.update(html.join(""));
16016 this.nodes = el.dom.childNodes;
16017 this.updateIndexes(0);
16022 * Function to override to reformat the data that is sent to
16023 * the template for each node.
16024 * DEPRICATED - use the preparedata event handler.
16025 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16026 * a JSON object for an UpdateManager bound view).
16028 prepareData : function(data, index, record)
16030 this.fireEvent("preparedata", this, data, index, record);
16034 onUpdate : function(ds, record){
16035 // Roo.log('on update');
16036 this.clearSelections();
16037 var index = this.store.indexOf(record);
16038 var n = this.nodes[index];
16039 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16040 n.parentNode.removeChild(n);
16041 this.updateIndexes(index, index);
16047 onAdd : function(ds, records, index)
16049 //Roo.log(['on Add', ds, records, index] );
16050 this.clearSelections();
16051 if(this.nodes.length == 0){
16055 var n = this.nodes[index];
16056 for(var i = 0, len = records.length; i < len; i++){
16057 var d = this.prepareData(records[i].data, i, records[i]);
16059 this.tpl.insertBefore(n, d);
16062 this.tpl.append(this.el, d);
16065 this.updateIndexes(index);
16068 onRemove : function(ds, record, index){
16069 // Roo.log('onRemove');
16070 this.clearSelections();
16071 var el = this.dataName ?
16072 this.el.child('.roo-tpl-' + this.dataName) :
16075 el.dom.removeChild(this.nodes[index]);
16076 this.updateIndexes(index);
16080 * Refresh an individual node.
16081 * @param {Number} index
16083 refreshNode : function(index){
16084 this.onUpdate(this.store, this.store.getAt(index));
16087 updateIndexes : function(startIndex, endIndex){
16088 var ns = this.nodes;
16089 startIndex = startIndex || 0;
16090 endIndex = endIndex || ns.length - 1;
16091 for(var i = startIndex; i <= endIndex; i++){
16092 ns[i].nodeIndex = i;
16097 * Changes the data store this view uses and refresh the view.
16098 * @param {Store} store
16100 setStore : function(store, initial){
16101 if(!initial && this.store){
16102 this.store.un("datachanged", this.refresh);
16103 this.store.un("add", this.onAdd);
16104 this.store.un("remove", this.onRemove);
16105 this.store.un("update", this.onUpdate);
16106 this.store.un("clear", this.refresh);
16107 this.store.un("beforeload", this.onBeforeLoad);
16108 this.store.un("load", this.onLoad);
16109 this.store.un("loadexception", this.onLoad);
16113 store.on("datachanged", this.refresh, this);
16114 store.on("add", this.onAdd, this);
16115 store.on("remove", this.onRemove, this);
16116 store.on("update", this.onUpdate, this);
16117 store.on("clear", this.refresh, this);
16118 store.on("beforeload", this.onBeforeLoad, this);
16119 store.on("load", this.onLoad, this);
16120 store.on("loadexception", this.onLoad, this);
16128 * onbeforeLoad - masks the loading area.
16131 onBeforeLoad : function(store,opts)
16133 //Roo.log('onBeforeLoad');
16135 this.el.update("");
16137 this.el.mask(this.mask ? this.mask : "Loading" );
16139 onLoad : function ()
16146 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16147 * @param {HTMLElement} node
16148 * @return {HTMLElement} The template node
16150 findItemFromChild : function(node){
16151 var el = this.dataName ?
16152 this.el.child('.roo-tpl-' + this.dataName,true) :
16155 if(!node || node.parentNode == el){
16158 var p = node.parentNode;
16159 while(p && p != el){
16160 if(p.parentNode == el){
16169 onClick : function(e){
16170 var item = this.findItemFromChild(e.getTarget());
16172 var index = this.indexOf(item);
16173 if(this.onItemClick(item, index, e) !== false){
16174 this.fireEvent("click", this, index, item, e);
16177 this.clearSelections();
16182 onContextMenu : function(e){
16183 var item = this.findItemFromChild(e.getTarget());
16185 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16190 onDblClick : function(e){
16191 var item = this.findItemFromChild(e.getTarget());
16193 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16197 onItemClick : function(item, index, e)
16199 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16202 if (this.toggleSelect) {
16203 var m = this.isSelected(item) ? 'unselect' : 'select';
16206 _t[m](item, true, false);
16209 if(this.multiSelect || this.singleSelect){
16210 if(this.multiSelect && e.shiftKey && this.lastSelection){
16211 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16213 this.select(item, this.multiSelect && e.ctrlKey);
16214 this.lastSelection = item;
16217 if(!this.tickable){
16218 e.preventDefault();
16226 * Get the number of selected nodes.
16229 getSelectionCount : function(){
16230 return this.selections.length;
16234 * Get the currently selected nodes.
16235 * @return {Array} An array of HTMLElements
16237 getSelectedNodes : function(){
16238 return this.selections;
16242 * Get the indexes of the selected nodes.
16245 getSelectedIndexes : function(){
16246 var indexes = [], s = this.selections;
16247 for(var i = 0, len = s.length; i < len; i++){
16248 indexes.push(s[i].nodeIndex);
16254 * Clear all selections
16255 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16257 clearSelections : function(suppressEvent){
16258 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16259 this.cmp.elements = this.selections;
16260 this.cmp.removeClass(this.selectedClass);
16261 this.selections = [];
16262 if(!suppressEvent){
16263 this.fireEvent("selectionchange", this, this.selections);
16269 * Returns true if the passed node is selected
16270 * @param {HTMLElement/Number} node The node or node index
16271 * @return {Boolean}
16273 isSelected : function(node){
16274 var s = this.selections;
16278 node = this.getNode(node);
16279 return s.indexOf(node) !== -1;
16284 * @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
16285 * @param {Boolean} keepExisting (optional) true to keep existing selections
16286 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16288 select : function(nodeInfo, keepExisting, suppressEvent){
16289 if(nodeInfo instanceof Array){
16291 this.clearSelections(true);
16293 for(var i = 0, len = nodeInfo.length; i < len; i++){
16294 this.select(nodeInfo[i], true, true);
16298 var node = this.getNode(nodeInfo);
16299 if(!node || this.isSelected(node)){
16300 return; // already selected.
16303 this.clearSelections(true);
16306 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16307 Roo.fly(node).addClass(this.selectedClass);
16308 this.selections.push(node);
16309 if(!suppressEvent){
16310 this.fireEvent("selectionchange", this, this.selections);
16318 * @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
16319 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16320 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16322 unselect : function(nodeInfo, keepExisting, suppressEvent)
16324 if(nodeInfo instanceof Array){
16325 Roo.each(this.selections, function(s) {
16326 this.unselect(s, nodeInfo);
16330 var node = this.getNode(nodeInfo);
16331 if(!node || !this.isSelected(node)){
16332 //Roo.log("not selected");
16333 return; // not selected.
16337 Roo.each(this.selections, function(s) {
16339 Roo.fly(node).removeClass(this.selectedClass);
16346 this.selections= ns;
16347 this.fireEvent("selectionchange", this, this.selections);
16351 * Gets a template node.
16352 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16353 * @return {HTMLElement} The node or null if it wasn't found
16355 getNode : function(nodeInfo){
16356 if(typeof nodeInfo == "string"){
16357 return document.getElementById(nodeInfo);
16358 }else if(typeof nodeInfo == "number"){
16359 return this.nodes[nodeInfo];
16365 * Gets a range template nodes.
16366 * @param {Number} startIndex
16367 * @param {Number} endIndex
16368 * @return {Array} An array of nodes
16370 getNodes : function(start, end){
16371 var ns = this.nodes;
16372 start = start || 0;
16373 end = typeof end == "undefined" ? ns.length - 1 : end;
16376 for(var i = start; i <= end; i++){
16380 for(var i = start; i >= end; i--){
16388 * Finds the index of the passed node
16389 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16390 * @return {Number} The index of the node or -1
16392 indexOf : function(node){
16393 node = this.getNode(node);
16394 if(typeof node.nodeIndex == "number"){
16395 return node.nodeIndex;
16397 var ns = this.nodes;
16398 for(var i = 0, len = ns.length; i < len; i++){
16409 * based on jquery fullcalendar
16413 Roo.bootstrap = Roo.bootstrap || {};
16415 * @class Roo.bootstrap.Calendar
16416 * @extends Roo.bootstrap.Component
16417 * Bootstrap Calendar class
16418 * @cfg {Boolean} loadMask (true|false) default false
16419 * @cfg {Object} header generate the user specific header of the calendar, default false
16422 * Create a new Container
16423 * @param {Object} config The config object
16428 Roo.bootstrap.Calendar = function(config){
16429 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16433 * Fires when a date is selected
16434 * @param {DatePicker} this
16435 * @param {Date} date The selected date
16439 * @event monthchange
16440 * Fires when the displayed month changes
16441 * @param {DatePicker} this
16442 * @param {Date} date The selected month
16444 'monthchange': true,
16446 * @event evententer
16447 * Fires when mouse over an event
16448 * @param {Calendar} this
16449 * @param {event} Event
16451 'evententer': true,
16453 * @event eventleave
16454 * Fires when the mouse leaves an
16455 * @param {Calendar} this
16458 'eventleave': true,
16460 * @event eventclick
16461 * Fires when the mouse click an
16462 * @param {Calendar} this
16471 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16474 * @cfg {Number} startDay
16475 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16483 getAutoCreate : function(){
16486 var fc_button = function(name, corner, style, content ) {
16487 return Roo.apply({},{
16489 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16491 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16494 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16505 style : 'width:100%',
16512 cls : 'fc-header-left',
16514 fc_button('prev', 'left', 'arrow', '‹' ),
16515 fc_button('next', 'right', 'arrow', '›' ),
16516 { tag: 'span', cls: 'fc-header-space' },
16517 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16525 cls : 'fc-header-center',
16529 cls: 'fc-header-title',
16532 html : 'month / year'
16540 cls : 'fc-header-right',
16542 /* fc_button('month', 'left', '', 'month' ),
16543 fc_button('week', '', '', 'week' ),
16544 fc_button('day', 'right', '', 'day' )
16556 header = this.header;
16559 var cal_heads = function() {
16561 // fixme - handle this.
16563 for (var i =0; i < Date.dayNames.length; i++) {
16564 var d = Date.dayNames[i];
16567 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16568 html : d.substring(0,3)
16572 ret[0].cls += ' fc-first';
16573 ret[6].cls += ' fc-last';
16576 var cal_cell = function(n) {
16579 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16584 cls: 'fc-day-number',
16588 cls: 'fc-day-content',
16592 style: 'position: relative;' // height: 17px;
16604 var cal_rows = function() {
16607 for (var r = 0; r < 6; r++) {
16614 for (var i =0; i < Date.dayNames.length; i++) {
16615 var d = Date.dayNames[i];
16616 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16619 row.cn[0].cls+=' fc-first';
16620 row.cn[0].cn[0].style = 'min-height:90px';
16621 row.cn[6].cls+=' fc-last';
16625 ret[0].cls += ' fc-first';
16626 ret[4].cls += ' fc-prev-last';
16627 ret[5].cls += ' fc-last';
16634 cls: 'fc-border-separate',
16635 style : 'width:100%',
16643 cls : 'fc-first fc-last',
16661 cls : 'fc-content',
16662 style : "position: relative;",
16665 cls : 'fc-view fc-view-month fc-grid',
16666 style : 'position: relative',
16667 unselectable : 'on',
16670 cls : 'fc-event-container',
16671 style : 'position:absolute;z-index:8;top:0;left:0;'
16689 initEvents : function()
16692 throw "can not find store for calendar";
16698 style: "text-align:center",
16702 style: "background-color:white;width:50%;margin:250 auto",
16706 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16717 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16719 var size = this.el.select('.fc-content', true).first().getSize();
16720 this.maskEl.setSize(size.width, size.height);
16721 this.maskEl.enableDisplayMode("block");
16722 if(!this.loadMask){
16723 this.maskEl.hide();
16726 this.store = Roo.factory(this.store, Roo.data);
16727 this.store.on('load', this.onLoad, this);
16728 this.store.on('beforeload', this.onBeforeLoad, this);
16732 this.cells = this.el.select('.fc-day',true);
16733 //Roo.log(this.cells);
16734 this.textNodes = this.el.query('.fc-day-number');
16735 this.cells.addClassOnOver('fc-state-hover');
16737 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16738 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16739 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16740 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16742 this.on('monthchange', this.onMonthChange, this);
16744 this.update(new Date().clearTime());
16747 resize : function() {
16748 var sz = this.el.getSize();
16750 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16751 this.el.select('.fc-day-content div',true).setHeight(34);
16756 showPrevMonth : function(e){
16757 this.update(this.activeDate.add("mo", -1));
16759 showToday : function(e){
16760 this.update(new Date().clearTime());
16763 showNextMonth : function(e){
16764 this.update(this.activeDate.add("mo", 1));
16768 showPrevYear : function(){
16769 this.update(this.activeDate.add("y", -1));
16773 showNextYear : function(){
16774 this.update(this.activeDate.add("y", 1));
16779 update : function(date)
16781 var vd = this.activeDate;
16782 this.activeDate = date;
16783 // if(vd && this.el){
16784 // var t = date.getTime();
16785 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16786 // Roo.log('using add remove');
16788 // this.fireEvent('monthchange', this, date);
16790 // this.cells.removeClass("fc-state-highlight");
16791 // this.cells.each(function(c){
16792 // if(c.dateValue == t){
16793 // c.addClass("fc-state-highlight");
16794 // setTimeout(function(){
16795 // try{c.dom.firstChild.focus();}catch(e){}
16805 var days = date.getDaysInMonth();
16807 var firstOfMonth = date.getFirstDateOfMonth();
16808 var startingPos = firstOfMonth.getDay()-this.startDay;
16810 if(startingPos < this.startDay){
16814 var pm = date.add(Date.MONTH, -1);
16815 var prevStart = pm.getDaysInMonth()-startingPos;
16817 this.cells = this.el.select('.fc-day',true);
16818 this.textNodes = this.el.query('.fc-day-number');
16819 this.cells.addClassOnOver('fc-state-hover');
16821 var cells = this.cells.elements;
16822 var textEls = this.textNodes;
16824 Roo.each(cells, function(cell){
16825 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16828 days += startingPos;
16830 // convert everything to numbers so it's fast
16831 var day = 86400000;
16832 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16835 //Roo.log(prevStart);
16837 var today = new Date().clearTime().getTime();
16838 var sel = date.clearTime().getTime();
16839 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16840 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16841 var ddMatch = this.disabledDatesRE;
16842 var ddText = this.disabledDatesText;
16843 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16844 var ddaysText = this.disabledDaysText;
16845 var format = this.format;
16847 var setCellClass = function(cal, cell){
16851 //Roo.log('set Cell Class');
16853 var t = d.getTime();
16857 cell.dateValue = t;
16859 cell.className += " fc-today";
16860 cell.className += " fc-state-highlight";
16861 cell.title = cal.todayText;
16864 // disable highlight in other month..
16865 //cell.className += " fc-state-highlight";
16870 cell.className = " fc-state-disabled";
16871 cell.title = cal.minText;
16875 cell.className = " fc-state-disabled";
16876 cell.title = cal.maxText;
16880 if(ddays.indexOf(d.getDay()) != -1){
16881 cell.title = ddaysText;
16882 cell.className = " fc-state-disabled";
16885 if(ddMatch && format){
16886 var fvalue = d.dateFormat(format);
16887 if(ddMatch.test(fvalue)){
16888 cell.title = ddText.replace("%0", fvalue);
16889 cell.className = " fc-state-disabled";
16893 if (!cell.initialClassName) {
16894 cell.initialClassName = cell.dom.className;
16897 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16902 for(; i < startingPos; i++) {
16903 textEls[i].innerHTML = (++prevStart);
16904 d.setDate(d.getDate()+1);
16906 cells[i].className = "fc-past fc-other-month";
16907 setCellClass(this, cells[i]);
16912 for(; i < days; i++){
16913 intDay = i - startingPos + 1;
16914 textEls[i].innerHTML = (intDay);
16915 d.setDate(d.getDate()+1);
16917 cells[i].className = ''; // "x-date-active";
16918 setCellClass(this, cells[i]);
16922 for(; i < 42; i++) {
16923 textEls[i].innerHTML = (++extraDays);
16924 d.setDate(d.getDate()+1);
16926 cells[i].className = "fc-future fc-other-month";
16927 setCellClass(this, cells[i]);
16930 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16932 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16934 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16935 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16937 if(totalRows != 6){
16938 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16939 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16942 this.fireEvent('monthchange', this, date);
16946 if(!this.internalRender){
16947 var main = this.el.dom.firstChild;
16948 var w = main.offsetWidth;
16949 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16950 Roo.fly(main).setWidth(w);
16951 this.internalRender = true;
16952 // opera does not respect the auto grow header center column
16953 // then, after it gets a width opera refuses to recalculate
16954 // without a second pass
16955 if(Roo.isOpera && !this.secondPass){
16956 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16957 this.secondPass = true;
16958 this.update.defer(10, this, [date]);
16965 findCell : function(dt) {
16966 dt = dt.clearTime().getTime();
16968 this.cells.each(function(c){
16969 //Roo.log("check " +c.dateValue + '?=' + dt);
16970 if(c.dateValue == dt){
16980 findCells : function(ev) {
16981 var s = ev.start.clone().clearTime().getTime();
16983 var e= ev.end.clone().clearTime().getTime();
16986 this.cells.each(function(c){
16987 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16989 if(c.dateValue > e){
16992 if(c.dateValue < s){
17001 // findBestRow: function(cells)
17005 // for (var i =0 ; i < cells.length;i++) {
17006 // ret = Math.max(cells[i].rows || 0,ret);
17013 addItem : function(ev)
17015 // look for vertical location slot in
17016 var cells = this.findCells(ev);
17018 // ev.row = this.findBestRow(cells);
17020 // work out the location.
17024 for(var i =0; i < cells.length; i++) {
17026 cells[i].row = cells[0].row;
17029 cells[i].row = cells[i].row + 1;
17039 if (crow.start.getY() == cells[i].getY()) {
17041 crow.end = cells[i];
17058 cells[0].events.push(ev);
17060 this.calevents.push(ev);
17063 clearEvents: function() {
17065 if(!this.calevents){
17069 Roo.each(this.cells.elements, function(c){
17075 Roo.each(this.calevents, function(e) {
17076 Roo.each(e.els, function(el) {
17077 el.un('mouseenter' ,this.onEventEnter, this);
17078 el.un('mouseleave' ,this.onEventLeave, this);
17083 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17089 renderEvents: function()
17093 this.cells.each(function(c) {
17102 if(c.row != c.events.length){
17103 r = 4 - (4 - (c.row - c.events.length));
17106 c.events = ev.slice(0, r);
17107 c.more = ev.slice(r);
17109 if(c.more.length && c.more.length == 1){
17110 c.events.push(c.more.pop());
17113 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17117 this.cells.each(function(c) {
17119 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17122 for (var e = 0; e < c.events.length; e++){
17123 var ev = c.events[e];
17124 var rows = ev.rows;
17126 for(var i = 0; i < rows.length; i++) {
17128 // how many rows should it span..
17131 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17132 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17134 unselectable : "on",
17137 cls: 'fc-event-inner',
17141 // cls: 'fc-event-time',
17142 // html : cells.length > 1 ? '' : ev.time
17146 cls: 'fc-event-title',
17147 html : String.format('{0}', ev.title)
17154 cls: 'ui-resizable-handle ui-resizable-e',
17155 html : '  '
17162 cfg.cls += ' fc-event-start';
17164 if ((i+1) == rows.length) {
17165 cfg.cls += ' fc-event-end';
17168 var ctr = _this.el.select('.fc-event-container',true).first();
17169 var cg = ctr.createChild(cfg);
17171 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17172 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17174 var r = (c.more.length) ? 1 : 0;
17175 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17176 cg.setWidth(ebox.right - sbox.x -2);
17178 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17179 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17180 cg.on('click', _this.onEventClick, _this, ev);
17191 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17192 style : 'position: absolute',
17193 unselectable : "on",
17196 cls: 'fc-event-inner',
17200 cls: 'fc-event-title',
17208 cls: 'ui-resizable-handle ui-resizable-e',
17209 html : '  '
17215 var ctr = _this.el.select('.fc-event-container',true).first();
17216 var cg = ctr.createChild(cfg);
17218 var sbox = c.select('.fc-day-content',true).first().getBox();
17219 var ebox = c.select('.fc-day-content',true).first().getBox();
17221 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17222 cg.setWidth(ebox.right - sbox.x -2);
17224 cg.on('click', _this.onMoreEventClick, _this, c.more);
17234 onEventEnter: function (e, el,event,d) {
17235 this.fireEvent('evententer', this, el, event);
17238 onEventLeave: function (e, el,event,d) {
17239 this.fireEvent('eventleave', this, el, event);
17242 onEventClick: function (e, el,event,d) {
17243 this.fireEvent('eventclick', this, el, event);
17246 onMonthChange: function () {
17250 onMoreEventClick: function(e, el, more)
17254 this.calpopover.placement = 'right';
17255 this.calpopover.setTitle('More');
17257 this.calpopover.setContent('');
17259 var ctr = this.calpopover.el.select('.popover-content', true).first();
17261 Roo.each(more, function(m){
17263 cls : 'fc-event-hori fc-event-draggable',
17266 var cg = ctr.createChild(cfg);
17268 cg.on('click', _this.onEventClick, _this, m);
17271 this.calpopover.show(el);
17276 onLoad: function ()
17278 this.calevents = [];
17281 if(this.store.getCount() > 0){
17282 this.store.data.each(function(d){
17285 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17286 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17287 time : d.data.start_time,
17288 title : d.data.title,
17289 description : d.data.description,
17290 venue : d.data.venue
17295 this.renderEvents();
17297 if(this.calevents.length && this.loadMask){
17298 this.maskEl.hide();
17302 onBeforeLoad: function()
17304 this.clearEvents();
17306 this.maskEl.show();
17320 * @class Roo.bootstrap.Popover
17321 * @extends Roo.bootstrap.Component
17322 * Bootstrap Popover class
17323 * @cfg {String} html contents of the popover (or false to use children..)
17324 * @cfg {String} title of popover (or false to hide)
17325 * @cfg {String} placement how it is placed
17326 * @cfg {String} trigger click || hover (or false to trigger manually)
17327 * @cfg {String} over what (parent or false to trigger manually.)
17328 * @cfg {Number} delay - delay before showing
17331 * Create a new Popover
17332 * @param {Object} config The config object
17335 Roo.bootstrap.Popover = function(config){
17336 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17342 * After the popover show
17344 * @param {Roo.bootstrap.Popover} this
17349 * After the popover hide
17351 * @param {Roo.bootstrap.Popover} this
17357 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17359 title: 'Fill in a title',
17362 placement : 'right',
17363 trigger : 'hover', // hover
17369 can_build_overlaid : false,
17371 getChildContainer : function()
17373 return this.el.select('.popover-content',true).first();
17376 getAutoCreate : function(){
17379 cls : 'popover roo-dynamic',
17380 style: 'display:block',
17386 cls : 'popover-inner',
17390 cls: 'popover-title',
17394 cls : 'popover-content',
17405 setTitle: function(str)
17408 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17410 setContent: function(str)
17413 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17415 // as it get's added to the bottom of the page.
17416 onRender : function(ct, position)
17418 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17420 var cfg = Roo.apply({}, this.getAutoCreate());
17424 cfg.cls += ' ' + this.cls;
17427 cfg.style = this.style;
17429 //Roo.log("adding to ");
17430 this.el = Roo.get(document.body).createChild(cfg, position);
17431 // Roo.log(this.el);
17436 initEvents : function()
17438 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17439 this.el.enableDisplayMode('block');
17441 if (this.over === false) {
17444 if (this.triggers === false) {
17447 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17448 var triggers = this.trigger ? this.trigger.split(' ') : [];
17449 Roo.each(triggers, function(trigger) {
17451 if (trigger == 'click') {
17452 on_el.on('click', this.toggle, this);
17453 } else if (trigger != 'manual') {
17454 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17455 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17457 on_el.on(eventIn ,this.enter, this);
17458 on_el.on(eventOut, this.leave, this);
17469 toggle : function () {
17470 this.hoverState == 'in' ? this.leave() : this.enter();
17473 enter : function () {
17475 clearTimeout(this.timeout);
17477 this.hoverState = 'in';
17479 if (!this.delay || !this.delay.show) {
17484 this.timeout = setTimeout(function () {
17485 if (_t.hoverState == 'in') {
17488 }, this.delay.show)
17491 leave : function() {
17492 clearTimeout(this.timeout);
17494 this.hoverState = 'out';
17496 if (!this.delay || !this.delay.hide) {
17501 this.timeout = setTimeout(function () {
17502 if (_t.hoverState == 'out') {
17505 }, this.delay.hide)
17508 show : function (on_el)
17511 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17515 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17516 if (this.html !== false) {
17517 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17519 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17520 if (!this.title.length) {
17521 this.el.select('.popover-title',true).hide();
17524 var placement = typeof this.placement == 'function' ?
17525 this.placement.call(this, this.el, on_el) :
17528 var autoToken = /\s?auto?\s?/i;
17529 var autoPlace = autoToken.test(placement);
17531 placement = placement.replace(autoToken, '') || 'top';
17535 //this.el.setXY([0,0]);
17537 this.el.dom.style.display='block';
17538 this.el.addClass(placement);
17540 //this.el.appendTo(on_el);
17542 var p = this.getPosition();
17543 var box = this.el.getBox();
17548 var align = Roo.bootstrap.Popover.alignment[placement];
17551 this.el.alignTo(on_el, align[0],align[1]);
17552 //var arrow = this.el.select('.arrow',true).first();
17553 //arrow.set(align[2],
17555 this.el.addClass('in');
17558 if (this.el.hasClass('fade')) {
17562 this.hoverState = 'in';
17564 this.fireEvent('show', this);
17569 this.el.setXY([0,0]);
17570 this.el.removeClass('in');
17572 this.hoverState = null;
17574 this.fireEvent('hide', this);
17579 Roo.bootstrap.Popover.alignment = {
17580 'left' : ['r-l', [-10,0], 'right'],
17581 'right' : ['l-r', [10,0], 'left'],
17582 'bottom' : ['t-b', [0,10], 'top'],
17583 'top' : [ 'b-t', [0,-10], 'bottom']
17594 * @class Roo.bootstrap.Progress
17595 * @extends Roo.bootstrap.Component
17596 * Bootstrap Progress class
17597 * @cfg {Boolean} striped striped of the progress bar
17598 * @cfg {Boolean} active animated of the progress bar
17602 * Create a new Progress
17603 * @param {Object} config The config object
17606 Roo.bootstrap.Progress = function(config){
17607 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17610 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17615 getAutoCreate : function(){
17623 cfg.cls += ' progress-striped';
17627 cfg.cls += ' active';
17646 * @class Roo.bootstrap.ProgressBar
17647 * @extends Roo.bootstrap.Component
17648 * Bootstrap ProgressBar class
17649 * @cfg {Number} aria_valuenow aria-value now
17650 * @cfg {Number} aria_valuemin aria-value min
17651 * @cfg {Number} aria_valuemax aria-value max
17652 * @cfg {String} label label for the progress bar
17653 * @cfg {String} panel (success | info | warning | danger )
17654 * @cfg {String} role role of the progress bar
17655 * @cfg {String} sr_only text
17659 * Create a new ProgressBar
17660 * @param {Object} config The config object
17663 Roo.bootstrap.ProgressBar = function(config){
17664 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17667 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17671 aria_valuemax : 100,
17677 getAutoCreate : function()
17682 cls: 'progress-bar',
17683 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17695 cfg.role = this.role;
17698 if(this.aria_valuenow){
17699 cfg['aria-valuenow'] = this.aria_valuenow;
17702 if(this.aria_valuemin){
17703 cfg['aria-valuemin'] = this.aria_valuemin;
17706 if(this.aria_valuemax){
17707 cfg['aria-valuemax'] = this.aria_valuemax;
17710 if(this.label && !this.sr_only){
17711 cfg.html = this.label;
17715 cfg.cls += ' progress-bar-' + this.panel;
17721 update : function(aria_valuenow)
17723 this.aria_valuenow = aria_valuenow;
17725 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17740 * @class Roo.bootstrap.TabGroup
17741 * @extends Roo.bootstrap.Column
17742 * Bootstrap Column class
17743 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17744 * @cfg {Boolean} carousel true to make the group behave like a carousel
17745 * @cfg {Boolean} bullets show bullets for the panels
17746 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17747 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17748 * @cfg {Boolean} showarrow (true|false) show arrow default true
17751 * Create a new TabGroup
17752 * @param {Object} config The config object
17755 Roo.bootstrap.TabGroup = function(config){
17756 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17758 this.navId = Roo.id();
17761 Roo.bootstrap.TabGroup.register(this);
17765 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17768 transition : false,
17773 slideOnTouch : false,
17776 getAutoCreate : function()
17778 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17780 cfg.cls += ' tab-content';
17782 if (this.carousel) {
17783 cfg.cls += ' carousel slide';
17786 cls : 'carousel-inner',
17790 if(this.bullets && !Roo.isTouch){
17793 cls : 'carousel-bullets',
17797 if(this.bullets_cls){
17798 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17805 cfg.cn[0].cn.push(bullets);
17808 if(this.showarrow){
17809 cfg.cn[0].cn.push({
17811 class : 'carousel-arrow',
17815 class : 'carousel-prev',
17819 class : 'fa fa-chevron-left'
17825 class : 'carousel-next',
17829 class : 'fa fa-chevron-right'
17842 initEvents: function()
17844 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17845 // this.el.on("touchstart", this.onTouchStart, this);
17848 if(this.autoslide){
17851 this.slideFn = window.setInterval(function() {
17852 _this.showPanelNext();
17856 if(this.showarrow){
17857 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17858 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17864 // onTouchStart : function(e, el, o)
17866 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17870 // this.showPanelNext();
17874 getChildContainer : function()
17876 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17880 * register a Navigation item
17881 * @param {Roo.bootstrap.NavItem} the navitem to add
17883 register : function(item)
17885 this.tabs.push( item);
17886 item.navId = this.navId; // not really needed..
17891 getActivePanel : function()
17894 Roo.each(this.tabs, function(t) {
17904 getPanelByName : function(n)
17907 Roo.each(this.tabs, function(t) {
17908 if (t.tabId == n) {
17916 indexOfPanel : function(p)
17919 Roo.each(this.tabs, function(t,i) {
17920 if (t.tabId == p.tabId) {
17929 * show a specific panel
17930 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17931 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17933 showPanel : function (pan)
17935 if(this.transition || typeof(pan) == 'undefined'){
17936 Roo.log("waiting for the transitionend");
17940 if (typeof(pan) == 'number') {
17941 pan = this.tabs[pan];
17944 if (typeof(pan) == 'string') {
17945 pan = this.getPanelByName(pan);
17948 var cur = this.getActivePanel();
17951 Roo.log('pan or acitve pan is undefined');
17955 if (pan.tabId == this.getActivePanel().tabId) {
17959 if (false === cur.fireEvent('beforedeactivate')) {
17963 if(this.bullets > 0 && !Roo.isTouch){
17964 this.setActiveBullet(this.indexOfPanel(pan));
17967 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17969 this.transition = true;
17970 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17971 var lr = dir == 'next' ? 'left' : 'right';
17972 pan.el.addClass(dir); // or prev
17973 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17974 cur.el.addClass(lr); // or right
17975 pan.el.addClass(lr);
17978 cur.el.on('transitionend', function() {
17979 Roo.log("trans end?");
17981 pan.el.removeClass([lr,dir]);
17982 pan.setActive(true);
17984 cur.el.removeClass([lr]);
17985 cur.setActive(false);
17987 _this.transition = false;
17989 }, this, { single: true } );
17994 cur.setActive(false);
17995 pan.setActive(true);
18000 showPanelNext : function()
18002 var i = this.indexOfPanel(this.getActivePanel());
18004 if (i >= this.tabs.length - 1 && !this.autoslide) {
18008 if (i >= this.tabs.length - 1 && this.autoslide) {
18012 this.showPanel(this.tabs[i+1]);
18015 showPanelPrev : function()
18017 var i = this.indexOfPanel(this.getActivePanel());
18019 if (i < 1 && !this.autoslide) {
18023 if (i < 1 && this.autoslide) {
18024 i = this.tabs.length;
18027 this.showPanel(this.tabs[i-1]);
18031 addBullet: function()
18033 if(!this.bullets || Roo.isTouch){
18036 var ctr = this.el.select('.carousel-bullets',true).first();
18037 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18038 var bullet = ctr.createChild({
18039 cls : 'bullet bullet-' + i
18040 },ctr.dom.lastChild);
18045 bullet.on('click', (function(e, el, o, ii, t){
18047 e.preventDefault();
18049 this.showPanel(ii);
18051 if(this.autoslide && this.slideFn){
18052 clearInterval(this.slideFn);
18053 this.slideFn = window.setInterval(function() {
18054 _this.showPanelNext();
18058 }).createDelegate(this, [i, bullet], true));
18063 setActiveBullet : function(i)
18069 Roo.each(this.el.select('.bullet', true).elements, function(el){
18070 el.removeClass('selected');
18073 var bullet = this.el.select('.bullet-' + i, true).first();
18079 bullet.addClass('selected');
18090 Roo.apply(Roo.bootstrap.TabGroup, {
18094 * register a Navigation Group
18095 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18097 register : function(navgrp)
18099 this.groups[navgrp.navId] = navgrp;
18103 * fetch a Navigation Group based on the navigation ID
18104 * if one does not exist , it will get created.
18105 * @param {string} the navgroup to add
18106 * @returns {Roo.bootstrap.NavGroup} the navgroup
18108 get: function(navId) {
18109 if (typeof(this.groups[navId]) == 'undefined') {
18110 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18112 return this.groups[navId] ;
18127 * @class Roo.bootstrap.TabPanel
18128 * @extends Roo.bootstrap.Component
18129 * Bootstrap TabPanel class
18130 * @cfg {Boolean} active panel active
18131 * @cfg {String} html panel content
18132 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18133 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18134 * @cfg {String} href click to link..
18138 * Create a new TabPanel
18139 * @param {Object} config The config object
18142 Roo.bootstrap.TabPanel = function(config){
18143 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18147 * Fires when the active status changes
18148 * @param {Roo.bootstrap.TabPanel} this
18149 * @param {Boolean} state the new state
18154 * @event beforedeactivate
18155 * Fires before a tab is de-activated - can be used to do validation on a form.
18156 * @param {Roo.bootstrap.TabPanel} this
18157 * @return {Boolean} false if there is an error
18160 'beforedeactivate': true
18163 this.tabId = this.tabId || Roo.id();
18167 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18175 getAutoCreate : function(){
18178 // item is needed for carousel - not sure if it has any effect otherwise
18179 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18180 html: this.html || ''
18184 cfg.cls += ' active';
18188 cfg.tabId = this.tabId;
18195 initEvents: function()
18197 var p = this.parent();
18199 this.navId = this.navId || p.navId;
18201 if (typeof(this.navId) != 'undefined') {
18202 // not really needed.. but just in case.. parent should be a NavGroup.
18203 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18207 var i = tg.tabs.length - 1;
18209 if(this.active && tg.bullets > 0 && i < tg.bullets){
18210 tg.setActiveBullet(i);
18214 this.el.on('click', this.onClick, this);
18217 this.el.on("touchstart", this.onTouchStart, this);
18218 this.el.on("touchmove", this.onTouchMove, this);
18219 this.el.on("touchend", this.onTouchEnd, this);
18224 onRender : function(ct, position)
18226 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18229 setActive : function(state)
18231 Roo.log("panel - set active " + this.tabId + "=" + state);
18233 this.active = state;
18235 this.el.removeClass('active');
18237 } else if (!this.el.hasClass('active')) {
18238 this.el.addClass('active');
18241 this.fireEvent('changed', this, state);
18244 onClick : function(e)
18246 e.preventDefault();
18248 if(!this.href.length){
18252 window.location.href = this.href;
18261 onTouchStart : function(e)
18263 this.swiping = false;
18265 this.startX = e.browserEvent.touches[0].clientX;
18266 this.startY = e.browserEvent.touches[0].clientY;
18269 onTouchMove : function(e)
18271 this.swiping = true;
18273 this.endX = e.browserEvent.touches[0].clientX;
18274 this.endY = e.browserEvent.touches[0].clientY;
18277 onTouchEnd : function(e)
18284 var tabGroup = this.parent();
18286 if(this.endX > this.startX){ // swiping right
18287 tabGroup.showPanelPrev();
18291 if(this.startX > this.endX){ // swiping left
18292 tabGroup.showPanelNext();
18311 * @class Roo.bootstrap.DateField
18312 * @extends Roo.bootstrap.Input
18313 * Bootstrap DateField class
18314 * @cfg {Number} weekStart default 0
18315 * @cfg {String} viewMode default empty, (months|years)
18316 * @cfg {String} minViewMode default empty, (months|years)
18317 * @cfg {Number} startDate default -Infinity
18318 * @cfg {Number} endDate default Infinity
18319 * @cfg {Boolean} todayHighlight default false
18320 * @cfg {Boolean} todayBtn default false
18321 * @cfg {Boolean} calendarWeeks default false
18322 * @cfg {Object} daysOfWeekDisabled default empty
18323 * @cfg {Boolean} singleMode default false (true | false)
18325 * @cfg {Boolean} keyboardNavigation default true
18326 * @cfg {String} language default en
18329 * Create a new DateField
18330 * @param {Object} config The config object
18333 Roo.bootstrap.DateField = function(config){
18334 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18338 * Fires when this field show.
18339 * @param {Roo.bootstrap.DateField} this
18340 * @param {Mixed} date The date value
18345 * Fires when this field hide.
18346 * @param {Roo.bootstrap.DateField} this
18347 * @param {Mixed} date The date value
18352 * Fires when select a date.
18353 * @param {Roo.bootstrap.DateField} this
18354 * @param {Mixed} date The date value
18358 * @event beforeselect
18359 * Fires when before select a date.
18360 * @param {Roo.bootstrap.DateField} this
18361 * @param {Mixed} date The date value
18363 beforeselect : true
18367 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18370 * @cfg {String} format
18371 * The default date format string which can be overriden for localization support. The format must be
18372 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18376 * @cfg {String} altFormats
18377 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18378 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18380 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18388 todayHighlight : false,
18394 keyboardNavigation: true,
18396 calendarWeeks: false,
18398 startDate: -Infinity,
18402 daysOfWeekDisabled: [],
18406 singleMode : false,
18408 UTCDate: function()
18410 return new Date(Date.UTC.apply(Date, arguments));
18413 UTCToday: function()
18415 var today = new Date();
18416 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18419 getDate: function() {
18420 var d = this.getUTCDate();
18421 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18424 getUTCDate: function() {
18428 setDate: function(d) {
18429 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18432 setUTCDate: function(d) {
18434 this.setValue(this.formatDate(this.date));
18437 onRender: function(ct, position)
18440 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18442 this.language = this.language || 'en';
18443 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18444 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18446 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18447 this.format = this.format || 'm/d/y';
18448 this.isInline = false;
18449 this.isInput = true;
18450 this.component = this.el.select('.add-on', true).first() || false;
18451 this.component = (this.component && this.component.length === 0) ? false : this.component;
18452 this.hasInput = this.component && this.inputEl().length;
18454 if (typeof(this.minViewMode === 'string')) {
18455 switch (this.minViewMode) {
18457 this.minViewMode = 1;
18460 this.minViewMode = 2;
18463 this.minViewMode = 0;
18468 if (typeof(this.viewMode === 'string')) {
18469 switch (this.viewMode) {
18482 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18484 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18486 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18488 this.picker().on('mousedown', this.onMousedown, this);
18489 this.picker().on('click', this.onClick, this);
18491 this.picker().addClass('datepicker-dropdown');
18493 this.startViewMode = this.viewMode;
18495 if(this.singleMode){
18496 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18497 v.setVisibilityMode(Roo.Element.DISPLAY);
18501 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18502 v.setStyle('width', '189px');
18506 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18507 if(!this.calendarWeeks){
18512 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18513 v.attr('colspan', function(i, val){
18514 return parseInt(val) + 1;
18519 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18521 this.setStartDate(this.startDate);
18522 this.setEndDate(this.endDate);
18524 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18531 if(this.isInline) {
18536 picker : function()
18538 return this.pickerEl;
18539 // return this.el.select('.datepicker', true).first();
18542 fillDow: function()
18544 var dowCnt = this.weekStart;
18553 if(this.calendarWeeks){
18561 while (dowCnt < this.weekStart + 7) {
18565 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18569 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18572 fillMonths: function()
18575 var months = this.picker().select('>.datepicker-months td', true).first();
18577 months.dom.innerHTML = '';
18583 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18586 months.createChild(month);
18593 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;
18595 if (this.date < this.startDate) {
18596 this.viewDate = new Date(this.startDate);
18597 } else if (this.date > this.endDate) {
18598 this.viewDate = new Date(this.endDate);
18600 this.viewDate = new Date(this.date);
18608 var d = new Date(this.viewDate),
18609 year = d.getUTCFullYear(),
18610 month = d.getUTCMonth(),
18611 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18612 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18613 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18614 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18615 currentDate = this.date && this.date.valueOf(),
18616 today = this.UTCToday();
18618 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18620 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18622 // this.picker.select('>tfoot th.today').
18623 // .text(dates[this.language].today)
18624 // .toggle(this.todayBtn !== false);
18626 this.updateNavArrows();
18629 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18631 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18633 prevMonth.setUTCDate(day);
18635 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18637 var nextMonth = new Date(prevMonth);
18639 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18641 nextMonth = nextMonth.valueOf();
18643 var fillMonths = false;
18645 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18647 while(prevMonth.valueOf() < nextMonth) {
18650 if (prevMonth.getUTCDay() === this.weekStart) {
18652 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18660 if(this.calendarWeeks){
18661 // ISO 8601: First week contains first thursday.
18662 // ISO also states week starts on Monday, but we can be more abstract here.
18664 // Start of current week: based on weekstart/current date
18665 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18666 // Thursday of this week
18667 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18668 // First Thursday of year, year from thursday
18669 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18670 // Calendar week: ms between thursdays, div ms per day, div 7 days
18671 calWeek = (th - yth) / 864e5 / 7 + 1;
18673 fillMonths.cn.push({
18681 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18683 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18686 if (this.todayHighlight &&
18687 prevMonth.getUTCFullYear() == today.getFullYear() &&
18688 prevMonth.getUTCMonth() == today.getMonth() &&
18689 prevMonth.getUTCDate() == today.getDate()) {
18690 clsName += ' today';
18693 if (currentDate && prevMonth.valueOf() === currentDate) {
18694 clsName += ' active';
18697 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18698 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18699 clsName += ' disabled';
18702 fillMonths.cn.push({
18704 cls: 'day ' + clsName,
18705 html: prevMonth.getDate()
18708 prevMonth.setDate(prevMonth.getDate()+1);
18711 var currentYear = this.date && this.date.getUTCFullYear();
18712 var currentMonth = this.date && this.date.getUTCMonth();
18714 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18716 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18717 v.removeClass('active');
18719 if(currentYear === year && k === currentMonth){
18720 v.addClass('active');
18723 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18724 v.addClass('disabled');
18730 year = parseInt(year/10, 10) * 10;
18732 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18734 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18737 for (var i = -1; i < 11; i++) {
18738 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18740 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18748 showMode: function(dir)
18751 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18754 Roo.each(this.picker().select('>div',true).elements, function(v){
18755 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18758 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18763 if(this.isInline) {
18767 this.picker().removeClass(['bottom', 'top']);
18769 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18771 * place to the top of element!
18775 this.picker().addClass('top');
18776 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18781 this.picker().addClass('bottom');
18783 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18786 parseDate : function(value)
18788 if(!value || value instanceof Date){
18791 var v = Date.parseDate(value, this.format);
18792 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18793 v = Date.parseDate(value, 'Y-m-d');
18795 if(!v && this.altFormats){
18796 if(!this.altFormatsArray){
18797 this.altFormatsArray = this.altFormats.split("|");
18799 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18800 v = Date.parseDate(value, this.altFormatsArray[i]);
18806 formatDate : function(date, fmt)
18808 return (!date || !(date instanceof Date)) ?
18809 date : date.dateFormat(fmt || this.format);
18812 onFocus : function()
18814 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18818 onBlur : function()
18820 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18822 var d = this.inputEl().getValue();
18831 this.picker().show();
18835 this.fireEvent('show', this, this.date);
18840 if(this.isInline) {
18843 this.picker().hide();
18844 this.viewMode = this.startViewMode;
18847 this.fireEvent('hide', this, this.date);
18851 onMousedown: function(e)
18853 e.stopPropagation();
18854 e.preventDefault();
18859 Roo.bootstrap.DateField.superclass.keyup.call(this);
18863 setValue: function(v)
18865 if(this.fireEvent('beforeselect', this, v) !== false){
18866 var d = new Date(this.parseDate(v) ).clearTime();
18868 if(isNaN(d.getTime())){
18869 this.date = this.viewDate = '';
18870 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18874 v = this.formatDate(d);
18876 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18878 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18882 this.fireEvent('select', this, this.date);
18886 getValue: function()
18888 return this.formatDate(this.date);
18891 fireKey: function(e)
18893 if (!this.picker().isVisible()){
18894 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18900 var dateChanged = false,
18902 newDate, newViewDate;
18907 e.preventDefault();
18911 if (!this.keyboardNavigation) {
18914 dir = e.keyCode == 37 ? -1 : 1;
18917 newDate = this.moveYear(this.date, dir);
18918 newViewDate = this.moveYear(this.viewDate, dir);
18919 } else if (e.shiftKey){
18920 newDate = this.moveMonth(this.date, dir);
18921 newViewDate = this.moveMonth(this.viewDate, dir);
18923 newDate = new Date(this.date);
18924 newDate.setUTCDate(this.date.getUTCDate() + dir);
18925 newViewDate = new Date(this.viewDate);
18926 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18928 if (this.dateWithinRange(newDate)){
18929 this.date = newDate;
18930 this.viewDate = newViewDate;
18931 this.setValue(this.formatDate(this.date));
18933 e.preventDefault();
18934 dateChanged = true;
18939 if (!this.keyboardNavigation) {
18942 dir = e.keyCode == 38 ? -1 : 1;
18944 newDate = this.moveYear(this.date, dir);
18945 newViewDate = this.moveYear(this.viewDate, dir);
18946 } else if (e.shiftKey){
18947 newDate = this.moveMonth(this.date, dir);
18948 newViewDate = this.moveMonth(this.viewDate, dir);
18950 newDate = new Date(this.date);
18951 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18952 newViewDate = new Date(this.viewDate);
18953 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18955 if (this.dateWithinRange(newDate)){
18956 this.date = newDate;
18957 this.viewDate = newViewDate;
18958 this.setValue(this.formatDate(this.date));
18960 e.preventDefault();
18961 dateChanged = true;
18965 this.setValue(this.formatDate(this.date));
18967 e.preventDefault();
18970 this.setValue(this.formatDate(this.date));
18984 onClick: function(e)
18986 e.stopPropagation();
18987 e.preventDefault();
18989 var target = e.getTarget();
18991 if(target.nodeName.toLowerCase() === 'i'){
18992 target = Roo.get(target).dom.parentNode;
18995 var nodeName = target.nodeName;
18996 var className = target.className;
18997 var html = target.innerHTML;
18998 //Roo.log(nodeName);
19000 switch(nodeName.toLowerCase()) {
19002 switch(className) {
19008 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19009 switch(this.viewMode){
19011 this.viewDate = this.moveMonth(this.viewDate, dir);
19015 this.viewDate = this.moveYear(this.viewDate, dir);
19021 var date = new Date();
19022 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19024 this.setValue(this.formatDate(this.date));
19031 if (className.indexOf('disabled') < 0) {
19032 this.viewDate.setUTCDate(1);
19033 if (className.indexOf('month') > -1) {
19034 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19036 var year = parseInt(html, 10) || 0;
19037 this.viewDate.setUTCFullYear(year);
19041 if(this.singleMode){
19042 this.setValue(this.formatDate(this.viewDate));
19053 //Roo.log(className);
19054 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19055 var day = parseInt(html, 10) || 1;
19056 var year = this.viewDate.getUTCFullYear(),
19057 month = this.viewDate.getUTCMonth();
19059 if (className.indexOf('old') > -1) {
19066 } else if (className.indexOf('new') > -1) {
19074 //Roo.log([year,month,day]);
19075 this.date = this.UTCDate(year, month, day,0,0,0,0);
19076 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19078 //Roo.log(this.formatDate(this.date));
19079 this.setValue(this.formatDate(this.date));
19086 setStartDate: function(startDate)
19088 this.startDate = startDate || -Infinity;
19089 if (this.startDate !== -Infinity) {
19090 this.startDate = this.parseDate(this.startDate);
19093 this.updateNavArrows();
19096 setEndDate: function(endDate)
19098 this.endDate = endDate || Infinity;
19099 if (this.endDate !== Infinity) {
19100 this.endDate = this.parseDate(this.endDate);
19103 this.updateNavArrows();
19106 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19108 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19109 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19110 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19112 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19113 return parseInt(d, 10);
19116 this.updateNavArrows();
19119 updateNavArrows: function()
19121 if(this.singleMode){
19125 var d = new Date(this.viewDate),
19126 year = d.getUTCFullYear(),
19127 month = d.getUTCMonth();
19129 Roo.each(this.picker().select('.prev', true).elements, function(v){
19131 switch (this.viewMode) {
19134 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19140 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19147 Roo.each(this.picker().select('.next', true).elements, function(v){
19149 switch (this.viewMode) {
19152 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19158 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19166 moveMonth: function(date, dir)
19171 var new_date = new Date(date.valueOf()),
19172 day = new_date.getUTCDate(),
19173 month = new_date.getUTCMonth(),
19174 mag = Math.abs(dir),
19176 dir = dir > 0 ? 1 : -1;
19179 // If going back one month, make sure month is not current month
19180 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19182 return new_date.getUTCMonth() == month;
19184 // If going forward one month, make sure month is as expected
19185 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19187 return new_date.getUTCMonth() != new_month;
19189 new_month = month + dir;
19190 new_date.setUTCMonth(new_month);
19191 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19192 if (new_month < 0 || new_month > 11) {
19193 new_month = (new_month + 12) % 12;
19196 // For magnitudes >1, move one month at a time...
19197 for (var i=0; i<mag; i++) {
19198 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19199 new_date = this.moveMonth(new_date, dir);
19201 // ...then reset the day, keeping it in the new month
19202 new_month = new_date.getUTCMonth();
19203 new_date.setUTCDate(day);
19205 return new_month != new_date.getUTCMonth();
19208 // Common date-resetting loop -- if date is beyond end of month, make it
19211 new_date.setUTCDate(--day);
19212 new_date.setUTCMonth(new_month);
19217 moveYear: function(date, dir)
19219 return this.moveMonth(date, dir*12);
19222 dateWithinRange: function(date)
19224 return date >= this.startDate && date <= this.endDate;
19230 this.picker().remove();
19233 validateValue : function(value)
19235 if(this.getVisibilityEl().hasClass('hidden')){
19239 if(value.length < 1) {
19240 if(this.allowBlank){
19246 if(value.length < this.minLength){
19249 if(value.length > this.maxLength){
19253 var vt = Roo.form.VTypes;
19254 if(!vt[this.vtype](value, this)){
19258 if(typeof this.validator == "function"){
19259 var msg = this.validator(value);
19265 if(this.regex && !this.regex.test(value)){
19269 if(typeof(this.parseDate(value)) == 'undefined'){
19273 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19277 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19285 setVisible : function(visible)
19291 this.getEl().removeClass('hidden');
19297 this.getEl().addClass('hidden');
19302 Roo.apply(Roo.bootstrap.DateField, {
19313 html: '<i class="fa fa-arrow-left"/>'
19323 html: '<i class="fa fa-arrow-right"/>'
19365 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19366 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19367 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19368 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19369 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19382 navFnc: 'FullYear',
19387 navFnc: 'FullYear',
19392 Roo.apply(Roo.bootstrap.DateField, {
19396 cls: 'datepicker dropdown-menu roo-dynamic',
19400 cls: 'datepicker-days',
19404 cls: 'table-condensed',
19406 Roo.bootstrap.DateField.head,
19410 Roo.bootstrap.DateField.footer
19417 cls: 'datepicker-months',
19421 cls: 'table-condensed',
19423 Roo.bootstrap.DateField.head,
19424 Roo.bootstrap.DateField.content,
19425 Roo.bootstrap.DateField.footer
19432 cls: 'datepicker-years',
19436 cls: 'table-condensed',
19438 Roo.bootstrap.DateField.head,
19439 Roo.bootstrap.DateField.content,
19440 Roo.bootstrap.DateField.footer
19459 * @class Roo.bootstrap.TimeField
19460 * @extends Roo.bootstrap.Input
19461 * Bootstrap DateField class
19465 * Create a new TimeField
19466 * @param {Object} config The config object
19469 Roo.bootstrap.TimeField = function(config){
19470 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19474 * Fires when this field show.
19475 * @param {Roo.bootstrap.DateField} thisthis
19476 * @param {Mixed} date The date value
19481 * Fires when this field hide.
19482 * @param {Roo.bootstrap.DateField} this
19483 * @param {Mixed} date The date value
19488 * Fires when select a date.
19489 * @param {Roo.bootstrap.DateField} this
19490 * @param {Mixed} date The date value
19496 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19499 * @cfg {String} format
19500 * The default time format string which can be overriden for localization support. The format must be
19501 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19505 onRender: function(ct, position)
19508 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19510 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19512 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19514 this.pop = this.picker().select('>.datepicker-time',true).first();
19515 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19517 this.picker().on('mousedown', this.onMousedown, this);
19518 this.picker().on('click', this.onClick, this);
19520 this.picker().addClass('datepicker-dropdown');
19525 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19526 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19527 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19528 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19529 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19530 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19534 fireKey: function(e){
19535 if (!this.picker().isVisible()){
19536 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19542 e.preventDefault();
19550 this.onTogglePeriod();
19553 this.onIncrementMinutes();
19556 this.onDecrementMinutes();
19565 onClick: function(e) {
19566 e.stopPropagation();
19567 e.preventDefault();
19570 picker : function()
19572 return this.el.select('.datepicker', true).first();
19575 fillTime: function()
19577 var time = this.pop.select('tbody', true).first();
19579 time.dom.innerHTML = '';
19594 cls: 'hours-up glyphicon glyphicon-chevron-up'
19614 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19635 cls: 'timepicker-hour',
19650 cls: 'timepicker-minute',
19665 cls: 'btn btn-primary period',
19687 cls: 'hours-down glyphicon glyphicon-chevron-down'
19707 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19725 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19732 var hours = this.time.getHours();
19733 var minutes = this.time.getMinutes();
19746 hours = hours - 12;
19750 hours = '0' + hours;
19754 minutes = '0' + minutes;
19757 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19758 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19759 this.pop.select('button', true).first().dom.innerHTML = period;
19765 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19767 var cls = ['bottom'];
19769 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19776 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19781 this.picker().addClass(cls.join('-'));
19785 Roo.each(cls, function(c){
19787 _this.picker().setTop(_this.inputEl().getHeight());
19791 _this.picker().setTop(0 - _this.picker().getHeight());
19796 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19800 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19807 onFocus : function()
19809 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19813 onBlur : function()
19815 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19821 this.picker().show();
19826 this.fireEvent('show', this, this.date);
19831 this.picker().hide();
19834 this.fireEvent('hide', this, this.date);
19837 setTime : function()
19840 this.setValue(this.time.format(this.format));
19842 this.fireEvent('select', this, this.date);
19847 onMousedown: function(e){
19848 e.stopPropagation();
19849 e.preventDefault();
19852 onIncrementHours: function()
19854 Roo.log('onIncrementHours');
19855 this.time = this.time.add(Date.HOUR, 1);
19860 onDecrementHours: function()
19862 Roo.log('onDecrementHours');
19863 this.time = this.time.add(Date.HOUR, -1);
19867 onIncrementMinutes: function()
19869 Roo.log('onIncrementMinutes');
19870 this.time = this.time.add(Date.MINUTE, 1);
19874 onDecrementMinutes: function()
19876 Roo.log('onDecrementMinutes');
19877 this.time = this.time.add(Date.MINUTE, -1);
19881 onTogglePeriod: function()
19883 Roo.log('onTogglePeriod');
19884 this.time = this.time.add(Date.HOUR, 12);
19891 Roo.apply(Roo.bootstrap.TimeField, {
19921 cls: 'btn btn-info ok',
19933 Roo.apply(Roo.bootstrap.TimeField, {
19937 cls: 'datepicker dropdown-menu',
19941 cls: 'datepicker-time',
19945 cls: 'table-condensed',
19947 Roo.bootstrap.TimeField.content,
19948 Roo.bootstrap.TimeField.footer
19967 * @class Roo.bootstrap.MonthField
19968 * @extends Roo.bootstrap.Input
19969 * Bootstrap MonthField class
19971 * @cfg {String} language default en
19974 * Create a new MonthField
19975 * @param {Object} config The config object
19978 Roo.bootstrap.MonthField = function(config){
19979 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19984 * Fires when this field show.
19985 * @param {Roo.bootstrap.MonthField} this
19986 * @param {Mixed} date The date value
19991 * Fires when this field hide.
19992 * @param {Roo.bootstrap.MonthField} this
19993 * @param {Mixed} date The date value
19998 * Fires when select a date.
19999 * @param {Roo.bootstrap.MonthField} this
20000 * @param {String} oldvalue The old value
20001 * @param {String} newvalue The new value
20007 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20009 onRender: function(ct, position)
20012 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20014 this.language = this.language || 'en';
20015 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20016 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20018 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20019 this.isInline = false;
20020 this.isInput = true;
20021 this.component = this.el.select('.add-on', true).first() || false;
20022 this.component = (this.component && this.component.length === 0) ? false : this.component;
20023 this.hasInput = this.component && this.inputEL().length;
20025 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20027 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20029 this.picker().on('mousedown', this.onMousedown, this);
20030 this.picker().on('click', this.onClick, this);
20032 this.picker().addClass('datepicker-dropdown');
20034 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20035 v.setStyle('width', '189px');
20042 if(this.isInline) {
20048 setValue: function(v, suppressEvent)
20050 var o = this.getValue();
20052 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20056 if(suppressEvent !== true){
20057 this.fireEvent('select', this, o, v);
20062 getValue: function()
20067 onClick: function(e)
20069 e.stopPropagation();
20070 e.preventDefault();
20072 var target = e.getTarget();
20074 if(target.nodeName.toLowerCase() === 'i'){
20075 target = Roo.get(target).dom.parentNode;
20078 var nodeName = target.nodeName;
20079 var className = target.className;
20080 var html = target.innerHTML;
20082 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20086 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20088 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20094 picker : function()
20096 return this.pickerEl;
20099 fillMonths: function()
20102 var months = this.picker().select('>.datepicker-months td', true).first();
20104 months.dom.innerHTML = '';
20110 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20113 months.createChild(month);
20122 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20123 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20126 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20127 e.removeClass('active');
20129 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20130 e.addClass('active');
20137 if(this.isInline) {
20141 this.picker().removeClass(['bottom', 'top']);
20143 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20145 * place to the top of element!
20149 this.picker().addClass('top');
20150 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20155 this.picker().addClass('bottom');
20157 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20160 onFocus : function()
20162 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20166 onBlur : function()
20168 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20170 var d = this.inputEl().getValue();
20179 this.picker().show();
20180 this.picker().select('>.datepicker-months', true).first().show();
20184 this.fireEvent('show', this, this.date);
20189 if(this.isInline) {
20192 this.picker().hide();
20193 this.fireEvent('hide', this, this.date);
20197 onMousedown: function(e)
20199 e.stopPropagation();
20200 e.preventDefault();
20205 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20209 fireKey: function(e)
20211 if (!this.picker().isVisible()){
20212 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20223 e.preventDefault();
20227 dir = e.keyCode == 37 ? -1 : 1;
20229 this.vIndex = this.vIndex + dir;
20231 if(this.vIndex < 0){
20235 if(this.vIndex > 11){
20239 if(isNaN(this.vIndex)){
20243 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20249 dir = e.keyCode == 38 ? -1 : 1;
20251 this.vIndex = this.vIndex + dir * 4;
20253 if(this.vIndex < 0){
20257 if(this.vIndex > 11){
20261 if(isNaN(this.vIndex)){
20265 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20270 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20271 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20275 e.preventDefault();
20278 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20279 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20295 this.picker().remove();
20300 Roo.apply(Roo.bootstrap.MonthField, {
20319 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20320 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20325 Roo.apply(Roo.bootstrap.MonthField, {
20329 cls: 'datepicker dropdown-menu roo-dynamic',
20333 cls: 'datepicker-months',
20337 cls: 'table-condensed',
20339 Roo.bootstrap.DateField.content
20359 * @class Roo.bootstrap.CheckBox
20360 * @extends Roo.bootstrap.Input
20361 * Bootstrap CheckBox class
20363 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20364 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20365 * @cfg {String} boxLabel The text that appears beside the checkbox
20366 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20367 * @cfg {Boolean} checked initnal the element
20368 * @cfg {Boolean} inline inline the element (default false)
20369 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20370 * @cfg {String} tooltip label tooltip
20373 * Create a new CheckBox
20374 * @param {Object} config The config object
20377 Roo.bootstrap.CheckBox = function(config){
20378 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20383 * Fires when the element is checked or unchecked.
20384 * @param {Roo.bootstrap.CheckBox} this This input
20385 * @param {Boolean} checked The new checked value
20390 * Fires when the element is click.
20391 * @param {Roo.bootstrap.CheckBox} this This input
20398 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20400 inputType: 'checkbox',
20409 getAutoCreate : function()
20411 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20417 cfg.cls = 'form-group ' + this.inputType; //input-group
20420 cfg.cls += ' ' + this.inputType + '-inline';
20426 type : this.inputType,
20427 value : this.inputValue,
20428 cls : 'roo-' + this.inputType, //'form-box',
20429 placeholder : this.placeholder || ''
20433 if(this.inputType != 'radio'){
20437 cls : 'roo-hidden-value',
20438 value : this.checked ? this.inputValue : this.valueOff
20443 if (this.weight) { // Validity check?
20444 cfg.cls += " " + this.inputType + "-" + this.weight;
20447 if (this.disabled) {
20448 input.disabled=true;
20452 input.checked = this.checked;
20457 input.name = this.name;
20459 if(this.inputType != 'radio'){
20460 hidden.name = this.name;
20461 input.name = '_hidden_' + this.name;
20466 input.cls += ' input-' + this.size;
20471 ['xs','sm','md','lg'].map(function(size){
20472 if (settings[size]) {
20473 cfg.cls += ' col-' + size + '-' + settings[size];
20477 var inputblock = input;
20479 if (this.before || this.after) {
20482 cls : 'input-group',
20487 inputblock.cn.push({
20489 cls : 'input-group-addon',
20494 inputblock.cn.push(input);
20496 if(this.inputType != 'radio'){
20497 inputblock.cn.push(hidden);
20501 inputblock.cn.push({
20503 cls : 'input-group-addon',
20510 if (align ==='left' && this.fieldLabel.length) {
20511 // Roo.log("left and has label");
20516 cls : 'control-label',
20517 html : this.fieldLabel
20527 if(this.labelWidth > 12){
20528 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20531 if(this.labelWidth < 13 && this.labelmd == 0){
20532 this.labelmd = this.labelWidth;
20535 if(this.labellg > 0){
20536 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20537 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20540 if(this.labelmd > 0){
20541 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20542 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20545 if(this.labelsm > 0){
20546 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20547 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20550 if(this.labelxs > 0){
20551 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20552 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20555 } else if ( this.fieldLabel.length) {
20556 // Roo.log(" label");
20560 tag: this.boxLabel ? 'span' : 'label',
20562 cls: 'control-label box-input-label',
20563 //cls : 'input-group-addon',
20564 html : this.fieldLabel
20573 // Roo.log(" no label && no align");
20574 cfg.cn = [ inputblock ] ;
20580 var boxLabelCfg = {
20582 //'for': id, // box label is handled by onclick - so no for...
20584 html: this.boxLabel
20588 boxLabelCfg.tooltip = this.tooltip;
20591 cfg.cn.push(boxLabelCfg);
20594 if(this.inputType != 'radio'){
20595 cfg.cn.push(hidden);
20603 * return the real input element.
20605 inputEl: function ()
20607 return this.el.select('input.roo-' + this.inputType,true).first();
20609 hiddenEl: function ()
20611 return this.el.select('input.roo-hidden-value',true).first();
20614 labelEl: function()
20616 return this.el.select('label.control-label',true).first();
20618 /* depricated... */
20622 return this.labelEl();
20625 boxLabelEl: function()
20627 return this.el.select('label.box-label',true).first();
20630 initEvents : function()
20632 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20634 this.inputEl().on('click', this.onClick, this);
20636 if (this.boxLabel) {
20637 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20640 this.startValue = this.getValue();
20643 Roo.bootstrap.CheckBox.register(this);
20647 onClick : function(e)
20649 if(this.fireEvent('click', this, e) !== false){
20650 this.setChecked(!this.checked);
20655 setChecked : function(state,suppressEvent)
20657 this.startValue = this.getValue();
20659 if(this.inputType == 'radio'){
20661 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20662 e.dom.checked = false;
20665 this.inputEl().dom.checked = true;
20667 this.inputEl().dom.value = this.inputValue;
20669 if(suppressEvent !== true){
20670 this.fireEvent('check', this, true);
20678 this.checked = state;
20680 this.inputEl().dom.checked = state;
20683 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20685 if(suppressEvent !== true){
20686 this.fireEvent('check', this, state);
20692 getValue : function()
20694 if(this.inputType == 'radio'){
20695 return this.getGroupValue();
20698 return this.hiddenEl().dom.value;
20702 getGroupValue : function()
20704 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20708 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20711 setValue : function(v,suppressEvent)
20713 if(this.inputType == 'radio'){
20714 this.setGroupValue(v, suppressEvent);
20718 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20723 setGroupValue : function(v, suppressEvent)
20725 this.startValue = this.getValue();
20727 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20728 e.dom.checked = false;
20730 if(e.dom.value == v){
20731 e.dom.checked = true;
20735 if(suppressEvent !== true){
20736 this.fireEvent('check', this, true);
20744 validate : function()
20746 if(this.getVisibilityEl().hasClass('hidden')){
20752 (this.inputType == 'radio' && this.validateRadio()) ||
20753 (this.inputType == 'checkbox' && this.validateCheckbox())
20759 this.markInvalid();
20763 validateRadio : function()
20765 if(this.getVisibilityEl().hasClass('hidden')){
20769 if(this.allowBlank){
20775 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20776 if(!e.dom.checked){
20788 validateCheckbox : function()
20791 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20792 //return (this.getValue() == this.inputValue) ? true : false;
20795 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20803 for(var i in group){
20804 if(group[i].el.isVisible(true)){
20812 for(var i in group){
20817 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20824 * Mark this field as valid
20826 markValid : function()
20830 this.fireEvent('valid', this);
20832 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20835 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20842 if(this.inputType == 'radio'){
20843 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20844 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20845 e.findParent('.form-group', false, true).addClass(_this.validClass);
20852 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20853 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20857 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20863 for(var i in group){
20864 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20865 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20870 * Mark this field as invalid
20871 * @param {String} msg The validation message
20873 markInvalid : function(msg)
20875 if(this.allowBlank){
20881 this.fireEvent('invalid', this, msg);
20883 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20886 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20890 label.markInvalid();
20893 if(this.inputType == 'radio'){
20894 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20895 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20896 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20903 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20904 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20908 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20914 for(var i in group){
20915 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20916 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20921 clearInvalid : function()
20923 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20925 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20927 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20929 if (label && label.iconEl) {
20930 label.iconEl.removeClass(label.validClass);
20931 label.iconEl.removeClass(label.invalidClass);
20935 disable : function()
20937 if(this.inputType != 'radio'){
20938 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20945 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20946 _this.getActionEl().addClass(this.disabledClass);
20947 e.dom.disabled = true;
20951 this.disabled = true;
20952 this.fireEvent("disable", this);
20956 enable : function()
20958 if(this.inputType != 'radio'){
20959 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20966 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20967 _this.getActionEl().removeClass(this.disabledClass);
20968 e.dom.disabled = false;
20972 this.disabled = false;
20973 this.fireEvent("enable", this);
20977 setBoxLabel : function(v)
20982 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20988 Roo.apply(Roo.bootstrap.CheckBox, {
20993 * register a CheckBox Group
20994 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20996 register : function(checkbox)
20998 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20999 this.groups[checkbox.groupId] = {};
21002 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21006 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21010 * fetch a CheckBox Group based on the group ID
21011 * @param {string} the group ID
21012 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21014 get: function(groupId) {
21015 if (typeof(this.groups[groupId]) == 'undefined') {
21019 return this.groups[groupId] ;
21032 * @class Roo.bootstrap.Radio
21033 * @extends Roo.bootstrap.Component
21034 * Bootstrap Radio class
21035 * @cfg {String} boxLabel - the label associated
21036 * @cfg {String} value - the value of radio
21039 * Create a new Radio
21040 * @param {Object} config The config object
21042 Roo.bootstrap.Radio = function(config){
21043 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21047 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21053 getAutoCreate : function()
21057 cls : 'form-group radio',
21062 html : this.boxLabel
21070 initEvents : function()
21072 this.parent().register(this);
21074 this.el.on('click', this.onClick, this);
21078 onClick : function(e)
21080 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21081 this.setChecked(true);
21085 setChecked : function(state, suppressEvent)
21087 this.parent().setValue(this.value, suppressEvent);
21091 setBoxLabel : function(v)
21096 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21111 * @class Roo.bootstrap.SecurePass
21112 * @extends Roo.bootstrap.Input
21113 * Bootstrap SecurePass class
21117 * Create a new SecurePass
21118 * @param {Object} config The config object
21121 Roo.bootstrap.SecurePass = function (config) {
21122 // these go here, so the translation tool can replace them..
21124 PwdEmpty: "Please type a password, and then retype it to confirm.",
21125 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21126 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21127 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21128 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21129 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21130 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21131 TooWeak: "Your password is Too Weak."
21133 this.meterLabel = "Password strength:";
21134 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21135 this.meterClass = [
21136 "roo-password-meter-tooweak",
21137 "roo-password-meter-weak",
21138 "roo-password-meter-medium",
21139 "roo-password-meter-strong",
21140 "roo-password-meter-grey"
21145 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21148 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21150 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21152 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21153 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21154 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21155 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21156 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21157 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21158 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21168 * @cfg {String/Object} Label for the strength meter (defaults to
21169 * 'Password strength:')
21174 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21175 * ['Weak', 'Medium', 'Strong'])
21178 pwdStrengths: false,
21191 initEvents: function ()
21193 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21195 if (this.el.is('input[type=password]') && Roo.isSafari) {
21196 this.el.on('keydown', this.SafariOnKeyDown, this);
21199 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21202 onRender: function (ct, position)
21204 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21205 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21206 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21208 this.trigger.createChild({
21213 cls: 'roo-password-meter-grey col-xs-12',
21216 //width: this.meterWidth + 'px'
21220 cls: 'roo-password-meter-text'
21226 if (this.hideTrigger) {
21227 this.trigger.setDisplayed(false);
21229 this.setSize(this.width || '', this.height || '');
21232 onDestroy: function ()
21234 if (this.trigger) {
21235 this.trigger.removeAllListeners();
21236 this.trigger.remove();
21239 this.wrap.remove();
21241 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21244 checkStrength: function ()
21246 var pwd = this.inputEl().getValue();
21247 if (pwd == this._lastPwd) {
21252 if (this.ClientSideStrongPassword(pwd)) {
21254 } else if (this.ClientSideMediumPassword(pwd)) {
21256 } else if (this.ClientSideWeakPassword(pwd)) {
21262 Roo.log('strength1: ' + strength);
21264 //var pm = this.trigger.child('div/div/div').dom;
21265 var pm = this.trigger.child('div/div');
21266 pm.removeClass(this.meterClass);
21267 pm.addClass(this.meterClass[strength]);
21270 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21272 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21274 this._lastPwd = pwd;
21278 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21280 this._lastPwd = '';
21282 var pm = this.trigger.child('div/div');
21283 pm.removeClass(this.meterClass);
21284 pm.addClass('roo-password-meter-grey');
21287 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21290 this.inputEl().dom.type='password';
21293 validateValue: function (value)
21296 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21299 if (value.length == 0) {
21300 if (this.allowBlank) {
21301 this.clearInvalid();
21305 this.markInvalid(this.errors.PwdEmpty);
21306 this.errorMsg = this.errors.PwdEmpty;
21314 if ('[\x21-\x7e]*'.match(value)) {
21315 this.markInvalid(this.errors.PwdBadChar);
21316 this.errorMsg = this.errors.PwdBadChar;
21319 if (value.length < 6) {
21320 this.markInvalid(this.errors.PwdShort);
21321 this.errorMsg = this.errors.PwdShort;
21324 if (value.length > 16) {
21325 this.markInvalid(this.errors.PwdLong);
21326 this.errorMsg = this.errors.PwdLong;
21330 if (this.ClientSideStrongPassword(value)) {
21332 } else if (this.ClientSideMediumPassword(value)) {
21334 } else if (this.ClientSideWeakPassword(value)) {
21341 if (strength < 2) {
21342 //this.markInvalid(this.errors.TooWeak);
21343 this.errorMsg = this.errors.TooWeak;
21348 console.log('strength2: ' + strength);
21350 //var pm = this.trigger.child('div/div/div').dom;
21352 var pm = this.trigger.child('div/div');
21353 pm.removeClass(this.meterClass);
21354 pm.addClass(this.meterClass[strength]);
21356 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21358 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21360 this.errorMsg = '';
21364 CharacterSetChecks: function (type)
21367 this.fResult = false;
21370 isctype: function (character, type)
21373 case this.kCapitalLetter:
21374 if (character >= 'A' && character <= 'Z') {
21379 case this.kSmallLetter:
21380 if (character >= 'a' && character <= 'z') {
21386 if (character >= '0' && character <= '9') {
21391 case this.kPunctuation:
21392 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21403 IsLongEnough: function (pwd, size)
21405 return !(pwd == null || isNaN(size) || pwd.length < size);
21408 SpansEnoughCharacterSets: function (word, nb)
21410 if (!this.IsLongEnough(word, nb))
21415 var characterSetChecks = new Array(
21416 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21417 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21420 for (var index = 0; index < word.length; ++index) {
21421 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21422 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21423 characterSetChecks[nCharSet].fResult = true;
21430 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21431 if (characterSetChecks[nCharSet].fResult) {
21436 if (nCharSets < nb) {
21442 ClientSideStrongPassword: function (pwd)
21444 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21447 ClientSideMediumPassword: function (pwd)
21449 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21452 ClientSideWeakPassword: function (pwd)
21454 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21457 })//<script type="text/javascript">
21460 * Based Ext JS Library 1.1.1
21461 * Copyright(c) 2006-2007, Ext JS, LLC.
21467 * @class Roo.HtmlEditorCore
21468 * @extends Roo.Component
21469 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21471 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21474 Roo.HtmlEditorCore = function(config){
21477 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21482 * @event initialize
21483 * Fires when the editor is fully initialized (including the iframe)
21484 * @param {Roo.HtmlEditorCore} this
21489 * Fires when the editor is first receives the focus. Any insertion must wait
21490 * until after this event.
21491 * @param {Roo.HtmlEditorCore} this
21495 * @event beforesync
21496 * Fires before the textarea is updated with content from the editor iframe. Return false
21497 * to cancel the sync.
21498 * @param {Roo.HtmlEditorCore} this
21499 * @param {String} html
21503 * @event beforepush
21504 * Fires before the iframe editor is updated with content from the textarea. Return false
21505 * to cancel the push.
21506 * @param {Roo.HtmlEditorCore} this
21507 * @param {String} html
21512 * Fires when the textarea is updated with content from the editor iframe.
21513 * @param {Roo.HtmlEditorCore} this
21514 * @param {String} html
21519 * Fires when the iframe editor is updated with content from the textarea.
21520 * @param {Roo.HtmlEditorCore} this
21521 * @param {String} html
21526 * @event editorevent
21527 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21528 * @param {Roo.HtmlEditorCore} this
21534 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21536 // defaults : white / black...
21537 this.applyBlacklists();
21544 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21548 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21554 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21559 * @cfg {Number} height (in pixels)
21563 * @cfg {Number} width (in pixels)
21568 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21571 stylesheets: false,
21576 // private properties
21577 validationEvent : false,
21579 initialized : false,
21581 sourceEditMode : false,
21582 onFocus : Roo.emptyFn,
21584 hideMode:'offsets',
21588 // blacklist + whitelisted elements..
21595 * Protected method that will not generally be called directly. It
21596 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21597 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21599 getDocMarkup : function(){
21603 // inherit styels from page...??
21604 if (this.stylesheets === false) {
21606 Roo.get(document.head).select('style').each(function(node) {
21607 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21610 Roo.get(document.head).select('link').each(function(node) {
21611 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21614 } else if (!this.stylesheets.length) {
21616 st = '<style type="text/css">' +
21617 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21620 st = '<style type="text/css">' +
21625 st += '<style type="text/css">' +
21626 'IMG { cursor: pointer } ' +
21629 var cls = 'roo-htmleditor-body';
21631 if(this.bodyCls.length){
21632 cls += ' ' + this.bodyCls;
21635 return '<html><head>' + st +
21636 //<style type="text/css">' +
21637 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21639 ' </head><body class="' + cls + '"></body></html>';
21643 onRender : function(ct, position)
21646 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21647 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21650 this.el.dom.style.border = '0 none';
21651 this.el.dom.setAttribute('tabIndex', -1);
21652 this.el.addClass('x-hidden hide');
21656 if(Roo.isIE){ // fix IE 1px bogus margin
21657 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21661 this.frameId = Roo.id();
21665 var iframe = this.owner.wrap.createChild({
21667 cls: 'form-control', // bootstrap..
21669 name: this.frameId,
21670 frameBorder : 'no',
21671 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21676 this.iframe = iframe.dom;
21678 this.assignDocWin();
21680 this.doc.designMode = 'on';
21683 this.doc.write(this.getDocMarkup());
21687 var task = { // must defer to wait for browser to be ready
21689 //console.log("run task?" + this.doc.readyState);
21690 this.assignDocWin();
21691 if(this.doc.body || this.doc.readyState == 'complete'){
21693 this.doc.designMode="on";
21697 Roo.TaskMgr.stop(task);
21698 this.initEditor.defer(10, this);
21705 Roo.TaskMgr.start(task);
21710 onResize : function(w, h)
21712 Roo.log('resize: ' +w + ',' + h );
21713 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21717 if(typeof w == 'number'){
21719 this.iframe.style.width = w + 'px';
21721 if(typeof h == 'number'){
21723 this.iframe.style.height = h + 'px';
21725 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21732 * Toggles the editor between standard and source edit mode.
21733 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21735 toggleSourceEdit : function(sourceEditMode){
21737 this.sourceEditMode = sourceEditMode === true;
21739 if(this.sourceEditMode){
21741 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21744 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21745 //this.iframe.className = '';
21748 //this.setSize(this.owner.wrap.getSize());
21749 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21756 * Protected method that will not generally be called directly. If you need/want
21757 * custom HTML cleanup, this is the method you should override.
21758 * @param {String} html The HTML to be cleaned
21759 * return {String} The cleaned HTML
21761 cleanHtml : function(html){
21762 html = String(html);
21763 if(html.length > 5){
21764 if(Roo.isSafari){ // strip safari nonsense
21765 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21768 if(html == ' '){
21775 * HTML Editor -> Textarea
21776 * Protected method that will not generally be called directly. Syncs the contents
21777 * of the editor iframe with the textarea.
21779 syncValue : function(){
21780 if(this.initialized){
21781 var bd = (this.doc.body || this.doc.documentElement);
21782 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21783 var html = bd.innerHTML;
21785 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21786 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21788 html = '<div style="'+m[0]+'">' + html + '</div>';
21791 html = this.cleanHtml(html);
21792 // fix up the special chars.. normaly like back quotes in word...
21793 // however we do not want to do this with chinese..
21794 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21795 var cc = b.charCodeAt();
21797 (cc >= 0x4E00 && cc < 0xA000 ) ||
21798 (cc >= 0x3400 && cc < 0x4E00 ) ||
21799 (cc >= 0xf900 && cc < 0xfb00 )
21805 if(this.owner.fireEvent('beforesync', this, html) !== false){
21806 this.el.dom.value = html;
21807 this.owner.fireEvent('sync', this, html);
21813 * Protected method that will not generally be called directly. Pushes the value of the textarea
21814 * into the iframe editor.
21816 pushValue : function(){
21817 if(this.initialized){
21818 var v = this.el.dom.value.trim();
21820 // if(v.length < 1){
21824 if(this.owner.fireEvent('beforepush', this, v) !== false){
21825 var d = (this.doc.body || this.doc.documentElement);
21827 this.cleanUpPaste();
21828 this.el.dom.value = d.innerHTML;
21829 this.owner.fireEvent('push', this, v);
21835 deferFocus : function(){
21836 this.focus.defer(10, this);
21840 focus : function(){
21841 if(this.win && !this.sourceEditMode){
21848 assignDocWin: function()
21850 var iframe = this.iframe;
21853 this.doc = iframe.contentWindow.document;
21854 this.win = iframe.contentWindow;
21856 // if (!Roo.get(this.frameId)) {
21859 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21860 // this.win = Roo.get(this.frameId).dom.contentWindow;
21862 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21866 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21867 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21872 initEditor : function(){
21873 //console.log("INIT EDITOR");
21874 this.assignDocWin();
21878 this.doc.designMode="on";
21880 this.doc.write(this.getDocMarkup());
21883 var dbody = (this.doc.body || this.doc.documentElement);
21884 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21885 // this copies styles from the containing element into thsi one..
21886 // not sure why we need all of this..
21887 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21889 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21890 //ss['background-attachment'] = 'fixed'; // w3c
21891 dbody.bgProperties = 'fixed'; // ie
21892 //Roo.DomHelper.applyStyles(dbody, ss);
21893 Roo.EventManager.on(this.doc, {
21894 //'mousedown': this.onEditorEvent,
21895 'mouseup': this.onEditorEvent,
21896 'dblclick': this.onEditorEvent,
21897 'click': this.onEditorEvent,
21898 'keyup': this.onEditorEvent,
21903 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21905 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21906 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21908 this.initialized = true;
21910 this.owner.fireEvent('initialize', this);
21915 onDestroy : function(){
21921 //for (var i =0; i < this.toolbars.length;i++) {
21922 // // fixme - ask toolbars for heights?
21923 // this.toolbars[i].onDestroy();
21926 //this.wrap.dom.innerHTML = '';
21927 //this.wrap.remove();
21932 onFirstFocus : function(){
21934 this.assignDocWin();
21937 this.activated = true;
21940 if(Roo.isGecko){ // prevent silly gecko errors
21942 var s = this.win.getSelection();
21943 if(!s.focusNode || s.focusNode.nodeType != 3){
21944 var r = s.getRangeAt(0);
21945 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21950 this.execCmd('useCSS', true);
21951 this.execCmd('styleWithCSS', false);
21954 this.owner.fireEvent('activate', this);
21958 adjustFont: function(btn){
21959 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21960 //if(Roo.isSafari){ // safari
21963 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21964 if(Roo.isSafari){ // safari
21965 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21966 v = (v < 10) ? 10 : v;
21967 v = (v > 48) ? 48 : v;
21968 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21973 v = Math.max(1, v+adjust);
21975 this.execCmd('FontSize', v );
21978 onEditorEvent : function(e)
21980 this.owner.fireEvent('editorevent', this, e);
21981 // this.updateToolbar();
21982 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21985 insertTag : function(tg)
21987 // could be a bit smarter... -> wrap the current selected tRoo..
21988 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21990 range = this.createRange(this.getSelection());
21991 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21992 wrappingNode.appendChild(range.extractContents());
21993 range.insertNode(wrappingNode);
22000 this.execCmd("formatblock", tg);
22004 insertText : function(txt)
22008 var range = this.createRange();
22009 range.deleteContents();
22010 //alert(Sender.getAttribute('label'));
22012 range.insertNode(this.doc.createTextNode(txt));
22018 * Executes a Midas editor command on the editor document and performs necessary focus and
22019 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22020 * @param {String} cmd The Midas command
22021 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22023 relayCmd : function(cmd, value){
22025 this.execCmd(cmd, value);
22026 this.owner.fireEvent('editorevent', this);
22027 //this.updateToolbar();
22028 this.owner.deferFocus();
22032 * Executes a Midas editor command directly on the editor document.
22033 * For visual commands, you should use {@link #relayCmd} instead.
22034 * <b>This should only be called after the editor is initialized.</b>
22035 * @param {String} cmd The Midas command
22036 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22038 execCmd : function(cmd, value){
22039 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22046 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22048 * @param {String} text | dom node..
22050 insertAtCursor : function(text)
22053 if(!this.activated){
22059 var r = this.doc.selection.createRange();
22070 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22074 // from jquery ui (MIT licenced)
22076 var win = this.win;
22078 if (win.getSelection && win.getSelection().getRangeAt) {
22079 range = win.getSelection().getRangeAt(0);
22080 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22081 range.insertNode(node);
22082 } else if (win.document.selection && win.document.selection.createRange) {
22083 // no firefox support
22084 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22085 win.document.selection.createRange().pasteHTML(txt);
22087 // no firefox support
22088 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22089 this.execCmd('InsertHTML', txt);
22098 mozKeyPress : function(e){
22100 var c = e.getCharCode(), cmd;
22103 c = String.fromCharCode(c).toLowerCase();
22117 this.cleanUpPaste.defer(100, this);
22125 e.preventDefault();
22133 fixKeys : function(){ // load time branching for fastest keydown performance
22135 return function(e){
22136 var k = e.getKey(), r;
22139 r = this.doc.selection.createRange();
22142 r.pasteHTML('    ');
22149 r = this.doc.selection.createRange();
22151 var target = r.parentElement();
22152 if(!target || target.tagName.toLowerCase() != 'li'){
22154 r.pasteHTML('<br />');
22160 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22161 this.cleanUpPaste.defer(100, this);
22167 }else if(Roo.isOpera){
22168 return function(e){
22169 var k = e.getKey();
22173 this.execCmd('InsertHTML','    ');
22176 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22177 this.cleanUpPaste.defer(100, this);
22182 }else if(Roo.isSafari){
22183 return function(e){
22184 var k = e.getKey();
22188 this.execCmd('InsertText','\t');
22192 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22193 this.cleanUpPaste.defer(100, this);
22201 getAllAncestors: function()
22203 var p = this.getSelectedNode();
22206 a.push(p); // push blank onto stack..
22207 p = this.getParentElement();
22211 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22215 a.push(this.doc.body);
22219 lastSelNode : false,
22222 getSelection : function()
22224 this.assignDocWin();
22225 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22228 getSelectedNode: function()
22230 // this may only work on Gecko!!!
22232 // should we cache this!!!!
22237 var range = this.createRange(this.getSelection()).cloneRange();
22240 var parent = range.parentElement();
22242 var testRange = range.duplicate();
22243 testRange.moveToElementText(parent);
22244 if (testRange.inRange(range)) {
22247 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22250 parent = parent.parentElement;
22255 // is ancestor a text element.
22256 var ac = range.commonAncestorContainer;
22257 if (ac.nodeType == 3) {
22258 ac = ac.parentNode;
22261 var ar = ac.childNodes;
22264 var other_nodes = [];
22265 var has_other_nodes = false;
22266 for (var i=0;i<ar.length;i++) {
22267 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22270 // fullly contained node.
22272 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22277 // probably selected..
22278 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22279 other_nodes.push(ar[i]);
22283 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22288 has_other_nodes = true;
22290 if (!nodes.length && other_nodes.length) {
22291 nodes= other_nodes;
22293 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22299 createRange: function(sel)
22301 // this has strange effects when using with
22302 // top toolbar - not sure if it's a great idea.
22303 //this.editor.contentWindow.focus();
22304 if (typeof sel != "undefined") {
22306 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22308 return this.doc.createRange();
22311 return this.doc.createRange();
22314 getParentElement: function()
22317 this.assignDocWin();
22318 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22320 var range = this.createRange(sel);
22323 var p = range.commonAncestorContainer;
22324 while (p.nodeType == 3) { // text node
22335 * Range intersection.. the hard stuff...
22339 * [ -- selected range --- ]
22343 * if end is before start or hits it. fail.
22344 * if start is after end or hits it fail.
22346 * if either hits (but other is outside. - then it's not
22352 // @see http://www.thismuchiknow.co.uk/?p=64.
22353 rangeIntersectsNode : function(range, node)
22355 var nodeRange = node.ownerDocument.createRange();
22357 nodeRange.selectNode(node);
22359 nodeRange.selectNodeContents(node);
22362 var rangeStartRange = range.cloneRange();
22363 rangeStartRange.collapse(true);
22365 var rangeEndRange = range.cloneRange();
22366 rangeEndRange.collapse(false);
22368 var nodeStartRange = nodeRange.cloneRange();
22369 nodeStartRange.collapse(true);
22371 var nodeEndRange = nodeRange.cloneRange();
22372 nodeEndRange.collapse(false);
22374 return rangeStartRange.compareBoundaryPoints(
22375 Range.START_TO_START, nodeEndRange) == -1 &&
22376 rangeEndRange.compareBoundaryPoints(
22377 Range.START_TO_START, nodeStartRange) == 1;
22381 rangeCompareNode : function(range, node)
22383 var nodeRange = node.ownerDocument.createRange();
22385 nodeRange.selectNode(node);
22387 nodeRange.selectNodeContents(node);
22391 range.collapse(true);
22393 nodeRange.collapse(true);
22395 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22396 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22398 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22400 var nodeIsBefore = ss == 1;
22401 var nodeIsAfter = ee == -1;
22403 if (nodeIsBefore && nodeIsAfter) {
22406 if (!nodeIsBefore && nodeIsAfter) {
22407 return 1; //right trailed.
22410 if (nodeIsBefore && !nodeIsAfter) {
22411 return 2; // left trailed.
22417 // private? - in a new class?
22418 cleanUpPaste : function()
22420 // cleans up the whole document..
22421 Roo.log('cleanuppaste');
22423 this.cleanUpChildren(this.doc.body);
22424 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22425 if (clean != this.doc.body.innerHTML) {
22426 this.doc.body.innerHTML = clean;
22431 cleanWordChars : function(input) {// change the chars to hex code
22432 var he = Roo.HtmlEditorCore;
22434 var output = input;
22435 Roo.each(he.swapCodes, function(sw) {
22436 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22438 output = output.replace(swapper, sw[1]);
22445 cleanUpChildren : function (n)
22447 if (!n.childNodes.length) {
22450 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22451 this.cleanUpChild(n.childNodes[i]);
22458 cleanUpChild : function (node)
22461 //console.log(node);
22462 if (node.nodeName == "#text") {
22463 // clean up silly Windows -- stuff?
22466 if (node.nodeName == "#comment") {
22467 node.parentNode.removeChild(node);
22468 // clean up silly Windows -- stuff?
22471 var lcname = node.tagName.toLowerCase();
22472 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22473 // whitelist of tags..
22475 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22477 node.parentNode.removeChild(node);
22482 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22484 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22485 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22487 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22488 // remove_keep_children = true;
22491 if (remove_keep_children) {
22492 this.cleanUpChildren(node);
22493 // inserts everything just before this node...
22494 while (node.childNodes.length) {
22495 var cn = node.childNodes[0];
22496 node.removeChild(cn);
22497 node.parentNode.insertBefore(cn, node);
22499 node.parentNode.removeChild(node);
22503 if (!node.attributes || !node.attributes.length) {
22504 this.cleanUpChildren(node);
22508 function cleanAttr(n,v)
22511 if (v.match(/^\./) || v.match(/^\//)) {
22514 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22517 if (v.match(/^#/)) {
22520 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22521 node.removeAttribute(n);
22525 var cwhite = this.cwhite;
22526 var cblack = this.cblack;
22528 function cleanStyle(n,v)
22530 if (v.match(/expression/)) { //XSS?? should we even bother..
22531 node.removeAttribute(n);
22535 var parts = v.split(/;/);
22538 Roo.each(parts, function(p) {
22539 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22543 var l = p.split(':').shift().replace(/\s+/g,'');
22544 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22546 if ( cwhite.length && cblack.indexOf(l) > -1) {
22547 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22548 //node.removeAttribute(n);
22552 // only allow 'c whitelisted system attributes'
22553 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22554 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22555 //node.removeAttribute(n);
22565 if (clean.length) {
22566 node.setAttribute(n, clean.join(';'));
22568 node.removeAttribute(n);
22574 for (var i = node.attributes.length-1; i > -1 ; i--) {
22575 var a = node.attributes[i];
22578 if (a.name.toLowerCase().substr(0,2)=='on') {
22579 node.removeAttribute(a.name);
22582 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22583 node.removeAttribute(a.name);
22586 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22587 cleanAttr(a.name,a.value); // fixme..
22590 if (a.name == 'style') {
22591 cleanStyle(a.name,a.value);
22594 /// clean up MS crap..
22595 // tecnically this should be a list of valid class'es..
22598 if (a.name == 'class') {
22599 if (a.value.match(/^Mso/)) {
22600 node.className = '';
22603 if (a.value.match(/^body$/)) {
22604 node.className = '';
22615 this.cleanUpChildren(node);
22621 * Clean up MS wordisms...
22623 cleanWord : function(node)
22628 this.cleanWord(this.doc.body);
22631 if (node.nodeName == "#text") {
22632 // clean up silly Windows -- stuff?
22635 if (node.nodeName == "#comment") {
22636 node.parentNode.removeChild(node);
22637 // clean up silly Windows -- stuff?
22641 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22642 node.parentNode.removeChild(node);
22646 // remove - but keep children..
22647 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22648 while (node.childNodes.length) {
22649 var cn = node.childNodes[0];
22650 node.removeChild(cn);
22651 node.parentNode.insertBefore(cn, node);
22653 node.parentNode.removeChild(node);
22654 this.iterateChildren(node, this.cleanWord);
22658 if (node.className.length) {
22660 var cn = node.className.split(/\W+/);
22662 Roo.each(cn, function(cls) {
22663 if (cls.match(/Mso[a-zA-Z]+/)) {
22668 node.className = cna.length ? cna.join(' ') : '';
22670 node.removeAttribute("class");
22674 if (node.hasAttribute("lang")) {
22675 node.removeAttribute("lang");
22678 if (node.hasAttribute("style")) {
22680 var styles = node.getAttribute("style").split(";");
22682 Roo.each(styles, function(s) {
22683 if (!s.match(/:/)) {
22686 var kv = s.split(":");
22687 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22690 // what ever is left... we allow.
22693 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22694 if (!nstyle.length) {
22695 node.removeAttribute('style');
22698 this.iterateChildren(node, this.cleanWord);
22704 * iterateChildren of a Node, calling fn each time, using this as the scole..
22705 * @param {DomNode} node node to iterate children of.
22706 * @param {Function} fn method of this class to call on each item.
22708 iterateChildren : function(node, fn)
22710 if (!node.childNodes.length) {
22713 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22714 fn.call(this, node.childNodes[i])
22720 * cleanTableWidths.
22722 * Quite often pasting from word etc.. results in tables with column and widths.
22723 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22726 cleanTableWidths : function(node)
22731 this.cleanTableWidths(this.doc.body);
22736 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22739 Roo.log(node.tagName);
22740 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22741 this.iterateChildren(node, this.cleanTableWidths);
22744 if (node.hasAttribute('width')) {
22745 node.removeAttribute('width');
22749 if (node.hasAttribute("style")) {
22752 var styles = node.getAttribute("style").split(";");
22754 Roo.each(styles, function(s) {
22755 if (!s.match(/:/)) {
22758 var kv = s.split(":");
22759 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22762 // what ever is left... we allow.
22765 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22766 if (!nstyle.length) {
22767 node.removeAttribute('style');
22771 this.iterateChildren(node, this.cleanTableWidths);
22779 domToHTML : function(currentElement, depth, nopadtext) {
22781 depth = depth || 0;
22782 nopadtext = nopadtext || false;
22784 if (!currentElement) {
22785 return this.domToHTML(this.doc.body);
22788 //Roo.log(currentElement);
22790 var allText = false;
22791 var nodeName = currentElement.nodeName;
22792 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22794 if (nodeName == '#text') {
22796 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22801 if (nodeName != 'BODY') {
22804 // Prints the node tagName, such as <A>, <IMG>, etc
22807 for(i = 0; i < currentElement.attributes.length;i++) {
22809 var aname = currentElement.attributes.item(i).name;
22810 if (!currentElement.attributes.item(i).value.length) {
22813 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22816 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22825 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22828 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22833 // Traverse the tree
22835 var currentElementChild = currentElement.childNodes.item(i);
22836 var allText = true;
22837 var innerHTML = '';
22839 while (currentElementChild) {
22840 // Formatting code (indent the tree so it looks nice on the screen)
22841 var nopad = nopadtext;
22842 if (lastnode == 'SPAN') {
22846 if (currentElementChild.nodeName == '#text') {
22847 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22848 toadd = nopadtext ? toadd : toadd.trim();
22849 if (!nopad && toadd.length > 80) {
22850 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22852 innerHTML += toadd;
22855 currentElementChild = currentElement.childNodes.item(i);
22861 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22863 // Recursively traverse the tree structure of the child node
22864 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22865 lastnode = currentElementChild.nodeName;
22867 currentElementChild=currentElement.childNodes.item(i);
22873 // The remaining code is mostly for formatting the tree
22874 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22879 ret+= "</"+tagName+">";
22885 applyBlacklists : function()
22887 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22888 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22892 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22893 if (b.indexOf(tag) > -1) {
22896 this.white.push(tag);
22900 Roo.each(w, function(tag) {
22901 if (b.indexOf(tag) > -1) {
22904 if (this.white.indexOf(tag) > -1) {
22907 this.white.push(tag);
22912 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22913 if (w.indexOf(tag) > -1) {
22916 this.black.push(tag);
22920 Roo.each(b, function(tag) {
22921 if (w.indexOf(tag) > -1) {
22924 if (this.black.indexOf(tag) > -1) {
22927 this.black.push(tag);
22932 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22933 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22937 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22938 if (b.indexOf(tag) > -1) {
22941 this.cwhite.push(tag);
22945 Roo.each(w, function(tag) {
22946 if (b.indexOf(tag) > -1) {
22949 if (this.cwhite.indexOf(tag) > -1) {
22952 this.cwhite.push(tag);
22957 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22958 if (w.indexOf(tag) > -1) {
22961 this.cblack.push(tag);
22965 Roo.each(b, function(tag) {
22966 if (w.indexOf(tag) > -1) {
22969 if (this.cblack.indexOf(tag) > -1) {
22972 this.cblack.push(tag);
22977 setStylesheets : function(stylesheets)
22979 if(typeof(stylesheets) == 'string'){
22980 Roo.get(this.iframe.contentDocument.head).createChild({
22982 rel : 'stylesheet',
22991 Roo.each(stylesheets, function(s) {
22996 Roo.get(_this.iframe.contentDocument.head).createChild({
22998 rel : 'stylesheet',
23007 removeStylesheets : function()
23011 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23016 setStyle : function(style)
23018 Roo.get(this.iframe.contentDocument.head).createChild({
23027 // hide stuff that is not compatible
23041 * @event specialkey
23045 * @cfg {String} fieldClass @hide
23048 * @cfg {String} focusClass @hide
23051 * @cfg {String} autoCreate @hide
23054 * @cfg {String} inputType @hide
23057 * @cfg {String} invalidClass @hide
23060 * @cfg {String} invalidText @hide
23063 * @cfg {String} msgFx @hide
23066 * @cfg {String} validateOnBlur @hide
23070 Roo.HtmlEditorCore.white = [
23071 'area', 'br', 'img', 'input', 'hr', 'wbr',
23073 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23074 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23075 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23076 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23077 'table', 'ul', 'xmp',
23079 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23082 'dir', 'menu', 'ol', 'ul', 'dl',
23088 Roo.HtmlEditorCore.black = [
23089 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23091 'base', 'basefont', 'bgsound', 'blink', 'body',
23092 'frame', 'frameset', 'head', 'html', 'ilayer',
23093 'iframe', 'layer', 'link', 'meta', 'object',
23094 'script', 'style' ,'title', 'xml' // clean later..
23096 Roo.HtmlEditorCore.clean = [
23097 'script', 'style', 'title', 'xml'
23099 Roo.HtmlEditorCore.remove = [
23104 Roo.HtmlEditorCore.ablack = [
23108 Roo.HtmlEditorCore.aclean = [
23109 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23113 Roo.HtmlEditorCore.pwhite= [
23114 'http', 'https', 'mailto'
23117 // white listed style attributes.
23118 Roo.HtmlEditorCore.cwhite= [
23119 // 'text-align', /// default is to allow most things..
23125 // black listed style attributes.
23126 Roo.HtmlEditorCore.cblack= [
23127 // 'font-size' -- this can be set by the project
23131 Roo.HtmlEditorCore.swapCodes =[
23150 * @class Roo.bootstrap.HtmlEditor
23151 * @extends Roo.bootstrap.TextArea
23152 * Bootstrap HtmlEditor class
23155 * Create a new HtmlEditor
23156 * @param {Object} config The config object
23159 Roo.bootstrap.HtmlEditor = function(config){
23160 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23161 if (!this.toolbars) {
23162 this.toolbars = [];
23165 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23168 * @event initialize
23169 * Fires when the editor is fully initialized (including the iframe)
23170 * @param {HtmlEditor} this
23175 * Fires when the editor is first receives the focus. Any insertion must wait
23176 * until after this event.
23177 * @param {HtmlEditor} this
23181 * @event beforesync
23182 * Fires before the textarea is updated with content from the editor iframe. Return false
23183 * to cancel the sync.
23184 * @param {HtmlEditor} this
23185 * @param {String} html
23189 * @event beforepush
23190 * Fires before the iframe editor is updated with content from the textarea. Return false
23191 * to cancel the push.
23192 * @param {HtmlEditor} this
23193 * @param {String} html
23198 * Fires when the textarea is updated with content from the editor iframe.
23199 * @param {HtmlEditor} this
23200 * @param {String} html
23205 * Fires when the iframe editor is updated with content from the textarea.
23206 * @param {HtmlEditor} this
23207 * @param {String} html
23211 * @event editmodechange
23212 * Fires when the editor switches edit modes
23213 * @param {HtmlEditor} this
23214 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23216 editmodechange: true,
23218 * @event editorevent
23219 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23220 * @param {HtmlEditor} this
23224 * @event firstfocus
23225 * Fires when on first focus - needed by toolbars..
23226 * @param {HtmlEditor} this
23231 * Auto save the htmlEditor value as a file into Events
23232 * @param {HtmlEditor} this
23236 * @event savedpreview
23237 * preview the saved version of htmlEditor
23238 * @param {HtmlEditor} this
23245 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23249 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23254 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23259 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23264 * @cfg {Number} height (in pixels)
23268 * @cfg {Number} width (in pixels)
23273 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23276 stylesheets: false,
23281 // private properties
23282 validationEvent : false,
23284 initialized : false,
23287 onFocus : Roo.emptyFn,
23289 hideMode:'offsets',
23291 tbContainer : false,
23295 toolbarContainer :function() {
23296 return this.wrap.select('.x-html-editor-tb',true).first();
23300 * Protected method that will not generally be called directly. It
23301 * is called when the editor creates its toolbar. Override this method if you need to
23302 * add custom toolbar buttons.
23303 * @param {HtmlEditor} editor
23305 createToolbar : function(){
23306 Roo.log('renewing');
23307 Roo.log("create toolbars");
23309 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23310 this.toolbars[0].render(this.toolbarContainer());
23314 // if (!editor.toolbars || !editor.toolbars.length) {
23315 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23318 // for (var i =0 ; i < editor.toolbars.length;i++) {
23319 // editor.toolbars[i] = Roo.factory(
23320 // typeof(editor.toolbars[i]) == 'string' ?
23321 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23322 // Roo.bootstrap.HtmlEditor);
23323 // editor.toolbars[i].init(editor);
23329 onRender : function(ct, position)
23331 // Roo.log("Call onRender: " + this.xtype);
23333 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23335 this.wrap = this.inputEl().wrap({
23336 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23339 this.editorcore.onRender(ct, position);
23341 if (this.resizable) {
23342 this.resizeEl = new Roo.Resizable(this.wrap, {
23346 minHeight : this.height,
23347 height: this.height,
23348 handles : this.resizable,
23351 resize : function(r, w, h) {
23352 _t.onResize(w,h); // -something
23358 this.createToolbar(this);
23361 if(!this.width && this.resizable){
23362 this.setSize(this.wrap.getSize());
23364 if (this.resizeEl) {
23365 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23366 // should trigger onReize..
23372 onResize : function(w, h)
23374 Roo.log('resize: ' +w + ',' + h );
23375 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23379 if(this.inputEl() ){
23380 if(typeof w == 'number'){
23381 var aw = w - this.wrap.getFrameWidth('lr');
23382 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23385 if(typeof h == 'number'){
23386 var tbh = -11; // fixme it needs to tool bar size!
23387 for (var i =0; i < this.toolbars.length;i++) {
23388 // fixme - ask toolbars for heights?
23389 tbh += this.toolbars[i].el.getHeight();
23390 //if (this.toolbars[i].footer) {
23391 // tbh += this.toolbars[i].footer.el.getHeight();
23399 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23400 ah -= 5; // knock a few pixes off for look..
23401 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23405 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23406 this.editorcore.onResize(ew,eh);
23411 * Toggles the editor between standard and source edit mode.
23412 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23414 toggleSourceEdit : function(sourceEditMode)
23416 this.editorcore.toggleSourceEdit(sourceEditMode);
23418 if(this.editorcore.sourceEditMode){
23419 Roo.log('editor - showing textarea');
23422 // Roo.log(this.syncValue());
23424 this.inputEl().removeClass(['hide', 'x-hidden']);
23425 this.inputEl().dom.removeAttribute('tabIndex');
23426 this.inputEl().focus();
23428 Roo.log('editor - hiding textarea');
23430 // Roo.log(this.pushValue());
23433 this.inputEl().addClass(['hide', 'x-hidden']);
23434 this.inputEl().dom.setAttribute('tabIndex', -1);
23435 //this.deferFocus();
23438 if(this.resizable){
23439 this.setSize(this.wrap.getSize());
23442 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23445 // private (for BoxComponent)
23446 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23448 // private (for BoxComponent)
23449 getResizeEl : function(){
23453 // private (for BoxComponent)
23454 getPositionEl : function(){
23459 initEvents : function(){
23460 this.originalValue = this.getValue();
23464 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23467 // markInvalid : Roo.emptyFn,
23469 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23472 // clearInvalid : Roo.emptyFn,
23474 setValue : function(v){
23475 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23476 this.editorcore.pushValue();
23481 deferFocus : function(){
23482 this.focus.defer(10, this);
23486 focus : function(){
23487 this.editorcore.focus();
23493 onDestroy : function(){
23499 for (var i =0; i < this.toolbars.length;i++) {
23500 // fixme - ask toolbars for heights?
23501 this.toolbars[i].onDestroy();
23504 this.wrap.dom.innerHTML = '';
23505 this.wrap.remove();
23510 onFirstFocus : function(){
23511 //Roo.log("onFirstFocus");
23512 this.editorcore.onFirstFocus();
23513 for (var i =0; i < this.toolbars.length;i++) {
23514 this.toolbars[i].onFirstFocus();
23520 syncValue : function()
23522 this.editorcore.syncValue();
23525 pushValue : function()
23527 this.editorcore.pushValue();
23531 // hide stuff that is not compatible
23545 * @event specialkey
23549 * @cfg {String} fieldClass @hide
23552 * @cfg {String} focusClass @hide
23555 * @cfg {String} autoCreate @hide
23558 * @cfg {String} inputType @hide
23561 * @cfg {String} invalidClass @hide
23564 * @cfg {String} invalidText @hide
23567 * @cfg {String} msgFx @hide
23570 * @cfg {String} validateOnBlur @hide
23579 Roo.namespace('Roo.bootstrap.htmleditor');
23581 * @class Roo.bootstrap.HtmlEditorToolbar1
23586 new Roo.bootstrap.HtmlEditor({
23589 new Roo.bootstrap.HtmlEditorToolbar1({
23590 disable : { fonts: 1 , format: 1, ..., ... , ...],
23596 * @cfg {Object} disable List of elements to disable..
23597 * @cfg {Array} btns List of additional buttons.
23601 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23604 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23607 Roo.apply(this, config);
23609 // default disabled, based on 'good practice'..
23610 this.disable = this.disable || {};
23611 Roo.applyIf(this.disable, {
23614 specialElements : true
23616 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23618 this.editor = config.editor;
23619 this.editorcore = config.editor.editorcore;
23621 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23623 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23624 // dont call parent... till later.
23626 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23631 editorcore : false,
23636 "h1","h2","h3","h4","h5","h6",
23638 "abbr", "acronym", "address", "cite", "samp", "var",
23642 onRender : function(ct, position)
23644 // Roo.log("Call onRender: " + this.xtype);
23646 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23648 this.el.dom.style.marginBottom = '0';
23650 var editorcore = this.editorcore;
23651 var editor= this.editor;
23654 var btn = function(id,cmd , toggle, handler, html){
23656 var event = toggle ? 'toggle' : 'click';
23661 xns: Roo.bootstrap,
23664 enableToggle:toggle !== false,
23666 pressed : toggle ? false : null,
23669 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23670 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23676 // var cb_box = function...
23681 xns: Roo.bootstrap,
23682 glyphicon : 'font',
23686 xns: Roo.bootstrap,
23690 Roo.each(this.formats, function(f) {
23691 style.menu.items.push({
23693 xns: Roo.bootstrap,
23694 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23699 editorcore.insertTag(this.tagname);
23706 children.push(style);
23708 btn('bold',false,true);
23709 btn('italic',false,true);
23710 btn('align-left', 'justifyleft',true);
23711 btn('align-center', 'justifycenter',true);
23712 btn('align-right' , 'justifyright',true);
23713 btn('link', false, false, function(btn) {
23714 //Roo.log("create link?");
23715 var url = prompt(this.createLinkText, this.defaultLinkValue);
23716 if(url && url != 'http:/'+'/'){
23717 this.editorcore.relayCmd('createlink', url);
23720 btn('list','insertunorderedlist',true);
23721 btn('pencil', false,true, function(btn){
23723 this.toggleSourceEdit(btn.pressed);
23726 if (this.editor.btns.length > 0) {
23727 for (var i = 0; i<this.editor.btns.length; i++) {
23728 children.push(this.editor.btns[i]);
23736 xns: Roo.bootstrap,
23741 xns: Roo.bootstrap,
23746 cog.menu.items.push({
23748 xns: Roo.bootstrap,
23749 html : Clean styles,
23754 editorcore.insertTag(this.tagname);
23763 this.xtype = 'NavSimplebar';
23765 for(var i=0;i< children.length;i++) {
23767 this.buttons.add(this.addxtypeChild(children[i]));
23771 editor.on('editorevent', this.updateToolbar, this);
23773 onBtnClick : function(id)
23775 this.editorcore.relayCmd(id);
23776 this.editorcore.focus();
23780 * Protected method that will not generally be called directly. It triggers
23781 * a toolbar update by reading the markup state of the current selection in the editor.
23783 updateToolbar: function(){
23785 if(!this.editorcore.activated){
23786 this.editor.onFirstFocus(); // is this neeed?
23790 var btns = this.buttons;
23791 var doc = this.editorcore.doc;
23792 btns.get('bold').setActive(doc.queryCommandState('bold'));
23793 btns.get('italic').setActive(doc.queryCommandState('italic'));
23794 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23796 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23797 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23798 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23800 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23801 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23804 var ans = this.editorcore.getAllAncestors();
23805 if (this.formatCombo) {
23808 var store = this.formatCombo.store;
23809 this.formatCombo.setValue("");
23810 for (var i =0; i < ans.length;i++) {
23811 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23813 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23821 // hides menus... - so this cant be on a menu...
23822 Roo.bootstrap.MenuMgr.hideAll();
23824 Roo.bootstrap.MenuMgr.hideAll();
23825 //this.editorsyncValue();
23827 onFirstFocus: function() {
23828 this.buttons.each(function(item){
23832 toggleSourceEdit : function(sourceEditMode){
23835 if(sourceEditMode){
23836 Roo.log("disabling buttons");
23837 this.buttons.each( function(item){
23838 if(item.cmd != 'pencil'){
23844 Roo.log("enabling buttons");
23845 if(this.editorcore.initialized){
23846 this.buttons.each( function(item){
23852 Roo.log("calling toggole on editor");
23853 // tell the editor that it's been pressed..
23854 this.editor.toggleSourceEdit(sourceEditMode);
23864 * @class Roo.bootstrap.Table.AbstractSelectionModel
23865 * @extends Roo.util.Observable
23866 * Abstract base class for grid SelectionModels. It provides the interface that should be
23867 * implemented by descendant classes. This class should not be directly instantiated.
23870 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23871 this.locked = false;
23872 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23876 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23877 /** @ignore Called by the grid automatically. Do not call directly. */
23878 init : function(grid){
23884 * Locks the selections.
23887 this.locked = true;
23891 * Unlocks the selections.
23893 unlock : function(){
23894 this.locked = false;
23898 * Returns true if the selections are locked.
23899 * @return {Boolean}
23901 isLocked : function(){
23902 return this.locked;
23906 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23907 * @class Roo.bootstrap.Table.RowSelectionModel
23908 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23909 * It supports multiple selections and keyboard selection/navigation.
23911 * @param {Object} config
23914 Roo.bootstrap.Table.RowSelectionModel = function(config){
23915 Roo.apply(this, config);
23916 this.selections = new Roo.util.MixedCollection(false, function(o){
23921 this.lastActive = false;
23925 * @event selectionchange
23926 * Fires when the selection changes
23927 * @param {SelectionModel} this
23929 "selectionchange" : true,
23931 * @event afterselectionchange
23932 * Fires after the selection changes (eg. by key press or clicking)
23933 * @param {SelectionModel} this
23935 "afterselectionchange" : true,
23937 * @event beforerowselect
23938 * Fires when a row is selected being selected, return false to cancel.
23939 * @param {SelectionModel} this
23940 * @param {Number} rowIndex The selected index
23941 * @param {Boolean} keepExisting False if other selections will be cleared
23943 "beforerowselect" : true,
23946 * Fires when a row is selected.
23947 * @param {SelectionModel} this
23948 * @param {Number} rowIndex The selected index
23949 * @param {Roo.data.Record} r The record
23951 "rowselect" : true,
23953 * @event rowdeselect
23954 * Fires when a row is deselected.
23955 * @param {SelectionModel} this
23956 * @param {Number} rowIndex The selected index
23958 "rowdeselect" : true
23960 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23961 this.locked = false;
23964 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23966 * @cfg {Boolean} singleSelect
23967 * True to allow selection of only one row at a time (defaults to false)
23969 singleSelect : false,
23972 initEvents : function()
23975 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23976 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23977 //}else{ // allow click to work like normal
23978 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23980 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23981 this.grid.on("rowclick", this.handleMouseDown, this);
23983 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23984 "up" : function(e){
23986 this.selectPrevious(e.shiftKey);
23987 }else if(this.last !== false && this.lastActive !== false){
23988 var last = this.last;
23989 this.selectRange(this.last, this.lastActive-1);
23990 this.grid.getView().focusRow(this.lastActive);
23991 if(last !== false){
23995 this.selectFirstRow();
23997 this.fireEvent("afterselectionchange", this);
23999 "down" : function(e){
24001 this.selectNext(e.shiftKey);
24002 }else if(this.last !== false && this.lastActive !== false){
24003 var last = this.last;
24004 this.selectRange(this.last, this.lastActive+1);
24005 this.grid.getView().focusRow(this.lastActive);
24006 if(last !== false){
24010 this.selectFirstRow();
24012 this.fireEvent("afterselectionchange", this);
24016 this.grid.store.on('load', function(){
24017 this.selections.clear();
24020 var view = this.grid.view;
24021 view.on("refresh", this.onRefresh, this);
24022 view.on("rowupdated", this.onRowUpdated, this);
24023 view.on("rowremoved", this.onRemove, this);
24028 onRefresh : function()
24030 var ds = this.grid.store, i, v = this.grid.view;
24031 var s = this.selections;
24032 s.each(function(r){
24033 if((i = ds.indexOfId(r.id)) != -1){
24042 onRemove : function(v, index, r){
24043 this.selections.remove(r);
24047 onRowUpdated : function(v, index, r){
24048 if(this.isSelected(r)){
24049 v.onRowSelect(index);
24055 * @param {Array} records The records to select
24056 * @param {Boolean} keepExisting (optional) True to keep existing selections
24058 selectRecords : function(records, keepExisting)
24061 this.clearSelections();
24063 var ds = this.grid.store;
24064 for(var i = 0, len = records.length; i < len; i++){
24065 this.selectRow(ds.indexOf(records[i]), true);
24070 * Gets the number of selected rows.
24073 getCount : function(){
24074 return this.selections.length;
24078 * Selects the first row in the grid.
24080 selectFirstRow : function(){
24085 * Select the last row.
24086 * @param {Boolean} keepExisting (optional) True to keep existing selections
24088 selectLastRow : function(keepExisting){
24089 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24090 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24094 * Selects the row immediately following the last selected row.
24095 * @param {Boolean} keepExisting (optional) True to keep existing selections
24097 selectNext : function(keepExisting)
24099 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24100 this.selectRow(this.last+1, keepExisting);
24101 this.grid.getView().focusRow(this.last);
24106 * Selects the row that precedes the last selected row.
24107 * @param {Boolean} keepExisting (optional) True to keep existing selections
24109 selectPrevious : function(keepExisting){
24111 this.selectRow(this.last-1, keepExisting);
24112 this.grid.getView().focusRow(this.last);
24117 * Returns the selected records
24118 * @return {Array} Array of selected records
24120 getSelections : function(){
24121 return [].concat(this.selections.items);
24125 * Returns the first selected record.
24128 getSelected : function(){
24129 return this.selections.itemAt(0);
24134 * Clears all selections.
24136 clearSelections : function(fast)
24142 var ds = this.grid.store;
24143 var s = this.selections;
24144 s.each(function(r){
24145 this.deselectRow(ds.indexOfId(r.id));
24149 this.selections.clear();
24156 * Selects all rows.
24158 selectAll : function(){
24162 this.selections.clear();
24163 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24164 this.selectRow(i, true);
24169 * Returns True if there is a selection.
24170 * @return {Boolean}
24172 hasSelection : function(){
24173 return this.selections.length > 0;
24177 * Returns True if the specified row is selected.
24178 * @param {Number/Record} record The record or index of the record to check
24179 * @return {Boolean}
24181 isSelected : function(index){
24182 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24183 return (r && this.selections.key(r.id) ? true : false);
24187 * Returns True if the specified record id is selected.
24188 * @param {String} id The id of record to check
24189 * @return {Boolean}
24191 isIdSelected : function(id){
24192 return (this.selections.key(id) ? true : false);
24197 handleMouseDBClick : function(e, t){
24201 handleMouseDown : function(e, t)
24203 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24204 if(this.isLocked() || rowIndex < 0 ){
24207 if(e.shiftKey && this.last !== false){
24208 var last = this.last;
24209 this.selectRange(last, rowIndex, e.ctrlKey);
24210 this.last = last; // reset the last
24214 var isSelected = this.isSelected(rowIndex);
24215 //Roo.log("select row:" + rowIndex);
24217 this.deselectRow(rowIndex);
24219 this.selectRow(rowIndex, true);
24223 if(e.button !== 0 && isSelected){
24224 alert('rowIndex 2: ' + rowIndex);
24225 view.focusRow(rowIndex);
24226 }else if(e.ctrlKey && isSelected){
24227 this.deselectRow(rowIndex);
24228 }else if(!isSelected){
24229 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24230 view.focusRow(rowIndex);
24234 this.fireEvent("afterselectionchange", this);
24237 handleDragableRowClick : function(grid, rowIndex, e)
24239 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24240 this.selectRow(rowIndex, false);
24241 grid.view.focusRow(rowIndex);
24242 this.fireEvent("afterselectionchange", this);
24247 * Selects multiple rows.
24248 * @param {Array} rows Array of the indexes of the row to select
24249 * @param {Boolean} keepExisting (optional) True to keep existing selections
24251 selectRows : function(rows, keepExisting){
24253 this.clearSelections();
24255 for(var i = 0, len = rows.length; i < len; i++){
24256 this.selectRow(rows[i], true);
24261 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24262 * @param {Number} startRow The index of the first row in the range
24263 * @param {Number} endRow The index of the last row in the range
24264 * @param {Boolean} keepExisting (optional) True to retain existing selections
24266 selectRange : function(startRow, endRow, keepExisting){
24271 this.clearSelections();
24273 if(startRow <= endRow){
24274 for(var i = startRow; i <= endRow; i++){
24275 this.selectRow(i, true);
24278 for(var i = startRow; i >= endRow; i--){
24279 this.selectRow(i, true);
24285 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24286 * @param {Number} startRow The index of the first row in the range
24287 * @param {Number} endRow The index of the last row in the range
24289 deselectRange : function(startRow, endRow, preventViewNotify){
24293 for(var i = startRow; i <= endRow; i++){
24294 this.deselectRow(i, preventViewNotify);
24300 * @param {Number} row The index of the row to select
24301 * @param {Boolean} keepExisting (optional) True to keep existing selections
24303 selectRow : function(index, keepExisting, preventViewNotify)
24305 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24308 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24309 if(!keepExisting || this.singleSelect){
24310 this.clearSelections();
24313 var r = this.grid.store.getAt(index);
24314 //console.log('selectRow - record id :' + r.id);
24316 this.selections.add(r);
24317 this.last = this.lastActive = index;
24318 if(!preventViewNotify){
24319 var proxy = new Roo.Element(
24320 this.grid.getRowDom(index)
24322 proxy.addClass('bg-info info');
24324 this.fireEvent("rowselect", this, index, r);
24325 this.fireEvent("selectionchange", this);
24331 * @param {Number} row The index of the row to deselect
24333 deselectRow : function(index, preventViewNotify)
24338 if(this.last == index){
24341 if(this.lastActive == index){
24342 this.lastActive = false;
24345 var r = this.grid.store.getAt(index);
24350 this.selections.remove(r);
24351 //.console.log('deselectRow - record id :' + r.id);
24352 if(!preventViewNotify){
24354 var proxy = new Roo.Element(
24355 this.grid.getRowDom(index)
24357 proxy.removeClass('bg-info info');
24359 this.fireEvent("rowdeselect", this, index);
24360 this.fireEvent("selectionchange", this);
24364 restoreLast : function(){
24366 this.last = this._last;
24371 acceptsNav : function(row, col, cm){
24372 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24376 onEditorKey : function(field, e){
24377 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24382 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24384 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24386 }else if(k == e.ENTER && !e.ctrlKey){
24390 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24392 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24394 }else if(k == e.ESC){
24398 g.startEditing(newCell[0], newCell[1]);
24404 * Ext JS Library 1.1.1
24405 * Copyright(c) 2006-2007, Ext JS, LLC.
24407 * Originally Released Under LGPL - original licence link has changed is not relivant.
24410 * <script type="text/javascript">
24414 * @class Roo.bootstrap.PagingToolbar
24415 * @extends Roo.bootstrap.NavSimplebar
24416 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24418 * Create a new PagingToolbar
24419 * @param {Object} config The config object
24420 * @param {Roo.data.Store} store
24422 Roo.bootstrap.PagingToolbar = function(config)
24424 // old args format still supported... - xtype is prefered..
24425 // created from xtype...
24427 this.ds = config.dataSource;
24429 if (config.store && !this.ds) {
24430 this.store= Roo.factory(config.store, Roo.data);
24431 this.ds = this.store;
24432 this.ds.xmodule = this.xmodule || false;
24435 this.toolbarItems = [];
24436 if (config.items) {
24437 this.toolbarItems = config.items;
24440 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24445 this.bind(this.ds);
24448 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24452 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24454 * @cfg {Roo.data.Store} dataSource
24455 * The underlying data store providing the paged data
24458 * @cfg {String/HTMLElement/Element} container
24459 * container The id or element that will contain the toolbar
24462 * @cfg {Boolean} displayInfo
24463 * True to display the displayMsg (defaults to false)
24466 * @cfg {Number} pageSize
24467 * The number of records to display per page (defaults to 20)
24471 * @cfg {String} displayMsg
24472 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24474 displayMsg : 'Displaying {0} - {1} of {2}',
24476 * @cfg {String} emptyMsg
24477 * The message to display when no records are found (defaults to "No data to display")
24479 emptyMsg : 'No data to display',
24481 * Customizable piece of the default paging text (defaults to "Page")
24484 beforePageText : "Page",
24486 * Customizable piece of the default paging text (defaults to "of %0")
24489 afterPageText : "of {0}",
24491 * Customizable piece of the default paging text (defaults to "First Page")
24494 firstText : "First Page",
24496 * Customizable piece of the default paging text (defaults to "Previous Page")
24499 prevText : "Previous Page",
24501 * Customizable piece of the default paging text (defaults to "Next Page")
24504 nextText : "Next Page",
24506 * Customizable piece of the default paging text (defaults to "Last Page")
24509 lastText : "Last Page",
24511 * Customizable piece of the default paging text (defaults to "Refresh")
24514 refreshText : "Refresh",
24518 onRender : function(ct, position)
24520 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24521 this.navgroup.parentId = this.id;
24522 this.navgroup.onRender(this.el, null);
24523 // add the buttons to the navgroup
24525 if(this.displayInfo){
24526 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24527 this.displayEl = this.el.select('.x-paging-info', true).first();
24528 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24529 // this.displayEl = navel.el.select('span',true).first();
24535 Roo.each(_this.buttons, function(e){ // this might need to use render????
24536 Roo.factory(e).render(_this.el);
24540 Roo.each(_this.toolbarItems, function(e) {
24541 _this.navgroup.addItem(e);
24545 this.first = this.navgroup.addItem({
24546 tooltip: this.firstText,
24548 icon : 'fa fa-backward',
24550 preventDefault: true,
24551 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24554 this.prev = this.navgroup.addItem({
24555 tooltip: this.prevText,
24557 icon : 'fa fa-step-backward',
24559 preventDefault: true,
24560 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24562 //this.addSeparator();
24565 var field = this.navgroup.addItem( {
24567 cls : 'x-paging-position',
24569 html : this.beforePageText +
24570 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24571 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24574 this.field = field.el.select('input', true).first();
24575 this.field.on("keydown", this.onPagingKeydown, this);
24576 this.field.on("focus", function(){this.dom.select();});
24579 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24580 //this.field.setHeight(18);
24581 //this.addSeparator();
24582 this.next = this.navgroup.addItem({
24583 tooltip: this.nextText,
24585 html : ' <i class="fa fa-step-forward">',
24587 preventDefault: true,
24588 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24590 this.last = this.navgroup.addItem({
24591 tooltip: this.lastText,
24592 icon : 'fa fa-forward',
24595 preventDefault: true,
24596 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24598 //this.addSeparator();
24599 this.loading = this.navgroup.addItem({
24600 tooltip: this.refreshText,
24601 icon: 'fa fa-refresh',
24602 preventDefault: true,
24603 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24609 updateInfo : function(){
24610 if(this.displayEl){
24611 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24612 var msg = count == 0 ?
24616 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24618 this.displayEl.update(msg);
24623 onLoad : function(ds, r, o)
24625 this.cursor = o.params.start ? o.params.start : 0;
24627 var d = this.getPageData(),
24632 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24633 this.field.dom.value = ap;
24634 this.first.setDisabled(ap == 1);
24635 this.prev.setDisabled(ap == 1);
24636 this.next.setDisabled(ap == ps);
24637 this.last.setDisabled(ap == ps);
24638 this.loading.enable();
24643 getPageData : function(){
24644 var total = this.ds.getTotalCount();
24647 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24648 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24653 onLoadError : function(){
24654 this.loading.enable();
24658 onPagingKeydown : function(e){
24659 var k = e.getKey();
24660 var d = this.getPageData();
24662 var v = this.field.dom.value, pageNum;
24663 if(!v || isNaN(pageNum = parseInt(v, 10))){
24664 this.field.dom.value = d.activePage;
24667 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24668 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24671 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))
24673 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24674 this.field.dom.value = pageNum;
24675 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24678 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24680 var v = this.field.dom.value, pageNum;
24681 var increment = (e.shiftKey) ? 10 : 1;
24682 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24685 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24686 this.field.dom.value = d.activePage;
24689 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24691 this.field.dom.value = parseInt(v, 10) + increment;
24692 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24693 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24700 beforeLoad : function(){
24702 this.loading.disable();
24707 onClick : function(which){
24716 ds.load({params:{start: 0, limit: this.pageSize}});
24719 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24722 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24725 var total = ds.getTotalCount();
24726 var extra = total % this.pageSize;
24727 var lastStart = extra ? (total - extra) : total-this.pageSize;
24728 ds.load({params:{start: lastStart, limit: this.pageSize}});
24731 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24737 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24738 * @param {Roo.data.Store} store The data store to unbind
24740 unbind : function(ds){
24741 ds.un("beforeload", this.beforeLoad, this);
24742 ds.un("load", this.onLoad, this);
24743 ds.un("loadexception", this.onLoadError, this);
24744 ds.un("remove", this.updateInfo, this);
24745 ds.un("add", this.updateInfo, this);
24746 this.ds = undefined;
24750 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24751 * @param {Roo.data.Store} store The data store to bind
24753 bind : function(ds){
24754 ds.on("beforeload", this.beforeLoad, this);
24755 ds.on("load", this.onLoad, this);
24756 ds.on("loadexception", this.onLoadError, this);
24757 ds.on("remove", this.updateInfo, this);
24758 ds.on("add", this.updateInfo, this);
24769 * @class Roo.bootstrap.MessageBar
24770 * @extends Roo.bootstrap.Component
24771 * Bootstrap MessageBar class
24772 * @cfg {String} html contents of the MessageBar
24773 * @cfg {String} weight (info | success | warning | danger) default info
24774 * @cfg {String} beforeClass insert the bar before the given class
24775 * @cfg {Boolean} closable (true | false) default false
24776 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24779 * Create a new Element
24780 * @param {Object} config The config object
24783 Roo.bootstrap.MessageBar = function(config){
24784 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24787 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24793 beforeClass: 'bootstrap-sticky-wrap',
24795 getAutoCreate : function(){
24799 cls: 'alert alert-dismissable alert-' + this.weight,
24804 html: this.html || ''
24810 cfg.cls += ' alert-messages-fixed';
24824 onRender : function(ct, position)
24826 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24829 var cfg = Roo.apply({}, this.getAutoCreate());
24833 cfg.cls += ' ' + this.cls;
24836 cfg.style = this.style;
24838 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24840 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24843 this.el.select('>button.close').on('click', this.hide, this);
24849 if (!this.rendered) {
24855 this.fireEvent('show', this);
24861 if (!this.rendered) {
24867 this.fireEvent('hide', this);
24870 update : function()
24872 // var e = this.el.dom.firstChild;
24874 // if(this.closable){
24875 // e = e.nextSibling;
24878 // e.data = this.html || '';
24880 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24896 * @class Roo.bootstrap.Graph
24897 * @extends Roo.bootstrap.Component
24898 * Bootstrap Graph class
24902 @cfg {String} graphtype bar | vbar | pie
24903 @cfg {number} g_x coodinator | centre x (pie)
24904 @cfg {number} g_y coodinator | centre y (pie)
24905 @cfg {number} g_r radius (pie)
24906 @cfg {number} g_height height of the chart (respected by all elements in the set)
24907 @cfg {number} g_width width of the chart (respected by all elements in the set)
24908 @cfg {Object} title The title of the chart
24911 -opts (object) options for the chart
24913 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24914 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24916 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.
24917 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24919 o stretch (boolean)
24921 -opts (object) options for the pie
24924 o startAngle (number)
24925 o endAngle (number)
24929 * Create a new Input
24930 * @param {Object} config The config object
24933 Roo.bootstrap.Graph = function(config){
24934 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24940 * The img click event for the img.
24941 * @param {Roo.EventObject} e
24947 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24958 //g_colors: this.colors,
24965 getAutoCreate : function(){
24976 onRender : function(ct,position){
24979 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24981 if (typeof(Raphael) == 'undefined') {
24982 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24986 this.raphael = Raphael(this.el.dom);
24988 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24989 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24990 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24991 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24993 r.text(160, 10, "Single Series Chart").attr(txtattr);
24994 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24995 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24996 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24998 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24999 r.barchart(330, 10, 300, 220, data1);
25000 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25001 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25004 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25005 // r.barchart(30, 30, 560, 250, xdata, {
25006 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25007 // axis : "0 0 1 1",
25008 // axisxlabels : xdata
25009 // //yvalues : cols,
25012 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25014 // this.load(null,xdata,{
25015 // axis : "0 0 1 1",
25016 // axisxlabels : xdata
25021 load : function(graphtype,xdata,opts)
25023 this.raphael.clear();
25025 graphtype = this.graphtype;
25030 var r = this.raphael,
25031 fin = function () {
25032 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25034 fout = function () {
25035 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25037 pfin = function() {
25038 this.sector.stop();
25039 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25042 this.label[0].stop();
25043 this.label[0].attr({ r: 7.5 });
25044 this.label[1].attr({ "font-weight": 800 });
25047 pfout = function() {
25048 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25051 this.label[0].animate({ r: 5 }, 500, "bounce");
25052 this.label[1].attr({ "font-weight": 400 });
25058 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25061 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25064 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25065 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25067 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25074 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25079 setTitle: function(o)
25084 initEvents: function() {
25087 this.el.on('click', this.onClick, this);
25091 onClick : function(e)
25093 Roo.log('img onclick');
25094 this.fireEvent('click', this, e);
25106 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25109 * @class Roo.bootstrap.dash.NumberBox
25110 * @extends Roo.bootstrap.Component
25111 * Bootstrap NumberBox class
25112 * @cfg {String} headline Box headline
25113 * @cfg {String} content Box content
25114 * @cfg {String} icon Box icon
25115 * @cfg {String} footer Footer text
25116 * @cfg {String} fhref Footer href
25119 * Create a new NumberBox
25120 * @param {Object} config The config object
25124 Roo.bootstrap.dash.NumberBox = function(config){
25125 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25129 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25138 getAutoCreate : function(){
25142 cls : 'small-box ',
25150 cls : 'roo-headline',
25151 html : this.headline
25155 cls : 'roo-content',
25156 html : this.content
25170 cls : 'ion ' + this.icon
25179 cls : 'small-box-footer',
25180 href : this.fhref || '#',
25184 cfg.cn.push(footer);
25191 onRender : function(ct,position){
25192 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25199 setHeadline: function (value)
25201 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25204 setFooter: function (value, href)
25206 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25209 this.el.select('a.small-box-footer',true).first().attr('href', href);
25214 setContent: function (value)
25216 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25219 initEvents: function()
25233 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25236 * @class Roo.bootstrap.dash.TabBox
25237 * @extends Roo.bootstrap.Component
25238 * Bootstrap TabBox class
25239 * @cfg {String} title Title of the TabBox
25240 * @cfg {String} icon Icon of the TabBox
25241 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25242 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25245 * Create a new TabBox
25246 * @param {Object} config The config object
25250 Roo.bootstrap.dash.TabBox = function(config){
25251 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25256 * When a pane is added
25257 * @param {Roo.bootstrap.dash.TabPane} pane
25261 * @event activatepane
25262 * When a pane is activated
25263 * @param {Roo.bootstrap.dash.TabPane} pane
25265 "activatepane" : true
25273 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25278 tabScrollable : false,
25280 getChildContainer : function()
25282 return this.el.select('.tab-content', true).first();
25285 getAutoCreate : function(){
25289 cls: 'pull-left header',
25297 cls: 'fa ' + this.icon
25303 cls: 'nav nav-tabs pull-right',
25309 if(this.tabScrollable){
25316 cls: 'nav nav-tabs pull-right',
25327 cls: 'nav-tabs-custom',
25332 cls: 'tab-content no-padding',
25340 initEvents : function()
25342 //Roo.log('add add pane handler');
25343 this.on('addpane', this.onAddPane, this);
25346 * Updates the box title
25347 * @param {String} html to set the title to.
25349 setTitle : function(value)
25351 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25353 onAddPane : function(pane)
25355 this.panes.push(pane);
25356 //Roo.log('addpane');
25358 // tabs are rendere left to right..
25359 if(!this.showtabs){
25363 var ctr = this.el.select('.nav-tabs', true).first();
25366 var existing = ctr.select('.nav-tab',true);
25367 var qty = existing.getCount();;
25370 var tab = ctr.createChild({
25372 cls : 'nav-tab' + (qty ? '' : ' active'),
25380 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25383 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25385 pane.el.addClass('active');
25390 onTabClick : function(ev,un,ob,pane)
25392 //Roo.log('tab - prev default');
25393 ev.preventDefault();
25396 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25397 pane.tab.addClass('active');
25398 //Roo.log(pane.title);
25399 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25400 // technically we should have a deactivate event.. but maybe add later.
25401 // and it should not de-activate the selected tab...
25402 this.fireEvent('activatepane', pane);
25403 pane.el.addClass('active');
25404 pane.fireEvent('activate');
25409 getActivePane : function()
25412 Roo.each(this.panes, function(p) {
25413 if(p.el.hasClass('active')){
25434 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25436 * @class Roo.bootstrap.TabPane
25437 * @extends Roo.bootstrap.Component
25438 * Bootstrap TabPane class
25439 * @cfg {Boolean} active (false | true) Default false
25440 * @cfg {String} title title of panel
25444 * Create a new TabPane
25445 * @param {Object} config The config object
25448 Roo.bootstrap.dash.TabPane = function(config){
25449 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25455 * When a pane is activated
25456 * @param {Roo.bootstrap.dash.TabPane} pane
25463 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25468 // the tabBox that this is attached to.
25471 getAutoCreate : function()
25479 cfg.cls += ' active';
25484 initEvents : function()
25486 //Roo.log('trigger add pane handler');
25487 this.parent().fireEvent('addpane', this)
25491 * Updates the tab title
25492 * @param {String} html to set the title to.
25494 setTitle: function(str)
25500 this.tab.select('a', true).first().dom.innerHTML = str;
25517 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25520 * @class Roo.bootstrap.menu.Menu
25521 * @extends Roo.bootstrap.Component
25522 * Bootstrap Menu class - container for Menu
25523 * @cfg {String} html Text of the menu
25524 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25525 * @cfg {String} icon Font awesome icon
25526 * @cfg {String} pos Menu align to (top | bottom) default bottom
25530 * Create a new Menu
25531 * @param {Object} config The config object
25535 Roo.bootstrap.menu.Menu = function(config){
25536 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25540 * @event beforeshow
25541 * Fires before this menu is displayed
25542 * @param {Roo.bootstrap.menu.Menu} this
25546 * @event beforehide
25547 * Fires before this menu is hidden
25548 * @param {Roo.bootstrap.menu.Menu} this
25553 * Fires after this menu is displayed
25554 * @param {Roo.bootstrap.menu.Menu} this
25559 * Fires after this menu is hidden
25560 * @param {Roo.bootstrap.menu.Menu} this
25565 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25566 * @param {Roo.bootstrap.menu.Menu} this
25567 * @param {Roo.EventObject} e
25574 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25578 weight : 'default',
25583 getChildContainer : function() {
25584 if(this.isSubMenu){
25588 return this.el.select('ul.dropdown-menu', true).first();
25591 getAutoCreate : function()
25596 cls : 'roo-menu-text',
25604 cls : 'fa ' + this.icon
25615 cls : 'dropdown-button btn btn-' + this.weight,
25620 cls : 'dropdown-toggle btn btn-' + this.weight,
25630 cls : 'dropdown-menu'
25636 if(this.pos == 'top'){
25637 cfg.cls += ' dropup';
25640 if(this.isSubMenu){
25643 cls : 'dropdown-menu'
25650 onRender : function(ct, position)
25652 this.isSubMenu = ct.hasClass('dropdown-submenu');
25654 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25657 initEvents : function()
25659 if(this.isSubMenu){
25663 this.hidden = true;
25665 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25666 this.triggerEl.on('click', this.onTriggerPress, this);
25668 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25669 this.buttonEl.on('click', this.onClick, this);
25675 if(this.isSubMenu){
25679 return this.el.select('ul.dropdown-menu', true).first();
25682 onClick : function(e)
25684 this.fireEvent("click", this, e);
25687 onTriggerPress : function(e)
25689 if (this.isVisible()) {
25696 isVisible : function(){
25697 return !this.hidden;
25702 this.fireEvent("beforeshow", this);
25704 this.hidden = false;
25705 this.el.addClass('open');
25707 Roo.get(document).on("mouseup", this.onMouseUp, this);
25709 this.fireEvent("show", this);
25716 this.fireEvent("beforehide", this);
25718 this.hidden = true;
25719 this.el.removeClass('open');
25721 Roo.get(document).un("mouseup", this.onMouseUp);
25723 this.fireEvent("hide", this);
25726 onMouseUp : function()
25740 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25743 * @class Roo.bootstrap.menu.Item
25744 * @extends Roo.bootstrap.Component
25745 * Bootstrap MenuItem class
25746 * @cfg {Boolean} submenu (true | false) default false
25747 * @cfg {String} html text of the item
25748 * @cfg {String} href the link
25749 * @cfg {Boolean} disable (true | false) default false
25750 * @cfg {Boolean} preventDefault (true | false) default true
25751 * @cfg {String} icon Font awesome icon
25752 * @cfg {String} pos Submenu align to (left | right) default right
25756 * Create a new Item
25757 * @param {Object} config The config object
25761 Roo.bootstrap.menu.Item = function(config){
25762 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25766 * Fires when the mouse is hovering over this menu
25767 * @param {Roo.bootstrap.menu.Item} this
25768 * @param {Roo.EventObject} e
25773 * Fires when the mouse exits this menu
25774 * @param {Roo.bootstrap.menu.Item} this
25775 * @param {Roo.EventObject} e
25781 * The raw click event for the entire grid.
25782 * @param {Roo.EventObject} e
25788 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25793 preventDefault: true,
25798 getAutoCreate : function()
25803 cls : 'roo-menu-item-text',
25811 cls : 'fa ' + this.icon
25820 href : this.href || '#',
25827 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25831 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25833 if(this.pos == 'left'){
25834 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25841 initEvents : function()
25843 this.el.on('mouseover', this.onMouseOver, this);
25844 this.el.on('mouseout', this.onMouseOut, this);
25846 this.el.select('a', true).first().on('click', this.onClick, this);
25850 onClick : function(e)
25852 if(this.preventDefault){
25853 e.preventDefault();
25856 this.fireEvent("click", this, e);
25859 onMouseOver : function(e)
25861 if(this.submenu && this.pos == 'left'){
25862 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25865 this.fireEvent("mouseover", this, e);
25868 onMouseOut : function(e)
25870 this.fireEvent("mouseout", this, e);
25882 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25885 * @class Roo.bootstrap.menu.Separator
25886 * @extends Roo.bootstrap.Component
25887 * Bootstrap Separator class
25890 * Create a new Separator
25891 * @param {Object} config The config object
25895 Roo.bootstrap.menu.Separator = function(config){
25896 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25899 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25901 getAutoCreate : function(){
25922 * @class Roo.bootstrap.Tooltip
25923 * Bootstrap Tooltip class
25924 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25925 * to determine which dom element triggers the tooltip.
25927 * It needs to add support for additional attributes like tooltip-position
25930 * Create a new Toolti
25931 * @param {Object} config The config object
25934 Roo.bootstrap.Tooltip = function(config){
25935 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25937 this.alignment = Roo.bootstrap.Tooltip.alignment;
25939 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25940 this.alignment = config.alignment;
25945 Roo.apply(Roo.bootstrap.Tooltip, {
25947 * @function init initialize tooltip monitoring.
25951 currentTip : false,
25952 currentRegion : false,
25958 Roo.get(document).on('mouseover', this.enter ,this);
25959 Roo.get(document).on('mouseout', this.leave, this);
25962 this.currentTip = new Roo.bootstrap.Tooltip();
25965 enter : function(ev)
25967 var dom = ev.getTarget();
25969 //Roo.log(['enter',dom]);
25970 var el = Roo.fly(dom);
25971 if (this.currentEl) {
25973 //Roo.log(this.currentEl);
25974 //Roo.log(this.currentEl.contains(dom));
25975 if (this.currentEl == el) {
25978 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25984 if (this.currentTip.el) {
25985 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25989 if(!el || el.dom == document){
25995 // you can not look for children, as if el is the body.. then everythign is the child..
25996 if (!el.attr('tooltip')) { //
25997 if (!el.select("[tooltip]").elements.length) {
26000 // is the mouse over this child...?
26001 bindEl = el.select("[tooltip]").first();
26002 var xy = ev.getXY();
26003 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26004 //Roo.log("not in region.");
26007 //Roo.log("child element over..");
26010 this.currentEl = bindEl;
26011 this.currentTip.bind(bindEl);
26012 this.currentRegion = Roo.lib.Region.getRegion(dom);
26013 this.currentTip.enter();
26016 leave : function(ev)
26018 var dom = ev.getTarget();
26019 //Roo.log(['leave',dom]);
26020 if (!this.currentEl) {
26025 if (dom != this.currentEl.dom) {
26028 var xy = ev.getXY();
26029 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26032 // only activate leave if mouse cursor is outside... bounding box..
26037 if (this.currentTip) {
26038 this.currentTip.leave();
26040 //Roo.log('clear currentEl');
26041 this.currentEl = false;
26046 'left' : ['r-l', [-2,0], 'right'],
26047 'right' : ['l-r', [2,0], 'left'],
26048 'bottom' : ['t-b', [0,2], 'top'],
26049 'top' : [ 'b-t', [0,-2], 'bottom']
26055 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26060 delay : null, // can be { show : 300 , hide: 500}
26064 hoverState : null, //???
26066 placement : 'bottom',
26070 getAutoCreate : function(){
26077 cls : 'tooltip-arrow'
26080 cls : 'tooltip-inner'
26087 bind : function(el)
26093 enter : function () {
26095 if (this.timeout != null) {
26096 clearTimeout(this.timeout);
26099 this.hoverState = 'in';
26100 //Roo.log("enter - show");
26101 if (!this.delay || !this.delay.show) {
26106 this.timeout = setTimeout(function () {
26107 if (_t.hoverState == 'in') {
26110 }, this.delay.show);
26114 clearTimeout(this.timeout);
26116 this.hoverState = 'out';
26117 if (!this.delay || !this.delay.hide) {
26123 this.timeout = setTimeout(function () {
26124 //Roo.log("leave - timeout");
26126 if (_t.hoverState == 'out') {
26128 Roo.bootstrap.Tooltip.currentEl = false;
26133 show : function (msg)
26136 this.render(document.body);
26139 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26141 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26143 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26145 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26147 var placement = typeof this.placement == 'function' ?
26148 this.placement.call(this, this.el, on_el) :
26151 var autoToken = /\s?auto?\s?/i;
26152 var autoPlace = autoToken.test(placement);
26154 placement = placement.replace(autoToken, '') || 'top';
26158 //this.el.setXY([0,0]);
26160 //this.el.dom.style.display='block';
26162 //this.el.appendTo(on_el);
26164 var p = this.getPosition();
26165 var box = this.el.getBox();
26171 var align = this.alignment[placement];
26173 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26175 if(placement == 'top' || placement == 'bottom'){
26177 placement = 'right';
26180 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26181 placement = 'left';
26184 var scroll = Roo.select('body', true).first().getScroll();
26186 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26192 this.el.alignTo(this.bindEl, align[0],align[1]);
26193 //var arrow = this.el.select('.arrow',true).first();
26194 //arrow.set(align[2],
26196 this.el.addClass(placement);
26198 this.el.addClass('in fade');
26200 this.hoverState = null;
26202 if (this.el.hasClass('fade')) {
26213 //this.el.setXY([0,0]);
26214 this.el.removeClass('in');
26230 * @class Roo.bootstrap.LocationPicker
26231 * @extends Roo.bootstrap.Component
26232 * Bootstrap LocationPicker class
26233 * @cfg {Number} latitude Position when init default 0
26234 * @cfg {Number} longitude Position when init default 0
26235 * @cfg {Number} zoom default 15
26236 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26237 * @cfg {Boolean} mapTypeControl default false
26238 * @cfg {Boolean} disableDoubleClickZoom default false
26239 * @cfg {Boolean} scrollwheel default true
26240 * @cfg {Boolean} streetViewControl default false
26241 * @cfg {Number} radius default 0
26242 * @cfg {String} locationName
26243 * @cfg {Boolean} draggable default true
26244 * @cfg {Boolean} enableAutocomplete default false
26245 * @cfg {Boolean} enableReverseGeocode default true
26246 * @cfg {String} markerTitle
26249 * Create a new LocationPicker
26250 * @param {Object} config The config object
26254 Roo.bootstrap.LocationPicker = function(config){
26256 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26261 * Fires when the picker initialized.
26262 * @param {Roo.bootstrap.LocationPicker} this
26263 * @param {Google Location} location
26267 * @event positionchanged
26268 * Fires when the picker position changed.
26269 * @param {Roo.bootstrap.LocationPicker} this
26270 * @param {Google Location} location
26272 positionchanged : true,
26275 * Fires when the map resize.
26276 * @param {Roo.bootstrap.LocationPicker} this
26281 * Fires when the map show.
26282 * @param {Roo.bootstrap.LocationPicker} this
26287 * Fires when the map hide.
26288 * @param {Roo.bootstrap.LocationPicker} this
26293 * Fires when click the map.
26294 * @param {Roo.bootstrap.LocationPicker} this
26295 * @param {Map event} e
26299 * @event mapRightClick
26300 * Fires when right click the map.
26301 * @param {Roo.bootstrap.LocationPicker} this
26302 * @param {Map event} e
26304 mapRightClick : true,
26306 * @event markerClick
26307 * Fires when click the marker.
26308 * @param {Roo.bootstrap.LocationPicker} this
26309 * @param {Map event} e
26311 markerClick : true,
26313 * @event markerRightClick
26314 * Fires when right click the marker.
26315 * @param {Roo.bootstrap.LocationPicker} this
26316 * @param {Map event} e
26318 markerRightClick : true,
26320 * @event OverlayViewDraw
26321 * Fires when OverlayView Draw
26322 * @param {Roo.bootstrap.LocationPicker} this
26324 OverlayViewDraw : true,
26326 * @event OverlayViewOnAdd
26327 * Fires when OverlayView Draw
26328 * @param {Roo.bootstrap.LocationPicker} this
26330 OverlayViewOnAdd : true,
26332 * @event OverlayViewOnRemove
26333 * Fires when OverlayView Draw
26334 * @param {Roo.bootstrap.LocationPicker} this
26336 OverlayViewOnRemove : true,
26338 * @event OverlayViewShow
26339 * Fires when OverlayView Draw
26340 * @param {Roo.bootstrap.LocationPicker} this
26341 * @param {Pixel} cpx
26343 OverlayViewShow : true,
26345 * @event OverlayViewHide
26346 * Fires when OverlayView Draw
26347 * @param {Roo.bootstrap.LocationPicker} this
26349 OverlayViewHide : true,
26351 * @event loadexception
26352 * Fires when load google lib failed.
26353 * @param {Roo.bootstrap.LocationPicker} this
26355 loadexception : true
26360 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26362 gMapContext: false,
26368 mapTypeControl: false,
26369 disableDoubleClickZoom: false,
26371 streetViewControl: false,
26375 enableAutocomplete: false,
26376 enableReverseGeocode: true,
26379 getAutoCreate: function()
26384 cls: 'roo-location-picker'
26390 initEvents: function(ct, position)
26392 if(!this.el.getWidth() || this.isApplied()){
26396 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26401 initial: function()
26403 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26404 this.fireEvent('loadexception', this);
26408 if(!this.mapTypeId){
26409 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26412 this.gMapContext = this.GMapContext();
26414 this.initOverlayView();
26416 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26420 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26421 _this.setPosition(_this.gMapContext.marker.position);
26424 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26425 _this.fireEvent('mapClick', this, event);
26429 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26430 _this.fireEvent('mapRightClick', this, event);
26434 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26435 _this.fireEvent('markerClick', this, event);
26439 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26440 _this.fireEvent('markerRightClick', this, event);
26444 this.setPosition(this.gMapContext.location);
26446 this.fireEvent('initial', this, this.gMapContext.location);
26449 initOverlayView: function()
26453 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26457 _this.fireEvent('OverlayViewDraw', _this);
26462 _this.fireEvent('OverlayViewOnAdd', _this);
26465 onRemove: function()
26467 _this.fireEvent('OverlayViewOnRemove', _this);
26470 show: function(cpx)
26472 _this.fireEvent('OverlayViewShow', _this, cpx);
26477 _this.fireEvent('OverlayViewHide', _this);
26483 fromLatLngToContainerPixel: function(event)
26485 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26488 isApplied: function()
26490 return this.getGmapContext() == false ? false : true;
26493 getGmapContext: function()
26495 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26498 GMapContext: function()
26500 var position = new google.maps.LatLng(this.latitude, this.longitude);
26502 var _map = new google.maps.Map(this.el.dom, {
26505 mapTypeId: this.mapTypeId,
26506 mapTypeControl: this.mapTypeControl,
26507 disableDoubleClickZoom: this.disableDoubleClickZoom,
26508 scrollwheel: this.scrollwheel,
26509 streetViewControl: this.streetViewControl,
26510 locationName: this.locationName,
26511 draggable: this.draggable,
26512 enableAutocomplete: this.enableAutocomplete,
26513 enableReverseGeocode: this.enableReverseGeocode
26516 var _marker = new google.maps.Marker({
26517 position: position,
26519 title: this.markerTitle,
26520 draggable: this.draggable
26527 location: position,
26528 radius: this.radius,
26529 locationName: this.locationName,
26530 addressComponents: {
26531 formatted_address: null,
26532 addressLine1: null,
26533 addressLine2: null,
26535 streetNumber: null,
26539 stateOrProvince: null
26542 domContainer: this.el.dom,
26543 geodecoder: new google.maps.Geocoder()
26547 drawCircle: function(center, radius, options)
26549 if (this.gMapContext.circle != null) {
26550 this.gMapContext.circle.setMap(null);
26554 options = Roo.apply({}, options, {
26555 strokeColor: "#0000FF",
26556 strokeOpacity: .35,
26558 fillColor: "#0000FF",
26562 options.map = this.gMapContext.map;
26563 options.radius = radius;
26564 options.center = center;
26565 this.gMapContext.circle = new google.maps.Circle(options);
26566 return this.gMapContext.circle;
26572 setPosition: function(location)
26574 this.gMapContext.location = location;
26575 this.gMapContext.marker.setPosition(location);
26576 this.gMapContext.map.panTo(location);
26577 this.drawCircle(location, this.gMapContext.radius, {});
26581 if (this.gMapContext.settings.enableReverseGeocode) {
26582 this.gMapContext.geodecoder.geocode({
26583 latLng: this.gMapContext.location
26584 }, function(results, status) {
26586 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26587 _this.gMapContext.locationName = results[0].formatted_address;
26588 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26590 _this.fireEvent('positionchanged', this, location);
26597 this.fireEvent('positionchanged', this, location);
26602 google.maps.event.trigger(this.gMapContext.map, "resize");
26604 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26606 this.fireEvent('resize', this);
26609 setPositionByLatLng: function(latitude, longitude)
26611 this.setPosition(new google.maps.LatLng(latitude, longitude));
26614 getCurrentPosition: function()
26617 latitude: this.gMapContext.location.lat(),
26618 longitude: this.gMapContext.location.lng()
26622 getAddressName: function()
26624 return this.gMapContext.locationName;
26627 getAddressComponents: function()
26629 return this.gMapContext.addressComponents;
26632 address_component_from_google_geocode: function(address_components)
26636 for (var i = 0; i < address_components.length; i++) {
26637 var component = address_components[i];
26638 if (component.types.indexOf("postal_code") >= 0) {
26639 result.postalCode = component.short_name;
26640 } else if (component.types.indexOf("street_number") >= 0) {
26641 result.streetNumber = component.short_name;
26642 } else if (component.types.indexOf("route") >= 0) {
26643 result.streetName = component.short_name;
26644 } else if (component.types.indexOf("neighborhood") >= 0) {
26645 result.city = component.short_name;
26646 } else if (component.types.indexOf("locality") >= 0) {
26647 result.city = component.short_name;
26648 } else if (component.types.indexOf("sublocality") >= 0) {
26649 result.district = component.short_name;
26650 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26651 result.stateOrProvince = component.short_name;
26652 } else if (component.types.indexOf("country") >= 0) {
26653 result.country = component.short_name;
26657 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26658 result.addressLine2 = "";
26662 setZoomLevel: function(zoom)
26664 this.gMapContext.map.setZoom(zoom);
26677 this.fireEvent('show', this);
26688 this.fireEvent('hide', this);
26693 Roo.apply(Roo.bootstrap.LocationPicker, {
26695 OverlayView : function(map, options)
26697 options = options || {};
26711 * @class Roo.bootstrap.Alert
26712 * @extends Roo.bootstrap.Component
26713 * Bootstrap Alert class
26714 * @cfg {String} title The title of alert
26715 * @cfg {String} html The content of alert
26716 * @cfg {String} weight ( success | info | warning | danger )
26717 * @cfg {String} faicon font-awesomeicon
26720 * Create a new alert
26721 * @param {Object} config The config object
26725 Roo.bootstrap.Alert = function(config){
26726 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26730 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26737 getAutoCreate : function()
26746 cls : 'roo-alert-icon'
26751 cls : 'roo-alert-title',
26756 cls : 'roo-alert-text',
26763 cfg.cn[0].cls += ' fa ' + this.faicon;
26767 cfg.cls += ' alert-' + this.weight;
26773 initEvents: function()
26775 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26778 setTitle : function(str)
26780 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26783 setText : function(str)
26785 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26788 setWeight : function(weight)
26791 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26794 this.weight = weight;
26796 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26799 setIcon : function(icon)
26802 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26805 this.faicon = icon;
26807 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26828 * @class Roo.bootstrap.UploadCropbox
26829 * @extends Roo.bootstrap.Component
26830 * Bootstrap UploadCropbox class
26831 * @cfg {String} emptyText show when image has been loaded
26832 * @cfg {String} rotateNotify show when image too small to rotate
26833 * @cfg {Number} errorTimeout default 3000
26834 * @cfg {Number} minWidth default 300
26835 * @cfg {Number} minHeight default 300
26836 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26837 * @cfg {Boolean} isDocument (true|false) default false
26838 * @cfg {String} url action url
26839 * @cfg {String} paramName default 'imageUpload'
26840 * @cfg {String} method default POST
26841 * @cfg {Boolean} loadMask (true|false) default true
26842 * @cfg {Boolean} loadingText default 'Loading...'
26845 * Create a new UploadCropbox
26846 * @param {Object} config The config object
26849 Roo.bootstrap.UploadCropbox = function(config){
26850 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26854 * @event beforeselectfile
26855 * Fire before select file
26856 * @param {Roo.bootstrap.UploadCropbox} this
26858 "beforeselectfile" : true,
26861 * Fire after initEvent
26862 * @param {Roo.bootstrap.UploadCropbox} this
26867 * Fire after initEvent
26868 * @param {Roo.bootstrap.UploadCropbox} this
26869 * @param {String} data
26874 * Fire when preparing the file data
26875 * @param {Roo.bootstrap.UploadCropbox} this
26876 * @param {Object} file
26881 * Fire when get exception
26882 * @param {Roo.bootstrap.UploadCropbox} this
26883 * @param {XMLHttpRequest} xhr
26885 "exception" : true,
26887 * @event beforeloadcanvas
26888 * Fire before load the canvas
26889 * @param {Roo.bootstrap.UploadCropbox} this
26890 * @param {String} src
26892 "beforeloadcanvas" : true,
26895 * Fire when trash image
26896 * @param {Roo.bootstrap.UploadCropbox} this
26901 * Fire when download the image
26902 * @param {Roo.bootstrap.UploadCropbox} this
26906 * @event footerbuttonclick
26907 * Fire when footerbuttonclick
26908 * @param {Roo.bootstrap.UploadCropbox} this
26909 * @param {String} type
26911 "footerbuttonclick" : true,
26915 * @param {Roo.bootstrap.UploadCropbox} this
26920 * Fire when rotate the image
26921 * @param {Roo.bootstrap.UploadCropbox} this
26922 * @param {String} pos
26927 * Fire when inspect the file
26928 * @param {Roo.bootstrap.UploadCropbox} this
26929 * @param {Object} file
26934 * Fire when xhr upload the file
26935 * @param {Roo.bootstrap.UploadCropbox} this
26936 * @param {Object} data
26941 * Fire when arrange the file data
26942 * @param {Roo.bootstrap.UploadCropbox} this
26943 * @param {Object} formData
26948 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26951 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26953 emptyText : 'Click to upload image',
26954 rotateNotify : 'Image is too small to rotate',
26955 errorTimeout : 3000,
26969 cropType : 'image/jpeg',
26971 canvasLoaded : false,
26972 isDocument : false,
26974 paramName : 'imageUpload',
26976 loadingText : 'Loading...',
26979 getAutoCreate : function()
26983 cls : 'roo-upload-cropbox',
26987 cls : 'roo-upload-cropbox-selector',
26992 cls : 'roo-upload-cropbox-body',
26993 style : 'cursor:pointer',
26997 cls : 'roo-upload-cropbox-preview'
27001 cls : 'roo-upload-cropbox-thumb'
27005 cls : 'roo-upload-cropbox-empty-notify',
27006 html : this.emptyText
27010 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27011 html : this.rotateNotify
27017 cls : 'roo-upload-cropbox-footer',
27020 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27030 onRender : function(ct, position)
27032 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27034 if (this.buttons.length) {
27036 Roo.each(this.buttons, function(bb) {
27038 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27040 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27046 this.maskEl = this.el;
27050 initEvents : function()
27052 this.urlAPI = (window.createObjectURL && window) ||
27053 (window.URL && URL.revokeObjectURL && URL) ||
27054 (window.webkitURL && webkitURL);
27056 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27057 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27059 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27060 this.selectorEl.hide();
27062 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27063 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27065 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27066 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27067 this.thumbEl.hide();
27069 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27070 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27072 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27073 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27074 this.errorEl.hide();
27076 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27077 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27078 this.footerEl.hide();
27080 this.setThumbBoxSize();
27086 this.fireEvent('initial', this);
27093 window.addEventListener("resize", function() { _this.resize(); } );
27095 this.bodyEl.on('click', this.beforeSelectFile, this);
27098 this.bodyEl.on('touchstart', this.onTouchStart, this);
27099 this.bodyEl.on('touchmove', this.onTouchMove, this);
27100 this.bodyEl.on('touchend', this.onTouchEnd, this);
27104 this.bodyEl.on('mousedown', this.onMouseDown, this);
27105 this.bodyEl.on('mousemove', this.onMouseMove, this);
27106 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27107 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27108 Roo.get(document).on('mouseup', this.onMouseUp, this);
27111 this.selectorEl.on('change', this.onFileSelected, this);
27117 this.baseScale = 1;
27119 this.baseRotate = 1;
27120 this.dragable = false;
27121 this.pinching = false;
27124 this.cropData = false;
27125 this.notifyEl.dom.innerHTML = this.emptyText;
27127 this.selectorEl.dom.value = '';
27131 resize : function()
27133 if(this.fireEvent('resize', this) != false){
27134 this.setThumbBoxPosition();
27135 this.setCanvasPosition();
27139 onFooterButtonClick : function(e, el, o, type)
27142 case 'rotate-left' :
27143 this.onRotateLeft(e);
27145 case 'rotate-right' :
27146 this.onRotateRight(e);
27149 this.beforeSelectFile(e);
27164 this.fireEvent('footerbuttonclick', this, type);
27167 beforeSelectFile : function(e)
27169 e.preventDefault();
27171 if(this.fireEvent('beforeselectfile', this) != false){
27172 this.selectorEl.dom.click();
27176 onFileSelected : function(e)
27178 e.preventDefault();
27180 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27184 var file = this.selectorEl.dom.files[0];
27186 if(this.fireEvent('inspect', this, file) != false){
27187 this.prepare(file);
27192 trash : function(e)
27194 this.fireEvent('trash', this);
27197 download : function(e)
27199 this.fireEvent('download', this);
27202 loadCanvas : function(src)
27204 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27208 this.imageEl = document.createElement('img');
27212 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27214 this.imageEl.src = src;
27218 onLoadCanvas : function()
27220 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27221 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27223 this.bodyEl.un('click', this.beforeSelectFile, this);
27225 this.notifyEl.hide();
27226 this.thumbEl.show();
27227 this.footerEl.show();
27229 this.baseRotateLevel();
27231 if(this.isDocument){
27232 this.setThumbBoxSize();
27235 this.setThumbBoxPosition();
27237 this.baseScaleLevel();
27243 this.canvasLoaded = true;
27246 this.maskEl.unmask();
27251 setCanvasPosition : function()
27253 if(!this.canvasEl){
27257 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27258 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27260 this.previewEl.setLeft(pw);
27261 this.previewEl.setTop(ph);
27265 onMouseDown : function(e)
27269 this.dragable = true;
27270 this.pinching = false;
27272 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27273 this.dragable = false;
27277 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27278 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27282 onMouseMove : function(e)
27286 if(!this.canvasLoaded){
27290 if (!this.dragable){
27294 var minX = Math.ceil(this.thumbEl.getLeft(true));
27295 var minY = Math.ceil(this.thumbEl.getTop(true));
27297 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27298 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27300 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27301 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27303 x = x - this.mouseX;
27304 y = y - this.mouseY;
27306 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27307 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27309 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27310 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27312 this.previewEl.setLeft(bgX);
27313 this.previewEl.setTop(bgY);
27315 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27316 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27319 onMouseUp : function(e)
27323 this.dragable = false;
27326 onMouseWheel : function(e)
27330 this.startScale = this.scale;
27332 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27334 if(!this.zoomable()){
27335 this.scale = this.startScale;
27344 zoomable : function()
27346 var minScale = this.thumbEl.getWidth() / this.minWidth;
27348 if(this.minWidth < this.minHeight){
27349 minScale = this.thumbEl.getHeight() / this.minHeight;
27352 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27353 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27357 (this.rotate == 0 || this.rotate == 180) &&
27359 width > this.imageEl.OriginWidth ||
27360 height > this.imageEl.OriginHeight ||
27361 (width < this.minWidth && height < this.minHeight)
27369 (this.rotate == 90 || this.rotate == 270) &&
27371 width > this.imageEl.OriginWidth ||
27372 height > this.imageEl.OriginHeight ||
27373 (width < this.minHeight && height < this.minWidth)
27380 !this.isDocument &&
27381 (this.rotate == 0 || this.rotate == 180) &&
27383 width < this.minWidth ||
27384 width > this.imageEl.OriginWidth ||
27385 height < this.minHeight ||
27386 height > this.imageEl.OriginHeight
27393 !this.isDocument &&
27394 (this.rotate == 90 || this.rotate == 270) &&
27396 width < this.minHeight ||
27397 width > this.imageEl.OriginWidth ||
27398 height < this.minWidth ||
27399 height > this.imageEl.OriginHeight
27409 onRotateLeft : function(e)
27411 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27413 var minScale = this.thumbEl.getWidth() / this.minWidth;
27415 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27416 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27418 this.startScale = this.scale;
27420 while (this.getScaleLevel() < minScale){
27422 this.scale = this.scale + 1;
27424 if(!this.zoomable()){
27429 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27430 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27435 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27442 this.scale = this.startScale;
27444 this.onRotateFail();
27449 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27451 if(this.isDocument){
27452 this.setThumbBoxSize();
27453 this.setThumbBoxPosition();
27454 this.setCanvasPosition();
27459 this.fireEvent('rotate', this, 'left');
27463 onRotateRight : function(e)
27465 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27467 var minScale = this.thumbEl.getWidth() / this.minWidth;
27469 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27470 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27472 this.startScale = this.scale;
27474 while (this.getScaleLevel() < minScale){
27476 this.scale = this.scale + 1;
27478 if(!this.zoomable()){
27483 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27484 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27489 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27496 this.scale = this.startScale;
27498 this.onRotateFail();
27503 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27505 if(this.isDocument){
27506 this.setThumbBoxSize();
27507 this.setThumbBoxPosition();
27508 this.setCanvasPosition();
27513 this.fireEvent('rotate', this, 'right');
27516 onRotateFail : function()
27518 this.errorEl.show(true);
27522 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27527 this.previewEl.dom.innerHTML = '';
27529 var canvasEl = document.createElement("canvas");
27531 var contextEl = canvasEl.getContext("2d");
27533 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27534 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27535 var center = this.imageEl.OriginWidth / 2;
27537 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27538 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27539 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27540 center = this.imageEl.OriginHeight / 2;
27543 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27545 contextEl.translate(center, center);
27546 contextEl.rotate(this.rotate * Math.PI / 180);
27548 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27550 this.canvasEl = document.createElement("canvas");
27552 this.contextEl = this.canvasEl.getContext("2d");
27554 switch (this.rotate) {
27557 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27558 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27560 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27565 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27566 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27568 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27569 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);
27573 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27578 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27579 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27581 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27582 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);
27586 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);
27591 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27592 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27594 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27595 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27599 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);
27606 this.previewEl.appendChild(this.canvasEl);
27608 this.setCanvasPosition();
27613 if(!this.canvasLoaded){
27617 var imageCanvas = document.createElement("canvas");
27619 var imageContext = imageCanvas.getContext("2d");
27621 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27622 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27624 var center = imageCanvas.width / 2;
27626 imageContext.translate(center, center);
27628 imageContext.rotate(this.rotate * Math.PI / 180);
27630 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27632 var canvas = document.createElement("canvas");
27634 var context = canvas.getContext("2d");
27636 canvas.width = this.minWidth;
27637 canvas.height = this.minHeight;
27639 switch (this.rotate) {
27642 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27643 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27645 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27646 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27648 var targetWidth = this.minWidth - 2 * x;
27649 var targetHeight = this.minHeight - 2 * y;
27653 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27654 scale = targetWidth / width;
27657 if(x > 0 && y == 0){
27658 scale = targetHeight / height;
27661 if(x > 0 && y > 0){
27662 scale = targetWidth / width;
27664 if(width < height){
27665 scale = targetHeight / height;
27669 context.scale(scale, scale);
27671 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27672 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27674 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27675 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27677 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27682 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27683 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27685 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27686 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27688 var targetWidth = this.minWidth - 2 * x;
27689 var targetHeight = this.minHeight - 2 * y;
27693 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27694 scale = targetWidth / width;
27697 if(x > 0 && y == 0){
27698 scale = targetHeight / height;
27701 if(x > 0 && y > 0){
27702 scale = targetWidth / width;
27704 if(width < height){
27705 scale = targetHeight / height;
27709 context.scale(scale, scale);
27711 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27712 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27714 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27715 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27717 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27719 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27724 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27725 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27727 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27728 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27730 var targetWidth = this.minWidth - 2 * x;
27731 var targetHeight = this.minHeight - 2 * y;
27735 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27736 scale = targetWidth / width;
27739 if(x > 0 && y == 0){
27740 scale = targetHeight / height;
27743 if(x > 0 && y > 0){
27744 scale = targetWidth / width;
27746 if(width < height){
27747 scale = targetHeight / height;
27751 context.scale(scale, scale);
27753 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27754 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27756 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27757 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27759 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27760 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27762 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27767 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27768 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27770 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27771 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27773 var targetWidth = this.minWidth - 2 * x;
27774 var targetHeight = this.minHeight - 2 * y;
27778 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27779 scale = targetWidth / width;
27782 if(x > 0 && y == 0){
27783 scale = targetHeight / height;
27786 if(x > 0 && y > 0){
27787 scale = targetWidth / width;
27789 if(width < height){
27790 scale = targetHeight / height;
27794 context.scale(scale, scale);
27796 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27797 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27799 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27800 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27802 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27804 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27811 this.cropData = canvas.toDataURL(this.cropType);
27813 if(this.fireEvent('crop', this, this.cropData) !== false){
27814 this.process(this.file, this.cropData);
27821 setThumbBoxSize : function()
27825 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27826 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27827 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27829 this.minWidth = width;
27830 this.minHeight = height;
27832 if(this.rotate == 90 || this.rotate == 270){
27833 this.minWidth = height;
27834 this.minHeight = width;
27839 width = Math.ceil(this.minWidth * height / this.minHeight);
27841 if(this.minWidth > this.minHeight){
27843 height = Math.ceil(this.minHeight * width / this.minWidth);
27846 this.thumbEl.setStyle({
27847 width : width + 'px',
27848 height : height + 'px'
27855 setThumbBoxPosition : function()
27857 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27858 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27860 this.thumbEl.setLeft(x);
27861 this.thumbEl.setTop(y);
27865 baseRotateLevel : function()
27867 this.baseRotate = 1;
27870 typeof(this.exif) != 'undefined' &&
27871 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27872 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27874 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27877 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27881 baseScaleLevel : function()
27885 if(this.isDocument){
27887 if(this.baseRotate == 6 || this.baseRotate == 8){
27889 height = this.thumbEl.getHeight();
27890 this.baseScale = height / this.imageEl.OriginWidth;
27892 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27893 width = this.thumbEl.getWidth();
27894 this.baseScale = width / this.imageEl.OriginHeight;
27900 height = this.thumbEl.getHeight();
27901 this.baseScale = height / this.imageEl.OriginHeight;
27903 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27904 width = this.thumbEl.getWidth();
27905 this.baseScale = width / this.imageEl.OriginWidth;
27911 if(this.baseRotate == 6 || this.baseRotate == 8){
27913 width = this.thumbEl.getHeight();
27914 this.baseScale = width / this.imageEl.OriginHeight;
27916 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27917 height = this.thumbEl.getWidth();
27918 this.baseScale = height / this.imageEl.OriginHeight;
27921 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27922 height = this.thumbEl.getWidth();
27923 this.baseScale = height / this.imageEl.OriginHeight;
27925 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27926 width = this.thumbEl.getHeight();
27927 this.baseScale = width / this.imageEl.OriginWidth;
27934 width = this.thumbEl.getWidth();
27935 this.baseScale = width / this.imageEl.OriginWidth;
27937 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27938 height = this.thumbEl.getHeight();
27939 this.baseScale = height / this.imageEl.OriginHeight;
27942 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27944 height = this.thumbEl.getHeight();
27945 this.baseScale = height / this.imageEl.OriginHeight;
27947 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27948 width = this.thumbEl.getWidth();
27949 this.baseScale = width / this.imageEl.OriginWidth;
27957 getScaleLevel : function()
27959 return this.baseScale * Math.pow(1.1, this.scale);
27962 onTouchStart : function(e)
27964 if(!this.canvasLoaded){
27965 this.beforeSelectFile(e);
27969 var touches = e.browserEvent.touches;
27975 if(touches.length == 1){
27976 this.onMouseDown(e);
27980 if(touches.length != 2){
27986 for(var i = 0, finger; finger = touches[i]; i++){
27987 coords.push(finger.pageX, finger.pageY);
27990 var x = Math.pow(coords[0] - coords[2], 2);
27991 var y = Math.pow(coords[1] - coords[3], 2);
27993 this.startDistance = Math.sqrt(x + y);
27995 this.startScale = this.scale;
27997 this.pinching = true;
27998 this.dragable = false;
28002 onTouchMove : function(e)
28004 if(!this.pinching && !this.dragable){
28008 var touches = e.browserEvent.touches;
28015 this.onMouseMove(e);
28021 for(var i = 0, finger; finger = touches[i]; i++){
28022 coords.push(finger.pageX, finger.pageY);
28025 var x = Math.pow(coords[0] - coords[2], 2);
28026 var y = Math.pow(coords[1] - coords[3], 2);
28028 this.endDistance = Math.sqrt(x + y);
28030 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28032 if(!this.zoomable()){
28033 this.scale = this.startScale;
28041 onTouchEnd : function(e)
28043 this.pinching = false;
28044 this.dragable = false;
28048 process : function(file, crop)
28051 this.maskEl.mask(this.loadingText);
28054 this.xhr = new XMLHttpRequest();
28056 file.xhr = this.xhr;
28058 this.xhr.open(this.method, this.url, true);
28061 "Accept": "application/json",
28062 "Cache-Control": "no-cache",
28063 "X-Requested-With": "XMLHttpRequest"
28066 for (var headerName in headers) {
28067 var headerValue = headers[headerName];
28069 this.xhr.setRequestHeader(headerName, headerValue);
28075 this.xhr.onload = function()
28077 _this.xhrOnLoad(_this.xhr);
28080 this.xhr.onerror = function()
28082 _this.xhrOnError(_this.xhr);
28085 var formData = new FormData();
28087 formData.append('returnHTML', 'NO');
28090 formData.append('crop', crop);
28093 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28094 formData.append(this.paramName, file, file.name);
28097 if(typeof(file.filename) != 'undefined'){
28098 formData.append('filename', file.filename);
28101 if(typeof(file.mimetype) != 'undefined'){
28102 formData.append('mimetype', file.mimetype);
28105 if(this.fireEvent('arrange', this, formData) != false){
28106 this.xhr.send(formData);
28110 xhrOnLoad : function(xhr)
28113 this.maskEl.unmask();
28116 if (xhr.readyState !== 4) {
28117 this.fireEvent('exception', this, xhr);
28121 var response = Roo.decode(xhr.responseText);
28123 if(!response.success){
28124 this.fireEvent('exception', this, xhr);
28128 var response = Roo.decode(xhr.responseText);
28130 this.fireEvent('upload', this, response);
28134 xhrOnError : function()
28137 this.maskEl.unmask();
28140 Roo.log('xhr on error');
28142 var response = Roo.decode(xhr.responseText);
28148 prepare : function(file)
28151 this.maskEl.mask(this.loadingText);
28157 if(typeof(file) === 'string'){
28158 this.loadCanvas(file);
28162 if(!file || !this.urlAPI){
28167 this.cropType = file.type;
28171 if(this.fireEvent('prepare', this, this.file) != false){
28173 var reader = new FileReader();
28175 reader.onload = function (e) {
28176 if (e.target.error) {
28177 Roo.log(e.target.error);
28181 var buffer = e.target.result,
28182 dataView = new DataView(buffer),
28184 maxOffset = dataView.byteLength - 4,
28188 if (dataView.getUint16(0) === 0xffd8) {
28189 while (offset < maxOffset) {
28190 markerBytes = dataView.getUint16(offset);
28192 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28193 markerLength = dataView.getUint16(offset + 2) + 2;
28194 if (offset + markerLength > dataView.byteLength) {
28195 Roo.log('Invalid meta data: Invalid segment size.');
28199 if(markerBytes == 0xffe1){
28200 _this.parseExifData(
28207 offset += markerLength;
28217 var url = _this.urlAPI.createObjectURL(_this.file);
28219 _this.loadCanvas(url);
28224 reader.readAsArrayBuffer(this.file);
28230 parseExifData : function(dataView, offset, length)
28232 var tiffOffset = offset + 10,
28236 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28237 // No Exif data, might be XMP data instead
28241 // Check for the ASCII code for "Exif" (0x45786966):
28242 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28243 // No Exif data, might be XMP data instead
28246 if (tiffOffset + 8 > dataView.byteLength) {
28247 Roo.log('Invalid Exif data: Invalid segment size.');
28250 // Check for the two null bytes:
28251 if (dataView.getUint16(offset + 8) !== 0x0000) {
28252 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28255 // Check the byte alignment:
28256 switch (dataView.getUint16(tiffOffset)) {
28258 littleEndian = true;
28261 littleEndian = false;
28264 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28267 // Check for the TIFF tag marker (0x002A):
28268 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28269 Roo.log('Invalid Exif data: Missing TIFF marker.');
28272 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28273 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28275 this.parseExifTags(
28278 tiffOffset + dirOffset,
28283 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28288 if (dirOffset + 6 > dataView.byteLength) {
28289 Roo.log('Invalid Exif data: Invalid directory offset.');
28292 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28293 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28294 if (dirEndOffset + 4 > dataView.byteLength) {
28295 Roo.log('Invalid Exif data: Invalid directory size.');
28298 for (i = 0; i < tagsNumber; i += 1) {
28302 dirOffset + 2 + 12 * i, // tag offset
28306 // Return the offset to the next directory:
28307 return dataView.getUint32(dirEndOffset, littleEndian);
28310 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28312 var tag = dataView.getUint16(offset, littleEndian);
28314 this.exif[tag] = this.getExifValue(
28318 dataView.getUint16(offset + 2, littleEndian), // tag type
28319 dataView.getUint32(offset + 4, littleEndian), // tag length
28324 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28326 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28335 Roo.log('Invalid Exif data: Invalid tag type.');
28339 tagSize = tagType.size * length;
28340 // Determine if the value is contained in the dataOffset bytes,
28341 // or if the value at the dataOffset is a pointer to the actual data:
28342 dataOffset = tagSize > 4 ?
28343 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28344 if (dataOffset + tagSize > dataView.byteLength) {
28345 Roo.log('Invalid Exif data: Invalid data offset.');
28348 if (length === 1) {
28349 return tagType.getValue(dataView, dataOffset, littleEndian);
28352 for (i = 0; i < length; i += 1) {
28353 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28356 if (tagType.ascii) {
28358 // Concatenate the chars:
28359 for (i = 0; i < values.length; i += 1) {
28361 // Ignore the terminating NULL byte(s):
28362 if (c === '\u0000') {
28374 Roo.apply(Roo.bootstrap.UploadCropbox, {
28376 'Orientation': 0x0112
28380 1: 0, //'top-left',
28382 3: 180, //'bottom-right',
28383 // 4: 'bottom-left',
28385 6: 90, //'right-top',
28386 // 7: 'right-bottom',
28387 8: 270 //'left-bottom'
28391 // byte, 8-bit unsigned int:
28393 getValue: function (dataView, dataOffset) {
28394 return dataView.getUint8(dataOffset);
28398 // ascii, 8-bit byte:
28400 getValue: function (dataView, dataOffset) {
28401 return String.fromCharCode(dataView.getUint8(dataOffset));
28406 // short, 16 bit int:
28408 getValue: function (dataView, dataOffset, littleEndian) {
28409 return dataView.getUint16(dataOffset, littleEndian);
28413 // long, 32 bit int:
28415 getValue: function (dataView, dataOffset, littleEndian) {
28416 return dataView.getUint32(dataOffset, littleEndian);
28420 // rational = two long values, first is numerator, second is denominator:
28422 getValue: function (dataView, dataOffset, littleEndian) {
28423 return dataView.getUint32(dataOffset, littleEndian) /
28424 dataView.getUint32(dataOffset + 4, littleEndian);
28428 // slong, 32 bit signed int:
28430 getValue: function (dataView, dataOffset, littleEndian) {
28431 return dataView.getInt32(dataOffset, littleEndian);
28435 // srational, two slongs, first is numerator, second is denominator:
28437 getValue: function (dataView, dataOffset, littleEndian) {
28438 return dataView.getInt32(dataOffset, littleEndian) /
28439 dataView.getInt32(dataOffset + 4, littleEndian);
28449 cls : 'btn-group roo-upload-cropbox-rotate-left',
28450 action : 'rotate-left',
28454 cls : 'btn btn-default',
28455 html : '<i class="fa fa-undo"></i>'
28461 cls : 'btn-group roo-upload-cropbox-picture',
28462 action : 'picture',
28466 cls : 'btn btn-default',
28467 html : '<i class="fa fa-picture-o"></i>'
28473 cls : 'btn-group roo-upload-cropbox-rotate-right',
28474 action : 'rotate-right',
28478 cls : 'btn btn-default',
28479 html : '<i class="fa fa-repeat"></i>'
28487 cls : 'btn-group roo-upload-cropbox-rotate-left',
28488 action : 'rotate-left',
28492 cls : 'btn btn-default',
28493 html : '<i class="fa fa-undo"></i>'
28499 cls : 'btn-group roo-upload-cropbox-download',
28500 action : 'download',
28504 cls : 'btn btn-default',
28505 html : '<i class="fa fa-download"></i>'
28511 cls : 'btn-group roo-upload-cropbox-crop',
28516 cls : 'btn btn-default',
28517 html : '<i class="fa fa-crop"></i>'
28523 cls : 'btn-group roo-upload-cropbox-trash',
28528 cls : 'btn btn-default',
28529 html : '<i class="fa fa-trash"></i>'
28535 cls : 'btn-group roo-upload-cropbox-rotate-right',
28536 action : 'rotate-right',
28540 cls : 'btn btn-default',
28541 html : '<i class="fa fa-repeat"></i>'
28549 cls : 'btn-group roo-upload-cropbox-rotate-left',
28550 action : 'rotate-left',
28554 cls : 'btn btn-default',
28555 html : '<i class="fa fa-undo"></i>'
28561 cls : 'btn-group roo-upload-cropbox-rotate-right',
28562 action : 'rotate-right',
28566 cls : 'btn btn-default',
28567 html : '<i class="fa fa-repeat"></i>'
28580 * @class Roo.bootstrap.DocumentManager
28581 * @extends Roo.bootstrap.Component
28582 * Bootstrap DocumentManager class
28583 * @cfg {String} paramName default 'imageUpload'
28584 * @cfg {String} toolTipName default 'filename'
28585 * @cfg {String} method default POST
28586 * @cfg {String} url action url
28587 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28588 * @cfg {Boolean} multiple multiple upload default true
28589 * @cfg {Number} thumbSize default 300
28590 * @cfg {String} fieldLabel
28591 * @cfg {Number} labelWidth default 4
28592 * @cfg {String} labelAlign (left|top) default left
28593 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28594 * @cfg {Number} labellg set the width of label (1-12)
28595 * @cfg {Number} labelmd set the width of label (1-12)
28596 * @cfg {Number} labelsm set the width of label (1-12)
28597 * @cfg {Number} labelxs set the width of label (1-12)
28600 * Create a new DocumentManager
28601 * @param {Object} config The config object
28604 Roo.bootstrap.DocumentManager = function(config){
28605 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28608 this.delegates = [];
28613 * Fire when initial the DocumentManager
28614 * @param {Roo.bootstrap.DocumentManager} this
28619 * inspect selected file
28620 * @param {Roo.bootstrap.DocumentManager} this
28621 * @param {File} file
28626 * Fire when xhr load exception
28627 * @param {Roo.bootstrap.DocumentManager} this
28628 * @param {XMLHttpRequest} xhr
28630 "exception" : true,
28632 * @event afterupload
28633 * Fire when xhr load exception
28634 * @param {Roo.bootstrap.DocumentManager} this
28635 * @param {XMLHttpRequest} xhr
28637 "afterupload" : true,
28640 * prepare the form data
28641 * @param {Roo.bootstrap.DocumentManager} this
28642 * @param {Object} formData
28647 * Fire when remove the file
28648 * @param {Roo.bootstrap.DocumentManager} this
28649 * @param {Object} file
28654 * Fire after refresh the file
28655 * @param {Roo.bootstrap.DocumentManager} this
28660 * Fire after click the image
28661 * @param {Roo.bootstrap.DocumentManager} this
28662 * @param {Object} file
28667 * Fire when upload a image and editable set to true
28668 * @param {Roo.bootstrap.DocumentManager} this
28669 * @param {Object} file
28673 * @event beforeselectfile
28674 * Fire before select file
28675 * @param {Roo.bootstrap.DocumentManager} this
28677 "beforeselectfile" : true,
28680 * Fire before process file
28681 * @param {Roo.bootstrap.DocumentManager} this
28682 * @param {Object} file
28686 * @event previewrendered
28687 * Fire when preview rendered
28688 * @param {Roo.bootstrap.DocumentManager} this
28689 * @param {Object} file
28691 "previewrendered" : true
28696 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28705 paramName : 'imageUpload',
28706 toolTipName : 'filename',
28709 labelAlign : 'left',
28719 getAutoCreate : function()
28721 var managerWidget = {
28723 cls : 'roo-document-manager',
28727 cls : 'roo-document-manager-selector',
28732 cls : 'roo-document-manager-uploader',
28736 cls : 'roo-document-manager-upload-btn',
28737 html : '<i class="fa fa-plus"></i>'
28748 cls : 'column col-md-12',
28753 if(this.fieldLabel.length){
28758 cls : 'column col-md-12',
28759 html : this.fieldLabel
28763 cls : 'column col-md-12',
28768 if(this.labelAlign == 'left'){
28773 html : this.fieldLabel
28782 if(this.labelWidth > 12){
28783 content[0].style = "width: " + this.labelWidth + 'px';
28786 if(this.labelWidth < 13 && this.labelmd == 0){
28787 this.labelmd = this.labelWidth;
28790 if(this.labellg > 0){
28791 content[0].cls += ' col-lg-' + this.labellg;
28792 content[1].cls += ' col-lg-' + (12 - this.labellg);
28795 if(this.labelmd > 0){
28796 content[0].cls += ' col-md-' + this.labelmd;
28797 content[1].cls += ' col-md-' + (12 - this.labelmd);
28800 if(this.labelsm > 0){
28801 content[0].cls += ' col-sm-' + this.labelsm;
28802 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28805 if(this.labelxs > 0){
28806 content[0].cls += ' col-xs-' + this.labelxs;
28807 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28815 cls : 'row clearfix',
28823 initEvents : function()
28825 this.managerEl = this.el.select('.roo-document-manager', true).first();
28826 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28828 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28829 this.selectorEl.hide();
28832 this.selectorEl.attr('multiple', 'multiple');
28835 this.selectorEl.on('change', this.onFileSelected, this);
28837 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28838 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28840 this.uploader.on('click', this.onUploaderClick, this);
28842 this.renderProgressDialog();
28846 window.addEventListener("resize", function() { _this.refresh(); } );
28848 this.fireEvent('initial', this);
28851 renderProgressDialog : function()
28855 this.progressDialog = new Roo.bootstrap.Modal({
28856 cls : 'roo-document-manager-progress-dialog',
28857 allow_close : false,
28867 btnclick : function() {
28868 _this.uploadCancel();
28874 this.progressDialog.render(Roo.get(document.body));
28876 this.progress = new Roo.bootstrap.Progress({
28877 cls : 'roo-document-manager-progress',
28882 this.progress.render(this.progressDialog.getChildContainer());
28884 this.progressBar = new Roo.bootstrap.ProgressBar({
28885 cls : 'roo-document-manager-progress-bar',
28888 aria_valuemax : 12,
28892 this.progressBar.render(this.progress.getChildContainer());
28895 onUploaderClick : function(e)
28897 e.preventDefault();
28899 if(this.fireEvent('beforeselectfile', this) != false){
28900 this.selectorEl.dom.click();
28905 onFileSelected : function(e)
28907 e.preventDefault();
28909 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28913 Roo.each(this.selectorEl.dom.files, function(file){
28914 if(this.fireEvent('inspect', this, file) != false){
28915 this.files.push(file);
28925 this.selectorEl.dom.value = '';
28927 if(!this.files || !this.files.length){
28931 if(this.boxes > 0 && this.files.length > this.boxes){
28932 this.files = this.files.slice(0, this.boxes);
28935 this.uploader.show();
28937 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28938 this.uploader.hide();
28947 Roo.each(this.files, function(file){
28949 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28950 var f = this.renderPreview(file);
28955 if(file.type.indexOf('image') != -1){
28956 this.delegates.push(
28958 _this.process(file);
28959 }).createDelegate(this)
28967 _this.process(file);
28968 }).createDelegate(this)
28973 this.files = files;
28975 this.delegates = this.delegates.concat(docs);
28977 if(!this.delegates.length){
28982 this.progressBar.aria_valuemax = this.delegates.length;
28989 arrange : function()
28991 if(!this.delegates.length){
28992 this.progressDialog.hide();
28997 var delegate = this.delegates.shift();
28999 this.progressDialog.show();
29001 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29003 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29008 refresh : function()
29010 this.uploader.show();
29012 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29013 this.uploader.hide();
29016 Roo.isTouch ? this.closable(false) : this.closable(true);
29018 this.fireEvent('refresh', this);
29021 onRemove : function(e, el, o)
29023 e.preventDefault();
29025 this.fireEvent('remove', this, o);
29029 remove : function(o)
29033 Roo.each(this.files, function(file){
29034 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29043 this.files = files;
29050 Roo.each(this.files, function(file){
29055 file.target.remove();
29064 onClick : function(e, el, o)
29066 e.preventDefault();
29068 this.fireEvent('click', this, o);
29072 closable : function(closable)
29074 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29076 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29088 xhrOnLoad : function(xhr)
29090 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29094 if (xhr.readyState !== 4) {
29096 this.fireEvent('exception', this, xhr);
29100 var response = Roo.decode(xhr.responseText);
29102 if(!response.success){
29104 this.fireEvent('exception', this, xhr);
29108 var file = this.renderPreview(response.data);
29110 this.files.push(file);
29114 this.fireEvent('afterupload', this, xhr);
29118 xhrOnError : function(xhr)
29120 Roo.log('xhr on error');
29122 var response = Roo.decode(xhr.responseText);
29129 process : function(file)
29131 if(this.fireEvent('process', this, file) !== false){
29132 if(this.editable && file.type.indexOf('image') != -1){
29133 this.fireEvent('edit', this, file);
29137 this.uploadStart(file, false);
29144 uploadStart : function(file, crop)
29146 this.xhr = new XMLHttpRequest();
29148 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29153 file.xhr = this.xhr;
29155 this.managerEl.createChild({
29157 cls : 'roo-document-manager-loading',
29161 tooltip : file.name,
29162 cls : 'roo-document-manager-thumb',
29163 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29169 this.xhr.open(this.method, this.url, true);
29172 "Accept": "application/json",
29173 "Cache-Control": "no-cache",
29174 "X-Requested-With": "XMLHttpRequest"
29177 for (var headerName in headers) {
29178 var headerValue = headers[headerName];
29180 this.xhr.setRequestHeader(headerName, headerValue);
29186 this.xhr.onload = function()
29188 _this.xhrOnLoad(_this.xhr);
29191 this.xhr.onerror = function()
29193 _this.xhrOnError(_this.xhr);
29196 var formData = new FormData();
29198 formData.append('returnHTML', 'NO');
29201 formData.append('crop', crop);
29204 formData.append(this.paramName, file, file.name);
29211 if(this.fireEvent('prepare', this, formData, options) != false){
29213 if(options.manually){
29217 this.xhr.send(formData);
29221 this.uploadCancel();
29224 uploadCancel : function()
29230 this.delegates = [];
29232 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29239 renderPreview : function(file)
29241 if(typeof(file.target) != 'undefined' && file.target){
29245 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29247 var previewEl = this.managerEl.createChild({
29249 cls : 'roo-document-manager-preview',
29253 tooltip : file[this.toolTipName],
29254 cls : 'roo-document-manager-thumb',
29255 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29260 html : '<i class="fa fa-times-circle"></i>'
29265 var close = previewEl.select('button.close', true).first();
29267 close.on('click', this.onRemove, this, file);
29269 file.target = previewEl;
29271 var image = previewEl.select('img', true).first();
29275 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29277 image.on('click', this.onClick, this, file);
29279 this.fireEvent('previewrendered', this, file);
29285 onPreviewLoad : function(file, image)
29287 if(typeof(file.target) == 'undefined' || !file.target){
29291 var width = image.dom.naturalWidth || image.dom.width;
29292 var height = image.dom.naturalHeight || image.dom.height;
29294 if(width > height){
29295 file.target.addClass('wide');
29299 file.target.addClass('tall');
29304 uploadFromSource : function(file, crop)
29306 this.xhr = new XMLHttpRequest();
29308 this.managerEl.createChild({
29310 cls : 'roo-document-manager-loading',
29314 tooltip : file.name,
29315 cls : 'roo-document-manager-thumb',
29316 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29322 this.xhr.open(this.method, this.url, true);
29325 "Accept": "application/json",
29326 "Cache-Control": "no-cache",
29327 "X-Requested-With": "XMLHttpRequest"
29330 for (var headerName in headers) {
29331 var headerValue = headers[headerName];
29333 this.xhr.setRequestHeader(headerName, headerValue);
29339 this.xhr.onload = function()
29341 _this.xhrOnLoad(_this.xhr);
29344 this.xhr.onerror = function()
29346 _this.xhrOnError(_this.xhr);
29349 var formData = new FormData();
29351 formData.append('returnHTML', 'NO');
29353 formData.append('crop', crop);
29355 if(typeof(file.filename) != 'undefined'){
29356 formData.append('filename', file.filename);
29359 if(typeof(file.mimetype) != 'undefined'){
29360 formData.append('mimetype', file.mimetype);
29365 if(this.fireEvent('prepare', this, formData) != false){
29366 this.xhr.send(formData);
29376 * @class Roo.bootstrap.DocumentViewer
29377 * @extends Roo.bootstrap.Component
29378 * Bootstrap DocumentViewer class
29379 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29380 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29383 * Create a new DocumentViewer
29384 * @param {Object} config The config object
29387 Roo.bootstrap.DocumentViewer = function(config){
29388 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29393 * Fire after initEvent
29394 * @param {Roo.bootstrap.DocumentViewer} this
29400 * @param {Roo.bootstrap.DocumentViewer} this
29405 * Fire after download button
29406 * @param {Roo.bootstrap.DocumentViewer} this
29411 * Fire after trash button
29412 * @param {Roo.bootstrap.DocumentViewer} this
29419 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29421 showDownload : true,
29425 getAutoCreate : function()
29429 cls : 'roo-document-viewer',
29433 cls : 'roo-document-viewer-body',
29437 cls : 'roo-document-viewer-thumb',
29441 cls : 'roo-document-viewer-image'
29449 cls : 'roo-document-viewer-footer',
29452 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29456 cls : 'btn-group roo-document-viewer-download',
29460 cls : 'btn btn-default',
29461 html : '<i class="fa fa-download"></i>'
29467 cls : 'btn-group roo-document-viewer-trash',
29471 cls : 'btn btn-default',
29472 html : '<i class="fa fa-trash"></i>'
29485 initEvents : function()
29487 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29488 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29490 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29491 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29493 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29494 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29496 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29497 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29499 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29500 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29502 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29503 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29505 this.bodyEl.on('click', this.onClick, this);
29506 this.downloadBtn.on('click', this.onDownload, this);
29507 this.trashBtn.on('click', this.onTrash, this);
29509 this.downloadBtn.hide();
29510 this.trashBtn.hide();
29512 if(this.showDownload){
29513 this.downloadBtn.show();
29516 if(this.showTrash){
29517 this.trashBtn.show();
29520 if(!this.showDownload && !this.showTrash) {
29521 this.footerEl.hide();
29526 initial : function()
29528 this.fireEvent('initial', this);
29532 onClick : function(e)
29534 e.preventDefault();
29536 this.fireEvent('click', this);
29539 onDownload : function(e)
29541 e.preventDefault();
29543 this.fireEvent('download', this);
29546 onTrash : function(e)
29548 e.preventDefault();
29550 this.fireEvent('trash', this);
29562 * @class Roo.bootstrap.NavProgressBar
29563 * @extends Roo.bootstrap.Component
29564 * Bootstrap NavProgressBar class
29567 * Create a new nav progress bar
29568 * @param {Object} config The config object
29571 Roo.bootstrap.NavProgressBar = function(config){
29572 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29574 this.bullets = this.bullets || [];
29576 // Roo.bootstrap.NavProgressBar.register(this);
29580 * Fires when the active item changes
29581 * @param {Roo.bootstrap.NavProgressBar} this
29582 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29583 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29590 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29595 getAutoCreate : function()
29597 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29601 cls : 'roo-navigation-bar-group',
29605 cls : 'roo-navigation-top-bar'
29609 cls : 'roo-navigation-bullets-bar',
29613 cls : 'roo-navigation-bar'
29620 cls : 'roo-navigation-bottom-bar'
29630 initEvents: function()
29635 onRender : function(ct, position)
29637 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29639 if(this.bullets.length){
29640 Roo.each(this.bullets, function(b){
29649 addItem : function(cfg)
29651 var item = new Roo.bootstrap.NavProgressItem(cfg);
29653 item.parentId = this.id;
29654 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29657 var top = new Roo.bootstrap.Element({
29659 cls : 'roo-navigation-bar-text'
29662 var bottom = new Roo.bootstrap.Element({
29664 cls : 'roo-navigation-bar-text'
29667 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29668 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29670 var topText = new Roo.bootstrap.Element({
29672 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29675 var bottomText = new Roo.bootstrap.Element({
29677 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29680 topText.onRender(top.el, null);
29681 bottomText.onRender(bottom.el, null);
29684 item.bottomEl = bottom;
29687 this.barItems.push(item);
29692 getActive : function()
29694 var active = false;
29696 Roo.each(this.barItems, function(v){
29698 if (!v.isActive()) {
29710 setActiveItem : function(item)
29714 Roo.each(this.barItems, function(v){
29715 if (v.rid == item.rid) {
29719 if (v.isActive()) {
29720 v.setActive(false);
29725 item.setActive(true);
29727 this.fireEvent('changed', this, item, prev);
29730 getBarItem: function(rid)
29734 Roo.each(this.barItems, function(e) {
29735 if (e.rid != rid) {
29746 indexOfItem : function(item)
29750 Roo.each(this.barItems, function(v, i){
29752 if (v.rid != item.rid) {
29763 setActiveNext : function()
29765 var i = this.indexOfItem(this.getActive());
29767 if (i > this.barItems.length) {
29771 this.setActiveItem(this.barItems[i+1]);
29774 setActivePrev : function()
29776 var i = this.indexOfItem(this.getActive());
29782 this.setActiveItem(this.barItems[i-1]);
29785 format : function()
29787 if(!this.barItems.length){
29791 var width = 100 / this.barItems.length;
29793 Roo.each(this.barItems, function(i){
29794 i.el.setStyle('width', width + '%');
29795 i.topEl.el.setStyle('width', width + '%');
29796 i.bottomEl.el.setStyle('width', width + '%');
29805 * Nav Progress Item
29810 * @class Roo.bootstrap.NavProgressItem
29811 * @extends Roo.bootstrap.Component
29812 * Bootstrap NavProgressItem class
29813 * @cfg {String} rid the reference id
29814 * @cfg {Boolean} active (true|false) Is item active default false
29815 * @cfg {Boolean} disabled (true|false) Is item active default false
29816 * @cfg {String} html
29817 * @cfg {String} position (top|bottom) text position default bottom
29818 * @cfg {String} icon show icon instead of number
29821 * Create a new NavProgressItem
29822 * @param {Object} config The config object
29824 Roo.bootstrap.NavProgressItem = function(config){
29825 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29830 * The raw click event for the entire grid.
29831 * @param {Roo.bootstrap.NavProgressItem} this
29832 * @param {Roo.EventObject} e
29839 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29845 position : 'bottom',
29848 getAutoCreate : function()
29850 var iconCls = 'roo-navigation-bar-item-icon';
29852 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29856 cls: 'roo-navigation-bar-item',
29866 cfg.cls += ' active';
29869 cfg.cls += ' disabled';
29875 disable : function()
29877 this.setDisabled(true);
29880 enable : function()
29882 this.setDisabled(false);
29885 initEvents: function()
29887 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29889 this.iconEl.on('click', this.onClick, this);
29892 onClick : function(e)
29894 e.preventDefault();
29900 if(this.fireEvent('click', this, e) === false){
29904 this.parent().setActiveItem(this);
29907 isActive: function ()
29909 return this.active;
29912 setActive : function(state)
29914 if(this.active == state){
29918 this.active = state;
29921 this.el.addClass('active');
29925 this.el.removeClass('active');
29930 setDisabled : function(state)
29932 if(this.disabled == state){
29936 this.disabled = state;
29939 this.el.addClass('disabled');
29943 this.el.removeClass('disabled');
29946 tooltipEl : function()
29948 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29961 * @class Roo.bootstrap.FieldLabel
29962 * @extends Roo.bootstrap.Component
29963 * Bootstrap FieldLabel class
29964 * @cfg {String} html contents of the element
29965 * @cfg {String} tag tag of the element default label
29966 * @cfg {String} cls class of the element
29967 * @cfg {String} target label target
29968 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29969 * @cfg {String} invalidClass default "text-warning"
29970 * @cfg {String} validClass default "text-success"
29971 * @cfg {String} iconTooltip default "This field is required"
29972 * @cfg {String} indicatorpos (left|right) default left
29975 * Create a new FieldLabel
29976 * @param {Object} config The config object
29979 Roo.bootstrap.FieldLabel = function(config){
29980 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29985 * Fires after the field has been marked as invalid.
29986 * @param {Roo.form.FieldLabel} this
29987 * @param {String} msg The validation message
29992 * Fires after the field has been validated with no errors.
29993 * @param {Roo.form.FieldLabel} this
29999 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30006 invalidClass : 'has-warning',
30007 validClass : 'has-success',
30008 iconTooltip : 'This field is required',
30009 indicatorpos : 'left',
30011 getAutoCreate : function(){
30015 cls : 'roo-bootstrap-field-label ' + this.cls,
30020 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30021 tooltip : this.iconTooltip
30030 if(this.indicatorpos == 'right'){
30033 cls : 'roo-bootstrap-field-label ' + this.cls,
30042 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30043 tooltip : this.iconTooltip
30052 initEvents: function()
30054 Roo.bootstrap.Element.superclass.initEvents.call(this);
30056 this.indicator = this.indicatorEl();
30058 if(this.indicator){
30059 this.indicator.removeClass('visible');
30060 this.indicator.addClass('invisible');
30063 Roo.bootstrap.FieldLabel.register(this);
30066 indicatorEl : function()
30068 var indicator = this.el.select('i.roo-required-indicator',true).first();
30079 * Mark this field as valid
30081 markValid : function()
30083 if(this.indicator){
30084 this.indicator.removeClass('visible');
30085 this.indicator.addClass('invisible');
30088 this.el.removeClass(this.invalidClass);
30090 this.el.addClass(this.validClass);
30092 this.fireEvent('valid', this);
30096 * Mark this field as invalid
30097 * @param {String} msg The validation message
30099 markInvalid : function(msg)
30101 if(this.indicator){
30102 this.indicator.removeClass('invisible');
30103 this.indicator.addClass('visible');
30106 this.el.removeClass(this.validClass);
30108 this.el.addClass(this.invalidClass);
30110 this.fireEvent('invalid', this, msg);
30116 Roo.apply(Roo.bootstrap.FieldLabel, {
30121 * register a FieldLabel Group
30122 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30124 register : function(label)
30126 if(this.groups.hasOwnProperty(label.target)){
30130 this.groups[label.target] = label;
30134 * fetch a FieldLabel Group based on the target
30135 * @param {string} target
30136 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30138 get: function(target) {
30139 if (typeof(this.groups[target]) == 'undefined') {
30143 return this.groups[target] ;
30152 * page DateSplitField.
30158 * @class Roo.bootstrap.DateSplitField
30159 * @extends Roo.bootstrap.Component
30160 * Bootstrap DateSplitField class
30161 * @cfg {string} fieldLabel - the label associated
30162 * @cfg {Number} labelWidth set the width of label (0-12)
30163 * @cfg {String} labelAlign (top|left)
30164 * @cfg {Boolean} dayAllowBlank (true|false) default false
30165 * @cfg {Boolean} monthAllowBlank (true|false) default false
30166 * @cfg {Boolean} yearAllowBlank (true|false) default false
30167 * @cfg {string} dayPlaceholder
30168 * @cfg {string} monthPlaceholder
30169 * @cfg {string} yearPlaceholder
30170 * @cfg {string} dayFormat default 'd'
30171 * @cfg {string} monthFormat default 'm'
30172 * @cfg {string} yearFormat default 'Y'
30173 * @cfg {Number} labellg set the width of label (1-12)
30174 * @cfg {Number} labelmd set the width of label (1-12)
30175 * @cfg {Number} labelsm set the width of label (1-12)
30176 * @cfg {Number} labelxs set the width of label (1-12)
30180 * Create a new DateSplitField
30181 * @param {Object} config The config object
30184 Roo.bootstrap.DateSplitField = function(config){
30185 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30191 * getting the data of years
30192 * @param {Roo.bootstrap.DateSplitField} this
30193 * @param {Object} years
30198 * getting the data of days
30199 * @param {Roo.bootstrap.DateSplitField} this
30200 * @param {Object} days
30205 * Fires after the field has been marked as invalid.
30206 * @param {Roo.form.Field} this
30207 * @param {String} msg The validation message
30212 * Fires after the field has been validated with no errors.
30213 * @param {Roo.form.Field} this
30219 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30222 labelAlign : 'top',
30224 dayAllowBlank : false,
30225 monthAllowBlank : false,
30226 yearAllowBlank : false,
30227 dayPlaceholder : '',
30228 monthPlaceholder : '',
30229 yearPlaceholder : '',
30233 isFormField : true,
30239 getAutoCreate : function()
30243 cls : 'row roo-date-split-field-group',
30248 cls : 'form-hidden-field roo-date-split-field-group-value',
30254 var labelCls = 'col-md-12';
30255 var contentCls = 'col-md-4';
30257 if(this.fieldLabel){
30261 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30265 html : this.fieldLabel
30270 if(this.labelAlign == 'left'){
30272 if(this.labelWidth > 12){
30273 label.style = "width: " + this.labelWidth + 'px';
30276 if(this.labelWidth < 13 && this.labelmd == 0){
30277 this.labelmd = this.labelWidth;
30280 if(this.labellg > 0){
30281 labelCls = ' col-lg-' + this.labellg;
30282 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30285 if(this.labelmd > 0){
30286 labelCls = ' col-md-' + this.labelmd;
30287 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30290 if(this.labelsm > 0){
30291 labelCls = ' col-sm-' + this.labelsm;
30292 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30295 if(this.labelxs > 0){
30296 labelCls = ' col-xs-' + this.labelxs;
30297 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30301 label.cls += ' ' + labelCls;
30303 cfg.cn.push(label);
30306 Roo.each(['day', 'month', 'year'], function(t){
30309 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30316 inputEl: function ()
30318 return this.el.select('.roo-date-split-field-group-value', true).first();
30321 onRender : function(ct, position)
30325 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30327 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30329 this.dayField = new Roo.bootstrap.ComboBox({
30330 allowBlank : this.dayAllowBlank,
30331 alwaysQuery : true,
30332 displayField : 'value',
30335 forceSelection : true,
30337 placeholder : this.dayPlaceholder,
30338 selectOnFocus : true,
30339 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30340 triggerAction : 'all',
30342 valueField : 'value',
30343 store : new Roo.data.SimpleStore({
30344 data : (function() {
30346 _this.fireEvent('days', _this, days);
30349 fields : [ 'value' ]
30352 select : function (_self, record, index)
30354 _this.setValue(_this.getValue());
30359 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30361 this.monthField = new Roo.bootstrap.MonthField({
30362 after : '<i class=\"fa fa-calendar\"></i>',
30363 allowBlank : this.monthAllowBlank,
30364 placeholder : this.monthPlaceholder,
30367 render : function (_self)
30369 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30370 e.preventDefault();
30374 select : function (_self, oldvalue, newvalue)
30376 _this.setValue(_this.getValue());
30381 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30383 this.yearField = new Roo.bootstrap.ComboBox({
30384 allowBlank : this.yearAllowBlank,
30385 alwaysQuery : true,
30386 displayField : 'value',
30389 forceSelection : true,
30391 placeholder : this.yearPlaceholder,
30392 selectOnFocus : true,
30393 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30394 triggerAction : 'all',
30396 valueField : 'value',
30397 store : new Roo.data.SimpleStore({
30398 data : (function() {
30400 _this.fireEvent('years', _this, years);
30403 fields : [ 'value' ]
30406 select : function (_self, record, index)
30408 _this.setValue(_this.getValue());
30413 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30416 setValue : function(v, format)
30418 this.inputEl.dom.value = v;
30420 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30422 var d = Date.parseDate(v, f);
30429 this.setDay(d.format(this.dayFormat));
30430 this.setMonth(d.format(this.monthFormat));
30431 this.setYear(d.format(this.yearFormat));
30438 setDay : function(v)
30440 this.dayField.setValue(v);
30441 this.inputEl.dom.value = this.getValue();
30446 setMonth : function(v)
30448 this.monthField.setValue(v, true);
30449 this.inputEl.dom.value = this.getValue();
30454 setYear : function(v)
30456 this.yearField.setValue(v);
30457 this.inputEl.dom.value = this.getValue();
30462 getDay : function()
30464 return this.dayField.getValue();
30467 getMonth : function()
30469 return this.monthField.getValue();
30472 getYear : function()
30474 return this.yearField.getValue();
30477 getValue : function()
30479 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30481 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30491 this.inputEl.dom.value = '';
30496 validate : function()
30498 var d = this.dayField.validate();
30499 var m = this.monthField.validate();
30500 var y = this.yearField.validate();
30505 (!this.dayAllowBlank && !d) ||
30506 (!this.monthAllowBlank && !m) ||
30507 (!this.yearAllowBlank && !y)
30512 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30521 this.markInvalid();
30526 markValid : function()
30529 var label = this.el.select('label', true).first();
30530 var icon = this.el.select('i.fa-star', true).first();
30536 this.fireEvent('valid', this);
30540 * Mark this field as invalid
30541 * @param {String} msg The validation message
30543 markInvalid : function(msg)
30546 var label = this.el.select('label', true).first();
30547 var icon = this.el.select('i.fa-star', true).first();
30549 if(label && !icon){
30550 this.el.select('.roo-date-split-field-label', true).createChild({
30552 cls : 'text-danger fa fa-lg fa-star',
30553 tooltip : 'This field is required',
30554 style : 'margin-right:5px;'
30558 this.fireEvent('invalid', this, msg);
30561 clearInvalid : function()
30563 var label = this.el.select('label', true).first();
30564 var icon = this.el.select('i.fa-star', true).first();
30570 this.fireEvent('valid', this);
30573 getName: function()
30583 * http://masonry.desandro.com
30585 * The idea is to render all the bricks based on vertical width...
30587 * The original code extends 'outlayer' - we might need to use that....
30593 * @class Roo.bootstrap.LayoutMasonry
30594 * @extends Roo.bootstrap.Component
30595 * Bootstrap Layout Masonry class
30598 * Create a new Element
30599 * @param {Object} config The config object
30602 Roo.bootstrap.LayoutMasonry = function(config){
30604 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30608 Roo.bootstrap.LayoutMasonry.register(this);
30614 * Fire after layout the items
30615 * @param {Roo.bootstrap.LayoutMasonry} this
30616 * @param {Roo.EventObject} e
30623 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30626 * @cfg {Boolean} isLayoutInstant = no animation?
30628 isLayoutInstant : false, // needed?
30631 * @cfg {Number} boxWidth width of the columns
30636 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30641 * @cfg {Number} padWidth padding below box..
30646 * @cfg {Number} gutter gutter width..
30651 * @cfg {Number} maxCols maximum number of columns
30657 * @cfg {Boolean} isAutoInitial defalut true
30659 isAutoInitial : true,
30664 * @cfg {Boolean} isHorizontal defalut false
30666 isHorizontal : false,
30668 currentSize : null,
30674 bricks: null, //CompositeElement
30678 _isLayoutInited : false,
30680 // isAlternative : false, // only use for vertical layout...
30683 * @cfg {Number} alternativePadWidth padding below box..
30685 alternativePadWidth : 50,
30687 selectedBrick : [],
30689 getAutoCreate : function(){
30691 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30695 cls: 'blog-masonary-wrapper ' + this.cls,
30697 cls : 'mas-boxes masonary'
30704 getChildContainer: function( )
30706 if (this.boxesEl) {
30707 return this.boxesEl;
30710 this.boxesEl = this.el.select('.mas-boxes').first();
30712 return this.boxesEl;
30716 initEvents : function()
30720 if(this.isAutoInitial){
30721 Roo.log('hook children rendered');
30722 this.on('childrenrendered', function() {
30723 Roo.log('children rendered');
30729 initial : function()
30731 this.selectedBrick = [];
30733 this.currentSize = this.el.getBox(true);
30735 Roo.EventManager.onWindowResize(this.resize, this);
30737 if(!this.isAutoInitial){
30745 //this.layout.defer(500,this);
30749 resize : function()
30751 var cs = this.el.getBox(true);
30754 this.currentSize.width == cs.width &&
30755 this.currentSize.x == cs.x &&
30756 this.currentSize.height == cs.height &&
30757 this.currentSize.y == cs.y
30759 Roo.log("no change in with or X or Y");
30763 this.currentSize = cs;
30769 layout : function()
30771 this._resetLayout();
30773 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30775 this.layoutItems( isInstant );
30777 this._isLayoutInited = true;
30779 this.fireEvent('layout', this);
30783 _resetLayout : function()
30785 if(this.isHorizontal){
30786 this.horizontalMeasureColumns();
30790 this.verticalMeasureColumns();
30794 verticalMeasureColumns : function()
30796 this.getContainerWidth();
30798 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30799 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30803 var boxWidth = this.boxWidth + this.padWidth;
30805 if(this.containerWidth < this.boxWidth){
30806 boxWidth = this.containerWidth
30809 var containerWidth = this.containerWidth;
30811 var cols = Math.floor(containerWidth / boxWidth);
30813 this.cols = Math.max( cols, 1 );
30815 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30817 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30819 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30821 this.colWidth = boxWidth + avail - this.padWidth;
30823 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30824 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30827 horizontalMeasureColumns : function()
30829 this.getContainerWidth();
30831 var boxWidth = this.boxWidth;
30833 if(this.containerWidth < boxWidth){
30834 boxWidth = this.containerWidth;
30837 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30839 this.el.setHeight(boxWidth);
30843 getContainerWidth : function()
30845 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30848 layoutItems : function( isInstant )
30850 Roo.log(this.bricks);
30852 var items = Roo.apply([], this.bricks);
30854 if(this.isHorizontal){
30855 this._horizontalLayoutItems( items , isInstant );
30859 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30860 // this._verticalAlternativeLayoutItems( items , isInstant );
30864 this._verticalLayoutItems( items , isInstant );
30868 _verticalLayoutItems : function ( items , isInstant)
30870 if ( !items || !items.length ) {
30875 ['xs', 'xs', 'xs', 'tall'],
30876 ['xs', 'xs', 'tall'],
30877 ['xs', 'xs', 'sm'],
30878 ['xs', 'xs', 'xs'],
30884 ['sm', 'xs', 'xs'],
30888 ['tall', 'xs', 'xs', 'xs'],
30889 ['tall', 'xs', 'xs'],
30901 Roo.each(items, function(item, k){
30903 switch (item.size) {
30904 // these layouts take up a full box,
30915 boxes.push([item]);
30938 var filterPattern = function(box, length)
30946 var pattern = box.slice(0, length);
30950 Roo.each(pattern, function(i){
30951 format.push(i.size);
30954 Roo.each(standard, function(s){
30956 if(String(s) != String(format)){
30965 if(!match && length == 1){
30970 filterPattern(box, length - 1);
30974 queue.push(pattern);
30976 box = box.slice(length, box.length);
30978 filterPattern(box, 4);
30984 Roo.each(boxes, function(box, k){
30990 if(box.length == 1){
30995 filterPattern(box, 4);
30999 this._processVerticalLayoutQueue( queue, isInstant );
31003 // _verticalAlternativeLayoutItems : function( items , isInstant )
31005 // if ( !items || !items.length ) {
31009 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31013 _horizontalLayoutItems : function ( items , isInstant)
31015 if ( !items || !items.length || items.length < 3) {
31021 var eItems = items.slice(0, 3);
31023 items = items.slice(3, items.length);
31026 ['xs', 'xs', 'xs', 'wide'],
31027 ['xs', 'xs', 'wide'],
31028 ['xs', 'xs', 'sm'],
31029 ['xs', 'xs', 'xs'],
31035 ['sm', 'xs', 'xs'],
31039 ['wide', 'xs', 'xs', 'xs'],
31040 ['wide', 'xs', 'xs'],
31053 Roo.each(items, function(item, k){
31055 switch (item.size) {
31066 boxes.push([item]);
31090 var filterPattern = function(box, length)
31098 var pattern = box.slice(0, length);
31102 Roo.each(pattern, function(i){
31103 format.push(i.size);
31106 Roo.each(standard, function(s){
31108 if(String(s) != String(format)){
31117 if(!match && length == 1){
31122 filterPattern(box, length - 1);
31126 queue.push(pattern);
31128 box = box.slice(length, box.length);
31130 filterPattern(box, 4);
31136 Roo.each(boxes, function(box, k){
31142 if(box.length == 1){
31147 filterPattern(box, 4);
31154 var pos = this.el.getBox(true);
31158 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31160 var hit_end = false;
31162 Roo.each(queue, function(box){
31166 Roo.each(box, function(b){
31168 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31178 Roo.each(box, function(b){
31180 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31183 mx = Math.max(mx, b.x);
31187 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31191 Roo.each(box, function(b){
31193 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31207 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31210 /** Sets position of item in DOM
31211 * @param {Element} item
31212 * @param {Number} x - horizontal position
31213 * @param {Number} y - vertical position
31214 * @param {Boolean} isInstant - disables transitions
31216 _processVerticalLayoutQueue : function( queue, isInstant )
31218 var pos = this.el.getBox(true);
31223 for (var i = 0; i < this.cols; i++){
31227 Roo.each(queue, function(box, k){
31229 var col = k % this.cols;
31231 Roo.each(box, function(b,kk){
31233 b.el.position('absolute');
31235 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31236 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31238 if(b.size == 'md-left' || b.size == 'md-right'){
31239 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31240 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31243 b.el.setWidth(width);
31244 b.el.setHeight(height);
31246 b.el.select('iframe',true).setSize(width,height);
31250 for (var i = 0; i < this.cols; i++){
31252 if(maxY[i] < maxY[col]){
31257 col = Math.min(col, i);
31261 x = pos.x + col * (this.colWidth + this.padWidth);
31265 var positions = [];
31267 switch (box.length){
31269 positions = this.getVerticalOneBoxColPositions(x, y, box);
31272 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31275 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31278 positions = this.getVerticalFourBoxColPositions(x, y, box);
31284 Roo.each(box, function(b,kk){
31286 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31288 var sz = b.el.getSize();
31290 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31298 for (var i = 0; i < this.cols; i++){
31299 mY = Math.max(mY, maxY[i]);
31302 this.el.setHeight(mY - pos.y);
31306 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31308 // var pos = this.el.getBox(true);
31311 // var maxX = pos.right;
31313 // var maxHeight = 0;
31315 // Roo.each(items, function(item, k){
31319 // item.el.position('absolute');
31321 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31323 // item.el.setWidth(width);
31325 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31327 // item.el.setHeight(height);
31330 // item.el.setXY([x, y], isInstant ? false : true);
31332 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31335 // y = y + height + this.alternativePadWidth;
31337 // maxHeight = maxHeight + height + this.alternativePadWidth;
31341 // this.el.setHeight(maxHeight);
31345 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31347 var pos = this.el.getBox(true);
31352 var maxX = pos.right;
31354 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31356 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31358 Roo.each(queue, function(box, k){
31360 Roo.each(box, function(b, kk){
31362 b.el.position('absolute');
31364 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31365 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31367 if(b.size == 'md-left' || b.size == 'md-right'){
31368 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31369 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31372 b.el.setWidth(width);
31373 b.el.setHeight(height);
31381 var positions = [];
31383 switch (box.length){
31385 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31388 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31391 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31394 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31400 Roo.each(box, function(b,kk){
31402 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31404 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31412 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31414 Roo.each(eItems, function(b,k){
31416 b.size = (k == 0) ? 'sm' : 'xs';
31417 b.x = (k == 0) ? 2 : 1;
31418 b.y = (k == 0) ? 2 : 1;
31420 b.el.position('absolute');
31422 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31424 b.el.setWidth(width);
31426 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31428 b.el.setHeight(height);
31432 var positions = [];
31435 x : maxX - this.unitWidth * 2 - this.gutter,
31440 x : maxX - this.unitWidth,
31441 y : minY + (this.unitWidth + this.gutter) * 2
31445 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31449 Roo.each(eItems, function(b,k){
31451 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31457 getVerticalOneBoxColPositions : function(x, y, box)
31461 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31463 if(box[0].size == 'md-left'){
31467 if(box[0].size == 'md-right'){
31472 x : x + (this.unitWidth + this.gutter) * rand,
31479 getVerticalTwoBoxColPositions : function(x, y, box)
31483 if(box[0].size == 'xs'){
31487 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31491 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31505 x : x + (this.unitWidth + this.gutter) * 2,
31506 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31513 getVerticalThreeBoxColPositions : function(x, y, box)
31517 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31525 x : x + (this.unitWidth + this.gutter) * 1,
31530 x : x + (this.unitWidth + this.gutter) * 2,
31538 if(box[0].size == 'xs' && box[1].size == 'xs'){
31547 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31551 x : x + (this.unitWidth + this.gutter) * 1,
31565 x : x + (this.unitWidth + this.gutter) * 2,
31570 x : x + (this.unitWidth + this.gutter) * 2,
31571 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31578 getVerticalFourBoxColPositions : function(x, y, box)
31582 if(box[0].size == 'xs'){
31591 y : y + (this.unitHeight + this.gutter) * 1
31596 y : y + (this.unitHeight + this.gutter) * 2
31600 x : x + (this.unitWidth + this.gutter) * 1,
31614 x : x + (this.unitWidth + this.gutter) * 2,
31619 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31620 y : y + (this.unitHeight + this.gutter) * 1
31624 x : x + (this.unitWidth + this.gutter) * 2,
31625 y : y + (this.unitWidth + this.gutter) * 2
31632 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31636 if(box[0].size == 'md-left'){
31638 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31645 if(box[0].size == 'md-right'){
31647 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31648 y : minY + (this.unitWidth + this.gutter) * 1
31654 var rand = Math.floor(Math.random() * (4 - box[0].y));
31657 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31658 y : minY + (this.unitWidth + this.gutter) * rand
31665 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31669 if(box[0].size == 'xs'){
31672 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31677 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31678 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31686 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31691 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31692 y : minY + (this.unitWidth + this.gutter) * 2
31699 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31703 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31706 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31711 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31712 y : minY + (this.unitWidth + this.gutter) * 1
31716 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31717 y : minY + (this.unitWidth + this.gutter) * 2
31724 if(box[0].size == 'xs' && box[1].size == 'xs'){
31727 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31732 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31737 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31738 y : minY + (this.unitWidth + this.gutter) * 1
31746 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31751 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31752 y : minY + (this.unitWidth + this.gutter) * 2
31756 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31757 y : minY + (this.unitWidth + this.gutter) * 2
31764 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31768 if(box[0].size == 'xs'){
31771 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31776 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31781 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),
31786 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31787 y : minY + (this.unitWidth + this.gutter) * 1
31795 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31800 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31801 y : minY + (this.unitWidth + this.gutter) * 2
31805 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31806 y : minY + (this.unitWidth + this.gutter) * 2
31810 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),
31811 y : minY + (this.unitWidth + this.gutter) * 2
31819 * remove a Masonry Brick
31820 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31822 removeBrick : function(brick_id)
31828 for (var i = 0; i<this.bricks.length; i++) {
31829 if (this.bricks[i].id == brick_id) {
31830 this.bricks.splice(i,1);
31831 this.el.dom.removeChild(Roo.get(brick_id).dom);
31838 * adds a Masonry Brick
31839 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31841 addBrick : function(cfg)
31843 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31844 //this.register(cn);
31845 cn.parentId = this.id;
31846 cn.onRender(this.el, null);
31851 * register a Masonry Brick
31852 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31855 register : function(brick)
31857 this.bricks.push(brick);
31858 brick.masonryId = this.id;
31862 * clear all the Masonry Brick
31864 clearAll : function()
31867 //this.getChildContainer().dom.innerHTML = "";
31868 this.el.dom.innerHTML = '';
31871 getSelected : function()
31873 if (!this.selectedBrick) {
31877 return this.selectedBrick;
31881 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31885 * register a Masonry Layout
31886 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31889 register : function(layout)
31891 this.groups[layout.id] = layout;
31894 * fetch a Masonry Layout based on the masonry layout ID
31895 * @param {string} the masonry layout to add
31896 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31899 get: function(layout_id) {
31900 if (typeof(this.groups[layout_id]) == 'undefined') {
31903 return this.groups[layout_id] ;
31915 * http://masonry.desandro.com
31917 * The idea is to render all the bricks based on vertical width...
31919 * The original code extends 'outlayer' - we might need to use that....
31925 * @class Roo.bootstrap.LayoutMasonryAuto
31926 * @extends Roo.bootstrap.Component
31927 * Bootstrap Layout Masonry class
31930 * Create a new Element
31931 * @param {Object} config The config object
31934 Roo.bootstrap.LayoutMasonryAuto = function(config){
31935 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31938 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31941 * @cfg {Boolean} isFitWidth - resize the width..
31943 isFitWidth : false, // options..
31945 * @cfg {Boolean} isOriginLeft = left align?
31947 isOriginLeft : true,
31949 * @cfg {Boolean} isOriginTop = top align?
31951 isOriginTop : false,
31953 * @cfg {Boolean} isLayoutInstant = no animation?
31955 isLayoutInstant : false, // needed?
31957 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31959 isResizingContainer : true,
31961 * @cfg {Number} columnWidth width of the columns
31967 * @cfg {Number} maxCols maximum number of columns
31972 * @cfg {Number} padHeight padding below box..
31978 * @cfg {Boolean} isAutoInitial defalut true
31981 isAutoInitial : true,
31987 initialColumnWidth : 0,
31988 currentSize : null,
31990 colYs : null, // array.
31997 bricks: null, //CompositeElement
31998 cols : 0, // array?
31999 // element : null, // wrapped now this.el
32000 _isLayoutInited : null,
32003 getAutoCreate : function(){
32007 cls: 'blog-masonary-wrapper ' + this.cls,
32009 cls : 'mas-boxes masonary'
32016 getChildContainer: function( )
32018 if (this.boxesEl) {
32019 return this.boxesEl;
32022 this.boxesEl = this.el.select('.mas-boxes').first();
32024 return this.boxesEl;
32028 initEvents : function()
32032 if(this.isAutoInitial){
32033 Roo.log('hook children rendered');
32034 this.on('childrenrendered', function() {
32035 Roo.log('children rendered');
32042 initial : function()
32044 this.reloadItems();
32046 this.currentSize = this.el.getBox(true);
32048 /// was window resize... - let's see if this works..
32049 Roo.EventManager.onWindowResize(this.resize, this);
32051 if(!this.isAutoInitial){
32056 this.layout.defer(500,this);
32059 reloadItems: function()
32061 this.bricks = this.el.select('.masonry-brick', true);
32063 this.bricks.each(function(b) {
32064 //Roo.log(b.getSize());
32065 if (!b.attr('originalwidth')) {
32066 b.attr('originalwidth', b.getSize().width);
32071 Roo.log(this.bricks.elements.length);
32074 resize : function()
32077 var cs = this.el.getBox(true);
32079 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32080 Roo.log("no change in with or X");
32083 this.currentSize = cs;
32087 layout : function()
32090 this._resetLayout();
32091 //this._manageStamps();
32093 // don't animate first layout
32094 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32095 this.layoutItems( isInstant );
32097 // flag for initalized
32098 this._isLayoutInited = true;
32101 layoutItems : function( isInstant )
32103 //var items = this._getItemsForLayout( this.items );
32104 // original code supports filtering layout items.. we just ignore it..
32106 this._layoutItems( this.bricks , isInstant );
32108 this._postLayout();
32110 _layoutItems : function ( items , isInstant)
32112 //this.fireEvent( 'layout', this, items );
32115 if ( !items || !items.elements.length ) {
32116 // no items, emit event with empty array
32121 items.each(function(item) {
32122 Roo.log("layout item");
32124 // get x/y object from method
32125 var position = this._getItemLayoutPosition( item );
32127 position.item = item;
32128 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32129 queue.push( position );
32132 this._processLayoutQueue( queue );
32134 /** Sets position of item in DOM
32135 * @param {Element} item
32136 * @param {Number} x - horizontal position
32137 * @param {Number} y - vertical position
32138 * @param {Boolean} isInstant - disables transitions
32140 _processLayoutQueue : function( queue )
32142 for ( var i=0, len = queue.length; i < len; i++ ) {
32143 var obj = queue[i];
32144 obj.item.position('absolute');
32145 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32151 * Any logic you want to do after each layout,
32152 * i.e. size the container
32154 _postLayout : function()
32156 this.resizeContainer();
32159 resizeContainer : function()
32161 if ( !this.isResizingContainer ) {
32164 var size = this._getContainerSize();
32166 this.el.setSize(size.width,size.height);
32167 this.boxesEl.setSize(size.width,size.height);
32173 _resetLayout : function()
32175 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32176 this.colWidth = this.el.getWidth();
32177 //this.gutter = this.el.getWidth();
32179 this.measureColumns();
32185 this.colYs.push( 0 );
32191 measureColumns : function()
32193 this.getContainerWidth();
32194 // if columnWidth is 0, default to outerWidth of first item
32195 if ( !this.columnWidth ) {
32196 var firstItem = this.bricks.first();
32197 Roo.log(firstItem);
32198 this.columnWidth = this.containerWidth;
32199 if (firstItem && firstItem.attr('originalwidth') ) {
32200 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32202 // columnWidth fall back to item of first element
32203 Roo.log("set column width?");
32204 this.initialColumnWidth = this.columnWidth ;
32206 // if first elem has no width, default to size of container
32211 if (this.initialColumnWidth) {
32212 this.columnWidth = this.initialColumnWidth;
32217 // column width is fixed at the top - however if container width get's smaller we should
32220 // this bit calcs how man columns..
32222 var columnWidth = this.columnWidth += this.gutter;
32224 // calculate columns
32225 var containerWidth = this.containerWidth + this.gutter;
32227 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32228 // fix rounding errors, typically with gutters
32229 var excess = columnWidth - containerWidth % columnWidth;
32232 // if overshoot is less than a pixel, round up, otherwise floor it
32233 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32234 cols = Math[ mathMethod ]( cols );
32235 this.cols = Math.max( cols, 1 );
32236 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32238 // padding positioning..
32239 var totalColWidth = this.cols * this.columnWidth;
32240 var padavail = this.containerWidth - totalColWidth;
32241 // so for 2 columns - we need 3 'pads'
32243 var padNeeded = (1+this.cols) * this.padWidth;
32245 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32247 this.columnWidth += padExtra
32248 //this.padWidth = Math.floor(padavail / ( this.cols));
32250 // adjust colum width so that padding is fixed??
32252 // we have 3 columns ... total = width * 3
32253 // we have X left over... that should be used by
32255 //if (this.expandC) {
32263 getContainerWidth : function()
32265 /* // container is parent if fit width
32266 var container = this.isFitWidth ? this.element.parentNode : this.element;
32267 // check that this.size and size are there
32268 // IE8 triggers resize on body size change, so they might not be
32270 var size = getSize( container ); //FIXME
32271 this.containerWidth = size && size.innerWidth; //FIXME
32274 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32278 _getItemLayoutPosition : function( item ) // what is item?
32280 // we resize the item to our columnWidth..
32282 item.setWidth(this.columnWidth);
32283 item.autoBoxAdjust = false;
32285 var sz = item.getSize();
32287 // how many columns does this brick span
32288 var remainder = this.containerWidth % this.columnWidth;
32290 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32291 // round if off by 1 pixel, otherwise use ceil
32292 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32293 colSpan = Math.min( colSpan, this.cols );
32295 // normally this should be '1' as we dont' currently allow multi width columns..
32297 var colGroup = this._getColGroup( colSpan );
32298 // get the minimum Y value from the columns
32299 var minimumY = Math.min.apply( Math, colGroup );
32300 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32302 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32304 // position the brick
32306 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32307 y: this.currentSize.y + minimumY + this.padHeight
32311 // apply setHeight to necessary columns
32312 var setHeight = minimumY + sz.height + this.padHeight;
32313 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32315 var setSpan = this.cols + 1 - colGroup.length;
32316 for ( var i = 0; i < setSpan; i++ ) {
32317 this.colYs[ shortColIndex + i ] = setHeight ;
32324 * @param {Number} colSpan - number of columns the element spans
32325 * @returns {Array} colGroup
32327 _getColGroup : function( colSpan )
32329 if ( colSpan < 2 ) {
32330 // if brick spans only one column, use all the column Ys
32335 // how many different places could this brick fit horizontally
32336 var groupCount = this.cols + 1 - colSpan;
32337 // for each group potential horizontal position
32338 for ( var i = 0; i < groupCount; i++ ) {
32339 // make an array of colY values for that one group
32340 var groupColYs = this.colYs.slice( i, i + colSpan );
32341 // and get the max value of the array
32342 colGroup[i] = Math.max.apply( Math, groupColYs );
32347 _manageStamp : function( stamp )
32349 var stampSize = stamp.getSize();
32350 var offset = stamp.getBox();
32351 // get the columns that this stamp affects
32352 var firstX = this.isOriginLeft ? offset.x : offset.right;
32353 var lastX = firstX + stampSize.width;
32354 var firstCol = Math.floor( firstX / this.columnWidth );
32355 firstCol = Math.max( 0, firstCol );
32357 var lastCol = Math.floor( lastX / this.columnWidth );
32358 // lastCol should not go over if multiple of columnWidth #425
32359 lastCol -= lastX % this.columnWidth ? 0 : 1;
32360 lastCol = Math.min( this.cols - 1, lastCol );
32362 // set colYs to bottom of the stamp
32363 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32366 for ( var i = firstCol; i <= lastCol; i++ ) {
32367 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32372 _getContainerSize : function()
32374 this.maxY = Math.max.apply( Math, this.colYs );
32379 if ( this.isFitWidth ) {
32380 size.width = this._getContainerFitWidth();
32386 _getContainerFitWidth : function()
32388 var unusedCols = 0;
32389 // count unused columns
32392 if ( this.colYs[i] !== 0 ) {
32397 // fit container to columns that have been used
32398 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32401 needsResizeLayout : function()
32403 var previousWidth = this.containerWidth;
32404 this.getContainerWidth();
32405 return previousWidth !== this.containerWidth;
32420 * @class Roo.bootstrap.MasonryBrick
32421 * @extends Roo.bootstrap.Component
32422 * Bootstrap MasonryBrick class
32425 * Create a new MasonryBrick
32426 * @param {Object} config The config object
32429 Roo.bootstrap.MasonryBrick = function(config){
32431 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32433 Roo.bootstrap.MasonryBrick.register(this);
32439 * When a MasonryBrick is clcik
32440 * @param {Roo.bootstrap.MasonryBrick} this
32441 * @param {Roo.EventObject} e
32447 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32450 * @cfg {String} title
32454 * @cfg {String} html
32458 * @cfg {String} bgimage
32462 * @cfg {String} videourl
32466 * @cfg {String} cls
32470 * @cfg {String} href
32474 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32479 * @cfg {String} placetitle (center|bottom)
32484 * @cfg {Boolean} isFitContainer defalut true
32486 isFitContainer : true,
32489 * @cfg {Boolean} preventDefault defalut false
32491 preventDefault : false,
32494 * @cfg {Boolean} inverse defalut false
32496 maskInverse : false,
32498 getAutoCreate : function()
32500 if(!this.isFitContainer){
32501 return this.getSplitAutoCreate();
32504 var cls = 'masonry-brick masonry-brick-full';
32506 if(this.href.length){
32507 cls += ' masonry-brick-link';
32510 if(this.bgimage.length){
32511 cls += ' masonry-brick-image';
32514 if(this.maskInverse){
32515 cls += ' mask-inverse';
32518 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32519 cls += ' enable-mask';
32523 cls += ' masonry-' + this.size + '-brick';
32526 if(this.placetitle.length){
32528 switch (this.placetitle) {
32530 cls += ' masonry-center-title';
32533 cls += ' masonry-bottom-title';
32540 if(!this.html.length && !this.bgimage.length){
32541 cls += ' masonry-center-title';
32544 if(!this.html.length && this.bgimage.length){
32545 cls += ' masonry-bottom-title';
32550 cls += ' ' + this.cls;
32554 tag: (this.href.length) ? 'a' : 'div',
32559 cls: 'masonry-brick-mask'
32563 cls: 'masonry-brick-paragraph',
32569 if(this.href.length){
32570 cfg.href = this.href;
32573 var cn = cfg.cn[1].cn;
32575 if(this.title.length){
32578 cls: 'masonry-brick-title',
32583 if(this.html.length){
32586 cls: 'masonry-brick-text',
32591 if (!this.title.length && !this.html.length) {
32592 cfg.cn[1].cls += ' hide';
32595 if(this.bgimage.length){
32598 cls: 'masonry-brick-image-view',
32603 if(this.videourl.length){
32604 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32605 // youtube support only?
32608 cls: 'masonry-brick-image-view',
32611 allowfullscreen : true
32619 getSplitAutoCreate : function()
32621 var cls = 'masonry-brick masonry-brick-split';
32623 if(this.href.length){
32624 cls += ' masonry-brick-link';
32627 if(this.bgimage.length){
32628 cls += ' masonry-brick-image';
32632 cls += ' masonry-' + this.size + '-brick';
32635 switch (this.placetitle) {
32637 cls += ' masonry-center-title';
32640 cls += ' masonry-bottom-title';
32643 if(!this.bgimage.length){
32644 cls += ' masonry-center-title';
32647 if(this.bgimage.length){
32648 cls += ' masonry-bottom-title';
32654 cls += ' ' + this.cls;
32658 tag: (this.href.length) ? 'a' : 'div',
32663 cls: 'masonry-brick-split-head',
32667 cls: 'masonry-brick-paragraph',
32674 cls: 'masonry-brick-split-body',
32680 if(this.href.length){
32681 cfg.href = this.href;
32684 if(this.title.length){
32685 cfg.cn[0].cn[0].cn.push({
32687 cls: 'masonry-brick-title',
32692 if(this.html.length){
32693 cfg.cn[1].cn.push({
32695 cls: 'masonry-brick-text',
32700 if(this.bgimage.length){
32701 cfg.cn[0].cn.push({
32703 cls: 'masonry-brick-image-view',
32708 if(this.videourl.length){
32709 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32710 // youtube support only?
32711 cfg.cn[0].cn.cn.push({
32713 cls: 'masonry-brick-image-view',
32716 allowfullscreen : true
32723 initEvents: function()
32725 switch (this.size) {
32758 this.el.on('touchstart', this.onTouchStart, this);
32759 this.el.on('touchmove', this.onTouchMove, this);
32760 this.el.on('touchend', this.onTouchEnd, this);
32761 this.el.on('contextmenu', this.onContextMenu, this);
32763 this.el.on('mouseenter' ,this.enter, this);
32764 this.el.on('mouseleave', this.leave, this);
32765 this.el.on('click', this.onClick, this);
32768 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32769 this.parent().bricks.push(this);
32774 onClick: function(e, el)
32776 var time = this.endTimer - this.startTimer;
32777 // Roo.log(e.preventDefault());
32780 e.preventDefault();
32785 if(!this.preventDefault){
32789 e.preventDefault();
32791 if (this.activeClass != '') {
32792 this.selectBrick();
32795 this.fireEvent('click', this, e);
32798 enter: function(e, el)
32800 e.preventDefault();
32802 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32806 if(this.bgimage.length && this.html.length){
32807 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32811 leave: function(e, el)
32813 e.preventDefault();
32815 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32819 if(this.bgimage.length && this.html.length){
32820 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32824 onTouchStart: function(e, el)
32826 // e.preventDefault();
32828 this.touchmoved = false;
32830 if(!this.isFitContainer){
32834 if(!this.bgimage.length || !this.html.length){
32838 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32840 this.timer = new Date().getTime();
32844 onTouchMove: function(e, el)
32846 this.touchmoved = true;
32849 onContextMenu : function(e,el)
32851 e.preventDefault();
32852 e.stopPropagation();
32856 onTouchEnd: function(e, el)
32858 // e.preventDefault();
32860 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32867 if(!this.bgimage.length || !this.html.length){
32869 if(this.href.length){
32870 window.location.href = this.href;
32876 if(!this.isFitContainer){
32880 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32882 window.location.href = this.href;
32885 //selection on single brick only
32886 selectBrick : function() {
32888 if (!this.parentId) {
32892 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32893 var index = m.selectedBrick.indexOf(this.id);
32896 m.selectedBrick.splice(index,1);
32897 this.el.removeClass(this.activeClass);
32901 for(var i = 0; i < m.selectedBrick.length; i++) {
32902 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32903 b.el.removeClass(b.activeClass);
32906 m.selectedBrick = [];
32908 m.selectedBrick.push(this.id);
32909 this.el.addClass(this.activeClass);
32913 isSelected : function(){
32914 return this.el.hasClass(this.activeClass);
32919 Roo.apply(Roo.bootstrap.MasonryBrick, {
32922 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32924 * register a Masonry Brick
32925 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32928 register : function(brick)
32930 //this.groups[brick.id] = brick;
32931 this.groups.add(brick.id, brick);
32934 * fetch a masonry brick based on the masonry brick ID
32935 * @param {string} the masonry brick to add
32936 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32939 get: function(brick_id)
32941 // if (typeof(this.groups[brick_id]) == 'undefined') {
32944 // return this.groups[brick_id] ;
32946 if(this.groups.key(brick_id)) {
32947 return this.groups.key(brick_id);
32965 * @class Roo.bootstrap.Brick
32966 * @extends Roo.bootstrap.Component
32967 * Bootstrap Brick class
32970 * Create a new Brick
32971 * @param {Object} config The config object
32974 Roo.bootstrap.Brick = function(config){
32975 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32981 * When a Brick is click
32982 * @param {Roo.bootstrap.Brick} this
32983 * @param {Roo.EventObject} e
32989 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32992 * @cfg {String} title
32996 * @cfg {String} html
33000 * @cfg {String} bgimage
33004 * @cfg {String} cls
33008 * @cfg {String} href
33012 * @cfg {String} video
33016 * @cfg {Boolean} square
33020 getAutoCreate : function()
33022 var cls = 'roo-brick';
33024 if(this.href.length){
33025 cls += ' roo-brick-link';
33028 if(this.bgimage.length){
33029 cls += ' roo-brick-image';
33032 if(!this.html.length && !this.bgimage.length){
33033 cls += ' roo-brick-center-title';
33036 if(!this.html.length && this.bgimage.length){
33037 cls += ' roo-brick-bottom-title';
33041 cls += ' ' + this.cls;
33045 tag: (this.href.length) ? 'a' : 'div',
33050 cls: 'roo-brick-paragraph',
33056 if(this.href.length){
33057 cfg.href = this.href;
33060 var cn = cfg.cn[0].cn;
33062 if(this.title.length){
33065 cls: 'roo-brick-title',
33070 if(this.html.length){
33073 cls: 'roo-brick-text',
33080 if(this.bgimage.length){
33083 cls: 'roo-brick-image-view',
33091 initEvents: function()
33093 if(this.title.length || this.html.length){
33094 this.el.on('mouseenter' ,this.enter, this);
33095 this.el.on('mouseleave', this.leave, this);
33098 Roo.EventManager.onWindowResize(this.resize, this);
33100 if(this.bgimage.length){
33101 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33102 this.imageEl.on('load', this.onImageLoad, this);
33109 onImageLoad : function()
33114 resize : function()
33116 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33118 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33120 if(this.bgimage.length){
33121 var image = this.el.select('.roo-brick-image-view', true).first();
33123 image.setWidth(paragraph.getWidth());
33126 image.setHeight(paragraph.getWidth());
33129 this.el.setHeight(image.getHeight());
33130 paragraph.setHeight(image.getHeight());
33136 enter: function(e, el)
33138 e.preventDefault();
33140 if(this.bgimage.length){
33141 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33142 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33146 leave: function(e, el)
33148 e.preventDefault();
33150 if(this.bgimage.length){
33151 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33152 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33167 * @class Roo.bootstrap.NumberField
33168 * @extends Roo.bootstrap.Input
33169 * Bootstrap NumberField class
33175 * Create a new NumberField
33176 * @param {Object} config The config object
33179 Roo.bootstrap.NumberField = function(config){
33180 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33183 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33186 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33188 allowDecimals : true,
33190 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33192 decimalSeparator : ".",
33194 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33196 decimalPrecision : 2,
33198 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33200 allowNegative : true,
33203 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33207 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33209 minValue : Number.NEGATIVE_INFINITY,
33211 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33213 maxValue : Number.MAX_VALUE,
33215 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33217 minText : "The minimum value for this field is {0}",
33219 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33221 maxText : "The maximum value for this field is {0}",
33223 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33224 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33226 nanText : "{0} is not a valid number",
33228 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33232 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33234 thousandsDelimiter : false,
33236 * @cfg {String} valueAlign alignment of value
33238 valueAlign : "left",
33240 getAutoCreate : function()
33242 var hiddenInput = {
33246 cls: 'hidden-number-input'
33250 hiddenInput.name = this.name;
33255 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33257 this.name = hiddenInput.name;
33259 if(cfg.cn.length > 0) {
33260 cfg.cn.push(hiddenInput);
33267 initEvents : function()
33269 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33271 var allowed = "0123456789";
33273 if(this.allowDecimals){
33274 allowed += this.decimalSeparator;
33277 if(this.allowNegative){
33281 if(this.thousandsDelimiter) {
33285 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33287 var keyPress = function(e){
33289 var k = e.getKey();
33291 var c = e.getCharCode();
33294 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33295 allowed.indexOf(String.fromCharCode(c)) === -1
33301 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33305 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33310 this.el.on("keypress", keyPress, this);
33313 validateValue : function(value)
33316 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33320 var num = this.parseValue(value);
33323 this.markInvalid(String.format(this.nanText, value));
33327 if(num < this.minValue){
33328 this.markInvalid(String.format(this.minText, this.minValue));
33332 if(num > this.maxValue){
33333 this.markInvalid(String.format(this.maxText, this.maxValue));
33340 getValue : function()
33342 var v = this.hiddenEl().getValue();
33344 return this.fixPrecision(this.parseValue(v));
33347 parseValue : function(value)
33349 if(this.thousandsDelimiter) {
33351 r = new RegExp(",", "g");
33352 value = value.replace(r, "");
33355 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33356 return isNaN(value) ? '' : value;
33359 fixPrecision : function(value)
33361 if(this.thousandsDelimiter) {
33363 r = new RegExp(",", "g");
33364 value = value.replace(r, "");
33367 var nan = isNaN(value);
33369 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33370 return nan ? '' : value;
33372 return parseFloat(value).toFixed(this.decimalPrecision);
33375 setValue : function(v)
33377 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33383 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33385 this.inputEl().dom.value = (v == '') ? '' :
33386 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33388 if(!this.allowZero && v === '0') {
33389 this.hiddenEl().dom.value = '';
33390 this.inputEl().dom.value = '';
33397 decimalPrecisionFcn : function(v)
33399 return Math.floor(v);
33402 beforeBlur : function()
33408 var v = this.parseValue(this.getRawValue());
33415 hiddenEl : function()
33417 return this.el.select('input.hidden-number-input',true).first();
33429 * @class Roo.bootstrap.DocumentSlider
33430 * @extends Roo.bootstrap.Component
33431 * Bootstrap DocumentSlider class
33434 * Create a new DocumentViewer
33435 * @param {Object} config The config object
33438 Roo.bootstrap.DocumentSlider = function(config){
33439 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33446 * Fire after initEvent
33447 * @param {Roo.bootstrap.DocumentSlider} this
33452 * Fire after update
33453 * @param {Roo.bootstrap.DocumentSlider} this
33459 * @param {Roo.bootstrap.DocumentSlider} this
33465 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33471 getAutoCreate : function()
33475 cls : 'roo-document-slider',
33479 cls : 'roo-document-slider-header',
33483 cls : 'roo-document-slider-header-title'
33489 cls : 'roo-document-slider-body',
33493 cls : 'roo-document-slider-prev',
33497 cls : 'fa fa-chevron-left'
33503 cls : 'roo-document-slider-thumb',
33507 cls : 'roo-document-slider-image'
33513 cls : 'roo-document-slider-next',
33517 cls : 'fa fa-chevron-right'
33529 initEvents : function()
33531 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33532 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33534 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33535 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33537 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33538 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33540 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33541 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33543 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33544 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33546 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33547 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33549 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33550 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33552 this.thumbEl.on('click', this.onClick, this);
33554 this.prevIndicator.on('click', this.prev, this);
33556 this.nextIndicator.on('click', this.next, this);
33560 initial : function()
33562 if(this.files.length){
33563 this.indicator = 1;
33567 this.fireEvent('initial', this);
33570 update : function()
33572 this.imageEl.attr('src', this.files[this.indicator - 1]);
33574 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33576 this.prevIndicator.show();
33578 if(this.indicator == 1){
33579 this.prevIndicator.hide();
33582 this.nextIndicator.show();
33584 if(this.indicator == this.files.length){
33585 this.nextIndicator.hide();
33588 this.thumbEl.scrollTo('top');
33590 this.fireEvent('update', this);
33593 onClick : function(e)
33595 e.preventDefault();
33597 this.fireEvent('click', this);
33602 e.preventDefault();
33604 this.indicator = Math.max(1, this.indicator - 1);
33611 e.preventDefault();
33613 this.indicator = Math.min(this.files.length, this.indicator + 1);
33627 * @class Roo.bootstrap.RadioSet
33628 * @extends Roo.bootstrap.Input
33629 * Bootstrap RadioSet class
33630 * @cfg {String} indicatorpos (left|right) default left
33631 * @cfg {Boolean} inline (true|false) inline the element (default true)
33632 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33634 * Create a new RadioSet
33635 * @param {Object} config The config object
33638 Roo.bootstrap.RadioSet = function(config){
33640 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33644 Roo.bootstrap.RadioSet.register(this);
33649 * Fires when the element is checked or unchecked.
33650 * @param {Roo.bootstrap.RadioSet} this This radio
33651 * @param {Roo.bootstrap.Radio} item The checked item
33656 * Fires when the element is click.
33657 * @param {Roo.bootstrap.RadioSet} this This radio set
33658 * @param {Roo.bootstrap.Radio} item The checked item
33659 * @param {Roo.EventObject} e The event object
33666 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33674 indicatorpos : 'left',
33676 getAutoCreate : function()
33680 cls : 'roo-radio-set-label',
33684 html : this.fieldLabel
33689 if(this.indicatorpos == 'left'){
33692 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33693 tooltip : 'This field is required'
33698 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33699 tooltip : 'This field is required'
33705 cls : 'roo-radio-set-items'
33708 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33710 if (align === 'left' && this.fieldLabel.length) {
33713 cls : "roo-radio-set-right",
33719 if(this.labelWidth > 12){
33720 label.style = "width: " + this.labelWidth + 'px';
33723 if(this.labelWidth < 13 && this.labelmd == 0){
33724 this.labelmd = this.labelWidth;
33727 if(this.labellg > 0){
33728 label.cls += ' col-lg-' + this.labellg;
33729 items.cls += ' col-lg-' + (12 - this.labellg);
33732 if(this.labelmd > 0){
33733 label.cls += ' col-md-' + this.labelmd;
33734 items.cls += ' col-md-' + (12 - this.labelmd);
33737 if(this.labelsm > 0){
33738 label.cls += ' col-sm-' + this.labelsm;
33739 items.cls += ' col-sm-' + (12 - this.labelsm);
33742 if(this.labelxs > 0){
33743 label.cls += ' col-xs-' + this.labelxs;
33744 items.cls += ' col-xs-' + (12 - this.labelxs);
33750 cls : 'roo-radio-set',
33754 cls : 'roo-radio-set-input',
33757 value : this.value ? this.value : ''
33764 if(this.weight.length){
33765 cfg.cls += ' roo-radio-' + this.weight;
33769 cfg.cls += ' roo-radio-set-inline';
33773 ['xs','sm','md','lg'].map(function(size){
33774 if (settings[size]) {
33775 cfg.cls += ' col-' + size + '-' + settings[size];
33783 initEvents : function()
33785 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33786 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33788 if(!this.fieldLabel.length){
33789 this.labelEl.hide();
33792 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33793 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33795 this.indicator = this.indicatorEl();
33797 if(this.indicator){
33798 this.indicator.addClass('invisible');
33801 this.originalValue = this.getValue();
33805 inputEl: function ()
33807 return this.el.select('.roo-radio-set-input', true).first();
33810 getChildContainer : function()
33812 return this.itemsEl;
33815 register : function(item)
33817 this.radioes.push(item);
33821 validate : function()
33823 if(this.getVisibilityEl().hasClass('hidden')){
33829 Roo.each(this.radioes, function(i){
33838 if(this.allowBlank) {
33842 if(this.disabled || valid){
33847 this.markInvalid();
33852 markValid : function()
33854 if(this.labelEl.isVisible(true)){
33855 this.indicatorEl().removeClass('visible');
33856 this.indicatorEl().addClass('invisible');
33859 this.el.removeClass([this.invalidClass, this.validClass]);
33860 this.el.addClass(this.validClass);
33862 this.fireEvent('valid', this);
33865 markInvalid : function(msg)
33867 if(this.allowBlank || this.disabled){
33871 if(this.labelEl.isVisible(true)){
33872 this.indicatorEl().removeClass('invisible');
33873 this.indicatorEl().addClass('visible');
33876 this.el.removeClass([this.invalidClass, this.validClass]);
33877 this.el.addClass(this.invalidClass);
33879 this.fireEvent('invalid', this, msg);
33883 setValue : function(v, suppressEvent)
33885 if(this.value === v){
33892 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33895 Roo.each(this.radioes, function(i){
33897 i.el.removeClass('checked');
33900 Roo.each(this.radioes, function(i){
33902 if(i.value === v || i.value.toString() === v.toString()){
33904 i.el.addClass('checked');
33906 if(suppressEvent !== true){
33907 this.fireEvent('check', this, i);
33918 clearInvalid : function(){
33920 if(!this.el || this.preventMark){
33924 this.el.removeClass([this.invalidClass]);
33926 this.fireEvent('valid', this);
33931 Roo.apply(Roo.bootstrap.RadioSet, {
33935 register : function(set)
33937 this.groups[set.name] = set;
33940 get: function(name)
33942 if (typeof(this.groups[name]) == 'undefined') {
33946 return this.groups[name] ;
33952 * Ext JS Library 1.1.1
33953 * Copyright(c) 2006-2007, Ext JS, LLC.
33955 * Originally Released Under LGPL - original licence link has changed is not relivant.
33958 * <script type="text/javascript">
33963 * @class Roo.bootstrap.SplitBar
33964 * @extends Roo.util.Observable
33965 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33969 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33970 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33971 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33972 split.minSize = 100;
33973 split.maxSize = 600;
33974 split.animate = true;
33975 split.on('moved', splitterMoved);
33978 * Create a new SplitBar
33979 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33980 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33981 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33982 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33983 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33984 position of the SplitBar).
33986 Roo.bootstrap.SplitBar = function(cfg){
33991 // dragElement : elm
33992 // resizingElement: el,
33994 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33995 // placement : Roo.bootstrap.SplitBar.LEFT ,
33996 // existingProxy ???
33999 this.el = Roo.get(cfg.dragElement, true);
34000 this.el.dom.unselectable = "on";
34002 this.resizingEl = Roo.get(cfg.resizingElement, true);
34006 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34007 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34010 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34013 * The minimum size of the resizing element. (Defaults to 0)
34019 * The maximum size of the resizing element. (Defaults to 2000)
34022 this.maxSize = 2000;
34025 * Whether to animate the transition to the new size
34028 this.animate = false;
34031 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34034 this.useShim = false;
34039 if(!cfg.existingProxy){
34041 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34043 this.proxy = Roo.get(cfg.existingProxy).dom;
34046 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34049 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34052 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34055 this.dragSpecs = {};
34058 * @private The adapter to use to positon and resize elements
34060 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34061 this.adapter.init(this);
34063 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34065 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34066 this.el.addClass("roo-splitbar-h");
34069 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34070 this.el.addClass("roo-splitbar-v");
34076 * Fires when the splitter is moved (alias for {@link #event-moved})
34077 * @param {Roo.bootstrap.SplitBar} this
34078 * @param {Number} newSize the new width or height
34083 * Fires when the splitter is moved
34084 * @param {Roo.bootstrap.SplitBar} this
34085 * @param {Number} newSize the new width or height
34089 * @event beforeresize
34090 * Fires before the splitter is dragged
34091 * @param {Roo.bootstrap.SplitBar} this
34093 "beforeresize" : true,
34095 "beforeapply" : true
34098 Roo.util.Observable.call(this);
34101 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34102 onStartProxyDrag : function(x, y){
34103 this.fireEvent("beforeresize", this);
34105 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34107 o.enableDisplayMode("block");
34108 // all splitbars share the same overlay
34109 Roo.bootstrap.SplitBar.prototype.overlay = o;
34111 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34112 this.overlay.show();
34113 Roo.get(this.proxy).setDisplayed("block");
34114 var size = this.adapter.getElementSize(this);
34115 this.activeMinSize = this.getMinimumSize();;
34116 this.activeMaxSize = this.getMaximumSize();;
34117 var c1 = size - this.activeMinSize;
34118 var c2 = Math.max(this.activeMaxSize - size, 0);
34119 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34120 this.dd.resetConstraints();
34121 this.dd.setXConstraint(
34122 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34123 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34125 this.dd.setYConstraint(0, 0);
34127 this.dd.resetConstraints();
34128 this.dd.setXConstraint(0, 0);
34129 this.dd.setYConstraint(
34130 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34131 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34134 this.dragSpecs.startSize = size;
34135 this.dragSpecs.startPoint = [x, y];
34136 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34140 * @private Called after the drag operation by the DDProxy
34142 onEndProxyDrag : function(e){
34143 Roo.get(this.proxy).setDisplayed(false);
34144 var endPoint = Roo.lib.Event.getXY(e);
34146 this.overlay.hide();
34149 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34150 newSize = this.dragSpecs.startSize +
34151 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34152 endPoint[0] - this.dragSpecs.startPoint[0] :
34153 this.dragSpecs.startPoint[0] - endPoint[0]
34156 newSize = this.dragSpecs.startSize +
34157 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34158 endPoint[1] - this.dragSpecs.startPoint[1] :
34159 this.dragSpecs.startPoint[1] - endPoint[1]
34162 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34163 if(newSize != this.dragSpecs.startSize){
34164 if(this.fireEvent('beforeapply', this, newSize) !== false){
34165 this.adapter.setElementSize(this, newSize);
34166 this.fireEvent("moved", this, newSize);
34167 this.fireEvent("resize", this, newSize);
34173 * Get the adapter this SplitBar uses
34174 * @return The adapter object
34176 getAdapter : function(){
34177 return this.adapter;
34181 * Set the adapter this SplitBar uses
34182 * @param {Object} adapter A SplitBar adapter object
34184 setAdapter : function(adapter){
34185 this.adapter = adapter;
34186 this.adapter.init(this);
34190 * Gets the minimum size for the resizing element
34191 * @return {Number} The minimum size
34193 getMinimumSize : function(){
34194 return this.minSize;
34198 * Sets the minimum size for the resizing element
34199 * @param {Number} minSize The minimum size
34201 setMinimumSize : function(minSize){
34202 this.minSize = minSize;
34206 * Gets the maximum size for the resizing element
34207 * @return {Number} The maximum size
34209 getMaximumSize : function(){
34210 return this.maxSize;
34214 * Sets the maximum size for the resizing element
34215 * @param {Number} maxSize The maximum size
34217 setMaximumSize : function(maxSize){
34218 this.maxSize = maxSize;
34222 * Sets the initialize size for the resizing element
34223 * @param {Number} size The initial size
34225 setCurrentSize : function(size){
34226 var oldAnimate = this.animate;
34227 this.animate = false;
34228 this.adapter.setElementSize(this, size);
34229 this.animate = oldAnimate;
34233 * Destroy this splitbar.
34234 * @param {Boolean} removeEl True to remove the element
34236 destroy : function(removeEl){
34238 this.shim.remove();
34241 this.proxy.parentNode.removeChild(this.proxy);
34249 * @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.
34251 Roo.bootstrap.SplitBar.createProxy = function(dir){
34252 var proxy = new Roo.Element(document.createElement("div"));
34253 proxy.unselectable();
34254 var cls = 'roo-splitbar-proxy';
34255 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34256 document.body.appendChild(proxy.dom);
34261 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34262 * Default Adapter. It assumes the splitter and resizing element are not positioned
34263 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34265 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34268 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34269 // do nothing for now
34270 init : function(s){
34274 * Called before drag operations to get the current size of the resizing element.
34275 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34277 getElementSize : function(s){
34278 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34279 return s.resizingEl.getWidth();
34281 return s.resizingEl.getHeight();
34286 * Called after drag operations to set the size of the resizing element.
34287 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34288 * @param {Number} newSize The new size to set
34289 * @param {Function} onComplete A function to be invoked when resizing is complete
34291 setElementSize : function(s, newSize, onComplete){
34292 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34294 s.resizingEl.setWidth(newSize);
34296 onComplete(s, newSize);
34299 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34304 s.resizingEl.setHeight(newSize);
34306 onComplete(s, newSize);
34309 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34316 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34317 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34318 * Adapter that moves the splitter element to align with the resized sizing element.
34319 * Used with an absolute positioned SplitBar.
34320 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34321 * document.body, make sure you assign an id to the body element.
34323 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34324 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34325 this.container = Roo.get(container);
34328 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34329 init : function(s){
34330 this.basic.init(s);
34333 getElementSize : function(s){
34334 return this.basic.getElementSize(s);
34337 setElementSize : function(s, newSize, onComplete){
34338 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34341 moveSplitter : function(s){
34342 var yes = Roo.bootstrap.SplitBar;
34343 switch(s.placement){
34345 s.el.setX(s.resizingEl.getRight());
34348 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34351 s.el.setY(s.resizingEl.getBottom());
34354 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34361 * Orientation constant - Create a vertical SplitBar
34365 Roo.bootstrap.SplitBar.VERTICAL = 1;
34368 * Orientation constant - Create a horizontal SplitBar
34372 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34375 * Placement constant - The resizing element is to the left of the splitter element
34379 Roo.bootstrap.SplitBar.LEFT = 1;
34382 * Placement constant - The resizing element is to the right of the splitter element
34386 Roo.bootstrap.SplitBar.RIGHT = 2;
34389 * Placement constant - The resizing element is positioned above the splitter element
34393 Roo.bootstrap.SplitBar.TOP = 3;
34396 * Placement constant - The resizing element is positioned under splitter element
34400 Roo.bootstrap.SplitBar.BOTTOM = 4;
34401 Roo.namespace("Roo.bootstrap.layout");/*
34403 * Ext JS Library 1.1.1
34404 * Copyright(c) 2006-2007, Ext JS, LLC.
34406 * Originally Released Under LGPL - original licence link has changed is not relivant.
34409 * <script type="text/javascript">
34413 * @class Roo.bootstrap.layout.Manager
34414 * @extends Roo.bootstrap.Component
34415 * Base class for layout managers.
34417 Roo.bootstrap.layout.Manager = function(config)
34419 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34425 /** false to disable window resize monitoring @type Boolean */
34426 this.monitorWindowResize = true;
34431 * Fires when a layout is performed.
34432 * @param {Roo.LayoutManager} this
34436 * @event regionresized
34437 * Fires when the user resizes a region.
34438 * @param {Roo.LayoutRegion} region The resized region
34439 * @param {Number} newSize The new size (width for east/west, height for north/south)
34441 "regionresized" : true,
34443 * @event regioncollapsed
34444 * Fires when a region is collapsed.
34445 * @param {Roo.LayoutRegion} region The collapsed region
34447 "regioncollapsed" : true,
34449 * @event regionexpanded
34450 * Fires when a region is expanded.
34451 * @param {Roo.LayoutRegion} region The expanded region
34453 "regionexpanded" : true
34455 this.updating = false;
34458 this.el = Roo.get(config.el);
34464 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34469 monitorWindowResize : true,
34475 onRender : function(ct, position)
34478 this.el = Roo.get(ct);
34481 //this.fireEvent('render',this);
34485 initEvents: function()
34489 // ie scrollbar fix
34490 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34491 document.body.scroll = "no";
34492 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34493 this.el.position('relative');
34495 this.id = this.el.id;
34496 this.el.addClass("roo-layout-container");
34497 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34498 if(this.el.dom != document.body ) {
34499 this.el.on('resize', this.layout,this);
34500 this.el.on('show', this.layout,this);
34506 * Returns true if this layout is currently being updated
34507 * @return {Boolean}
34509 isUpdating : function(){
34510 return this.updating;
34514 * Suspend the LayoutManager from doing auto-layouts while
34515 * making multiple add or remove calls
34517 beginUpdate : function(){
34518 this.updating = true;
34522 * Restore auto-layouts and optionally disable the manager from performing a layout
34523 * @param {Boolean} noLayout true to disable a layout update
34525 endUpdate : function(noLayout){
34526 this.updating = false;
34532 layout: function(){
34536 onRegionResized : function(region, newSize){
34537 this.fireEvent("regionresized", region, newSize);
34541 onRegionCollapsed : function(region){
34542 this.fireEvent("regioncollapsed", region);
34545 onRegionExpanded : function(region){
34546 this.fireEvent("regionexpanded", region);
34550 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34551 * performs box-model adjustments.
34552 * @return {Object} The size as an object {width: (the width), height: (the height)}
34554 getViewSize : function()
34557 if(this.el.dom != document.body){
34558 size = this.el.getSize();
34560 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34562 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34563 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34568 * Returns the Element this layout is bound to.
34569 * @return {Roo.Element}
34571 getEl : function(){
34576 * Returns the specified region.
34577 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34578 * @return {Roo.LayoutRegion}
34580 getRegion : function(target){
34581 return this.regions[target.toLowerCase()];
34584 onWindowResize : function(){
34585 if(this.monitorWindowResize){
34592 * Ext JS Library 1.1.1
34593 * Copyright(c) 2006-2007, Ext JS, LLC.
34595 * Originally Released Under LGPL - original licence link has changed is not relivant.
34598 * <script type="text/javascript">
34601 * @class Roo.bootstrap.layout.Border
34602 * @extends Roo.bootstrap.layout.Manager
34603 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34604 * please see: examples/bootstrap/nested.html<br><br>
34606 <b>The container the layout is rendered into can be either the body element or any other element.
34607 If it is not the body element, the container needs to either be an absolute positioned element,
34608 or you will need to add "position:relative" to the css of the container. You will also need to specify
34609 the container size if it is not the body element.</b>
34612 * Create a new Border
34613 * @param {Object} config Configuration options
34615 Roo.bootstrap.layout.Border = function(config){
34616 config = config || {};
34617 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34621 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34622 if(config[region]){
34623 config[region].region = region;
34624 this.addRegion(config[region]);
34630 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34632 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34634 * Creates and adds a new region if it doesn't already exist.
34635 * @param {String} target The target region key (north, south, east, west or center).
34636 * @param {Object} config The regions config object
34637 * @return {BorderLayoutRegion} The new region
34639 addRegion : function(config)
34641 if(!this.regions[config.region]){
34642 var r = this.factory(config);
34643 this.bindRegion(r);
34645 return this.regions[config.region];
34649 bindRegion : function(r){
34650 this.regions[r.config.region] = r;
34652 r.on("visibilitychange", this.layout, this);
34653 r.on("paneladded", this.layout, this);
34654 r.on("panelremoved", this.layout, this);
34655 r.on("invalidated", this.layout, this);
34656 r.on("resized", this.onRegionResized, this);
34657 r.on("collapsed", this.onRegionCollapsed, this);
34658 r.on("expanded", this.onRegionExpanded, this);
34662 * Performs a layout update.
34664 layout : function()
34666 if(this.updating) {
34670 // render all the rebions if they have not been done alreayd?
34671 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34672 if(this.regions[region] && !this.regions[region].bodyEl){
34673 this.regions[region].onRender(this.el)
34677 var size = this.getViewSize();
34678 var w = size.width;
34679 var h = size.height;
34684 //var x = 0, y = 0;
34686 var rs = this.regions;
34687 var north = rs["north"];
34688 var south = rs["south"];
34689 var west = rs["west"];
34690 var east = rs["east"];
34691 var center = rs["center"];
34692 //if(this.hideOnLayout){ // not supported anymore
34693 //c.el.setStyle("display", "none");
34695 if(north && north.isVisible()){
34696 var b = north.getBox();
34697 var m = north.getMargins();
34698 b.width = w - (m.left+m.right);
34701 centerY = b.height + b.y + m.bottom;
34702 centerH -= centerY;
34703 north.updateBox(this.safeBox(b));
34705 if(south && south.isVisible()){
34706 var b = south.getBox();
34707 var m = south.getMargins();
34708 b.width = w - (m.left+m.right);
34710 var totalHeight = (b.height + m.top + m.bottom);
34711 b.y = h - totalHeight + m.top;
34712 centerH -= totalHeight;
34713 south.updateBox(this.safeBox(b));
34715 if(west && west.isVisible()){
34716 var b = west.getBox();
34717 var m = west.getMargins();
34718 b.height = centerH - (m.top+m.bottom);
34720 b.y = centerY + m.top;
34721 var totalWidth = (b.width + m.left + m.right);
34722 centerX += totalWidth;
34723 centerW -= totalWidth;
34724 west.updateBox(this.safeBox(b));
34726 if(east && east.isVisible()){
34727 var b = east.getBox();
34728 var m = east.getMargins();
34729 b.height = centerH - (m.top+m.bottom);
34730 var totalWidth = (b.width + m.left + m.right);
34731 b.x = w - totalWidth + m.left;
34732 b.y = centerY + m.top;
34733 centerW -= totalWidth;
34734 east.updateBox(this.safeBox(b));
34737 var m = center.getMargins();
34739 x: centerX + m.left,
34740 y: centerY + m.top,
34741 width: centerW - (m.left+m.right),
34742 height: centerH - (m.top+m.bottom)
34744 //if(this.hideOnLayout){
34745 //center.el.setStyle("display", "block");
34747 center.updateBox(this.safeBox(centerBox));
34750 this.fireEvent("layout", this);
34754 safeBox : function(box){
34755 box.width = Math.max(0, box.width);
34756 box.height = Math.max(0, box.height);
34761 * Adds a ContentPanel (or subclass) to this layout.
34762 * @param {String} target The target region key (north, south, east, west or center).
34763 * @param {Roo.ContentPanel} panel The panel to add
34764 * @return {Roo.ContentPanel} The added panel
34766 add : function(target, panel){
34768 target = target.toLowerCase();
34769 return this.regions[target].add(panel);
34773 * Remove a ContentPanel (or subclass) to this layout.
34774 * @param {String} target The target region key (north, south, east, west or center).
34775 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34776 * @return {Roo.ContentPanel} The removed panel
34778 remove : function(target, panel){
34779 target = target.toLowerCase();
34780 return this.regions[target].remove(panel);
34784 * Searches all regions for a panel with the specified id
34785 * @param {String} panelId
34786 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34788 findPanel : function(panelId){
34789 var rs = this.regions;
34790 for(var target in rs){
34791 if(typeof rs[target] != "function"){
34792 var p = rs[target].getPanel(panelId);
34802 * Searches all regions for a panel with the specified id and activates (shows) it.
34803 * @param {String/ContentPanel} panelId The panels id or the panel itself
34804 * @return {Roo.ContentPanel} The shown panel or null
34806 showPanel : function(panelId) {
34807 var rs = this.regions;
34808 for(var target in rs){
34809 var r = rs[target];
34810 if(typeof r != "function"){
34811 if(r.hasPanel(panelId)){
34812 return r.showPanel(panelId);
34820 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34821 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34824 restoreState : function(provider){
34826 provider = Roo.state.Manager;
34828 var sm = new Roo.LayoutStateManager();
34829 sm.init(this, provider);
34835 * Adds a xtype elements to the layout.
34839 xtype : 'ContentPanel',
34846 xtype : 'NestedLayoutPanel',
34852 items : [ ... list of content panels or nested layout panels.. ]
34856 * @param {Object} cfg Xtype definition of item to add.
34858 addxtype : function(cfg)
34860 // basically accepts a pannel...
34861 // can accept a layout region..!?!?
34862 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34865 // theory? children can only be panels??
34867 //if (!cfg.xtype.match(/Panel$/)) {
34872 if (typeof(cfg.region) == 'undefined') {
34873 Roo.log("Failed to add Panel, region was not set");
34877 var region = cfg.region;
34883 xitems = cfg.items;
34890 case 'Content': // ContentPanel (el, cfg)
34891 case 'Scroll': // ContentPanel (el, cfg)
34893 cfg.autoCreate = true;
34894 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34896 // var el = this.el.createChild();
34897 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34900 this.add(region, ret);
34904 case 'TreePanel': // our new panel!
34905 cfg.el = this.el.createChild();
34906 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34907 this.add(region, ret);
34912 // create a new Layout (which is a Border Layout...
34914 var clayout = cfg.layout;
34915 clayout.el = this.el.createChild();
34916 clayout.items = clayout.items || [];
34920 // replace this exitems with the clayout ones..
34921 xitems = clayout.items;
34923 // force background off if it's in center...
34924 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34925 cfg.background = false;
34927 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34930 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34931 //console.log('adding nested layout panel ' + cfg.toSource());
34932 this.add(region, ret);
34933 nb = {}; /// find first...
34938 // needs grid and region
34940 //var el = this.getRegion(region).el.createChild();
34942 *var el = this.el.createChild();
34943 // create the grid first...
34944 cfg.grid.container = el;
34945 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34948 if (region == 'center' && this.active ) {
34949 cfg.background = false;
34952 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34954 this.add(region, ret);
34956 if (cfg.background) {
34957 // render grid on panel activation (if panel background)
34958 ret.on('activate', function(gp) {
34959 if (!gp.grid.rendered) {
34960 // gp.grid.render(el);
34964 // cfg.grid.render(el);
34970 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34971 // it was the old xcomponent building that caused this before.
34972 // espeically if border is the top element in the tree.
34982 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34984 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34985 this.add(region, ret);
34989 throw "Can not add '" + cfg.xtype + "' to Border";
34995 this.beginUpdate();
34999 Roo.each(xitems, function(i) {
35000 region = nb && i.region ? i.region : false;
35002 var add = ret.addxtype(i);
35005 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35006 if (!i.background) {
35007 abn[region] = nb[region] ;
35014 // make the last non-background panel active..
35015 //if (nb) { Roo.log(abn); }
35018 for(var r in abn) {
35019 region = this.getRegion(r);
35021 // tried using nb[r], but it does not work..
35023 region.showPanel(abn[r]);
35034 factory : function(cfg)
35037 var validRegions = Roo.bootstrap.layout.Border.regions;
35039 var target = cfg.region;
35042 var r = Roo.bootstrap.layout;
35046 return new r.North(cfg);
35048 return new r.South(cfg);
35050 return new r.East(cfg);
35052 return new r.West(cfg);
35054 return new r.Center(cfg);
35056 throw 'Layout region "'+target+'" not supported.';
35063 * Ext JS Library 1.1.1
35064 * Copyright(c) 2006-2007, Ext JS, LLC.
35066 * Originally Released Under LGPL - original licence link has changed is not relivant.
35069 * <script type="text/javascript">
35073 * @class Roo.bootstrap.layout.Basic
35074 * @extends Roo.util.Observable
35075 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35076 * and does not have a titlebar, tabs or any other features. All it does is size and position
35077 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35078 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35079 * @cfg {string} region the region that it inhabits..
35080 * @cfg {bool} skipConfig skip config?
35084 Roo.bootstrap.layout.Basic = function(config){
35086 this.mgr = config.mgr;
35088 this.position = config.region;
35090 var skipConfig = config.skipConfig;
35094 * @scope Roo.BasicLayoutRegion
35098 * @event beforeremove
35099 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35100 * @param {Roo.LayoutRegion} this
35101 * @param {Roo.ContentPanel} panel The panel
35102 * @param {Object} e The cancel event object
35104 "beforeremove" : true,
35106 * @event invalidated
35107 * Fires when the layout for this region is changed.
35108 * @param {Roo.LayoutRegion} this
35110 "invalidated" : true,
35112 * @event visibilitychange
35113 * Fires when this region is shown or hidden
35114 * @param {Roo.LayoutRegion} this
35115 * @param {Boolean} visibility true or false
35117 "visibilitychange" : true,
35119 * @event paneladded
35120 * Fires when a panel is added.
35121 * @param {Roo.LayoutRegion} this
35122 * @param {Roo.ContentPanel} panel The panel
35124 "paneladded" : true,
35126 * @event panelremoved
35127 * Fires when a panel is removed.
35128 * @param {Roo.LayoutRegion} this
35129 * @param {Roo.ContentPanel} panel The panel
35131 "panelremoved" : true,
35133 * @event beforecollapse
35134 * Fires when this region before collapse.
35135 * @param {Roo.LayoutRegion} this
35137 "beforecollapse" : true,
35140 * Fires when this region is collapsed.
35141 * @param {Roo.LayoutRegion} this
35143 "collapsed" : true,
35146 * Fires when this region is expanded.
35147 * @param {Roo.LayoutRegion} this
35152 * Fires when this region is slid into view.
35153 * @param {Roo.LayoutRegion} this
35155 "slideshow" : true,
35158 * Fires when this region slides out of view.
35159 * @param {Roo.LayoutRegion} this
35161 "slidehide" : true,
35163 * @event panelactivated
35164 * Fires when a panel is activated.
35165 * @param {Roo.LayoutRegion} this
35166 * @param {Roo.ContentPanel} panel The activated panel
35168 "panelactivated" : true,
35171 * Fires when the user resizes this region.
35172 * @param {Roo.LayoutRegion} this
35173 * @param {Number} newSize The new size (width for east/west, height for north/south)
35177 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35178 this.panels = new Roo.util.MixedCollection();
35179 this.panels.getKey = this.getPanelId.createDelegate(this);
35181 this.activePanel = null;
35182 // ensure listeners are added...
35184 if (config.listeners || config.events) {
35185 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35186 listeners : config.listeners || {},
35187 events : config.events || {}
35191 if(skipConfig !== true){
35192 this.applyConfig(config);
35196 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35198 getPanelId : function(p){
35202 applyConfig : function(config){
35203 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35204 this.config = config;
35209 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35210 * the width, for horizontal (north, south) the height.
35211 * @param {Number} newSize The new width or height
35213 resizeTo : function(newSize){
35214 var el = this.el ? this.el :
35215 (this.activePanel ? this.activePanel.getEl() : null);
35217 switch(this.position){
35220 el.setWidth(newSize);
35221 this.fireEvent("resized", this, newSize);
35225 el.setHeight(newSize);
35226 this.fireEvent("resized", this, newSize);
35232 getBox : function(){
35233 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35236 getMargins : function(){
35237 return this.margins;
35240 updateBox : function(box){
35242 var el = this.activePanel.getEl();
35243 el.dom.style.left = box.x + "px";
35244 el.dom.style.top = box.y + "px";
35245 this.activePanel.setSize(box.width, box.height);
35249 * Returns the container element for this region.
35250 * @return {Roo.Element}
35252 getEl : function(){
35253 return this.activePanel;
35257 * Returns true if this region is currently visible.
35258 * @return {Boolean}
35260 isVisible : function(){
35261 return this.activePanel ? true : false;
35264 setActivePanel : function(panel){
35265 panel = this.getPanel(panel);
35266 if(this.activePanel && this.activePanel != panel){
35267 this.activePanel.setActiveState(false);
35268 this.activePanel.getEl().setLeftTop(-10000,-10000);
35270 this.activePanel = panel;
35271 panel.setActiveState(true);
35273 panel.setSize(this.box.width, this.box.height);
35275 this.fireEvent("panelactivated", this, panel);
35276 this.fireEvent("invalidated");
35280 * Show the specified panel.
35281 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35282 * @return {Roo.ContentPanel} The shown panel or null
35284 showPanel : function(panel){
35285 panel = this.getPanel(panel);
35287 this.setActivePanel(panel);
35293 * Get the active panel for this region.
35294 * @return {Roo.ContentPanel} The active panel or null
35296 getActivePanel : function(){
35297 return this.activePanel;
35301 * Add the passed ContentPanel(s)
35302 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35303 * @return {Roo.ContentPanel} The panel added (if only one was added)
35305 add : function(panel){
35306 if(arguments.length > 1){
35307 for(var i = 0, len = arguments.length; i < len; i++) {
35308 this.add(arguments[i]);
35312 if(this.hasPanel(panel)){
35313 this.showPanel(panel);
35316 var el = panel.getEl();
35317 if(el.dom.parentNode != this.mgr.el.dom){
35318 this.mgr.el.dom.appendChild(el.dom);
35320 if(panel.setRegion){
35321 panel.setRegion(this);
35323 this.panels.add(panel);
35324 el.setStyle("position", "absolute");
35325 if(!panel.background){
35326 this.setActivePanel(panel);
35327 if(this.config.initialSize && this.panels.getCount()==1){
35328 this.resizeTo(this.config.initialSize);
35331 this.fireEvent("paneladded", this, panel);
35336 * Returns true if the panel is in this region.
35337 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35338 * @return {Boolean}
35340 hasPanel : function(panel){
35341 if(typeof panel == "object"){ // must be panel obj
35342 panel = panel.getId();
35344 return this.getPanel(panel) ? true : false;
35348 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35349 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35350 * @param {Boolean} preservePanel Overrides the config preservePanel option
35351 * @return {Roo.ContentPanel} The panel that was removed
35353 remove : function(panel, preservePanel){
35354 panel = this.getPanel(panel);
35359 this.fireEvent("beforeremove", this, panel, e);
35360 if(e.cancel === true){
35363 var panelId = panel.getId();
35364 this.panels.removeKey(panelId);
35369 * Returns the panel specified or null if it's not in this region.
35370 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35371 * @return {Roo.ContentPanel}
35373 getPanel : function(id){
35374 if(typeof id == "object"){ // must be panel obj
35377 return this.panels.get(id);
35381 * Returns this regions position (north/south/east/west/center).
35384 getPosition: function(){
35385 return this.position;
35389 * Ext JS Library 1.1.1
35390 * Copyright(c) 2006-2007, Ext JS, LLC.
35392 * Originally Released Under LGPL - original licence link has changed is not relivant.
35395 * <script type="text/javascript">
35399 * @class Roo.bootstrap.layout.Region
35400 * @extends Roo.bootstrap.layout.Basic
35401 * This class represents a region in a layout manager.
35403 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35404 * @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})
35405 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35406 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35407 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35408 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35409 * @cfg {String} title The title for the region (overrides panel titles)
35410 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35411 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35412 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35413 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35414 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35415 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35416 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35417 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35418 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35419 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35421 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35422 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35423 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35424 * @cfg {Number} width For East/West panels
35425 * @cfg {Number} height For North/South panels
35426 * @cfg {Boolean} split To show the splitter
35427 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35429 * @cfg {string} cls Extra CSS classes to add to region
35431 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35432 * @cfg {string} region the region that it inhabits..
35435 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35436 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35438 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35439 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35440 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35442 Roo.bootstrap.layout.Region = function(config)
35444 this.applyConfig(config);
35446 var mgr = config.mgr;
35447 var pos = config.region;
35448 config.skipConfig = true;
35449 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35452 this.onRender(mgr.el);
35455 this.visible = true;
35456 this.collapsed = false;
35457 this.unrendered_panels = [];
35460 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35462 position: '', // set by wrapper (eg. north/south etc..)
35463 unrendered_panels : null, // unrendered panels.
35464 createBody : function(){
35465 /** This region's body element
35466 * @type Roo.Element */
35467 this.bodyEl = this.el.createChild({
35469 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35473 onRender: function(ctr, pos)
35475 var dh = Roo.DomHelper;
35476 /** This region's container element
35477 * @type Roo.Element */
35478 this.el = dh.append(ctr.dom, {
35480 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35482 /** This region's title element
35483 * @type Roo.Element */
35485 this.titleEl = dh.append(this.el.dom,
35488 unselectable: "on",
35489 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35491 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35492 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35495 this.titleEl.enableDisplayMode();
35496 /** This region's title text element
35497 * @type HTMLElement */
35498 this.titleTextEl = this.titleEl.dom.firstChild;
35499 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35501 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35502 this.closeBtn.enableDisplayMode();
35503 this.closeBtn.on("click", this.closeClicked, this);
35504 this.closeBtn.hide();
35506 this.createBody(this.config);
35507 if(this.config.hideWhenEmpty){
35509 this.on("paneladded", this.validateVisibility, this);
35510 this.on("panelremoved", this.validateVisibility, this);
35512 if(this.autoScroll){
35513 this.bodyEl.setStyle("overflow", "auto");
35515 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35517 //if(c.titlebar !== false){
35518 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35519 this.titleEl.hide();
35521 this.titleEl.show();
35522 if(this.config.title){
35523 this.titleTextEl.innerHTML = this.config.title;
35527 if(this.config.collapsed){
35528 this.collapse(true);
35530 if(this.config.hidden){
35534 if (this.unrendered_panels && this.unrendered_panels.length) {
35535 for (var i =0;i< this.unrendered_panels.length; i++) {
35536 this.add(this.unrendered_panels[i]);
35538 this.unrendered_panels = null;
35544 applyConfig : function(c)
35547 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35548 var dh = Roo.DomHelper;
35549 if(c.titlebar !== false){
35550 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35551 this.collapseBtn.on("click", this.collapse, this);
35552 this.collapseBtn.enableDisplayMode();
35554 if(c.showPin === true || this.showPin){
35555 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35556 this.stickBtn.enableDisplayMode();
35557 this.stickBtn.on("click", this.expand, this);
35558 this.stickBtn.hide();
35563 /** This region's collapsed element
35564 * @type Roo.Element */
35567 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35568 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35571 if(c.floatable !== false){
35572 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35573 this.collapsedEl.on("click", this.collapseClick, this);
35576 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35577 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35578 id: "message", unselectable: "on", style:{"float":"left"}});
35579 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35581 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35582 this.expandBtn.on("click", this.expand, this);
35586 if(this.collapseBtn){
35587 this.collapseBtn.setVisible(c.collapsible == true);
35590 this.cmargins = c.cmargins || this.cmargins ||
35591 (this.position == "west" || this.position == "east" ?
35592 {top: 0, left: 2, right:2, bottom: 0} :
35593 {top: 2, left: 0, right:0, bottom: 2});
35595 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35598 this.bottomTabs = c.tabPosition != "top";
35600 this.autoScroll = c.autoScroll || false;
35605 this.duration = c.duration || .30;
35606 this.slideDuration = c.slideDuration || .45;
35611 * Returns true if this region is currently visible.
35612 * @return {Boolean}
35614 isVisible : function(){
35615 return this.visible;
35619 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35620 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35622 //setCollapsedTitle : function(title){
35623 // title = title || " ";
35624 // if(this.collapsedTitleTextEl){
35625 // this.collapsedTitleTextEl.innerHTML = title;
35629 getBox : function(){
35631 // if(!this.collapsed){
35632 b = this.el.getBox(false, true);
35634 // b = this.collapsedEl.getBox(false, true);
35639 getMargins : function(){
35640 return this.margins;
35641 //return this.collapsed ? this.cmargins : this.margins;
35644 highlight : function(){
35645 this.el.addClass("x-layout-panel-dragover");
35648 unhighlight : function(){
35649 this.el.removeClass("x-layout-panel-dragover");
35652 updateBox : function(box)
35654 if (!this.bodyEl) {
35655 return; // not rendered yet..
35659 if(!this.collapsed){
35660 this.el.dom.style.left = box.x + "px";
35661 this.el.dom.style.top = box.y + "px";
35662 this.updateBody(box.width, box.height);
35664 this.collapsedEl.dom.style.left = box.x + "px";
35665 this.collapsedEl.dom.style.top = box.y + "px";
35666 this.collapsedEl.setSize(box.width, box.height);
35669 this.tabs.autoSizeTabs();
35673 updateBody : function(w, h)
35676 this.el.setWidth(w);
35677 w -= this.el.getBorderWidth("rl");
35678 if(this.config.adjustments){
35679 w += this.config.adjustments[0];
35682 if(h !== null && h > 0){
35683 this.el.setHeight(h);
35684 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35685 h -= this.el.getBorderWidth("tb");
35686 if(this.config.adjustments){
35687 h += this.config.adjustments[1];
35689 this.bodyEl.setHeight(h);
35691 h = this.tabs.syncHeight(h);
35694 if(this.panelSize){
35695 w = w !== null ? w : this.panelSize.width;
35696 h = h !== null ? h : this.panelSize.height;
35698 if(this.activePanel){
35699 var el = this.activePanel.getEl();
35700 w = w !== null ? w : el.getWidth();
35701 h = h !== null ? h : el.getHeight();
35702 this.panelSize = {width: w, height: h};
35703 this.activePanel.setSize(w, h);
35705 if(Roo.isIE && this.tabs){
35706 this.tabs.el.repaint();
35711 * Returns the container element for this region.
35712 * @return {Roo.Element}
35714 getEl : function(){
35719 * Hides this region.
35722 //if(!this.collapsed){
35723 this.el.dom.style.left = "-2000px";
35726 // this.collapsedEl.dom.style.left = "-2000px";
35727 // this.collapsedEl.hide();
35729 this.visible = false;
35730 this.fireEvent("visibilitychange", this, false);
35734 * Shows this region if it was previously hidden.
35737 //if(!this.collapsed){
35740 // this.collapsedEl.show();
35742 this.visible = true;
35743 this.fireEvent("visibilitychange", this, true);
35746 closeClicked : function(){
35747 if(this.activePanel){
35748 this.remove(this.activePanel);
35752 collapseClick : function(e){
35754 e.stopPropagation();
35757 e.stopPropagation();
35763 * Collapses this region.
35764 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35767 collapse : function(skipAnim, skipCheck = false){
35768 if(this.collapsed) {
35772 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35774 this.collapsed = true;
35776 this.split.el.hide();
35778 if(this.config.animate && skipAnim !== true){
35779 this.fireEvent("invalidated", this);
35780 this.animateCollapse();
35782 this.el.setLocation(-20000,-20000);
35784 this.collapsedEl.show();
35785 this.fireEvent("collapsed", this);
35786 this.fireEvent("invalidated", this);
35792 animateCollapse : function(){
35797 * Expands this region if it was previously collapsed.
35798 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35799 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35802 expand : function(e, skipAnim){
35804 e.stopPropagation();
35806 if(!this.collapsed || this.el.hasActiveFx()) {
35810 this.afterSlideIn();
35813 this.collapsed = false;
35814 if(this.config.animate && skipAnim !== true){
35815 this.animateExpand();
35819 this.split.el.show();
35821 this.collapsedEl.setLocation(-2000,-2000);
35822 this.collapsedEl.hide();
35823 this.fireEvent("invalidated", this);
35824 this.fireEvent("expanded", this);
35828 animateExpand : function(){
35832 initTabs : function()
35834 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35836 var ts = new Roo.bootstrap.panel.Tabs({
35837 el: this.bodyEl.dom,
35838 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35839 disableTooltips: this.config.disableTabTips,
35840 toolbar : this.config.toolbar
35843 if(this.config.hideTabs){
35844 ts.stripWrap.setDisplayed(false);
35847 ts.resizeTabs = this.config.resizeTabs === true;
35848 ts.minTabWidth = this.config.minTabWidth || 40;
35849 ts.maxTabWidth = this.config.maxTabWidth || 250;
35850 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35851 ts.monitorResize = false;
35852 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35853 ts.bodyEl.addClass('roo-layout-tabs-body');
35854 this.panels.each(this.initPanelAsTab, this);
35857 initPanelAsTab : function(panel){
35858 var ti = this.tabs.addTab(
35862 this.config.closeOnTab && panel.isClosable(),
35865 if(panel.tabTip !== undefined){
35866 ti.setTooltip(panel.tabTip);
35868 ti.on("activate", function(){
35869 this.setActivePanel(panel);
35872 if(this.config.closeOnTab){
35873 ti.on("beforeclose", function(t, e){
35875 this.remove(panel);
35879 panel.tabItem = ti;
35884 updatePanelTitle : function(panel, title)
35886 if(this.activePanel == panel){
35887 this.updateTitle(title);
35890 var ti = this.tabs.getTab(panel.getEl().id);
35892 if(panel.tabTip !== undefined){
35893 ti.setTooltip(panel.tabTip);
35898 updateTitle : function(title){
35899 if(this.titleTextEl && !this.config.title){
35900 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35904 setActivePanel : function(panel)
35906 panel = this.getPanel(panel);
35907 if(this.activePanel && this.activePanel != panel){
35908 if(this.activePanel.setActiveState(false) === false){
35912 this.activePanel = panel;
35913 panel.setActiveState(true);
35914 if(this.panelSize){
35915 panel.setSize(this.panelSize.width, this.panelSize.height);
35918 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35920 this.updateTitle(panel.getTitle());
35922 this.fireEvent("invalidated", this);
35924 this.fireEvent("panelactivated", this, panel);
35928 * Shows the specified panel.
35929 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35930 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35932 showPanel : function(panel)
35934 panel = this.getPanel(panel);
35937 var tab = this.tabs.getTab(panel.getEl().id);
35938 if(tab.isHidden()){
35939 this.tabs.unhideTab(tab.id);
35943 this.setActivePanel(panel);
35950 * Get the active panel for this region.
35951 * @return {Roo.ContentPanel} The active panel or null
35953 getActivePanel : function(){
35954 return this.activePanel;
35957 validateVisibility : function(){
35958 if(this.panels.getCount() < 1){
35959 this.updateTitle(" ");
35960 this.closeBtn.hide();
35963 if(!this.isVisible()){
35970 * Adds the passed ContentPanel(s) to this region.
35971 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35972 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35974 add : function(panel)
35976 if(arguments.length > 1){
35977 for(var i = 0, len = arguments.length; i < len; i++) {
35978 this.add(arguments[i]);
35983 // if we have not been rendered yet, then we can not really do much of this..
35984 if (!this.bodyEl) {
35985 this.unrendered_panels.push(panel);
35992 if(this.hasPanel(panel)){
35993 this.showPanel(panel);
35996 panel.setRegion(this);
35997 this.panels.add(panel);
35998 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35999 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36000 // and hide them... ???
36001 this.bodyEl.dom.appendChild(panel.getEl().dom);
36002 if(panel.background !== true){
36003 this.setActivePanel(panel);
36005 this.fireEvent("paneladded", this, panel);
36012 this.initPanelAsTab(panel);
36016 if(panel.background !== true){
36017 this.tabs.activate(panel.getEl().id);
36019 this.fireEvent("paneladded", this, panel);
36024 * Hides the tab for the specified panel.
36025 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36027 hidePanel : function(panel){
36028 if(this.tabs && (panel = this.getPanel(panel))){
36029 this.tabs.hideTab(panel.getEl().id);
36034 * Unhides the tab for a previously hidden panel.
36035 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36037 unhidePanel : function(panel){
36038 if(this.tabs && (panel = this.getPanel(panel))){
36039 this.tabs.unhideTab(panel.getEl().id);
36043 clearPanels : function(){
36044 while(this.panels.getCount() > 0){
36045 this.remove(this.panels.first());
36050 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36051 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36052 * @param {Boolean} preservePanel Overrides the config preservePanel option
36053 * @return {Roo.ContentPanel} The panel that was removed
36055 remove : function(panel, preservePanel)
36057 panel = this.getPanel(panel);
36062 this.fireEvent("beforeremove", this, panel, e);
36063 if(e.cancel === true){
36066 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36067 var panelId = panel.getId();
36068 this.panels.removeKey(panelId);
36070 document.body.appendChild(panel.getEl().dom);
36073 this.tabs.removeTab(panel.getEl().id);
36074 }else if (!preservePanel){
36075 this.bodyEl.dom.removeChild(panel.getEl().dom);
36077 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36078 var p = this.panels.first();
36079 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36080 tempEl.appendChild(p.getEl().dom);
36081 this.bodyEl.update("");
36082 this.bodyEl.dom.appendChild(p.getEl().dom);
36084 this.updateTitle(p.getTitle());
36086 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36087 this.setActivePanel(p);
36089 panel.setRegion(null);
36090 if(this.activePanel == panel){
36091 this.activePanel = null;
36093 if(this.config.autoDestroy !== false && preservePanel !== true){
36094 try{panel.destroy();}catch(e){}
36096 this.fireEvent("panelremoved", this, panel);
36101 * Returns the TabPanel component used by this region
36102 * @return {Roo.TabPanel}
36104 getTabs : function(){
36108 createTool : function(parentEl, className){
36109 var btn = Roo.DomHelper.append(parentEl, {
36111 cls: "x-layout-tools-button",
36114 cls: "roo-layout-tools-button-inner " + className,
36118 btn.addClassOnOver("roo-layout-tools-button-over");
36123 * Ext JS Library 1.1.1
36124 * Copyright(c) 2006-2007, Ext JS, LLC.
36126 * Originally Released Under LGPL - original licence link has changed is not relivant.
36129 * <script type="text/javascript">
36135 * @class Roo.SplitLayoutRegion
36136 * @extends Roo.LayoutRegion
36137 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36139 Roo.bootstrap.layout.Split = function(config){
36140 this.cursor = config.cursor;
36141 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36144 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36146 splitTip : "Drag to resize.",
36147 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36148 useSplitTips : false,
36150 applyConfig : function(config){
36151 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36154 onRender : function(ctr,pos) {
36156 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36157 if(!this.config.split){
36162 var splitEl = Roo.DomHelper.append(ctr.dom, {
36164 id: this.el.id + "-split",
36165 cls: "roo-layout-split roo-layout-split-"+this.position,
36168 /** The SplitBar for this region
36169 * @type Roo.SplitBar */
36170 // does not exist yet...
36171 Roo.log([this.position, this.orientation]);
36173 this.split = new Roo.bootstrap.SplitBar({
36174 dragElement : splitEl,
36175 resizingElement: this.el,
36176 orientation : this.orientation
36179 this.split.on("moved", this.onSplitMove, this);
36180 this.split.useShim = this.config.useShim === true;
36181 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36182 if(this.useSplitTips){
36183 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36185 //if(config.collapsible){
36186 // this.split.el.on("dblclick", this.collapse, this);
36189 if(typeof this.config.minSize != "undefined"){
36190 this.split.minSize = this.config.minSize;
36192 if(typeof this.config.maxSize != "undefined"){
36193 this.split.maxSize = this.config.maxSize;
36195 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36196 this.hideSplitter();
36201 getHMaxSize : function(){
36202 var cmax = this.config.maxSize || 10000;
36203 var center = this.mgr.getRegion("center");
36204 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36207 getVMaxSize : function(){
36208 var cmax = this.config.maxSize || 10000;
36209 var center = this.mgr.getRegion("center");
36210 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36213 onSplitMove : function(split, newSize){
36214 this.fireEvent("resized", this, newSize);
36218 * Returns the {@link Roo.SplitBar} for this region.
36219 * @return {Roo.SplitBar}
36221 getSplitBar : function(){
36226 this.hideSplitter();
36227 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36230 hideSplitter : function(){
36232 this.split.el.setLocation(-2000,-2000);
36233 this.split.el.hide();
36239 this.split.el.show();
36241 Roo.bootstrap.layout.Split.superclass.show.call(this);
36244 beforeSlide: function(){
36245 if(Roo.isGecko){// firefox overflow auto bug workaround
36246 this.bodyEl.clip();
36248 this.tabs.bodyEl.clip();
36250 if(this.activePanel){
36251 this.activePanel.getEl().clip();
36253 if(this.activePanel.beforeSlide){
36254 this.activePanel.beforeSlide();
36260 afterSlide : function(){
36261 if(Roo.isGecko){// firefox overflow auto bug workaround
36262 this.bodyEl.unclip();
36264 this.tabs.bodyEl.unclip();
36266 if(this.activePanel){
36267 this.activePanel.getEl().unclip();
36268 if(this.activePanel.afterSlide){
36269 this.activePanel.afterSlide();
36275 initAutoHide : function(){
36276 if(this.autoHide !== false){
36277 if(!this.autoHideHd){
36278 var st = new Roo.util.DelayedTask(this.slideIn, this);
36279 this.autoHideHd = {
36280 "mouseout": function(e){
36281 if(!e.within(this.el, true)){
36285 "mouseover" : function(e){
36291 this.el.on(this.autoHideHd);
36295 clearAutoHide : function(){
36296 if(this.autoHide !== false){
36297 this.el.un("mouseout", this.autoHideHd.mouseout);
36298 this.el.un("mouseover", this.autoHideHd.mouseover);
36302 clearMonitor : function(){
36303 Roo.get(document).un("click", this.slideInIf, this);
36306 // these names are backwards but not changed for compat
36307 slideOut : function(){
36308 if(this.isSlid || this.el.hasActiveFx()){
36311 this.isSlid = true;
36312 if(this.collapseBtn){
36313 this.collapseBtn.hide();
36315 this.closeBtnState = this.closeBtn.getStyle('display');
36316 this.closeBtn.hide();
36318 this.stickBtn.show();
36321 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36322 this.beforeSlide();
36323 this.el.setStyle("z-index", 10001);
36324 this.el.slideIn(this.getSlideAnchor(), {
36325 callback: function(){
36327 this.initAutoHide();
36328 Roo.get(document).on("click", this.slideInIf, this);
36329 this.fireEvent("slideshow", this);
36336 afterSlideIn : function(){
36337 this.clearAutoHide();
36338 this.isSlid = false;
36339 this.clearMonitor();
36340 this.el.setStyle("z-index", "");
36341 if(this.collapseBtn){
36342 this.collapseBtn.show();
36344 this.closeBtn.setStyle('display', this.closeBtnState);
36346 this.stickBtn.hide();
36348 this.fireEvent("slidehide", this);
36351 slideIn : function(cb){
36352 if(!this.isSlid || this.el.hasActiveFx()){
36356 this.isSlid = false;
36357 this.beforeSlide();
36358 this.el.slideOut(this.getSlideAnchor(), {
36359 callback: function(){
36360 this.el.setLeftTop(-10000, -10000);
36362 this.afterSlideIn();
36370 slideInIf : function(e){
36371 if(!e.within(this.el)){
36376 animateCollapse : function(){
36377 this.beforeSlide();
36378 this.el.setStyle("z-index", 20000);
36379 var anchor = this.getSlideAnchor();
36380 this.el.slideOut(anchor, {
36381 callback : function(){
36382 this.el.setStyle("z-index", "");
36383 this.collapsedEl.slideIn(anchor, {duration:.3});
36385 this.el.setLocation(-10000,-10000);
36387 this.fireEvent("collapsed", this);
36394 animateExpand : function(){
36395 this.beforeSlide();
36396 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36397 this.el.setStyle("z-index", 20000);
36398 this.collapsedEl.hide({
36401 this.el.slideIn(this.getSlideAnchor(), {
36402 callback : function(){
36403 this.el.setStyle("z-index", "");
36406 this.split.el.show();
36408 this.fireEvent("invalidated", this);
36409 this.fireEvent("expanded", this);
36437 getAnchor : function(){
36438 return this.anchors[this.position];
36441 getCollapseAnchor : function(){
36442 return this.canchors[this.position];
36445 getSlideAnchor : function(){
36446 return this.sanchors[this.position];
36449 getAlignAdj : function(){
36450 var cm = this.cmargins;
36451 switch(this.position){
36467 getExpandAdj : function(){
36468 var c = this.collapsedEl, cm = this.cmargins;
36469 switch(this.position){
36471 return [-(cm.right+c.getWidth()+cm.left), 0];
36474 return [cm.right+c.getWidth()+cm.left, 0];
36477 return [0, -(cm.top+cm.bottom+c.getHeight())];
36480 return [0, cm.top+cm.bottom+c.getHeight()];
36486 * Ext JS Library 1.1.1
36487 * Copyright(c) 2006-2007, Ext JS, LLC.
36489 * Originally Released Under LGPL - original licence link has changed is not relivant.
36492 * <script type="text/javascript">
36495 * These classes are private internal classes
36497 Roo.bootstrap.layout.Center = function(config){
36498 config.region = "center";
36499 Roo.bootstrap.layout.Region.call(this, config);
36500 this.visible = true;
36501 this.minWidth = config.minWidth || 20;
36502 this.minHeight = config.minHeight || 20;
36505 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36507 // center panel can't be hidden
36511 // center panel can't be hidden
36514 getMinWidth: function(){
36515 return this.minWidth;
36518 getMinHeight: function(){
36519 return this.minHeight;
36532 Roo.bootstrap.layout.North = function(config)
36534 config.region = 'north';
36535 config.cursor = 'n-resize';
36537 Roo.bootstrap.layout.Split.call(this, config);
36541 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36542 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36543 this.split.el.addClass("roo-layout-split-v");
36545 var size = config.initialSize || config.height;
36546 if(typeof size != "undefined"){
36547 this.el.setHeight(size);
36550 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36552 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36556 getBox : function(){
36557 if(this.collapsed){
36558 return this.collapsedEl.getBox();
36560 var box = this.el.getBox();
36562 box.height += this.split.el.getHeight();
36567 updateBox : function(box){
36568 if(this.split && !this.collapsed){
36569 box.height -= this.split.el.getHeight();
36570 this.split.el.setLeft(box.x);
36571 this.split.el.setTop(box.y+box.height);
36572 this.split.el.setWidth(box.width);
36574 if(this.collapsed){
36575 this.updateBody(box.width, null);
36577 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36585 Roo.bootstrap.layout.South = function(config){
36586 config.region = 'south';
36587 config.cursor = 's-resize';
36588 Roo.bootstrap.layout.Split.call(this, config);
36590 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36591 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36592 this.split.el.addClass("roo-layout-split-v");
36594 var size = config.initialSize || config.height;
36595 if(typeof size != "undefined"){
36596 this.el.setHeight(size);
36600 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36601 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36602 getBox : function(){
36603 if(this.collapsed){
36604 return this.collapsedEl.getBox();
36606 var box = this.el.getBox();
36608 var sh = this.split.el.getHeight();
36615 updateBox : function(box){
36616 if(this.split && !this.collapsed){
36617 var sh = this.split.el.getHeight();
36620 this.split.el.setLeft(box.x);
36621 this.split.el.setTop(box.y-sh);
36622 this.split.el.setWidth(box.width);
36624 if(this.collapsed){
36625 this.updateBody(box.width, null);
36627 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36631 Roo.bootstrap.layout.East = function(config){
36632 config.region = "east";
36633 config.cursor = "e-resize";
36634 Roo.bootstrap.layout.Split.call(this, config);
36636 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36637 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36638 this.split.el.addClass("roo-layout-split-h");
36640 var size = config.initialSize || config.width;
36641 if(typeof size != "undefined"){
36642 this.el.setWidth(size);
36645 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36646 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36647 getBox : function(){
36648 if(this.collapsed){
36649 return this.collapsedEl.getBox();
36651 var box = this.el.getBox();
36653 var sw = this.split.el.getWidth();
36660 updateBox : function(box){
36661 if(this.split && !this.collapsed){
36662 var sw = this.split.el.getWidth();
36664 this.split.el.setLeft(box.x);
36665 this.split.el.setTop(box.y);
36666 this.split.el.setHeight(box.height);
36669 if(this.collapsed){
36670 this.updateBody(null, box.height);
36672 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36676 Roo.bootstrap.layout.West = function(config){
36677 config.region = "west";
36678 config.cursor = "w-resize";
36680 Roo.bootstrap.layout.Split.call(this, config);
36682 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36683 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36684 this.split.el.addClass("roo-layout-split-h");
36688 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36689 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36691 onRender: function(ctr, pos)
36693 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36694 var size = this.config.initialSize || this.config.width;
36695 if(typeof size != "undefined"){
36696 this.el.setWidth(size);
36700 getBox : function(){
36701 if(this.collapsed){
36702 return this.collapsedEl.getBox();
36704 var box = this.el.getBox();
36706 box.width += this.split.el.getWidth();
36711 updateBox : function(box){
36712 if(this.split && !this.collapsed){
36713 var sw = this.split.el.getWidth();
36715 this.split.el.setLeft(box.x+box.width);
36716 this.split.el.setTop(box.y);
36717 this.split.el.setHeight(box.height);
36719 if(this.collapsed){
36720 this.updateBody(null, box.height);
36722 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36725 Roo.namespace("Roo.bootstrap.panel");/*
36727 * Ext JS Library 1.1.1
36728 * Copyright(c) 2006-2007, Ext JS, LLC.
36730 * Originally Released Under LGPL - original licence link has changed is not relivant.
36733 * <script type="text/javascript">
36736 * @class Roo.ContentPanel
36737 * @extends Roo.util.Observable
36738 * A basic ContentPanel element.
36739 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36740 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36741 * @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
36742 * @cfg {Boolean} closable True if the panel can be closed/removed
36743 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36744 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36745 * @cfg {Toolbar} toolbar A toolbar for this panel
36746 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36747 * @cfg {String} title The title for this panel
36748 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36749 * @cfg {String} url Calls {@link #setUrl} with this value
36750 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36751 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36752 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36753 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36754 * @cfg {Boolean} badges render the badges
36757 * Create a new ContentPanel.
36758 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36759 * @param {String/Object} config A string to set only the title or a config object
36760 * @param {String} content (optional) Set the HTML content for this panel
36761 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36763 Roo.bootstrap.panel.Content = function( config){
36765 this.tpl = config.tpl || false;
36767 var el = config.el;
36768 var content = config.content;
36770 if(config.autoCreate){ // xtype is available if this is called from factory
36773 this.el = Roo.get(el);
36774 if(!this.el && config && config.autoCreate){
36775 if(typeof config.autoCreate == "object"){
36776 if(!config.autoCreate.id){
36777 config.autoCreate.id = config.id||el;
36779 this.el = Roo.DomHelper.append(document.body,
36780 config.autoCreate, true);
36782 var elcfg = { tag: "div",
36783 cls: "roo-layout-inactive-content",
36787 elcfg.html = config.html;
36791 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36794 this.closable = false;
36795 this.loaded = false;
36796 this.active = false;
36799 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36801 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36803 this.wrapEl = this.el; //this.el.wrap();
36805 if (config.toolbar.items) {
36806 ti = config.toolbar.items ;
36807 delete config.toolbar.items ;
36811 this.toolbar.render(this.wrapEl, 'before');
36812 for(var i =0;i < ti.length;i++) {
36813 // Roo.log(['add child', items[i]]);
36814 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36816 this.toolbar.items = nitems;
36817 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36818 delete config.toolbar;
36822 // xtype created footer. - not sure if will work as we normally have to render first..
36823 if (this.footer && !this.footer.el && this.footer.xtype) {
36824 if (!this.wrapEl) {
36825 this.wrapEl = this.el.wrap();
36828 this.footer.container = this.wrapEl.createChild();
36830 this.footer = Roo.factory(this.footer, Roo);
36835 if(typeof config == "string"){
36836 this.title = config;
36838 Roo.apply(this, config);
36842 this.resizeEl = Roo.get(this.resizeEl, true);
36844 this.resizeEl = this.el;
36846 // handle view.xtype
36854 * Fires when this panel is activated.
36855 * @param {Roo.ContentPanel} this
36859 * @event deactivate
36860 * Fires when this panel is activated.
36861 * @param {Roo.ContentPanel} this
36863 "deactivate" : true,
36867 * Fires when this panel is resized if fitToFrame is true.
36868 * @param {Roo.ContentPanel} this
36869 * @param {Number} width The width after any component adjustments
36870 * @param {Number} height The height after any component adjustments
36876 * Fires when this tab is created
36877 * @param {Roo.ContentPanel} this
36888 if(this.autoScroll){
36889 this.resizeEl.setStyle("overflow", "auto");
36891 // fix randome scrolling
36892 //this.el.on('scroll', function() {
36893 // Roo.log('fix random scolling');
36894 // this.scrollTo('top',0);
36897 content = content || this.content;
36899 this.setContent(content);
36901 if(config && config.url){
36902 this.setUrl(this.url, this.params, this.loadOnce);
36907 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36909 if (this.view && typeof(this.view.xtype) != 'undefined') {
36910 this.view.el = this.el.appendChild(document.createElement("div"));
36911 this.view = Roo.factory(this.view);
36912 this.view.render && this.view.render(false, '');
36916 this.fireEvent('render', this);
36919 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36923 setRegion : function(region){
36924 this.region = region;
36925 this.setActiveClass(region && !this.background);
36929 setActiveClass: function(state)
36932 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36933 this.el.setStyle('position','relative');
36935 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36936 this.el.setStyle('position', 'absolute');
36941 * Returns the toolbar for this Panel if one was configured.
36942 * @return {Roo.Toolbar}
36944 getToolbar : function(){
36945 return this.toolbar;
36948 setActiveState : function(active)
36950 this.active = active;
36951 this.setActiveClass(active);
36953 if(this.fireEvent("deactivate", this) === false){
36958 this.fireEvent("activate", this);
36962 * Updates this panel's element
36963 * @param {String} content The new content
36964 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36966 setContent : function(content, loadScripts){
36967 this.el.update(content, loadScripts);
36970 ignoreResize : function(w, h){
36971 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36974 this.lastSize = {width: w, height: h};
36979 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36980 * @return {Roo.UpdateManager} The UpdateManager
36982 getUpdateManager : function(){
36983 return this.el.getUpdateManager();
36986 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36987 * @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:
36990 url: "your-url.php",
36991 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36992 callback: yourFunction,
36993 scope: yourObject, //(optional scope)
36996 text: "Loading...",
37001 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37002 * 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.
37003 * @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}
37004 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37005 * @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.
37006 * @return {Roo.ContentPanel} this
37009 var um = this.el.getUpdateManager();
37010 um.update.apply(um, arguments);
37016 * 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.
37017 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37018 * @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)
37019 * @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)
37020 * @return {Roo.UpdateManager} The UpdateManager
37022 setUrl : function(url, params, loadOnce){
37023 if(this.refreshDelegate){
37024 this.removeListener("activate", this.refreshDelegate);
37026 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37027 this.on("activate", this.refreshDelegate);
37028 return this.el.getUpdateManager();
37031 _handleRefresh : function(url, params, loadOnce){
37032 if(!loadOnce || !this.loaded){
37033 var updater = this.el.getUpdateManager();
37034 updater.update(url, params, this._setLoaded.createDelegate(this));
37038 _setLoaded : function(){
37039 this.loaded = true;
37043 * Returns this panel's id
37046 getId : function(){
37051 * Returns this panel's element - used by regiosn to add.
37052 * @return {Roo.Element}
37054 getEl : function(){
37055 return this.wrapEl || this.el;
37060 adjustForComponents : function(width, height)
37062 //Roo.log('adjustForComponents ');
37063 if(this.resizeEl != this.el){
37064 width -= this.el.getFrameWidth('lr');
37065 height -= this.el.getFrameWidth('tb');
37068 var te = this.toolbar.getEl();
37069 te.setWidth(width);
37070 height -= te.getHeight();
37073 var te = this.footer.getEl();
37074 te.setWidth(width);
37075 height -= te.getHeight();
37079 if(this.adjustments){
37080 width += this.adjustments[0];
37081 height += this.adjustments[1];
37083 return {"width": width, "height": height};
37086 setSize : function(width, height){
37087 if(this.fitToFrame && !this.ignoreResize(width, height)){
37088 if(this.fitContainer && this.resizeEl != this.el){
37089 this.el.setSize(width, height);
37091 var size = this.adjustForComponents(width, height);
37092 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37093 this.fireEvent('resize', this, size.width, size.height);
37098 * Returns this panel's title
37101 getTitle : function(){
37103 if (typeof(this.title) != 'object') {
37108 for (var k in this.title) {
37109 if (!this.title.hasOwnProperty(k)) {
37113 if (k.indexOf('-') >= 0) {
37114 var s = k.split('-');
37115 for (var i = 0; i<s.length; i++) {
37116 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37119 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37126 * Set this panel's title
37127 * @param {String} title
37129 setTitle : function(title){
37130 this.title = title;
37132 this.region.updatePanelTitle(this, title);
37137 * Returns true is this panel was configured to be closable
37138 * @return {Boolean}
37140 isClosable : function(){
37141 return this.closable;
37144 beforeSlide : function(){
37146 this.resizeEl.clip();
37149 afterSlide : function(){
37151 this.resizeEl.unclip();
37155 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37156 * Will fail silently if the {@link #setUrl} method has not been called.
37157 * This does not activate the panel, just updates its content.
37159 refresh : function(){
37160 if(this.refreshDelegate){
37161 this.loaded = false;
37162 this.refreshDelegate();
37167 * Destroys this panel
37169 destroy : function(){
37170 this.el.removeAllListeners();
37171 var tempEl = document.createElement("span");
37172 tempEl.appendChild(this.el.dom);
37173 tempEl.innerHTML = "";
37179 * form - if the content panel contains a form - this is a reference to it.
37180 * @type {Roo.form.Form}
37184 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37185 * This contains a reference to it.
37191 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37201 * @param {Object} cfg Xtype definition of item to add.
37205 getChildContainer: function () {
37206 return this.getEl();
37211 var ret = new Roo.factory(cfg);
37216 if (cfg.xtype.match(/^Form$/)) {
37219 //if (this.footer) {
37220 // el = this.footer.container.insertSibling(false, 'before');
37222 el = this.el.createChild();
37225 this.form = new Roo.form.Form(cfg);
37228 if ( this.form.allItems.length) {
37229 this.form.render(el.dom);
37233 // should only have one of theses..
37234 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37235 // views.. should not be just added - used named prop 'view''
37237 cfg.el = this.el.appendChild(document.createElement("div"));
37240 var ret = new Roo.factory(cfg);
37242 ret.render && ret.render(false, ''); // render blank..
37252 * @class Roo.bootstrap.panel.Grid
37253 * @extends Roo.bootstrap.panel.Content
37255 * Create a new GridPanel.
37256 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37257 * @param {Object} config A the config object
37263 Roo.bootstrap.panel.Grid = function(config)
37267 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37268 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37270 config.el = this.wrapper;
37271 //this.el = this.wrapper;
37273 if (config.container) {
37274 // ctor'ed from a Border/panel.grid
37277 this.wrapper.setStyle("overflow", "hidden");
37278 this.wrapper.addClass('roo-grid-container');
37283 if(config.toolbar){
37284 var tool_el = this.wrapper.createChild();
37285 this.toolbar = Roo.factory(config.toolbar);
37287 if (config.toolbar.items) {
37288 ti = config.toolbar.items ;
37289 delete config.toolbar.items ;
37293 this.toolbar.render(tool_el);
37294 for(var i =0;i < ti.length;i++) {
37295 // Roo.log(['add child', items[i]]);
37296 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37298 this.toolbar.items = nitems;
37300 delete config.toolbar;
37303 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37304 config.grid.scrollBody = true;;
37305 config.grid.monitorWindowResize = false; // turn off autosizing
37306 config.grid.autoHeight = false;
37307 config.grid.autoWidth = false;
37309 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37311 if (config.background) {
37312 // render grid on panel activation (if panel background)
37313 this.on('activate', function(gp) {
37314 if (!gp.grid.rendered) {
37315 gp.grid.render(this.wrapper);
37316 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37321 this.grid.render(this.wrapper);
37322 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37325 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37326 // ??? needed ??? config.el = this.wrapper;
37331 // xtype created footer. - not sure if will work as we normally have to render first..
37332 if (this.footer && !this.footer.el && this.footer.xtype) {
37334 var ctr = this.grid.getView().getFooterPanel(true);
37335 this.footer.dataSource = this.grid.dataSource;
37336 this.footer = Roo.factory(this.footer, Roo);
37337 this.footer.render(ctr);
37347 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37348 getId : function(){
37349 return this.grid.id;
37353 * Returns the grid for this panel
37354 * @return {Roo.bootstrap.Table}
37356 getGrid : function(){
37360 setSize : function(width, height){
37361 if(!this.ignoreResize(width, height)){
37362 var grid = this.grid;
37363 var size = this.adjustForComponents(width, height);
37364 var gridel = grid.getGridEl();
37365 gridel.setSize(size.width, size.height);
37367 var thd = grid.getGridEl().select('thead',true).first();
37368 var tbd = grid.getGridEl().select('tbody', true).first();
37370 tbd.setSize(width, height - thd.getHeight());
37379 beforeSlide : function(){
37380 this.grid.getView().scroller.clip();
37383 afterSlide : function(){
37384 this.grid.getView().scroller.unclip();
37387 destroy : function(){
37388 this.grid.destroy();
37390 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37395 * @class Roo.bootstrap.panel.Nest
37396 * @extends Roo.bootstrap.panel.Content
37398 * Create a new Panel, that can contain a layout.Border.
37401 * @param {Roo.BorderLayout} layout The layout for this panel
37402 * @param {String/Object} config A string to set only the title or a config object
37404 Roo.bootstrap.panel.Nest = function(config)
37406 // construct with only one argument..
37407 /* FIXME - implement nicer consturctors
37408 if (layout.layout) {
37410 layout = config.layout;
37411 delete config.layout;
37413 if (layout.xtype && !layout.getEl) {
37414 // then layout needs constructing..
37415 layout = Roo.factory(layout, Roo);
37419 config.el = config.layout.getEl();
37421 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37423 config.layout.monitorWindowResize = false; // turn off autosizing
37424 this.layout = config.layout;
37425 this.layout.getEl().addClass("roo-layout-nested-layout");
37432 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37434 setSize : function(width, height){
37435 if(!this.ignoreResize(width, height)){
37436 var size = this.adjustForComponents(width, height);
37437 var el = this.layout.getEl();
37438 if (size.height < 1) {
37439 el.setWidth(size.width);
37441 el.setSize(size.width, size.height);
37443 var touch = el.dom.offsetWidth;
37444 this.layout.layout();
37445 // ie requires a double layout on the first pass
37446 if(Roo.isIE && !this.initialized){
37447 this.initialized = true;
37448 this.layout.layout();
37453 // activate all subpanels if not currently active..
37455 setActiveState : function(active){
37456 this.active = active;
37457 this.setActiveClass(active);
37460 this.fireEvent("deactivate", this);
37464 this.fireEvent("activate", this);
37465 // not sure if this should happen before or after..
37466 if (!this.layout) {
37467 return; // should not happen..
37470 for (var r in this.layout.regions) {
37471 reg = this.layout.getRegion(r);
37472 if (reg.getActivePanel()) {
37473 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37474 reg.setActivePanel(reg.getActivePanel());
37477 if (!reg.panels.length) {
37480 reg.showPanel(reg.getPanel(0));
37489 * Returns the nested BorderLayout for this panel
37490 * @return {Roo.BorderLayout}
37492 getLayout : function(){
37493 return this.layout;
37497 * Adds a xtype elements to the layout of the nested panel
37501 xtype : 'ContentPanel',
37508 xtype : 'NestedLayoutPanel',
37514 items : [ ... list of content panels or nested layout panels.. ]
37518 * @param {Object} cfg Xtype definition of item to add.
37520 addxtype : function(cfg) {
37521 return this.layout.addxtype(cfg);
37526 * Ext JS Library 1.1.1
37527 * Copyright(c) 2006-2007, Ext JS, LLC.
37529 * Originally Released Under LGPL - original licence link has changed is not relivant.
37532 * <script type="text/javascript">
37535 * @class Roo.TabPanel
37536 * @extends Roo.util.Observable
37537 * A lightweight tab container.
37541 // basic tabs 1, built from existing content
37542 var tabs = new Roo.TabPanel("tabs1");
37543 tabs.addTab("script", "View Script");
37544 tabs.addTab("markup", "View Markup");
37545 tabs.activate("script");
37547 // more advanced tabs, built from javascript
37548 var jtabs = new Roo.TabPanel("jtabs");
37549 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37551 // set up the UpdateManager
37552 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37553 var updater = tab2.getUpdateManager();
37554 updater.setDefaultUrl("ajax1.htm");
37555 tab2.on('activate', updater.refresh, updater, true);
37557 // Use setUrl for Ajax loading
37558 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37559 tab3.setUrl("ajax2.htm", null, true);
37562 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37565 jtabs.activate("jtabs-1");
37568 * Create a new TabPanel.
37569 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37570 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37572 Roo.bootstrap.panel.Tabs = function(config){
37574 * The container element for this TabPanel.
37575 * @type Roo.Element
37577 this.el = Roo.get(config.el);
37580 if(typeof config == "boolean"){
37581 this.tabPosition = config ? "bottom" : "top";
37583 Roo.apply(this, config);
37587 if(this.tabPosition == "bottom"){
37588 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37589 this.el.addClass("roo-tabs-bottom");
37591 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37592 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37593 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37595 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37597 if(this.tabPosition != "bottom"){
37598 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37599 * @type Roo.Element
37601 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37602 this.el.addClass("roo-tabs-top");
37606 this.bodyEl.setStyle("position", "relative");
37608 this.active = null;
37609 this.activateDelegate = this.activate.createDelegate(this);
37614 * Fires when the active tab changes
37615 * @param {Roo.TabPanel} this
37616 * @param {Roo.TabPanelItem} activePanel The new active tab
37620 * @event beforetabchange
37621 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37622 * @param {Roo.TabPanel} this
37623 * @param {Object} e Set cancel to true on this object to cancel the tab change
37624 * @param {Roo.TabPanelItem} tab The tab being changed to
37626 "beforetabchange" : true
37629 Roo.EventManager.onWindowResize(this.onResize, this);
37630 this.cpad = this.el.getPadding("lr");
37631 this.hiddenCount = 0;
37634 // toolbar on the tabbar support...
37635 if (this.toolbar) {
37636 alert("no toolbar support yet");
37637 this.toolbar = false;
37639 var tcfg = this.toolbar;
37640 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37641 this.toolbar = new Roo.Toolbar(tcfg);
37642 if (Roo.isSafari) {
37643 var tbl = tcfg.container.child('table', true);
37644 tbl.setAttribute('width', '100%');
37652 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37655 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37657 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37659 tabPosition : "top",
37661 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37663 currentTabWidth : 0,
37665 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37669 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37673 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37675 preferredTabWidth : 175,
37677 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37679 resizeTabs : false,
37681 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37683 monitorResize : true,
37685 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37690 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37691 * @param {String} id The id of the div to use <b>or create</b>
37692 * @param {String} text The text for the tab
37693 * @param {String} content (optional) Content to put in the TabPanelItem body
37694 * @param {Boolean} closable (optional) True to create a close icon on the tab
37695 * @return {Roo.TabPanelItem} The created TabPanelItem
37697 addTab : function(id, text, content, closable, tpl)
37699 var item = new Roo.bootstrap.panel.TabItem({
37703 closable : closable,
37706 this.addTabItem(item);
37708 item.setContent(content);
37714 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37715 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37716 * @return {Roo.TabPanelItem}
37718 getTab : function(id){
37719 return this.items[id];
37723 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37724 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37726 hideTab : function(id){
37727 var t = this.items[id];
37730 this.hiddenCount++;
37731 this.autoSizeTabs();
37736 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37737 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37739 unhideTab : function(id){
37740 var t = this.items[id];
37742 t.setHidden(false);
37743 this.hiddenCount--;
37744 this.autoSizeTabs();
37749 * Adds an existing {@link Roo.TabPanelItem}.
37750 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37752 addTabItem : function(item){
37753 this.items[item.id] = item;
37754 this.items.push(item);
37755 // if(this.resizeTabs){
37756 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37757 // this.autoSizeTabs();
37759 // item.autoSize();
37764 * Removes a {@link Roo.TabPanelItem}.
37765 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37767 removeTab : function(id){
37768 var items = this.items;
37769 var tab = items[id];
37770 if(!tab) { return; }
37771 var index = items.indexOf(tab);
37772 if(this.active == tab && items.length > 1){
37773 var newTab = this.getNextAvailable(index);
37778 this.stripEl.dom.removeChild(tab.pnode.dom);
37779 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37780 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37782 items.splice(index, 1);
37783 delete this.items[tab.id];
37784 tab.fireEvent("close", tab);
37785 tab.purgeListeners();
37786 this.autoSizeTabs();
37789 getNextAvailable : function(start){
37790 var items = this.items;
37792 // look for a next tab that will slide over to
37793 // replace the one being removed
37794 while(index < items.length){
37795 var item = items[++index];
37796 if(item && !item.isHidden()){
37800 // if one isn't found select the previous tab (on the left)
37803 var item = items[--index];
37804 if(item && !item.isHidden()){
37812 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37813 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37815 disableTab : function(id){
37816 var tab = this.items[id];
37817 if(tab && this.active != tab){
37823 * Enables a {@link Roo.TabPanelItem} that is disabled.
37824 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37826 enableTab : function(id){
37827 var tab = this.items[id];
37832 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37833 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37834 * @return {Roo.TabPanelItem} The TabPanelItem.
37836 activate : function(id){
37837 var tab = this.items[id];
37841 if(tab == this.active || tab.disabled){
37845 this.fireEvent("beforetabchange", this, e, tab);
37846 if(e.cancel !== true && !tab.disabled){
37848 this.active.hide();
37850 this.active = this.items[id];
37851 this.active.show();
37852 this.fireEvent("tabchange", this, this.active);
37858 * Gets the active {@link Roo.TabPanelItem}.
37859 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37861 getActiveTab : function(){
37862 return this.active;
37866 * Updates the tab body element to fit the height of the container element
37867 * for overflow scrolling
37868 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37870 syncHeight : function(targetHeight){
37871 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37872 var bm = this.bodyEl.getMargins();
37873 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37874 this.bodyEl.setHeight(newHeight);
37878 onResize : function(){
37879 if(this.monitorResize){
37880 this.autoSizeTabs();
37885 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37887 beginUpdate : function(){
37888 this.updating = true;
37892 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37894 endUpdate : function(){
37895 this.updating = false;
37896 this.autoSizeTabs();
37900 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37902 autoSizeTabs : function(){
37903 var count = this.items.length;
37904 var vcount = count - this.hiddenCount;
37905 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37908 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37909 var availWidth = Math.floor(w / vcount);
37910 var b = this.stripBody;
37911 if(b.getWidth() > w){
37912 var tabs = this.items;
37913 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37914 if(availWidth < this.minTabWidth){
37915 /*if(!this.sleft){ // incomplete scrolling code
37916 this.createScrollButtons();
37919 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37922 if(this.currentTabWidth < this.preferredTabWidth){
37923 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37929 * Returns the number of tabs in this TabPanel.
37932 getCount : function(){
37933 return this.items.length;
37937 * Resizes all the tabs to the passed width
37938 * @param {Number} The new width
37940 setTabWidth : function(width){
37941 this.currentTabWidth = width;
37942 for(var i = 0, len = this.items.length; i < len; i++) {
37943 if(!this.items[i].isHidden()) {
37944 this.items[i].setWidth(width);
37950 * Destroys this TabPanel
37951 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37953 destroy : function(removeEl){
37954 Roo.EventManager.removeResizeListener(this.onResize, this);
37955 for(var i = 0, len = this.items.length; i < len; i++){
37956 this.items[i].purgeListeners();
37958 if(removeEl === true){
37959 this.el.update("");
37964 createStrip : function(container)
37966 var strip = document.createElement("nav");
37967 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37968 container.appendChild(strip);
37972 createStripList : function(strip)
37974 // div wrapper for retard IE
37975 // returns the "tr" element.
37976 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37977 //'<div class="x-tabs-strip-wrap">'+
37978 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37979 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37980 return strip.firstChild; //.firstChild.firstChild.firstChild;
37982 createBody : function(container)
37984 var body = document.createElement("div");
37985 Roo.id(body, "tab-body");
37986 //Roo.fly(body).addClass("x-tabs-body");
37987 Roo.fly(body).addClass("tab-content");
37988 container.appendChild(body);
37991 createItemBody :function(bodyEl, id){
37992 var body = Roo.getDom(id);
37994 body = document.createElement("div");
37997 //Roo.fly(body).addClass("x-tabs-item-body");
37998 Roo.fly(body).addClass("tab-pane");
37999 bodyEl.insertBefore(body, bodyEl.firstChild);
38003 createStripElements : function(stripEl, text, closable, tpl)
38005 var td = document.createElement("li"); // was td..
38008 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38011 stripEl.appendChild(td);
38013 td.className = "x-tabs-closable";
38014 if(!this.closeTpl){
38015 this.closeTpl = new Roo.Template(
38016 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38017 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38018 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38021 var el = this.closeTpl.overwrite(td, {"text": text});
38022 var close = el.getElementsByTagName("div")[0];
38023 var inner = el.getElementsByTagName("em")[0];
38024 return {"el": el, "close": close, "inner": inner};
38027 // not sure what this is..
38028 // if(!this.tabTpl){
38029 //this.tabTpl = new Roo.Template(
38030 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38031 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38033 // this.tabTpl = new Roo.Template(
38034 // '<a href="#">' +
38035 // '<span unselectable="on"' +
38036 // (this.disableTooltips ? '' : ' title="{text}"') +
38037 // ' >{text}</span></a>'
38043 var template = tpl || this.tabTpl || false;
38047 template = new Roo.Template(
38049 '<span unselectable="on"' +
38050 (this.disableTooltips ? '' : ' title="{text}"') +
38051 ' >{text}</span></a>'
38055 switch (typeof(template)) {
38059 template = new Roo.Template(template);
38065 var el = template.overwrite(td, {"text": text});
38067 var inner = el.getElementsByTagName("span")[0];
38069 return {"el": el, "inner": inner};
38077 * @class Roo.TabPanelItem
38078 * @extends Roo.util.Observable
38079 * Represents an individual item (tab plus body) in a TabPanel.
38080 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38081 * @param {String} id The id of this TabPanelItem
38082 * @param {String} text The text for the tab of this TabPanelItem
38083 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38085 Roo.bootstrap.panel.TabItem = function(config){
38087 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38088 * @type Roo.TabPanel
38090 this.tabPanel = config.panel;
38092 * The id for this TabPanelItem
38095 this.id = config.id;
38097 this.disabled = false;
38099 this.text = config.text;
38101 this.loaded = false;
38102 this.closable = config.closable;
38105 * The body element for this TabPanelItem.
38106 * @type Roo.Element
38108 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38109 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38110 this.bodyEl.setStyle("display", "block");
38111 this.bodyEl.setStyle("zoom", "1");
38112 //this.hideAction();
38114 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38116 this.el = Roo.get(els.el);
38117 this.inner = Roo.get(els.inner, true);
38118 this.textEl = Roo.get(this.el.dom.firstChild, true);
38119 this.pnode = Roo.get(els.el.parentNode, true);
38120 // this.el.on("mousedown", this.onTabMouseDown, this);
38121 this.el.on("click", this.onTabClick, this);
38123 if(config.closable){
38124 var c = Roo.get(els.close, true);
38125 c.dom.title = this.closeText;
38126 c.addClassOnOver("close-over");
38127 c.on("click", this.closeClick, this);
38133 * Fires when this tab becomes the active tab.
38134 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38135 * @param {Roo.TabPanelItem} this
38139 * @event beforeclose
38140 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38141 * @param {Roo.TabPanelItem} this
38142 * @param {Object} e Set cancel to true on this object to cancel the close.
38144 "beforeclose": true,
38147 * Fires when this tab is closed.
38148 * @param {Roo.TabPanelItem} this
38152 * @event deactivate
38153 * Fires when this tab is no longer the active tab.
38154 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38155 * @param {Roo.TabPanelItem} this
38157 "deactivate" : true
38159 this.hidden = false;
38161 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38164 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38166 purgeListeners : function(){
38167 Roo.util.Observable.prototype.purgeListeners.call(this);
38168 this.el.removeAllListeners();
38171 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38174 this.pnode.addClass("active");
38177 this.tabPanel.stripWrap.repaint();
38179 this.fireEvent("activate", this.tabPanel, this);
38183 * Returns true if this tab is the active tab.
38184 * @return {Boolean}
38186 isActive : function(){
38187 return this.tabPanel.getActiveTab() == this;
38191 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38194 this.pnode.removeClass("active");
38196 this.fireEvent("deactivate", this.tabPanel, this);
38199 hideAction : function(){
38200 this.bodyEl.hide();
38201 this.bodyEl.setStyle("position", "absolute");
38202 this.bodyEl.setLeft("-20000px");
38203 this.bodyEl.setTop("-20000px");
38206 showAction : function(){
38207 this.bodyEl.setStyle("position", "relative");
38208 this.bodyEl.setTop("");
38209 this.bodyEl.setLeft("");
38210 this.bodyEl.show();
38214 * Set the tooltip for the tab.
38215 * @param {String} tooltip The tab's tooltip
38217 setTooltip : function(text){
38218 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38219 this.textEl.dom.qtip = text;
38220 this.textEl.dom.removeAttribute('title');
38222 this.textEl.dom.title = text;
38226 onTabClick : function(e){
38227 e.preventDefault();
38228 this.tabPanel.activate(this.id);
38231 onTabMouseDown : function(e){
38232 e.preventDefault();
38233 this.tabPanel.activate(this.id);
38236 getWidth : function(){
38237 return this.inner.getWidth();
38240 setWidth : function(width){
38241 var iwidth = width - this.pnode.getPadding("lr");
38242 this.inner.setWidth(iwidth);
38243 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38244 this.pnode.setWidth(width);
38248 * Show or hide the tab
38249 * @param {Boolean} hidden True to hide or false to show.
38251 setHidden : function(hidden){
38252 this.hidden = hidden;
38253 this.pnode.setStyle("display", hidden ? "none" : "");
38257 * Returns true if this tab is "hidden"
38258 * @return {Boolean}
38260 isHidden : function(){
38261 return this.hidden;
38265 * Returns the text for this tab
38268 getText : function(){
38272 autoSize : function(){
38273 //this.el.beginMeasure();
38274 this.textEl.setWidth(1);
38276 * #2804 [new] Tabs in Roojs
38277 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38279 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38280 //this.el.endMeasure();
38284 * Sets the text for the tab (Note: this also sets the tooltip text)
38285 * @param {String} text The tab's text and tooltip
38287 setText : function(text){
38289 this.textEl.update(text);
38290 this.setTooltip(text);
38291 //if(!this.tabPanel.resizeTabs){
38292 // this.autoSize();
38296 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38298 activate : function(){
38299 this.tabPanel.activate(this.id);
38303 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38305 disable : function(){
38306 if(this.tabPanel.active != this){
38307 this.disabled = true;
38308 this.pnode.addClass("disabled");
38313 * Enables this TabPanelItem if it was previously disabled.
38315 enable : function(){
38316 this.disabled = false;
38317 this.pnode.removeClass("disabled");
38321 * Sets the content for this TabPanelItem.
38322 * @param {String} content The content
38323 * @param {Boolean} loadScripts true to look for and load scripts
38325 setContent : function(content, loadScripts){
38326 this.bodyEl.update(content, loadScripts);
38330 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38331 * @return {Roo.UpdateManager} The UpdateManager
38333 getUpdateManager : function(){
38334 return this.bodyEl.getUpdateManager();
38338 * Set a URL to be used to load the content for this TabPanelItem.
38339 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38340 * @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)
38341 * @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)
38342 * @return {Roo.UpdateManager} The UpdateManager
38344 setUrl : function(url, params, loadOnce){
38345 if(this.refreshDelegate){
38346 this.un('activate', this.refreshDelegate);
38348 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38349 this.on("activate", this.refreshDelegate);
38350 return this.bodyEl.getUpdateManager();
38354 _handleRefresh : function(url, params, loadOnce){
38355 if(!loadOnce || !this.loaded){
38356 var updater = this.bodyEl.getUpdateManager();
38357 updater.update(url, params, this._setLoaded.createDelegate(this));
38362 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38363 * Will fail silently if the setUrl method has not been called.
38364 * This does not activate the panel, just updates its content.
38366 refresh : function(){
38367 if(this.refreshDelegate){
38368 this.loaded = false;
38369 this.refreshDelegate();
38374 _setLoaded : function(){
38375 this.loaded = true;
38379 closeClick : function(e){
38382 this.fireEvent("beforeclose", this, o);
38383 if(o.cancel !== true){
38384 this.tabPanel.removeTab(this.id);
38388 * The text displayed in the tooltip for the close icon.
38391 closeText : "Close this tab"
38394 * This script refer to:
38395 * Title: International Telephone Input
38396 * Author: Jack O'Connor
38397 * Code version: v12.1.12
38398 * Availability: https://github.com/jackocnr/intl-tel-input.git
38401 Roo.bootstrap.PhoneInputData = function() {
38404 "Afghanistan (افغانستان)",
38409 "Albania (Shqipëri)",
38414 "Algeria (الجزائر)",
38439 "Antigua and Barbuda",
38449 "Armenia (Հայաստան)",
38465 "Austria (Österreich)",
38470 "Azerbaijan (Azərbaycan)",
38480 "Bahrain (البحرين)",
38485 "Bangladesh (বাংলাদেশ)",
38495 "Belarus (Беларусь)",
38500 "Belgium (België)",
38530 "Bosnia and Herzegovina (Босна и Херцеговина)",
38545 "British Indian Ocean Territory",
38550 "British Virgin Islands",
38560 "Bulgaria (България)",
38570 "Burundi (Uburundi)",
38575 "Cambodia (កម្ពុជា)",
38580 "Cameroon (Cameroun)",
38589 ["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"]
38592 "Cape Verde (Kabu Verdi)",
38597 "Caribbean Netherlands",
38608 "Central African Republic (République centrafricaine)",
38628 "Christmas Island",
38634 "Cocos (Keeling) Islands",
38645 "Comoros (جزر القمر)",
38650 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38655 "Congo (Republic) (Congo-Brazzaville)",
38675 "Croatia (Hrvatska)",
38696 "Czech Republic (Česká republika)",
38701 "Denmark (Danmark)",
38716 "Dominican Republic (República Dominicana)",
38720 ["809", "829", "849"]
38738 "Equatorial Guinea (Guinea Ecuatorial)",
38758 "Falkland Islands (Islas Malvinas)",
38763 "Faroe Islands (Føroyar)",
38784 "French Guiana (Guyane française)",
38789 "French Polynesia (Polynésie française)",
38804 "Georgia (საქართველო)",
38809 "Germany (Deutschland)",
38829 "Greenland (Kalaallit Nunaat)",
38866 "Guinea-Bissau (Guiné Bissau)",
38891 "Hungary (Magyarország)",
38896 "Iceland (Ísland)",
38916 "Iraq (العراق)",
38932 "Israel (ישראל)",
38959 "Jordan (الأردن)",
38964 "Kazakhstan (Казахстан)",
38985 "Kuwait (الكويت)",
38990 "Kyrgyzstan (Кыргызстан)",
39000 "Latvia (Latvija)",
39005 "Lebanon (لبنان)",
39020 "Libya (ليبيا)",
39030 "Lithuania (Lietuva)",
39045 "Macedonia (FYROM) (Македонија)",
39050 "Madagascar (Madagasikara)",
39080 "Marshall Islands",
39090 "Mauritania (موريتانيا)",
39095 "Mauritius (Moris)",
39116 "Moldova (Republica Moldova)",
39126 "Mongolia (Монгол)",
39131 "Montenegro (Crna Gora)",
39141 "Morocco (المغرب)",
39147 "Mozambique (Moçambique)",
39152 "Myanmar (Burma) (မြန်မာ)",
39157 "Namibia (Namibië)",
39172 "Netherlands (Nederland)",
39177 "New Caledonia (Nouvelle-Calédonie)",
39212 "North Korea (조선 민주주의 인민 공화국)",
39217 "Northern Mariana Islands",
39233 "Pakistan (پاکستان)",
39243 "Palestine (فلسطين)",
39253 "Papua New Guinea",
39295 "Réunion (La Réunion)",
39301 "Romania (România)",
39317 "Saint Barthélemy",
39328 "Saint Kitts and Nevis",
39338 "Saint Martin (Saint-Martin (partie française))",
39344 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39349 "Saint Vincent and the Grenadines",
39364 "São Tomé and Príncipe (São Tomé e Príncipe)",
39369 "Saudi Arabia (المملكة العربية السعودية)",
39374 "Senegal (Sénégal)",
39404 "Slovakia (Slovensko)",
39409 "Slovenia (Slovenija)",
39419 "Somalia (Soomaaliya)",
39429 "South Korea (대한민국)",
39434 "South Sudan (جنوب السودان)",
39444 "Sri Lanka (ශ්රී ලංකාව)",
39449 "Sudan (السودان)",
39459 "Svalbard and Jan Mayen",
39470 "Sweden (Sverige)",
39475 "Switzerland (Schweiz)",
39480 "Syria (سوريا)",
39525 "Trinidad and Tobago",
39530 "Tunisia (تونس)",
39535 "Turkey (Türkiye)",
39545 "Turks and Caicos Islands",
39555 "U.S. Virgin Islands",
39565 "Ukraine (Україна)",
39570 "United Arab Emirates (الإمارات العربية المتحدة)",
39592 "Uzbekistan (Oʻzbekiston)",
39602 "Vatican City (Città del Vaticano)",
39613 "Vietnam (Việt Nam)",
39618 "Wallis and Futuna (Wallis-et-Futuna)",
39623 "Western Sahara (الصحراء الغربية)",
39629 "Yemen (اليمن)",
39653 * This script refer to:
39654 * Title: International Telephone Input
39655 * Author: Jack O'Connor
39656 * Code version: v12.1.12
39657 * Availability: https://github.com/jackocnr/intl-tel-input.git
39661 * @class Roo.bootstrap.PhoneInput
39662 * @extends Roo.bootstrap.TriggerField
39663 * An input with International dial-code selection
39665 * @cfg {String} defaultDialCode default '+852'
39666 * @cfg {Array} preferedCountries default []
39669 * Create a new PhoneInput.
39670 * @param {Object} config Configuration options
39673 Roo.bootstrap.PhoneInput = function(config) {
39674 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39677 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39679 listWidth: undefined,
39681 selectedClass: 'active',
39683 invalidClass : "has-warning",
39685 validClass: 'has-success',
39687 allowed: '0123456789',
39690 * @cfg {String} defaultDialCode The default dial code when initializing the input
39692 defaultDialCode: '+852',
39695 * @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
39697 preferedCountries: false,
39699 getAutoCreate : function()
39701 var data = Roo.bootstrap.PhoneInputData();
39702 var align = this.labelAlign || this.parentLabelAlign();
39705 this.allCountries = [];
39706 this.dialCodeMapping = [];
39708 for (var i = 0; i < data.length; i++) {
39710 this.allCountries[i] = {
39714 priority: c[3] || 0,
39715 areaCodes: c[4] || null
39717 this.dialCodeMapping[c[2]] = {
39720 priority: c[3] || 0,
39721 areaCodes: c[4] || null
39733 cls : 'form-control tel-input',
39734 autocomplete: 'new-password'
39737 var hiddenInput = {
39740 cls: 'hidden-tel-input'
39744 hiddenInput.name = this.name;
39747 if (this.disabled) {
39748 input.disabled = true;
39751 var flag_container = {
39768 cls: this.hasFeedback ? 'has-feedback' : '',
39774 cls: 'dial-code-holder',
39781 cls: 'roo-select2-container input-group',
39788 if (this.fieldLabel.length) {
39791 tooltip: 'This field is required'
39797 cls: 'control-label',
39803 html: this.fieldLabel
39806 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39812 if(this.indicatorpos == 'right') {
39813 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39820 if(align == 'left') {
39828 if(this.labelWidth > 12){
39829 label.style = "width: " + this.labelWidth + 'px';
39831 if(this.labelWidth < 13 && this.labelmd == 0){
39832 this.labelmd = this.labelWidth;
39834 if(this.labellg > 0){
39835 label.cls += ' col-lg-' + this.labellg;
39836 input.cls += ' col-lg-' + (12 - this.labellg);
39838 if(this.labelmd > 0){
39839 label.cls += ' col-md-' + this.labelmd;
39840 container.cls += ' col-md-' + (12 - this.labelmd);
39842 if(this.labelsm > 0){
39843 label.cls += ' col-sm-' + this.labelsm;
39844 container.cls += ' col-sm-' + (12 - this.labelsm);
39846 if(this.labelxs > 0){
39847 label.cls += ' col-xs-' + this.labelxs;
39848 container.cls += ' col-xs-' + (12 - this.labelxs);
39858 var settings = this;
39860 ['xs','sm','md','lg'].map(function(size){
39861 if (settings[size]) {
39862 cfg.cls += ' col-' + size + '-' + settings[size];
39866 this.store = new Roo.data.Store({
39867 proxy : new Roo.data.MemoryProxy({}),
39868 reader : new Roo.data.JsonReader({
39879 'name' : 'dialCode',
39883 'name' : 'priority',
39887 'name' : 'areaCodes',
39894 if(!this.preferedCountries) {
39895 this.preferedCountries = [
39902 var p = this.preferedCountries.reverse();
39905 for (var i = 0; i < p.length; i++) {
39906 for (var j = 0; j < this.allCountries.length; j++) {
39907 if(this.allCountries[j].iso2 == p[i]) {
39908 var t = this.allCountries[j];
39909 this.allCountries.splice(j,1);
39910 this.allCountries.unshift(t);
39916 this.store.proxy.data = {
39918 data: this.allCountries
39924 initEvents : function()
39927 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39929 this.indicator = this.indicatorEl();
39930 this.flag = this.flagEl();
39931 this.dialCodeHolder = this.dialCodeHolderEl();
39933 this.trigger = this.el.select('div.flag-box',true).first();
39934 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39939 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39940 _this.list.setWidth(lw);
39943 this.list.on('mouseover', this.onViewOver, this);
39944 this.list.on('mousemove', this.onViewMove, this);
39945 this.inputEl().on("keyup", this.onKeyUp, this);
39947 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39949 this.view = new Roo.View(this.list, this.tpl, {
39950 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39953 this.view.on('click', this.onViewClick, this);
39954 this.setValue(this.defaultDialCode);
39957 onTriggerClick : function(e)
39959 Roo.log('trigger click');
39964 if(this.isExpanded()){
39966 this.hasFocus = false;
39968 this.store.load({});
39969 this.hasFocus = true;
39974 isExpanded : function()
39976 return this.list.isVisible();
39979 collapse : function()
39981 if(!this.isExpanded()){
39985 Roo.get(document).un('mousedown', this.collapseIf, this);
39986 Roo.get(document).un('mousewheel', this.collapseIf, this);
39987 this.fireEvent('collapse', this);
39991 expand : function()
39995 if(this.isExpanded() || !this.hasFocus){
39999 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40000 this.list.setWidth(lw);
40003 this.restrictHeight();
40005 Roo.get(document).on('mousedown', this.collapseIf, this);
40006 Roo.get(document).on('mousewheel', this.collapseIf, this);
40008 this.fireEvent('expand', this);
40011 restrictHeight : function()
40013 this.list.alignTo(this.inputEl(), this.listAlign);
40014 this.list.alignTo(this.inputEl(), this.listAlign);
40017 onViewOver : function(e, t)
40019 if(this.inKeyMode){
40022 var item = this.view.findItemFromChild(t);
40025 var index = this.view.indexOf(item);
40026 this.select(index, false);
40031 onViewClick : function(view, doFocus, el, e)
40033 var index = this.view.getSelectedIndexes()[0];
40035 var r = this.store.getAt(index);
40038 this.onSelect(r, index);
40040 if(doFocus !== false && !this.blockFocus){
40041 this.inputEl().focus();
40045 onViewMove : function(e, t)
40047 this.inKeyMode = false;
40050 select : function(index, scrollIntoView)
40052 this.selectedIndex = index;
40053 this.view.select(index);
40054 if(scrollIntoView !== false){
40055 var el = this.view.getNode(index);
40057 this.list.scrollChildIntoView(el, false);
40062 createList : function()
40064 this.list = Roo.get(document.body).createChild({
40066 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40067 style: 'display:none'
40070 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40073 collapseIf : function(e)
40075 var in_combo = e.within(this.el);
40076 var in_list = e.within(this.list);
40077 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40079 if (in_combo || in_list || is_list) {
40085 onSelect : function(record, index)
40087 if(this.fireEvent('beforeselect', this, record, index) !== false){
40089 this.setFlagClass(record.data.iso2);
40090 this.setDialCode(record.data.dialCode);
40091 this.hasFocus = false;
40093 this.fireEvent('select', this, record, index);
40097 flagEl : function()
40099 var flag = this.el.select('div.flag',true).first();
40106 dialCodeHolderEl : function()
40108 var d = this.el.select('input.dial-code-holder',true).first();
40115 setDialCode : function(v)
40117 this.dialCodeHolder.dom.value = '+'+v;
40120 setFlagClass : function(n)
40122 this.flag.dom.className = 'flag '+n;
40125 getValue : function()
40127 var v = this.inputEl().getValue();
40128 if(this.dialCodeHolder) {
40129 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40134 setValue : function(v)
40136 var d = this.getDialCode(v);
40138 //invalid dial code
40139 if(v.length == 0 || !d || d.length == 0) {
40141 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40142 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40148 this.setFlagClass(this.dialCodeMapping[d].iso2);
40149 this.setDialCode(d);
40150 this.inputEl().dom.value = v.replace('+'+d,'');
40151 this.hiddenEl().dom.value = this.getValue();
40156 getDialCode : function(v)
40160 if (v.length == 0) {
40161 return this.dialCodeHolder.dom.value;
40165 if (v.charAt(0) != "+") {
40168 var numericChars = "";
40169 for (var i = 1; i < v.length; i++) {
40170 var c = v.charAt(i);
40173 if (this.dialCodeMapping[numericChars]) {
40174 dialCode = v.substr(1, i);
40176 if (numericChars.length == 4) {
40186 this.setValue(this.defaultDialCode);
40190 hiddenEl : function()
40192 return this.el.select('input.hidden-tel-input',true).first();
40195 onKeyUp : function(e){
40197 var k = e.getKey();
40198 var c = e.getCharCode();
40201 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40202 this.allowed.indexOf(String.fromCharCode(c)) === -1
40207 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40210 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40214 this.setValue(this.getValue());
40219 * @class Roo.bootstrap.MoneyField
40220 * @extends Roo.bootstrap.ComboBox
40221 * Bootstrap MoneyField class
40224 * Create a new MoneyField.
40225 * @param {Object} config Configuration options
40228 Roo.bootstrap.MoneyField = function(config) {
40230 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40234 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40237 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40239 allowDecimals : true,
40241 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40243 decimalSeparator : ".",
40245 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40247 decimalPrecision : 0,
40249 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40251 allowNegative : true,
40253 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40257 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40259 minValue : Number.NEGATIVE_INFINITY,
40261 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40263 maxValue : Number.MAX_VALUE,
40265 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40267 minText : "The minimum value for this field is {0}",
40269 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40271 maxText : "The maximum value for this field is {0}",
40273 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40274 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40276 nanText : "{0} is not a valid number",
40278 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40282 * @cfg {String} defaults currency of the MoneyField
40283 * value should be in lkey
40285 defaultCurrency : false,
40287 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40289 thousandsDelimiter : false,
40299 getAutoCreate : function()
40301 var align = this.labelAlign || this.parentLabelAlign();
40313 cls : 'form-control roo-money-amount-input',
40314 autocomplete: 'new-password'
40317 var hiddenInput = {
40321 cls: 'hidden-number-input'
40325 hiddenInput.name = this.name;
40328 if (this.disabled) {
40329 input.disabled = true;
40332 var clg = 12 - this.inputlg;
40333 var cmd = 12 - this.inputmd;
40334 var csm = 12 - this.inputsm;
40335 var cxs = 12 - this.inputxs;
40339 cls : 'row roo-money-field',
40343 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40347 cls: 'roo-select2-container input-group',
40351 cls : 'form-control roo-money-currency-input',
40352 autocomplete: 'new-password',
40354 name : this.currencyName
40358 cls : 'input-group-addon',
40372 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40376 cls: this.hasFeedback ? 'has-feedback' : '',
40387 if (this.fieldLabel.length) {
40390 tooltip: 'This field is required'
40396 cls: 'control-label',
40402 html: this.fieldLabel
40405 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40411 if(this.indicatorpos == 'right') {
40412 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40419 if(align == 'left') {
40427 if(this.labelWidth > 12){
40428 label.style = "width: " + this.labelWidth + 'px';
40430 if(this.labelWidth < 13 && this.labelmd == 0){
40431 this.labelmd = this.labelWidth;
40433 if(this.labellg > 0){
40434 label.cls += ' col-lg-' + this.labellg;
40435 input.cls += ' col-lg-' + (12 - this.labellg);
40437 if(this.labelmd > 0){
40438 label.cls += ' col-md-' + this.labelmd;
40439 container.cls += ' col-md-' + (12 - this.labelmd);
40441 if(this.labelsm > 0){
40442 label.cls += ' col-sm-' + this.labelsm;
40443 container.cls += ' col-sm-' + (12 - this.labelsm);
40445 if(this.labelxs > 0){
40446 label.cls += ' col-xs-' + this.labelxs;
40447 container.cls += ' col-xs-' + (12 - this.labelxs);
40458 var settings = this;
40460 ['xs','sm','md','lg'].map(function(size){
40461 if (settings[size]) {
40462 cfg.cls += ' col-' + size + '-' + settings[size];
40469 initEvents : function()
40471 this.indicator = this.indicatorEl();
40473 this.initCurrencyEvent();
40475 this.initNumberEvent();
40478 initCurrencyEvent : function()
40481 throw "can not find store for combo";
40484 this.store = Roo.factory(this.store, Roo.data);
40485 this.store.parent = this;
40489 this.triggerEl = this.el.select('.input-group-addon', true).first();
40491 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40496 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40497 _this.list.setWidth(lw);
40500 this.list.on('mouseover', this.onViewOver, this);
40501 this.list.on('mousemove', this.onViewMove, this);
40502 this.list.on('scroll', this.onViewScroll, this);
40505 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40508 this.view = new Roo.View(this.list, this.tpl, {
40509 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40512 this.view.on('click', this.onViewClick, this);
40514 this.store.on('beforeload', this.onBeforeLoad, this);
40515 this.store.on('load', this.onLoad, this);
40516 this.store.on('loadexception', this.onLoadException, this);
40518 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40519 "up" : function(e){
40520 this.inKeyMode = true;
40524 "down" : function(e){
40525 if(!this.isExpanded()){
40526 this.onTriggerClick();
40528 this.inKeyMode = true;
40533 "enter" : function(e){
40536 if(this.fireEvent("specialkey", this, e)){
40537 this.onViewClick(false);
40543 "esc" : function(e){
40547 "tab" : function(e){
40550 if(this.fireEvent("specialkey", this, e)){
40551 this.onViewClick(false);
40559 doRelay : function(foo, bar, hname){
40560 if(hname == 'down' || this.scope.isExpanded()){
40561 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40569 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40573 initNumberEvent : function(e)
40575 this.inputEl().on("keydown" , this.fireKey, this);
40576 this.inputEl().on("focus", this.onFocus, this);
40577 this.inputEl().on("blur", this.onBlur, this);
40579 this.inputEl().relayEvent('keyup', this);
40581 if(this.indicator){
40582 this.indicator.addClass('invisible');
40585 this.originalValue = this.getValue();
40587 if(this.validationEvent == 'keyup'){
40588 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40589 this.inputEl().on('keyup', this.filterValidation, this);
40591 else if(this.validationEvent !== false){
40592 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40595 if(this.selectOnFocus){
40596 this.on("focus", this.preFocus, this);
40599 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40600 this.inputEl().on("keypress", this.filterKeys, this);
40602 this.inputEl().relayEvent('keypress', this);
40605 var allowed = "0123456789";
40607 if(this.allowDecimals){
40608 allowed += this.decimalSeparator;
40611 if(this.allowNegative){
40615 if(this.thousandsDelimiter) {
40619 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40621 var keyPress = function(e){
40623 var k = e.getKey();
40625 var c = e.getCharCode();
40628 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40629 allowed.indexOf(String.fromCharCode(c)) === -1
40635 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40639 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40644 this.inputEl().on("keypress", keyPress, this);
40648 onTriggerClick : function(e)
40655 this.loadNext = false;
40657 if(this.isExpanded()){
40662 this.hasFocus = true;
40664 if(this.triggerAction == 'all') {
40665 this.doQuery(this.allQuery, true);
40669 this.doQuery(this.getRawValue());
40672 getCurrency : function()
40674 var v = this.currencyEl().getValue();
40679 restrictHeight : function()
40681 this.list.alignTo(this.currencyEl(), this.listAlign);
40682 this.list.alignTo(this.currencyEl(), this.listAlign);
40685 onViewClick : function(view, doFocus, el, e)
40687 var index = this.view.getSelectedIndexes()[0];
40689 var r = this.store.getAt(index);
40692 this.onSelect(r, index);
40696 onSelect : function(record, index){
40698 if(this.fireEvent('beforeselect', this, record, index) !== false){
40700 this.setFromCurrencyData(index > -1 ? record.data : false);
40704 this.fireEvent('select', this, record, index);
40708 setFromCurrencyData : function(o)
40712 this.lastCurrency = o;
40714 if (this.currencyField) {
40715 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40717 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40720 this.lastSelectionText = currency;
40722 //setting default currency
40723 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40724 this.setCurrency(this.defaultCurrency);
40728 this.setCurrency(currency);
40731 setFromData : function(o)
40735 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40737 this.setFromCurrencyData(c);
40742 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40744 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40747 this.setValue(value);
40751 setCurrency : function(v)
40753 this.currencyValue = v;
40756 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40761 setValue : function(v)
40763 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40769 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40771 this.inputEl().dom.value = (v == '') ? '' :
40772 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40774 if(!this.allowZero && v === '0') {
40775 this.hiddenEl().dom.value = '';
40776 this.inputEl().dom.value = '';
40783 getRawValue : function()
40785 var v = this.inputEl().getValue();
40790 getValue : function()
40792 return this.fixPrecision(this.parseValue(this.getRawValue()));
40795 parseValue : function(value)
40797 if(this.thousandsDelimiter) {
40799 r = new RegExp(",", "g");
40800 value = value.replace(r, "");
40803 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40804 return isNaN(value) ? '' : value;
40808 fixPrecision : function(value)
40810 if(this.thousandsDelimiter) {
40812 r = new RegExp(",", "g");
40813 value = value.replace(r, "");
40816 var nan = isNaN(value);
40818 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40819 return nan ? '' : value;
40821 return parseFloat(value).toFixed(this.decimalPrecision);
40824 decimalPrecisionFcn : function(v)
40826 return Math.floor(v);
40829 validateValue : function(value)
40831 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40835 var num = this.parseValue(value);
40838 this.markInvalid(String.format(this.nanText, value));
40842 if(num < this.minValue){
40843 this.markInvalid(String.format(this.minText, this.minValue));
40847 if(num > this.maxValue){
40848 this.markInvalid(String.format(this.maxText, this.maxValue));
40855 validate : function()
40857 if(this.disabled || this.allowBlank){
40862 var currency = this.getCurrency();
40864 if(this.validateValue(this.getRawValue()) && currency.length){
40869 this.markInvalid();
40873 getName: function()
40878 beforeBlur : function()
40884 var v = this.parseValue(this.getRawValue());
40891 onBlur : function()
40895 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40896 //this.el.removeClass(this.focusClass);
40899 this.hasFocus = false;
40901 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40905 var v = this.getValue();
40907 if(String(v) !== String(this.startValue)){
40908 this.fireEvent('change', this, v, this.startValue);
40911 this.fireEvent("blur", this);
40914 inputEl : function()
40916 return this.el.select('.roo-money-amount-input', true).first();
40919 currencyEl : function()
40921 return this.el.select('.roo-money-currency-input', true).first();
40924 hiddenEl : function()
40926 return this.el.select('input.hidden-number-input',true).first();