4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
51 allowDomMove : false, // to stop relocations in parent onRender...
61 * Initialize Events for the element
63 initEvents : function() { },
69 can_build_overlaid : true,
71 container_method : false,
78 // returns the parent component..
79 return Roo.ComponentMgr.get(this.parentId)
85 onRender : function(ct, position)
87 // Roo.log("Call onRender: " + this.xtype);
89 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92 if (this.el.attr('xtype')) {
93 this.el.attr('xtypex', this.el.attr('xtype'));
94 this.el.dom.removeAttribute('xtype');
104 var cfg = Roo.apply({}, this.getAutoCreate());
106 cfg.id = this.id || Roo.id();
108 // fill in the extra attributes
109 if (this.xattr && typeof(this.xattr) =='object') {
110 for (var i in this.xattr) {
111 cfg[i] = this.xattr[i];
116 cfg.dataId = this.dataId;
120 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
123 if (this.style) { // fixme needs to support more complex style data.
124 cfg.style = this.style;
128 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
166 //Roo.log(['addxtype', cn]);
168 cn.parentType = this.xtype; //??
169 cn.parentId = this.id;
171 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 if (typeof(cn.container_method) == 'string') {
173 cntr = cn.container_method;
177 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
179 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
181 var build_from_html = Roo.XComponent.build_from_html;
183 var is_body = (tree.xtype == 'Body') ;
185 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
187 var self_cntr_el = Roo.get(this[cntr](false));
189 // do not try and build conditional elements
190 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
194 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196 return this.addxtypeChild(tree,cntr, is_body);
199 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
202 return this.addxtypeChild(Roo.apply({}, tree),cntr);
205 Roo.log('skipping render');
211 if (!build_from_html) {
215 // this i think handles overlaying multiple children of the same type
216 // with the sam eelement.. - which might be buggy..
218 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
224 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
228 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
235 addxtypeChild : function (tree, cntr, is_body)
237 Roo.debug && Roo.log('addxtypeChild:' + cntr);
239 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243 (typeof(tree['flexy:foreach']) != 'undefined');
247 skip_children = false;
248 // render the element if it's not BODY.
251 // if parent was disabled, then do not try and create the children..
252 if(!this[cntr](true)){
257 cn = Roo.factory(tree);
259 cn.parentType = this.xtype; //??
260 cn.parentId = this.id;
262 var build_from_html = Roo.XComponent.build_from_html;
265 // does the container contain child eleemnts with 'xtype' attributes.
266 // that match this xtype..
267 // note - when we render we create these as well..
268 // so we should check to see if body has xtype set.
269 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
271 var self_cntr_el = Roo.get(this[cntr](false));
272 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
274 //Roo.log(Roo.XComponent.build_from_html);
275 //Roo.log("got echild:");
278 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279 // and are not displayed -this causes this to use up the wrong element when matching.
280 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
283 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
290 //echild.dom.removeAttribute('xtype');
292 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293 Roo.debug && Roo.log(self_cntr_el);
294 Roo.debug && Roo.log(echild);
295 Roo.debug && Roo.log(cn);
301 // if object has flexy:if - then it may or may not be rendered.
302 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
303 // skip a flexy if element.
304 Roo.debug && Roo.log('skipping render');
305 Roo.debug && Roo.log(tree);
307 Roo.debug && Roo.log('skipping all children');
308 skip_children = true;
313 // actually if flexy:foreach is found, we really want to create
314 // multiple copies here...
316 //Roo.log(this[cntr]());
317 // some elements do not have render methods.. like the layouts...
319 if(this[cntr](true) === false){
324 cn.render && cn.render(this[cntr](true));
327 // then add the element..
334 if (typeof (tree.menu) != 'undefined') {
335 tree.menu.parentType = cn.xtype;
336 tree.menu.triggerEl = cn.el;
337 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
341 if (!tree.items || !tree.items.length) {
343 //Roo.log(["no children", this]);
348 var items = tree.items;
351 //Roo.log(items.length);
353 if (!skip_children) {
354 for(var i =0;i < items.length;i++) {
355 // Roo.log(['add child', items[i]]);
356 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
362 //Roo.log("fire childrenrendered");
364 cn.fireEvent('childrenrendered', this);
370 * Set the element that will be used to show or hide
372 setVisibilityEl : function(el)
374 this.visibilityEl = el;
378 * Get the element that will be used to show or hide
380 getVisibilityEl : function()
382 if (typeof(this.visibilityEl) == 'object') {
383 return this.visibilityEl;
386 if (typeof(this.visibilityEl) == 'string') {
387 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
394 * Show a component - removes 'hidden' class
398 if(!this.getVisibilityEl()){
402 this.getVisibilityEl().removeClass('hidden');
407 * Hide a component - adds 'hidden' class
411 if(!this.getVisibilityEl()){
415 this.getVisibilityEl().addClass('hidden');
428 * @class Roo.bootstrap.Body
429 * @extends Roo.bootstrap.Component
430 * Bootstrap Body class
434 * @param {Object} config The config object
437 Roo.bootstrap.Body = function(config){
439 config = config || {};
441 Roo.bootstrap.Body.superclass.constructor.call(this, config);
442 this.el = Roo.get(config.el ? config.el : document.body );
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
450 is_body : true,// just to make sure it's constructed?
455 onRender : function(ct, position)
457 /* Roo.log("Roo.bootstrap.Body - onRender");
458 if (this.cls && this.cls.length) {
459 Roo.get(document.body).addClass(this.cls);
478 * @class Roo.bootstrap.ButtonGroup
479 * @extends Roo.bootstrap.Component
480 * Bootstrap ButtonGroup class
481 * @cfg {String} size lg | sm | xs (default empty normal)
482 * @cfg {String} align vertical | justified (default none)
483 * @cfg {String} direction up | down (default down)
484 * @cfg {Boolean} toolbar false | true
485 * @cfg {Boolean} btn true | false
490 * @param {Object} config The config object
493 Roo.bootstrap.ButtonGroup = function(config){
494 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
505 getAutoCreate : function(){
511 cfg.html = this.html || cfg.html;
522 if (['vertical','justified'].indexOf(this.align)!==-1) {
523 cfg.cls = 'btn-group-' + this.align;
525 if (this.align == 'justified') {
526 console.log(this.items);
530 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531 cfg.cls += ' btn-group-' + this.size;
534 if (this.direction == 'up') {
535 cfg.cls += ' dropup' ;
551 * @class Roo.bootstrap.Button
552 * @extends Roo.bootstrap.Component
553 * Bootstrap Button class
554 * @cfg {String} html The button content
555 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
556 * @cfg {String} size ( lg | sm | xs)
557 * @cfg {String} tag ( a | input | submit)
558 * @cfg {String} href empty or href
559 * @cfg {Boolean} disabled default false;
560 * @cfg {Boolean} isClose default false;
561 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
562 * @cfg {String} badge text for badge
563 * @cfg {String} theme (default|glow)
564 * @cfg {Boolean} inverse dark themed version
565 * @cfg {Boolean} toggle is it a slidy toggle button
566 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567 * @cfg {String} ontext text for on slidy toggle state
568 * @cfg {String} offtext text for off slidy toggle state
569 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
570 * @cfg {Boolean} removeClass remove the standard class..
571 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
574 * Create a new button
575 * @param {Object} config The config object
579 Roo.bootstrap.Button = function(config){
580 Roo.bootstrap.Button.superclass.constructor.call(this, config);
581 this.weightClass = ["btn-default",
593 * When a butotn is pressed
594 * @param {Roo.bootstrap.Button} btn
595 * @param {Roo.EventObject} e
600 * After the button has been toggles
601 * @param {Roo.bootstrap.Button} btn
602 * @param {Roo.EventObject} e
603 * @param {boolean} pressed (also available as button.pressed)
609 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
627 preventDefault: true,
635 getAutoCreate : function(){
643 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
644 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
651 if (this.toggle == true) {
654 cls: 'slider-frame roo-button',
659 'data-off-text':'OFF',
660 cls: 'slider-button',
666 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667 cfg.cls += ' '+this.weight;
676 cfg["aria-hidden"] = true;
678 cfg.html = "×";
684 if (this.theme==='default') {
685 cfg.cls = 'btn roo-button';
687 //if (this.parentType != 'Navbar') {
688 this.weight = this.weight.length ? this.weight : 'default';
690 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
692 cfg.cls += ' btn-' + this.weight;
694 } else if (this.theme==='glow') {
697 cfg.cls = 'btn-glow roo-button';
699 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
701 cfg.cls += ' ' + this.weight;
707 this.cls += ' inverse';
711 if (this.active || this.pressed === true) {
712 cfg.cls += ' active';
716 cfg.disabled = 'disabled';
720 Roo.log('changing to ul' );
722 this.glyphicon = 'caret';
725 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
727 //gsRoo.log(this.parentType);
728 if (this.parentType === 'Navbar' && !this.parent().bar) {
729 Roo.log('changing to li?');
738 href : this.href || '#'
741 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
742 cfg.cls += ' dropdown';
749 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
751 if (this.glyphicon) {
752 cfg.html = ' ' + cfg.html;
757 cls: 'glyphicon glyphicon-' + this.glyphicon
767 // cfg.cls='btn roo-button';
771 var value = cfg.html;
776 cls: 'glyphicon glyphicon-' + this.glyphicon,
795 cfg.cls += ' dropdown';
796 cfg.html = typeof(cfg.html) != 'undefined' ?
797 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
800 if (cfg.tag !== 'a' && this.href !== '') {
801 throw "Tag must be a to set href.";
802 } else if (this.href.length > 0) {
803 cfg.href = this.href;
806 if(this.removeClass){
811 cfg.target = this.target;
816 initEvents: function() {
817 // Roo.log('init events?');
818 // Roo.log(this.el.dom);
821 if (typeof (this.menu) != 'undefined') {
822 this.menu.parentType = this.xtype;
823 this.menu.triggerEl = this.el;
824 this.addxtype(Roo.apply({}, this.menu));
828 if (this.el.hasClass('roo-button')) {
829 this.el.on('click', this.onClick, this);
831 this.el.select('.roo-button').on('click', this.onClick, this);
834 if(this.removeClass){
835 this.el.on('click', this.onClick, this);
838 this.el.enableDisplayMode();
841 onClick : function(e)
847 Roo.log('button on click ');
848 if(this.preventDefault){
852 if (this.pressed === true || this.pressed === false) {
853 this.toggleActive(e);
857 this.fireEvent('click', this, e);
861 * Enables this button
865 this.disabled = false;
866 this.el.removeClass('disabled');
870 * Disable this button
874 this.disabled = true;
875 this.el.addClass('disabled');
878 * sets the active state on/off,
879 * @param {Boolean} state (optional) Force a particular state
881 setActive : function(v) {
883 this.el[v ? 'addClass' : 'removeClass']('active');
887 * toggles the current active state
889 toggleActive : function(e)
891 this.setActive(!this.pressed);
892 this.fireEvent('toggle', this, e, !this.pressed);
895 * get the current active state
896 * @return {boolean} true if it's active
898 isActive : function()
900 return this.el.hasClass('active');
903 * set the text of the first selected button
905 setText : function(str)
907 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
910 * get the text of the first selected button
914 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
925 setWeight : function(str)
927 this.el.removeClass(this.weightClass);
928 this.el.addClass('btn-' + str);
942 * @class Roo.bootstrap.Column
943 * @extends Roo.bootstrap.Component
944 * Bootstrap Column class
945 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
946 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
947 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
948 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
949 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
950 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
951 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
952 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
955 * @cfg {Boolean} hidden (true|false) hide the element
956 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
957 * @cfg {String} fa (ban|check|...) font awesome icon
958 * @cfg {Number} fasize (1|2|....) font awsome size
960 * @cfg {String} icon (info-sign|check|...) glyphicon name
962 * @cfg {String} html content of column.
965 * Create a new Column
966 * @param {Object} config The config object
969 Roo.bootstrap.Column = function(config){
970 Roo.bootstrap.Column.superclass.constructor.call(this, config);
973 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
991 getAutoCreate : function(){
992 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1000 ['xs','sm','md','lg'].map(function(size){
1001 //Roo.log( size + ':' + settings[size]);
1003 if (settings[size+'off'] !== false) {
1004 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1007 if (settings[size] === false) {
1011 if (!settings[size]) { // 0 = hidden
1012 cfg.cls += ' hidden-' + size;
1015 cfg.cls += ' col-' + size + '-' + settings[size];
1020 cfg.cls += ' hidden';
1023 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1024 cfg.cls +=' alert alert-' + this.alert;
1028 if (this.html.length) {
1029 cfg.html = this.html;
1033 if (this.fasize > 1) {
1034 fasize = ' fa-' + this.fasize + 'x';
1036 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1041 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1060 * @class Roo.bootstrap.Container
1061 * @extends Roo.bootstrap.Component
1062 * Bootstrap Container class
1063 * @cfg {Boolean} jumbotron is it a jumbotron element
1064 * @cfg {String} html content of element
1065 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1066 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1067 * @cfg {String} header content of header (for panel)
1068 * @cfg {String} footer content of footer (for panel)
1069 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1070 * @cfg {String} tag (header|aside|section) type of HTML tag.
1071 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1072 * @cfg {String} fa font awesome icon
1073 * @cfg {String} icon (info-sign|check|...) glyphicon name
1074 * @cfg {Boolean} hidden (true|false) hide the element
1075 * @cfg {Boolean} expandable (true|false) default false
1076 * @cfg {Boolean} expanded (true|false) default true
1077 * @cfg {String} rheader contet on the right of header
1078 * @cfg {Boolean} clickable (true|false) default false
1082 * Create a new Container
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Container = function(config){
1087 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1093 * After the panel has been expand
1095 * @param {Roo.bootstrap.Container} this
1100 * After the panel has been collapsed
1102 * @param {Roo.bootstrap.Container} this
1107 * When a element is chick
1108 * @param {Roo.bootstrap.Container} this
1109 * @param {Roo.EventObject} e
1115 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1133 getChildContainer : function() {
1139 if (this.panel.length) {
1140 return this.el.select('.panel-body',true).first();
1147 getAutoCreate : function(){
1150 tag : this.tag || 'div',
1154 if (this.jumbotron) {
1155 cfg.cls = 'jumbotron';
1160 // - this is applied by the parent..
1162 // cfg.cls = this.cls + '';
1165 if (this.sticky.length) {
1167 var bd = Roo.get(document.body);
1168 if (!bd.hasClass('bootstrap-sticky')) {
1169 bd.addClass('bootstrap-sticky');
1170 Roo.select('html',true).setStyle('height', '100%');
1173 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1177 if (this.well.length) {
1178 switch (this.well) {
1181 cfg.cls +=' well well-' +this.well;
1190 cfg.cls += ' hidden';
1194 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1195 cfg.cls +=' alert alert-' + this.alert;
1200 if (this.panel.length) {
1201 cfg.cls += ' panel panel-' + this.panel;
1203 if (this.header.length) {
1207 if(this.expandable){
1209 cfg.cls = cfg.cls + ' expandable';
1213 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1221 cls : 'panel-title',
1222 html : (this.expandable ? ' ' : '') + this.header
1226 cls: 'panel-header-right',
1232 cls : 'panel-heading',
1233 style : this.expandable ? 'cursor: pointer' : '',
1241 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1246 if (this.footer.length) {
1248 cls : 'panel-footer',
1257 body.html = this.html || cfg.html;
1258 // prefix with the icons..
1260 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1263 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1268 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1269 cfg.cls = 'container';
1275 initEvents: function()
1277 if(this.expandable){
1278 var headerEl = this.headerEl();
1281 headerEl.on('click', this.onToggleClick, this);
1286 this.el.on('click', this.onClick, this);
1291 onToggleClick : function()
1293 var headerEl = this.headerEl();
1309 if(this.fireEvent('expand', this)) {
1311 this.expanded = true;
1313 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1315 this.el.select('.panel-body',true).first().removeClass('hide');
1317 var toggleEl = this.toggleEl();
1323 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1328 collapse : function()
1330 if(this.fireEvent('collapse', this)) {
1332 this.expanded = false;
1334 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1335 this.el.select('.panel-body',true).first().addClass('hide');
1337 var toggleEl = this.toggleEl();
1343 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1347 toggleEl : function()
1349 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1353 return this.el.select('.panel-heading .fa',true).first();
1356 headerEl : function()
1358 if(!this.el || !this.panel.length || !this.header.length){
1362 return this.el.select('.panel-heading',true).first()
1367 if(!this.el || !this.panel.length){
1371 return this.el.select('.panel-body',true).first()
1374 titleEl : function()
1376 if(!this.el || !this.panel.length || !this.header.length){
1380 return this.el.select('.panel-title',true).first();
1383 setTitle : function(v)
1385 var titleEl = this.titleEl();
1391 titleEl.dom.innerHTML = v;
1394 getTitle : function()
1397 var titleEl = this.titleEl();
1403 return titleEl.dom.innerHTML;
1406 setRightTitle : function(v)
1408 var t = this.el.select('.panel-header-right',true).first();
1414 t.dom.innerHTML = v;
1417 onClick : function(e)
1421 this.fireEvent('click', this, e);
1434 * @class Roo.bootstrap.Img
1435 * @extends Roo.bootstrap.Component
1436 * Bootstrap Img class
1437 * @cfg {Boolean} imgResponsive false | true
1438 * @cfg {String} border rounded | circle | thumbnail
1439 * @cfg {String} src image source
1440 * @cfg {String} alt image alternative text
1441 * @cfg {String} href a tag href
1442 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1443 * @cfg {String} xsUrl xs image source
1444 * @cfg {String} smUrl sm image source
1445 * @cfg {String} mdUrl md image source
1446 * @cfg {String} lgUrl lg image source
1449 * Create a new Input
1450 * @param {Object} config The config object
1453 Roo.bootstrap.Img = function(config){
1454 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1460 * The img click event for the img.
1461 * @param {Roo.EventObject} e
1467 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1469 imgResponsive: true,
1479 getAutoCreate : function()
1481 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1482 return this.createSingleImg();
1487 cls: 'roo-image-responsive-group',
1492 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1494 if(!_this[size + 'Url']){
1500 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1501 html: _this.html || cfg.html,
1502 src: _this[size + 'Url']
1505 img.cls += ' roo-image-responsive-' + size;
1507 var s = ['xs', 'sm', 'md', 'lg'];
1509 s.splice(s.indexOf(size), 1);
1511 Roo.each(s, function(ss){
1512 img.cls += ' hidden-' + ss;
1515 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1516 cfg.cls += ' img-' + _this.border;
1520 cfg.alt = _this.alt;
1533 a.target = _this.target;
1537 cfg.cn.push((_this.href) ? a : img);
1544 createSingleImg : function()
1548 cls: (this.imgResponsive) ? 'img-responsive' : '',
1550 src : 'about:blank' // just incase src get's set to undefined?!?
1553 cfg.html = this.html || cfg.html;
1555 cfg.src = this.src || cfg.src;
1557 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1558 cfg.cls += ' img-' + this.border;
1575 a.target = this.target;
1580 return (this.href) ? a : cfg;
1583 initEvents: function()
1586 this.el.on('click', this.onClick, this);
1591 onClick : function(e)
1593 Roo.log('img onclick');
1594 this.fireEvent('click', this, e);
1597 * Sets the url of the image - used to update it
1598 * @param {String} url the url of the image
1601 setSrc : function(url)
1605 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1606 this.el.dom.src = url;
1610 this.el.select('img', true).first().dom.src = url;
1626 * @class Roo.bootstrap.Link
1627 * @extends Roo.bootstrap.Component
1628 * Bootstrap Link Class
1629 * @cfg {String} alt image alternative text
1630 * @cfg {String} href a tag href
1631 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1632 * @cfg {String} html the content of the link.
1633 * @cfg {String} anchor name for the anchor link
1634 * @cfg {String} fa - favicon
1636 * @cfg {Boolean} preventDefault (true | false) default false
1640 * Create a new Input
1641 * @param {Object} config The config object
1644 Roo.bootstrap.Link = function(config){
1645 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1651 * The img click event for the img.
1652 * @param {Roo.EventObject} e
1658 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1662 preventDefault: false,
1668 getAutoCreate : function()
1670 var html = this.html || '';
1672 if (this.fa !== false) {
1673 html = '<i class="fa fa-' + this.fa + '"></i>';
1678 // anchor's do not require html/href...
1679 if (this.anchor === false) {
1681 cfg.href = this.href || '#';
1683 cfg.name = this.anchor;
1684 if (this.html !== false || this.fa !== false) {
1687 if (this.href !== false) {
1688 cfg.href = this.href;
1692 if(this.alt !== false){
1697 if(this.target !== false) {
1698 cfg.target = this.target;
1704 initEvents: function() {
1706 if(!this.href || this.preventDefault){
1707 this.el.on('click', this.onClick, this);
1711 onClick : function(e)
1713 if(this.preventDefault){
1716 //Roo.log('img onclick');
1717 this.fireEvent('click', this, e);
1730 * @class Roo.bootstrap.Header
1731 * @extends Roo.bootstrap.Component
1732 * Bootstrap Header class
1733 * @cfg {String} html content of header
1734 * @cfg {Number} level (1|2|3|4|5|6) default 1
1737 * Create a new Header
1738 * @param {Object} config The config object
1742 Roo.bootstrap.Header = function(config){
1743 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1746 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1754 getAutoCreate : function(){
1759 tag: 'h' + (1 *this.level),
1760 html: this.html || ''
1772 * Ext JS Library 1.1.1
1773 * Copyright(c) 2006-2007, Ext JS, LLC.
1775 * Originally Released Under LGPL - original licence link has changed is not relivant.
1778 * <script type="text/javascript">
1782 * @class Roo.bootstrap.MenuMgr
1783 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1786 Roo.bootstrap.MenuMgr = function(){
1787 var menus, active, groups = {}, attached = false, lastShow = new Date();
1789 // private - called when first menu is created
1792 active = new Roo.util.MixedCollection();
1793 Roo.get(document).addKeyListener(27, function(){
1794 if(active.length > 0){
1802 if(active && active.length > 0){
1803 var c = active.clone();
1813 if(active.length < 1){
1814 Roo.get(document).un("mouseup", onMouseDown);
1822 var last = active.last();
1823 lastShow = new Date();
1826 Roo.get(document).on("mouseup", onMouseDown);
1831 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1832 m.parentMenu.activeChild = m;
1833 }else if(last && last.isVisible()){
1834 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1839 function onBeforeHide(m){
1841 m.activeChild.hide();
1843 if(m.autoHideTimer){
1844 clearTimeout(m.autoHideTimer);
1845 delete m.autoHideTimer;
1850 function onBeforeShow(m){
1851 var pm = m.parentMenu;
1852 if(!pm && !m.allowOtherMenus){
1854 }else if(pm && pm.activeChild && active != m){
1855 pm.activeChild.hide();
1859 // private this should really trigger on mouseup..
1860 function onMouseDown(e){
1861 Roo.log("on Mouse Up");
1863 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1864 Roo.log("MenuManager hideAll");
1873 function onBeforeCheck(mi, state){
1875 var g = groups[mi.group];
1876 for(var i = 0, l = g.length; i < l; i++){
1878 g[i].setChecked(false);
1887 * Hides all menus that are currently visible
1889 hideAll : function(){
1894 register : function(menu){
1898 menus[menu.id] = menu;
1899 menu.on("beforehide", onBeforeHide);
1900 menu.on("hide", onHide);
1901 menu.on("beforeshow", onBeforeShow);
1902 menu.on("show", onShow);
1904 if(g && menu.events["checkchange"]){
1908 groups[g].push(menu);
1909 menu.on("checkchange", onCheck);
1914 * Returns a {@link Roo.menu.Menu} object
1915 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1916 * be used to generate and return a new Menu instance.
1918 get : function(menu){
1919 if(typeof menu == "string"){ // menu id
1921 }else if(menu.events){ // menu instance
1924 /*else if(typeof menu.length == 'number'){ // array of menu items?
1925 return new Roo.bootstrap.Menu({items:menu});
1926 }else{ // otherwise, must be a config
1927 return new Roo.bootstrap.Menu(menu);
1934 unregister : function(menu){
1935 delete menus[menu.id];
1936 menu.un("beforehide", onBeforeHide);
1937 menu.un("hide", onHide);
1938 menu.un("beforeshow", onBeforeShow);
1939 menu.un("show", onShow);
1941 if(g && menu.events["checkchange"]){
1942 groups[g].remove(menu);
1943 menu.un("checkchange", onCheck);
1948 registerCheckable : function(menuItem){
1949 var g = menuItem.group;
1954 groups[g].push(menuItem);
1955 menuItem.on("beforecheckchange", onBeforeCheck);
1960 unregisterCheckable : function(menuItem){
1961 var g = menuItem.group;
1963 groups[g].remove(menuItem);
1964 menuItem.un("beforecheckchange", onBeforeCheck);
1976 * @class Roo.bootstrap.Menu
1977 * @extends Roo.bootstrap.Component
1978 * Bootstrap Menu class - container for MenuItems
1979 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1980 * @cfg {bool} hidden if the menu should be hidden when rendered.
1981 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1982 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1986 * @param {Object} config The config object
1990 Roo.bootstrap.Menu = function(config){
1991 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1992 if (this.registerMenu && this.type != 'treeview') {
1993 Roo.bootstrap.MenuMgr.register(this);
1998 * Fires before this menu is displayed
1999 * @param {Roo.menu.Menu} this
2004 * Fires before this menu is hidden
2005 * @param {Roo.menu.Menu} this
2010 * Fires after this menu is displayed
2011 * @param {Roo.menu.Menu} this
2016 * Fires after this menu is hidden
2017 * @param {Roo.menu.Menu} this
2022 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2023 * @param {Roo.menu.Menu} this
2024 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2025 * @param {Roo.EventObject} e
2030 * Fires when the mouse is hovering over this menu
2031 * @param {Roo.menu.Menu} this
2032 * @param {Roo.EventObject} e
2033 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2038 * Fires when the mouse exits this menu
2039 * @param {Roo.menu.Menu} this
2040 * @param {Roo.EventObject} e
2041 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2046 * Fires when a menu item contained in this menu is clicked
2047 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2048 * @param {Roo.EventObject} e
2052 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2055 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2059 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2062 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2064 registerMenu : true,
2066 menuItems :false, // stores the menu items..
2076 getChildContainer : function() {
2080 getAutoCreate : function(){
2082 //if (['right'].indexOf(this.align)!==-1) {
2083 // cfg.cn[1].cls += ' pull-right'
2089 cls : 'dropdown-menu' ,
2090 style : 'z-index:1000'
2094 if (this.type === 'submenu') {
2095 cfg.cls = 'submenu active';
2097 if (this.type === 'treeview') {
2098 cfg.cls = 'treeview-menu';
2103 initEvents : function() {
2105 // Roo.log("ADD event");
2106 // Roo.log(this.triggerEl.dom);
2108 this.triggerEl.on('click', this.onTriggerClick, this);
2110 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2112 this.triggerEl.addClass('dropdown-toggle');
2115 this.el.on('touchstart' , this.onTouch, this);
2117 this.el.on('click' , this.onClick, this);
2119 this.el.on("mouseover", this.onMouseOver, this);
2120 this.el.on("mouseout", this.onMouseOut, this);
2124 findTargetItem : function(e)
2126 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2130 //Roo.log(t); Roo.log(t.id);
2132 //Roo.log(this.menuitems);
2133 return this.menuitems.get(t.id);
2135 //return this.items.get(t.menuItemId);
2141 onTouch : function(e)
2143 Roo.log("menu.onTouch");
2144 //e.stopEvent(); this make the user popdown broken
2148 onClick : function(e)
2150 Roo.log("menu.onClick");
2152 var t = this.findTargetItem(e);
2153 if(!t || t.isContainer){
2158 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2159 if(t == this.activeItem && t.shouldDeactivate(e)){
2160 this.activeItem.deactivate();
2161 delete this.activeItem;
2165 this.setActiveItem(t, true);
2173 Roo.log('pass click event');
2177 this.fireEvent("click", this, t, e);
2181 if(!t.href.length || t.href == '#'){
2182 (function() { _this.hide(); }).defer(100);
2187 onMouseOver : function(e){
2188 var t = this.findTargetItem(e);
2191 // if(t.canActivate && !t.disabled){
2192 // this.setActiveItem(t, true);
2196 this.fireEvent("mouseover", this, e, t);
2198 isVisible : function(){
2199 return !this.hidden;
2201 onMouseOut : function(e){
2202 var t = this.findTargetItem(e);
2205 // if(t == this.activeItem && t.shouldDeactivate(e)){
2206 // this.activeItem.deactivate();
2207 // delete this.activeItem;
2210 this.fireEvent("mouseout", this, e, t);
2215 * Displays this menu relative to another element
2216 * @param {String/HTMLElement/Roo.Element} element The element to align to
2217 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2218 * the element (defaults to this.defaultAlign)
2219 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2221 show : function(el, pos, parentMenu){
2222 this.parentMenu = parentMenu;
2226 this.fireEvent("beforeshow", this);
2228 this.triggerEl.addClass('open');
2230 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2233 * Displays this menu at a specific xy position
2234 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2235 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2237 showAt : function(xy, parentMenu, /* private: */_e){
2238 this.parentMenu = parentMenu;
2243 this.fireEvent("beforeshow", this);
2244 // xy = this.el.adjustForConstraints(xy);
2248 this.hideMenuItems();
2249 this.hidden = false;
2250 this.triggerEl.addClass('open');
2252 // xy = this.el.getAlignToXY(this.triggerEl, '?');
2254 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2255 xy[0] = xy[0] - (Roo.lib.Dom.getViewWidth() - this.triggerEl.getBox().right);
2259 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2260 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2263 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2268 this.fireEvent("show", this);
2274 this.doFocus.defer(50, this);
2278 doFocus : function(){
2280 this.focusEl.focus();
2285 * Hides this menu and optionally all parent menus
2286 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2288 hide : function(deep)
2291 this.hideMenuItems();
2292 if(this.el && this.isVisible()){
2293 this.fireEvent("beforehide", this);
2294 if(this.activeItem){
2295 this.activeItem.deactivate();
2296 this.activeItem = null;
2298 this.triggerEl.removeClass('open');;
2300 this.fireEvent("hide", this);
2302 if(deep === true && this.parentMenu){
2303 this.parentMenu.hide(true);
2307 onTriggerClick : function(e)
2309 Roo.log('trigger click');
2311 var target = e.getTarget();
2313 Roo.log(target.nodeName.toLowerCase());
2315 if(target.nodeName.toLowerCase() === 'i'){
2321 onTriggerPress : function(e)
2323 Roo.log('trigger press');
2324 //Roo.log(e.getTarget());
2325 // Roo.log(this.triggerEl.dom);
2327 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2328 var pel = Roo.get(e.getTarget());
2329 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2330 Roo.log('is treeview or dropdown?');
2334 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2338 if (this.isVisible()) {
2343 this.show(this.triggerEl, false, false);
2346 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2353 hideMenuItems : function()
2355 Roo.log("hide Menu Items");
2359 //$(backdrop).remove()
2360 this.el.select('.open',true).each(function(aa) {
2362 aa.removeClass('open');
2363 //var parent = getParent($(this))
2364 //var relatedTarget = { relatedTarget: this }
2366 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2367 //if (e.isDefaultPrevented()) return
2368 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2371 addxtypeChild : function (tree, cntr) {
2372 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2374 this.menuitems.add(comp);
2386 this.getEl().dom.innerHTML = '';
2387 this.menuitems.clear();
2401 * @class Roo.bootstrap.MenuItem
2402 * @extends Roo.bootstrap.Component
2403 * Bootstrap MenuItem class
2404 * @cfg {String} html the menu label
2405 * @cfg {String} href the link
2406 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2407 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2408 * @cfg {Boolean} active used on sidebars to highlight active itesm
2409 * @cfg {String} fa favicon to show on left of menu item.
2410 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2414 * Create a new MenuItem
2415 * @param {Object} config The config object
2419 Roo.bootstrap.MenuItem = function(config){
2420 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2425 * The raw click event for the entire grid.
2426 * @param {Roo.bootstrap.MenuItem} this
2427 * @param {Roo.EventObject} e
2433 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2437 preventDefault: false,
2438 isContainer : false,
2442 getAutoCreate : function(){
2444 if(this.isContainer){
2447 cls: 'dropdown-menu-item'
2461 if (this.fa !== false) {
2464 cls : 'fa fa-' + this.fa
2473 cls: 'dropdown-menu-item',
2476 if (this.parent().type == 'treeview') {
2477 cfg.cls = 'treeview-menu';
2480 cfg.cls += ' active';
2485 anc.href = this.href || cfg.cn[0].href ;
2486 ctag.html = this.html || cfg.cn[0].html ;
2490 initEvents: function()
2492 if (this.parent().type == 'treeview') {
2493 this.el.select('a').on('click', this.onClick, this);
2497 this.menu.parentType = this.xtype;
2498 this.menu.triggerEl = this.el;
2499 this.menu = this.addxtype(Roo.apply({}, this.menu));
2503 onClick : function(e)
2505 Roo.log('item on click ');
2507 if(this.preventDefault){
2510 //this.parent().hideMenuItems();
2512 this.fireEvent('click', this, e);
2531 * @class Roo.bootstrap.MenuSeparator
2532 * @extends Roo.bootstrap.Component
2533 * Bootstrap MenuSeparator class
2536 * Create a new MenuItem
2537 * @param {Object} config The config object
2541 Roo.bootstrap.MenuSeparator = function(config){
2542 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2545 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2547 getAutoCreate : function(){
2566 * @class Roo.bootstrap.Modal
2567 * @extends Roo.bootstrap.Component
2568 * Bootstrap Modal class
2569 * @cfg {String} title Title of dialog
2570 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2571 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2572 * @cfg {Boolean} specificTitle default false
2573 * @cfg {Array} buttons Array of buttons or standard button set..
2574 * @cfg {String} buttonPosition (left|right|center) default right
2575 * @cfg {Boolean} animate default true
2576 * @cfg {Boolean} allow_close default true
2577 * @cfg {Boolean} fitwindow default false
2578 * @cfg {String} size (sm|lg) default empty
2582 * Create a new Modal Dialog
2583 * @param {Object} config The config object
2586 Roo.bootstrap.Modal = function(config){
2587 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2592 * The raw btnclick event for the button
2593 * @param {Roo.EventObject} e
2598 * Fire when dialog resize
2599 * @param {Roo.bootstrap.Modal} this
2600 * @param {Roo.EventObject} e
2604 this.buttons = this.buttons || [];
2607 this.tmpl = Roo.factory(this.tmpl);
2612 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2614 title : 'test dialog',
2624 specificTitle: false,
2626 buttonPosition: 'right',
2645 onRender : function(ct, position)
2647 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2650 var cfg = Roo.apply({}, this.getAutoCreate());
2653 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2655 //if (!cfg.name.length) {
2659 cfg.cls += ' ' + this.cls;
2662 cfg.style = this.style;
2664 this.el = Roo.get(document.body).createChild(cfg, position);
2666 //var type = this.el.dom.type;
2669 if(this.tabIndex !== undefined){
2670 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2673 this.dialogEl = this.el.select('.modal-dialog',true).first();
2674 this.bodyEl = this.el.select('.modal-body',true).first();
2675 this.closeEl = this.el.select('.modal-header .close', true).first();
2676 this.headerEl = this.el.select('.modal-header',true).first();
2677 this.titleEl = this.el.select('.modal-title',true).first();
2678 this.footerEl = this.el.select('.modal-footer',true).first();
2680 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2682 //this.el.addClass("x-dlg-modal");
2684 if (this.buttons.length) {
2685 Roo.each(this.buttons, function(bb) {
2686 var b = Roo.apply({}, bb);
2687 b.xns = b.xns || Roo.bootstrap;
2688 b.xtype = b.xtype || 'Button';
2689 if (typeof(b.listeners) == 'undefined') {
2690 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2693 var btn = Roo.factory(b);
2695 btn.render(this.el.select('.modal-footer div').first());
2699 // render the children.
2702 if(typeof(this.items) != 'undefined'){
2703 var items = this.items;
2706 for(var i =0;i < items.length;i++) {
2707 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2711 this.items = nitems;
2713 // where are these used - they used to be body/close/footer
2717 //this.el.addClass([this.fieldClass, this.cls]);
2721 getAutoCreate : function(){
2726 html : this.html || ''
2731 cls : 'modal-title',
2735 if(this.specificTitle){
2741 if (this.allow_close) {
2753 if(this.size.length){
2754 size = 'modal-' + this.size;
2761 cls: "modal-dialog " + size,
2764 cls : "modal-content",
2767 cls : 'modal-header',
2772 cls : 'modal-footer',
2776 cls: 'btn-' + this.buttonPosition
2793 modal.cls += ' fade';
2799 getChildContainer : function() {
2804 getButtonContainer : function() {
2805 return this.el.select('.modal-footer div',true).first();
2808 initEvents : function()
2810 if (this.allow_close) {
2811 this.closeEl.on('click', this.hide, this);
2813 Roo.EventManager.onWindowResize(this.resize, this, true);
2820 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2821 if (this.fitwindow) {
2822 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2823 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2828 setSize : function(w,h)
2838 if (!this.rendered) {
2842 //this.el.setStyle('display', 'block');
2843 this.el.removeClass('hideing');
2844 this.el.addClass('show');
2846 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2849 this.el.addClass('in');
2852 this.el.addClass('in');
2856 // not sure how we can show data in here..
2858 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2861 Roo.get(document.body).addClass("x-body-masked");
2863 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2864 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2865 this.maskEl.addClass('show');
2869 this.fireEvent('show', this);
2871 // set zindex here - otherwise it appears to be ignored...
2872 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2875 this.items.forEach( function(e) {
2876 e.layout ? e.layout() : false;
2884 if(this.fireEvent("beforehide", this) !== false){
2885 this.maskEl.removeClass('show');
2886 Roo.get(document.body).removeClass("x-body-masked");
2887 this.el.removeClass('in');
2888 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2890 if(this.animate){ // why
2891 this.el.addClass('hideing');
2893 if (!this.el.hasClass('hideing')) {
2894 return; // it's been shown again...
2896 this.el.removeClass('show');
2897 this.el.removeClass('hideing');
2901 this.el.removeClass('show');
2903 this.fireEvent('hide', this);
2906 isVisible : function()
2909 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2913 addButton : function(str, cb)
2917 var b = Roo.apply({}, { html : str } );
2918 b.xns = b.xns || Roo.bootstrap;
2919 b.xtype = b.xtype || 'Button';
2920 if (typeof(b.listeners) == 'undefined') {
2921 b.listeners = { click : cb.createDelegate(this) };
2924 var btn = Roo.factory(b);
2926 btn.render(this.el.select('.modal-footer div').first());
2932 setDefaultButton : function(btn)
2934 //this.el.select('.modal-footer').()
2938 resizeTo: function(w,h)
2942 this.dialogEl.setWidth(w);
2943 if (this.diff === false) {
2944 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2947 this.bodyEl.setHeight(h-this.diff);
2949 this.fireEvent('resize', this);
2952 setContentSize : function(w, h)
2956 onButtonClick: function(btn,e)
2959 this.fireEvent('btnclick', btn.name, e);
2962 * Set the title of the Dialog
2963 * @param {String} str new Title
2965 setTitle: function(str) {
2966 this.titleEl.dom.innerHTML = str;
2969 * Set the body of the Dialog
2970 * @param {String} str new Title
2972 setBody: function(str) {
2973 this.bodyEl.dom.innerHTML = str;
2976 * Set the body of the Dialog using the template
2977 * @param {Obj} data - apply this data to the template and replace the body contents.
2979 applyBody: function(obj)
2982 Roo.log("Error - using apply Body without a template");
2985 this.tmpl.overwrite(this.bodyEl, obj);
2991 Roo.apply(Roo.bootstrap.Modal, {
2993 * Button config that displays a single OK button
3002 * Button config that displays Yes and No buttons
3018 * Button config that displays OK and Cancel buttons
3033 * Button config that displays Yes, No and Cancel buttons
3057 * messagebox - can be used as a replace
3061 * @class Roo.MessageBox
3062 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3066 Roo.Msg.alert('Status', 'Changes saved successfully.');
3068 // Prompt for user data:
3069 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3071 // process text value...
3075 // Show a dialog using config options:
3077 title:'Save Changes?',
3078 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3079 buttons: Roo.Msg.YESNOCANCEL,
3086 Roo.bootstrap.MessageBox = function(){
3087 var dlg, opt, mask, waitTimer;
3088 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3089 var buttons, activeTextEl, bwidth;
3093 var handleButton = function(button){
3095 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3099 var handleHide = function(){
3101 dlg.el.removeClass(opt.cls);
3104 // Roo.TaskMgr.stop(waitTimer);
3105 // waitTimer = null;
3110 var updateButtons = function(b){
3113 buttons["ok"].hide();
3114 buttons["cancel"].hide();
3115 buttons["yes"].hide();
3116 buttons["no"].hide();
3117 //dlg.footer.dom.style.display = 'none';
3120 dlg.footerEl.dom.style.display = '';
3121 for(var k in buttons){
3122 if(typeof buttons[k] != "function"){
3125 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3126 width += buttons[k].el.getWidth()+15;
3136 var handleEsc = function(d, k, e){
3137 if(opt && opt.closable !== false){
3147 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3148 * @return {Roo.BasicDialog} The BasicDialog element
3150 getDialog : function(){
3152 dlg = new Roo.bootstrap.Modal( {
3155 //constraintoviewport:false,
3157 //collapsible : false,
3162 //buttonAlign:"center",
3163 closeClick : function(){
3164 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3167 handleButton("cancel");
3172 dlg.on("hide", handleHide);
3174 //dlg.addKeyListener(27, handleEsc);
3176 this.buttons = buttons;
3177 var bt = this.buttonText;
3178 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3179 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3180 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3181 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3183 bodyEl = dlg.bodyEl.createChild({
3185 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3186 '<textarea class="roo-mb-textarea"></textarea>' +
3187 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3189 msgEl = bodyEl.dom.firstChild;
3190 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3191 textboxEl.enableDisplayMode();
3192 textboxEl.addKeyListener([10,13], function(){
3193 if(dlg.isVisible() && opt && opt.buttons){
3196 }else if(opt.buttons.yes){
3197 handleButton("yes");
3201 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3202 textareaEl.enableDisplayMode();
3203 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3204 progressEl.enableDisplayMode();
3206 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3207 var pf = progressEl.dom.firstChild;
3209 pp = Roo.get(pf.firstChild);
3210 pp.setHeight(pf.offsetHeight);
3218 * Updates the message box body text
3219 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3220 * the XHTML-compliant non-breaking space character '&#160;')
3221 * @return {Roo.MessageBox} This message box
3223 updateText : function(text)
3225 if(!dlg.isVisible() && !opt.width){
3226 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3227 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3229 msgEl.innerHTML = text || ' ';
3231 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3232 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3234 Math.min(opt.width || cw , this.maxWidth),
3235 Math.max(opt.minWidth || this.minWidth, bwidth)
3238 activeTextEl.setWidth(w);
3240 if(dlg.isVisible()){
3241 dlg.fixedcenter = false;
3243 // to big, make it scroll. = But as usual stupid IE does not support
3246 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3247 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3248 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3250 bodyEl.dom.style.height = '';
3251 bodyEl.dom.style.overflowY = '';
3254 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3256 bodyEl.dom.style.overflowX = '';
3259 dlg.setContentSize(w, bodyEl.getHeight());
3260 if(dlg.isVisible()){
3261 dlg.fixedcenter = true;
3267 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3268 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3269 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3270 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3271 * @return {Roo.MessageBox} This message box
3273 updateProgress : function(value, text){
3275 this.updateText(text);
3278 if (pp) { // weird bug on my firefox - for some reason this is not defined
3279 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3280 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3286 * Returns true if the message box is currently displayed
3287 * @return {Boolean} True if the message box is visible, else false
3289 isVisible : function(){
3290 return dlg && dlg.isVisible();
3294 * Hides the message box if it is displayed
3297 if(this.isVisible()){
3303 * Displays a new message box, or reinitializes an existing message box, based on the config options
3304 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3305 * The following config object properties are supported:
3307 Property Type Description
3308 ---------- --------------- ------------------------------------------------------------------------------------
3309 animEl String/Element An id or Element from which the message box should animate as it opens and
3310 closes (defaults to undefined)
3311 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3312 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3313 closable Boolean False to hide the top-right close button (defaults to true). Note that
3314 progress and wait dialogs will ignore this property and always hide the
3315 close button as they can only be closed programmatically.
3316 cls String A custom CSS class to apply to the message box element
3317 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3318 displayed (defaults to 75)
3319 fn Function A callback function to execute after closing the dialog. The arguments to the
3320 function will be btn (the name of the button that was clicked, if applicable,
3321 e.g. "ok"), and text (the value of the active text field, if applicable).
3322 Progress and wait dialogs will ignore this option since they do not respond to
3323 user actions and can only be closed programmatically, so any required function
3324 should be called by the same code after it closes the dialog.
3325 icon String A CSS class that provides a background image to be used as an icon for
3326 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3327 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3328 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3329 modal Boolean False to allow user interaction with the page while the message box is
3330 displayed (defaults to true)
3331 msg String A string that will replace the existing message box body text (defaults
3332 to the XHTML-compliant non-breaking space character ' ')
3333 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3334 progress Boolean True to display a progress bar (defaults to false)
3335 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3336 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3337 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3338 title String The title text
3339 value String The string value to set into the active textbox element if displayed
3340 wait Boolean True to display a progress bar (defaults to false)
3341 width Number The width of the dialog in pixels
3348 msg: 'Please enter your address:',
3350 buttons: Roo.MessageBox.OKCANCEL,
3353 animEl: 'addAddressBtn'
3356 * @param {Object} config Configuration options
3357 * @return {Roo.MessageBox} This message box
3359 show : function(options)
3362 // this causes nightmares if you show one dialog after another
3363 // especially on callbacks..
3365 if(this.isVisible()){
3368 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3369 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3370 Roo.log("New Dialog Message:" + options.msg )
3371 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3372 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3375 var d = this.getDialog();
3377 d.setTitle(opt.title || " ");
3378 d.closeEl.setDisplayed(opt.closable !== false);
3379 activeTextEl = textboxEl;
3380 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3385 textareaEl.setHeight(typeof opt.multiline == "number" ?
3386 opt.multiline : this.defaultTextHeight);
3387 activeTextEl = textareaEl;
3396 progressEl.setDisplayed(opt.progress === true);
3397 this.updateProgress(0);
3398 activeTextEl.dom.value = opt.value || "";
3400 dlg.setDefaultButton(activeTextEl);
3402 var bs = opt.buttons;
3406 }else if(bs && bs.yes){
3407 db = buttons["yes"];
3409 dlg.setDefaultButton(db);
3411 bwidth = updateButtons(opt.buttons);
3412 this.updateText(opt.msg);
3414 d.el.addClass(opt.cls);
3416 d.proxyDrag = opt.proxyDrag === true;
3417 d.modal = opt.modal !== false;
3418 d.mask = opt.modal !== false ? mask : false;
3420 // force it to the end of the z-index stack so it gets a cursor in FF
3421 document.body.appendChild(dlg.el.dom);
3422 d.animateTarget = null;
3423 d.show(options.animEl);
3429 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3430 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3431 * and closing the message box when the process is complete.
3432 * @param {String} title The title bar text
3433 * @param {String} msg The message box body text
3434 * @return {Roo.MessageBox} This message box
3436 progress : function(title, msg){
3443 minWidth: this.minProgressWidth,
3450 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3451 * If a callback function is passed it will be called after the user clicks the button, and the
3452 * id of the button that was clicked will be passed as the only parameter to the callback
3453 * (could also be the top-right close button).
3454 * @param {String} title The title bar text
3455 * @param {String} msg The message box body text
3456 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3457 * @param {Object} scope (optional) The scope of the callback function
3458 * @return {Roo.MessageBox} This message box
3460 alert : function(title, msg, fn, scope)
3475 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3476 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3477 * You are responsible for closing the message box when the process is complete.
3478 * @param {String} msg The message box body text
3479 * @param {String} title (optional) The title bar text
3480 * @return {Roo.MessageBox} This message box
3482 wait : function(msg, title){
3493 waitTimer = Roo.TaskMgr.start({
3495 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3503 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3504 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3505 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3506 * @param {String} title The title bar text
3507 * @param {String} msg The message box body text
3508 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3509 * @param {Object} scope (optional) The scope of the callback function
3510 * @return {Roo.MessageBox} This message box
3512 confirm : function(title, msg, fn, scope){
3516 buttons: this.YESNO,
3525 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3526 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3527 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3528 * (could also be the top-right close button) and the text that was entered will be passed as the two
3529 * parameters to the callback.
3530 * @param {String} title The title bar text
3531 * @param {String} msg The message box body text
3532 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3533 * @param {Object} scope (optional) The scope of the callback function
3534 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3535 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3536 * @return {Roo.MessageBox} This message box
3538 prompt : function(title, msg, fn, scope, multiline){
3542 buttons: this.OKCANCEL,
3547 multiline: multiline,
3554 * Button config that displays a single OK button
3559 * Button config that displays Yes and No buttons
3562 YESNO : {yes:true, no:true},
3564 * Button config that displays OK and Cancel buttons
3567 OKCANCEL : {ok:true, cancel:true},
3569 * Button config that displays Yes, No and Cancel buttons
3572 YESNOCANCEL : {yes:true, no:true, cancel:true},
3575 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3578 defaultTextHeight : 75,
3580 * The maximum width in pixels of the message box (defaults to 600)
3585 * The minimum width in pixels of the message box (defaults to 100)
3590 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3591 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3594 minProgressWidth : 250,
3596 * An object containing the default button text strings that can be overriden for localized language support.
3597 * Supported properties are: ok, cancel, yes and no.
3598 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3611 * Shorthand for {@link Roo.MessageBox}
3613 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3614 Roo.Msg = Roo.Msg || Roo.MessageBox;
3623 * @class Roo.bootstrap.Navbar
3624 * @extends Roo.bootstrap.Component
3625 * Bootstrap Navbar class
3628 * Create a new Navbar
3629 * @param {Object} config The config object
3633 Roo.bootstrap.Navbar = function(config){
3634 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3638 * @event beforetoggle
3639 * Fire before toggle the menu
3640 * @param {Roo.EventObject} e
3642 "beforetoggle" : true
3646 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3655 getAutoCreate : function(){
3658 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3662 initEvents :function ()
3664 //Roo.log(this.el.select('.navbar-toggle',true));
3665 this.el.select('.navbar-toggle',true).on('click', function() {
3666 if(this.fireEvent('beforetoggle', this) !== false){
3667 this.el.select('.navbar-collapse',true).toggleClass('in');
3677 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3679 var size = this.el.getSize();
3680 this.maskEl.setSize(size.width, size.height);
3681 this.maskEl.enableDisplayMode("block");
3690 getChildContainer : function()
3692 if (this.el.select('.collapse').getCount()) {
3693 return this.el.select('.collapse',true).first();
3726 * @class Roo.bootstrap.NavSimplebar
3727 * @extends Roo.bootstrap.Navbar
3728 * Bootstrap Sidebar class
3730 * @cfg {Boolean} inverse is inverted color
3732 * @cfg {String} type (nav | pills | tabs)
3733 * @cfg {Boolean} arrangement stacked | justified
3734 * @cfg {String} align (left | right) alignment
3736 * @cfg {Boolean} main (true|false) main nav bar? default false
3737 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3739 * @cfg {String} tag (header|footer|nav|div) default is nav
3745 * Create a new Sidebar
3746 * @param {Object} config The config object
3750 Roo.bootstrap.NavSimplebar = function(config){
3751 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3754 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3770 getAutoCreate : function(){
3774 tag : this.tag || 'div',
3787 this.type = this.type || 'nav';
3788 if (['tabs','pills'].indexOf(this.type)!==-1) {
3789 cfg.cn[0].cls += ' nav-' + this.type
3793 if (this.type!=='nav') {
3794 Roo.log('nav type must be nav/tabs/pills')
3796 cfg.cn[0].cls += ' navbar-nav'
3802 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3803 cfg.cn[0].cls += ' nav-' + this.arrangement;
3807 if (this.align === 'right') {
3808 cfg.cn[0].cls += ' navbar-right';
3812 cfg.cls += ' navbar-inverse';
3839 * @class Roo.bootstrap.NavHeaderbar
3840 * @extends Roo.bootstrap.NavSimplebar
3841 * Bootstrap Sidebar class
3843 * @cfg {String} brand what is brand
3844 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3845 * @cfg {String} brand_href href of the brand
3846 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3847 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3848 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3849 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3852 * Create a new Sidebar
3853 * @param {Object} config The config object
3857 Roo.bootstrap.NavHeaderbar = function(config){
3858 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3862 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3869 desktopCenter : false,
3872 getAutoCreate : function(){
3875 tag: this.nav || 'nav',
3882 if (this.desktopCenter) {
3883 cn.push({cls : 'container', cn : []});
3890 cls: 'navbar-header',
3895 cls: 'navbar-toggle',
3896 'data-toggle': 'collapse',
3901 html: 'Toggle navigation'
3923 cls: 'collapse navbar-collapse',
3927 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3929 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3930 cfg.cls += ' navbar-' + this.position;
3932 // tag can override this..
3934 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3937 if (this.brand !== '') {
3940 href: this.brand_href ? this.brand_href : '#',
3941 cls: 'navbar-brand',
3949 cfg.cls += ' main-nav';
3957 getHeaderChildContainer : function()
3959 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3960 return this.el.select('.navbar-header',true).first();
3963 return this.getChildContainer();
3967 initEvents : function()
3969 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3971 if (this.autohide) {
3976 Roo.get(document).on('scroll',function(e) {
3977 var ns = Roo.get(document).getScroll().top;
3978 var os = prevScroll;
3982 ft.removeClass('slideDown');
3983 ft.addClass('slideUp');
3986 ft.removeClass('slideUp');
3987 ft.addClass('slideDown');
4008 * @class Roo.bootstrap.NavSidebar
4009 * @extends Roo.bootstrap.Navbar
4010 * Bootstrap Sidebar class
4013 * Create a new Sidebar
4014 * @param {Object} config The config object
4018 Roo.bootstrap.NavSidebar = function(config){
4019 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4022 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4024 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4026 getAutoCreate : function(){
4031 cls: 'sidebar sidebar-nav'
4053 * @class Roo.bootstrap.NavGroup
4054 * @extends Roo.bootstrap.Component
4055 * Bootstrap NavGroup class
4056 * @cfg {String} align (left|right)
4057 * @cfg {Boolean} inverse
4058 * @cfg {String} type (nav|pills|tab) default nav
4059 * @cfg {String} navId - reference Id for navbar.
4063 * Create a new nav group
4064 * @param {Object} config The config object
4067 Roo.bootstrap.NavGroup = function(config){
4068 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4071 Roo.bootstrap.NavGroup.register(this);
4075 * Fires when the active item changes
4076 * @param {Roo.bootstrap.NavGroup} this
4077 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4078 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4085 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4096 getAutoCreate : function()
4098 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4105 if (['tabs','pills'].indexOf(this.type)!==-1) {
4106 cfg.cls += ' nav-' + this.type
4108 if (this.type!=='nav') {
4109 Roo.log('nav type must be nav/tabs/pills')
4111 cfg.cls += ' navbar-nav'
4114 if (this.parent() && this.parent().sidebar) {
4117 cls: 'dashboard-menu sidebar-menu'
4123 if (this.form === true) {
4129 if (this.align === 'right') {
4130 cfg.cls += ' navbar-right';
4132 cfg.cls += ' navbar-left';
4136 if (this.align === 'right') {
4137 cfg.cls += ' navbar-right';
4141 cfg.cls += ' navbar-inverse';
4149 * sets the active Navigation item
4150 * @param {Roo.bootstrap.NavItem} the new current navitem
4152 setActiveItem : function(item)
4155 Roo.each(this.navItems, function(v){
4160 v.setActive(false, true);
4167 item.setActive(true, true);
4168 this.fireEvent('changed', this, item, prev);
4173 * gets the active Navigation item
4174 * @return {Roo.bootstrap.NavItem} the current navitem
4176 getActive : function()
4180 Roo.each(this.navItems, function(v){
4191 indexOfNav : function()
4195 Roo.each(this.navItems, function(v,i){
4206 * adds a Navigation item
4207 * @param {Roo.bootstrap.NavItem} the navitem to add
4209 addItem : function(cfg)
4211 var cn = new Roo.bootstrap.NavItem(cfg);
4213 cn.parentId = this.id;
4214 cn.onRender(this.el, null);
4218 * register a Navigation item
4219 * @param {Roo.bootstrap.NavItem} the navitem to add
4221 register : function(item)
4223 this.navItems.push( item);
4224 item.navId = this.navId;
4229 * clear all the Navigation item
4232 clearAll : function()
4235 this.el.dom.innerHTML = '';
4238 getNavItem: function(tabId)
4241 Roo.each(this.navItems, function(e) {
4242 if (e.tabId == tabId) {
4252 setActiveNext : function()
4254 var i = this.indexOfNav(this.getActive());
4255 if (i > this.navItems.length) {
4258 this.setActiveItem(this.navItems[i+1]);
4260 setActivePrev : function()
4262 var i = this.indexOfNav(this.getActive());
4266 this.setActiveItem(this.navItems[i-1]);
4268 clearWasActive : function(except) {
4269 Roo.each(this.navItems, function(e) {
4270 if (e.tabId != except.tabId && e.was_active) {
4271 e.was_active = false;
4278 getWasActive : function ()
4281 Roo.each(this.navItems, function(e) {
4296 Roo.apply(Roo.bootstrap.NavGroup, {
4300 * register a Navigation Group
4301 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4303 register : function(navgrp)
4305 this.groups[navgrp.navId] = navgrp;
4309 * fetch a Navigation Group based on the navigation ID
4310 * @param {string} the navgroup to add
4311 * @returns {Roo.bootstrap.NavGroup} the navgroup
4313 get: function(navId) {
4314 if (typeof(this.groups[navId]) == 'undefined') {
4316 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4318 return this.groups[navId] ;
4333 * @class Roo.bootstrap.NavItem
4334 * @extends Roo.bootstrap.Component
4335 * Bootstrap Navbar.NavItem class
4336 * @cfg {String} href link to
4337 * @cfg {String} html content of button
4338 * @cfg {String} badge text inside badge
4339 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4340 * @cfg {String} glyphicon name of glyphicon
4341 * @cfg {String} icon name of font awesome icon
4342 * @cfg {Boolean} active Is item active
4343 * @cfg {Boolean} disabled Is item disabled
4345 * @cfg {Boolean} preventDefault (true | false) default false
4346 * @cfg {String} tabId the tab that this item activates.
4347 * @cfg {String} tagtype (a|span) render as a href or span?
4348 * @cfg {Boolean} animateRef (true|false) link to element default false
4351 * Create a new Navbar Item
4352 * @param {Object} config The config object
4354 Roo.bootstrap.NavItem = function(config){
4355 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4360 * The raw click event for the entire grid.
4361 * @param {Roo.EventObject} e
4366 * Fires when the active item active state changes
4367 * @param {Roo.bootstrap.NavItem} this
4368 * @param {boolean} state the new state
4374 * Fires when scroll to element
4375 * @param {Roo.bootstrap.NavItem} this
4376 * @param {Object} options
4377 * @param {Roo.EventObject} e
4385 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4393 preventDefault : false,
4400 getAutoCreate : function(){
4409 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4411 if (this.disabled) {
4412 cfg.cls += ' disabled';
4415 if (this.href || this.html || this.glyphicon || this.icon) {
4419 href : this.href || "#",
4420 html: this.html || ''
4425 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4428 if(this.glyphicon) {
4429 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4434 cfg.cn[0].html += " <span class='caret'></span>";
4438 if (this.badge !== '') {
4440 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4448 initEvents: function()
4450 if (typeof (this.menu) != 'undefined') {
4451 this.menu.parentType = this.xtype;
4452 this.menu.triggerEl = this.el;
4453 this.menu = this.addxtype(Roo.apply({}, this.menu));
4456 this.el.select('a',true).on('click', this.onClick, this);
4458 if(this.tagtype == 'span'){
4459 this.el.select('span',true).on('click', this.onClick, this);
4462 // at this point parent should be available..
4463 this.parent().register(this);
4466 onClick : function(e)
4468 if (e.getTarget('.dropdown-menu-item')) {
4469 // did you click on a menu itemm.... - then don't trigger onclick..
4474 this.preventDefault ||
4477 Roo.log("NavItem - prevent Default?");
4481 if (this.disabled) {
4485 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4486 if (tg && tg.transition) {
4487 Roo.log("waiting for the transitionend");
4493 //Roo.log("fire event clicked");
4494 if(this.fireEvent('click', this, e) === false){
4498 if(this.tagtype == 'span'){
4502 //Roo.log(this.href);
4503 var ael = this.el.select('a',true).first();
4506 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4507 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4508 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4509 return; // ignore... - it's a 'hash' to another page.
4511 Roo.log("NavItem - prevent Default?");
4513 this.scrollToElement(e);
4517 var p = this.parent();
4519 if (['tabs','pills'].indexOf(p.type)!==-1) {
4520 if (typeof(p.setActiveItem) !== 'undefined') {
4521 p.setActiveItem(this);
4525 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4526 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4527 // remove the collapsed menu expand...
4528 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4532 isActive: function () {
4535 setActive : function(state, fire, is_was_active)
4537 if (this.active && !state && this.navId) {
4538 this.was_active = true;
4539 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4541 nv.clearWasActive(this);
4545 this.active = state;
4548 this.el.removeClass('active');
4549 } else if (!this.el.hasClass('active')) {
4550 this.el.addClass('active');
4553 this.fireEvent('changed', this, state);
4556 // show a panel if it's registered and related..
4558 if (!this.navId || !this.tabId || !state || is_was_active) {
4562 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4566 var pan = tg.getPanelByName(this.tabId);
4570 // if we can not flip to new panel - go back to old nav highlight..
4571 if (false == tg.showPanel(pan)) {
4572 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4574 var onav = nv.getWasActive();
4576 onav.setActive(true, false, true);
4585 // this should not be here...
4586 setDisabled : function(state)
4588 this.disabled = state;
4590 this.el.removeClass('disabled');
4591 } else if (!this.el.hasClass('disabled')) {
4592 this.el.addClass('disabled');
4598 * Fetch the element to display the tooltip on.
4599 * @return {Roo.Element} defaults to this.el
4601 tooltipEl : function()
4603 return this.el.select('' + this.tagtype + '', true).first();
4606 scrollToElement : function(e)
4608 var c = document.body;
4611 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4613 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4614 c = document.documentElement;
4617 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4623 var o = target.calcOffsetsTo(c);
4630 this.fireEvent('scrollto', this, options, e);
4632 Roo.get(c).scrollTo('top', options.value, true);
4645 * <span> icon </span>
4646 * <span> text </span>
4647 * <span>badge </span>
4651 * @class Roo.bootstrap.NavSidebarItem
4652 * @extends Roo.bootstrap.NavItem
4653 * Bootstrap Navbar.NavSidebarItem class
4654 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4655 * {Boolean} open is the menu open
4656 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4657 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4658 * {String} buttonSize (sm|md|lg)the extra classes for the button
4659 * {Boolean} showArrow show arrow next to the text (default true)
4661 * Create a new Navbar Button
4662 * @param {Object} config The config object
4664 Roo.bootstrap.NavSidebarItem = function(config){
4665 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4670 * The raw click event for the entire grid.
4671 * @param {Roo.EventObject} e
4676 * Fires when the active item active state changes
4677 * @param {Roo.bootstrap.NavSidebarItem} this
4678 * @param {boolean} state the new state
4686 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4688 badgeWeight : 'default',
4694 buttonWeight : 'default',
4700 getAutoCreate : function(){
4705 href : this.href || '#',
4711 if(this.buttonView){
4714 href : this.href || '#',
4715 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4728 cfg.cls += ' active';
4731 if (this.disabled) {
4732 cfg.cls += ' disabled';
4735 cfg.cls += ' open x-open';
4738 if (this.glyphicon || this.icon) {
4739 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4740 a.cn.push({ tag : 'i', cls : c }) ;
4743 if(!this.buttonView){
4746 html : this.html || ''
4753 if (this.badge !== '') {
4754 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4760 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4763 a.cls += ' dropdown-toggle treeview' ;
4769 initEvents : function()
4771 if (typeof (this.menu) != 'undefined') {
4772 this.menu.parentType = this.xtype;
4773 this.menu.triggerEl = this.el;
4774 this.menu = this.addxtype(Roo.apply({}, this.menu));
4777 this.el.on('click', this.onClick, this);
4779 if(this.badge !== ''){
4780 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4785 onClick : function(e)
4792 if(this.preventDefault){
4796 this.fireEvent('click', this);
4799 disable : function()
4801 this.setDisabled(true);
4806 this.setDisabled(false);
4809 setDisabled : function(state)
4811 if(this.disabled == state){
4815 this.disabled = state;
4818 this.el.addClass('disabled');
4822 this.el.removeClass('disabled');
4827 setActive : function(state)
4829 if(this.active == state){
4833 this.active = state;
4836 this.el.addClass('active');
4840 this.el.removeClass('active');
4845 isActive: function ()
4850 setBadge : function(str)
4856 this.badgeEl.dom.innerHTML = str;
4873 * @class Roo.bootstrap.Row
4874 * @extends Roo.bootstrap.Component
4875 * Bootstrap Row class (contains columns...)
4879 * @param {Object} config The config object
4882 Roo.bootstrap.Row = function(config){
4883 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4886 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4888 getAutoCreate : function(){
4907 * @class Roo.bootstrap.Element
4908 * @extends Roo.bootstrap.Component
4909 * Bootstrap Element class
4910 * @cfg {String} html contents of the element
4911 * @cfg {String} tag tag of the element
4912 * @cfg {String} cls class of the element
4913 * @cfg {Boolean} preventDefault (true|false) default false
4914 * @cfg {Boolean} clickable (true|false) default false
4917 * Create a new Element
4918 * @param {Object} config The config object
4921 Roo.bootstrap.Element = function(config){
4922 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4928 * When a element is chick
4929 * @param {Roo.bootstrap.Element} this
4930 * @param {Roo.EventObject} e
4936 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4941 preventDefault: false,
4944 getAutoCreate : function(){
4948 // cls: this.cls, double assign in parent class Component.js :: onRender
4955 initEvents: function()
4957 Roo.bootstrap.Element.superclass.initEvents.call(this);
4960 this.el.on('click', this.onClick, this);
4965 onClick : function(e)
4967 if(this.preventDefault){
4971 this.fireEvent('click', this, e);
4974 getValue : function()
4976 return this.el.dom.innerHTML;
4979 setValue : function(value)
4981 this.el.dom.innerHTML = value;
4996 * @class Roo.bootstrap.Pagination
4997 * @extends Roo.bootstrap.Component
4998 * Bootstrap Pagination class
4999 * @cfg {String} size xs | sm | md | lg
5000 * @cfg {Boolean} inverse false | true
5003 * Create a new Pagination
5004 * @param {Object} config The config object
5007 Roo.bootstrap.Pagination = function(config){
5008 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5011 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5017 getAutoCreate : function(){
5023 cfg.cls += ' inverse';
5029 cfg.cls += " " + this.cls;
5047 * @class Roo.bootstrap.PaginationItem
5048 * @extends Roo.bootstrap.Component
5049 * Bootstrap PaginationItem class
5050 * @cfg {String} html text
5051 * @cfg {String} href the link
5052 * @cfg {Boolean} preventDefault (true | false) default true
5053 * @cfg {Boolean} active (true | false) default false
5054 * @cfg {Boolean} disabled default false
5058 * Create a new PaginationItem
5059 * @param {Object} config The config object
5063 Roo.bootstrap.PaginationItem = function(config){
5064 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5069 * The raw click event for the entire grid.
5070 * @param {Roo.EventObject} e
5076 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5080 preventDefault: true,
5085 getAutoCreate : function(){
5091 href : this.href ? this.href : '#',
5092 html : this.html ? this.html : ''
5102 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5106 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5112 initEvents: function() {
5114 this.el.on('click', this.onClick, this);
5117 onClick : function(e)
5119 Roo.log('PaginationItem on click ');
5120 if(this.preventDefault){
5128 this.fireEvent('click', this, e);
5144 * @class Roo.bootstrap.Slider
5145 * @extends Roo.bootstrap.Component
5146 * Bootstrap Slider class
5149 * Create a new Slider
5150 * @param {Object} config The config object
5153 Roo.bootstrap.Slider = function(config){
5154 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5157 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5159 getAutoCreate : function(){
5163 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5167 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5179 * Ext JS Library 1.1.1
5180 * Copyright(c) 2006-2007, Ext JS, LLC.
5182 * Originally Released Under LGPL - original licence link has changed is not relivant.
5185 * <script type="text/javascript">
5190 * @class Roo.grid.ColumnModel
5191 * @extends Roo.util.Observable
5192 * This is the default implementation of a ColumnModel used by the Grid. It defines
5193 * the columns in the grid.
5196 var colModel = new Roo.grid.ColumnModel([
5197 {header: "Ticker", width: 60, sortable: true, locked: true},
5198 {header: "Company Name", width: 150, sortable: true},
5199 {header: "Market Cap.", width: 100, sortable: true},
5200 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5201 {header: "Employees", width: 100, sortable: true, resizable: false}
5206 * The config options listed for this class are options which may appear in each
5207 * individual column definition.
5208 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5210 * @param {Object} config An Array of column config objects. See this class's
5211 * config objects for details.
5213 Roo.grid.ColumnModel = function(config){
5215 * The config passed into the constructor
5217 this.config = config;
5220 // if no id, create one
5221 // if the column does not have a dataIndex mapping,
5222 // map it to the order it is in the config
5223 for(var i = 0, len = config.length; i < len; i++){
5225 if(typeof c.dataIndex == "undefined"){
5228 if(typeof c.renderer == "string"){
5229 c.renderer = Roo.util.Format[c.renderer];
5231 if(typeof c.id == "undefined"){
5234 if(c.editor && c.editor.xtype){
5235 c.editor = Roo.factory(c.editor, Roo.grid);
5237 if(c.editor && c.editor.isFormField){
5238 c.editor = new Roo.grid.GridEditor(c.editor);
5240 this.lookup[c.id] = c;
5244 * The width of columns which have no width specified (defaults to 100)
5247 this.defaultWidth = 100;
5250 * Default sortable of columns which have no sortable specified (defaults to false)
5253 this.defaultSortable = false;
5257 * @event widthchange
5258 * Fires when the width of a column changes.
5259 * @param {ColumnModel} this
5260 * @param {Number} columnIndex The column index
5261 * @param {Number} newWidth The new width
5263 "widthchange": true,
5265 * @event headerchange
5266 * Fires when the text of a header changes.
5267 * @param {ColumnModel} this
5268 * @param {Number} columnIndex The column index
5269 * @param {Number} newText The new header text
5271 "headerchange": true,
5273 * @event hiddenchange
5274 * Fires when a column is hidden or "unhidden".
5275 * @param {ColumnModel} this
5276 * @param {Number} columnIndex The column index
5277 * @param {Boolean} hidden true if hidden, false otherwise
5279 "hiddenchange": true,
5281 * @event columnmoved
5282 * Fires when a column is moved.
5283 * @param {ColumnModel} this
5284 * @param {Number} oldIndex
5285 * @param {Number} newIndex
5287 "columnmoved" : true,
5289 * @event columlockchange
5290 * Fires when a column's locked state is changed
5291 * @param {ColumnModel} this
5292 * @param {Number} colIndex
5293 * @param {Boolean} locked true if locked
5295 "columnlockchange" : true
5297 Roo.grid.ColumnModel.superclass.constructor.call(this);
5299 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5301 * @cfg {String} header The header text to display in the Grid view.
5304 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5305 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5306 * specified, the column's index is used as an index into the Record's data Array.
5309 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5310 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5313 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5314 * Defaults to the value of the {@link #defaultSortable} property.
5315 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5318 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5321 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5324 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5327 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5330 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5331 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5332 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5333 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5336 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5339 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5342 * @cfg {String} cursor (Optional)
5345 * @cfg {String} tooltip (Optional)
5348 * @cfg {Number} xs (Optional)
5351 * @cfg {Number} sm (Optional)
5354 * @cfg {Number} md (Optional)
5357 * @cfg {Number} lg (Optional)
5360 * Returns the id of the column at the specified index.
5361 * @param {Number} index The column index
5362 * @return {String} the id
5364 getColumnId : function(index){
5365 return this.config[index].id;
5369 * Returns the column for a specified id.
5370 * @param {String} id The column id
5371 * @return {Object} the column
5373 getColumnById : function(id){
5374 return this.lookup[id];
5379 * Returns the column for a specified dataIndex.
5380 * @param {String} dataIndex The column dataIndex
5381 * @return {Object|Boolean} the column or false if not found
5383 getColumnByDataIndex: function(dataIndex){
5384 var index = this.findColumnIndex(dataIndex);
5385 return index > -1 ? this.config[index] : false;
5389 * Returns the index for a specified column id.
5390 * @param {String} id The column id
5391 * @return {Number} the index, or -1 if not found
5393 getIndexById : function(id){
5394 for(var i = 0, len = this.config.length; i < len; i++){
5395 if(this.config[i].id == id){
5403 * Returns the index for a specified column dataIndex.
5404 * @param {String} dataIndex The column dataIndex
5405 * @return {Number} the index, or -1 if not found
5408 findColumnIndex : function(dataIndex){
5409 for(var i = 0, len = this.config.length; i < len; i++){
5410 if(this.config[i].dataIndex == dataIndex){
5418 moveColumn : function(oldIndex, newIndex){
5419 var c = this.config[oldIndex];
5420 this.config.splice(oldIndex, 1);
5421 this.config.splice(newIndex, 0, c);
5422 this.dataMap = null;
5423 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5426 isLocked : function(colIndex){
5427 return this.config[colIndex].locked === true;
5430 setLocked : function(colIndex, value, suppressEvent){
5431 if(this.isLocked(colIndex) == value){
5434 this.config[colIndex].locked = value;
5436 this.fireEvent("columnlockchange", this, colIndex, value);
5440 getTotalLockedWidth : function(){
5442 for(var i = 0; i < this.config.length; i++){
5443 if(this.isLocked(i) && !this.isHidden(i)){
5444 this.totalWidth += this.getColumnWidth(i);
5450 getLockedCount : function(){
5451 for(var i = 0, len = this.config.length; i < len; i++){
5452 if(!this.isLocked(i)){
5457 return this.config.length;
5461 * Returns the number of columns.
5464 getColumnCount : function(visibleOnly){
5465 if(visibleOnly === true){
5467 for(var i = 0, len = this.config.length; i < len; i++){
5468 if(!this.isHidden(i)){
5474 return this.config.length;
5478 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5479 * @param {Function} fn
5480 * @param {Object} scope (optional)
5481 * @return {Array} result
5483 getColumnsBy : function(fn, scope){
5485 for(var i = 0, len = this.config.length; i < len; i++){
5486 var c = this.config[i];
5487 if(fn.call(scope||this, c, i) === true){
5495 * Returns true if the specified column is sortable.
5496 * @param {Number} col The column index
5499 isSortable : function(col){
5500 if(typeof this.config[col].sortable == "undefined"){
5501 return this.defaultSortable;
5503 return this.config[col].sortable;
5507 * Returns the rendering (formatting) function defined for the column.
5508 * @param {Number} col The column index.
5509 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5511 getRenderer : function(col){
5512 if(!this.config[col].renderer){
5513 return Roo.grid.ColumnModel.defaultRenderer;
5515 return this.config[col].renderer;
5519 * Sets the rendering (formatting) function for a column.
5520 * @param {Number} col The column index
5521 * @param {Function} fn The function to use to process the cell's raw data
5522 * to return HTML markup for the grid view. The render function is called with
5523 * the following parameters:<ul>
5524 * <li>Data value.</li>
5525 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5526 * <li>css A CSS style string to apply to the table cell.</li>
5527 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5528 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5529 * <li>Row index</li>
5530 * <li>Column index</li>
5531 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5533 setRenderer : function(col, fn){
5534 this.config[col].renderer = fn;
5538 * Returns the width for the specified column.
5539 * @param {Number} col The column index
5542 getColumnWidth : function(col){
5543 return this.config[col].width * 1 || this.defaultWidth;
5547 * Sets the width for a column.
5548 * @param {Number} col The column index
5549 * @param {Number} width The new width
5551 setColumnWidth : function(col, width, suppressEvent){
5552 this.config[col].width = width;
5553 this.totalWidth = null;
5555 this.fireEvent("widthchange", this, col, width);
5560 * Returns the total width of all columns.
5561 * @param {Boolean} includeHidden True to include hidden column widths
5564 getTotalWidth : function(includeHidden){
5565 if(!this.totalWidth){
5566 this.totalWidth = 0;
5567 for(var i = 0, len = this.config.length; i < len; i++){
5568 if(includeHidden || !this.isHidden(i)){
5569 this.totalWidth += this.getColumnWidth(i);
5573 return this.totalWidth;
5577 * Returns the header for the specified column.
5578 * @param {Number} col The column index
5581 getColumnHeader : function(col){
5582 return this.config[col].header;
5586 * Sets the header for a column.
5587 * @param {Number} col The column index
5588 * @param {String} header The new header
5590 setColumnHeader : function(col, header){
5591 this.config[col].header = header;
5592 this.fireEvent("headerchange", this, col, header);
5596 * Returns the tooltip for the specified column.
5597 * @param {Number} col The column index
5600 getColumnTooltip : function(col){
5601 return this.config[col].tooltip;
5604 * Sets the tooltip for a column.
5605 * @param {Number} col The column index
5606 * @param {String} tooltip The new tooltip
5608 setColumnTooltip : function(col, tooltip){
5609 this.config[col].tooltip = tooltip;
5613 * Returns the dataIndex for the specified column.
5614 * @param {Number} col The column index
5617 getDataIndex : function(col){
5618 return this.config[col].dataIndex;
5622 * Sets the dataIndex for a column.
5623 * @param {Number} col The column index
5624 * @param {Number} dataIndex The new dataIndex
5626 setDataIndex : function(col, dataIndex){
5627 this.config[col].dataIndex = dataIndex;
5633 * Returns true if the cell is editable.
5634 * @param {Number} colIndex The column index
5635 * @param {Number} rowIndex The row index - this is nto actually used..?
5638 isCellEditable : function(colIndex, rowIndex){
5639 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5643 * Returns the editor defined for the cell/column.
5644 * return false or null to disable editing.
5645 * @param {Number} colIndex The column index
5646 * @param {Number} rowIndex The row index
5649 getCellEditor : function(colIndex, rowIndex){
5650 return this.config[colIndex].editor;
5654 * Sets if a column is editable.
5655 * @param {Number} col The column index
5656 * @param {Boolean} editable True if the column is editable
5658 setEditable : function(col, editable){
5659 this.config[col].editable = editable;
5664 * Returns true if the column is hidden.
5665 * @param {Number} colIndex The column index
5668 isHidden : function(colIndex){
5669 return this.config[colIndex].hidden;
5674 * Returns true if the column width cannot be changed
5676 isFixed : function(colIndex){
5677 return this.config[colIndex].fixed;
5681 * Returns true if the column can be resized
5684 isResizable : function(colIndex){
5685 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5688 * Sets if a column is hidden.
5689 * @param {Number} colIndex The column index
5690 * @param {Boolean} hidden True if the column is hidden
5692 setHidden : function(colIndex, hidden){
5693 this.config[colIndex].hidden = hidden;
5694 this.totalWidth = null;
5695 this.fireEvent("hiddenchange", this, colIndex, hidden);
5699 * Sets the editor for a column.
5700 * @param {Number} col The column index
5701 * @param {Object} editor The editor object
5703 setEditor : function(col, editor){
5704 this.config[col].editor = editor;
5708 Roo.grid.ColumnModel.defaultRenderer = function(value)
5710 if(typeof value == "object") {
5713 if(typeof value == "string" && value.length < 1){
5717 return String.format("{0}", value);
5720 // Alias for backwards compatibility
5721 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5724 * Ext JS Library 1.1.1
5725 * Copyright(c) 2006-2007, Ext JS, LLC.
5727 * Originally Released Under LGPL - original licence link has changed is not relivant.
5730 * <script type="text/javascript">
5734 * @class Roo.LoadMask
5735 * A simple utility class for generically masking elements while loading data. If the element being masked has
5736 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5737 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5738 * element's UpdateManager load indicator and will be destroyed after the initial load.
5740 * Create a new LoadMask
5741 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5742 * @param {Object} config The config object
5744 Roo.LoadMask = function(el, config){
5745 this.el = Roo.get(el);
5746 Roo.apply(this, config);
5748 this.store.on('beforeload', this.onBeforeLoad, this);
5749 this.store.on('load', this.onLoad, this);
5750 this.store.on('loadexception', this.onLoadException, this);
5751 this.removeMask = false;
5753 var um = this.el.getUpdateManager();
5754 um.showLoadIndicator = false; // disable the default indicator
5755 um.on('beforeupdate', this.onBeforeLoad, this);
5756 um.on('update', this.onLoad, this);
5757 um.on('failure', this.onLoad, this);
5758 this.removeMask = true;
5762 Roo.LoadMask.prototype = {
5764 * @cfg {Boolean} removeMask
5765 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5766 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5770 * The text to display in a centered loading message box (defaults to 'Loading...')
5774 * @cfg {String} msgCls
5775 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5777 msgCls : 'x-mask-loading',
5780 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5786 * Disables the mask to prevent it from being displayed
5788 disable : function(){
5789 this.disabled = true;
5793 * Enables the mask so that it can be displayed
5795 enable : function(){
5796 this.disabled = false;
5799 onLoadException : function()
5803 if (typeof(arguments[3]) != 'undefined') {
5804 Roo.MessageBox.alert("Error loading",arguments[3]);
5808 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5809 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5816 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5821 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5825 onBeforeLoad : function(){
5827 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5832 destroy : function(){
5834 this.store.un('beforeload', this.onBeforeLoad, this);
5835 this.store.un('load', this.onLoad, this);
5836 this.store.un('loadexception', this.onLoadException, this);
5838 var um = this.el.getUpdateManager();
5839 um.un('beforeupdate', this.onBeforeLoad, this);
5840 um.un('update', this.onLoad, this);
5841 um.un('failure', this.onLoad, this);
5852 * @class Roo.bootstrap.Table
5853 * @extends Roo.bootstrap.Component
5854 * Bootstrap Table class
5855 * @cfg {String} cls table class
5856 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5857 * @cfg {String} bgcolor Specifies the background color for a table
5858 * @cfg {Number} border Specifies whether the table cells should have borders or not
5859 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5860 * @cfg {Number} cellspacing Specifies the space between cells
5861 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5862 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5863 * @cfg {String} sortable Specifies that the table should be sortable
5864 * @cfg {String} summary Specifies a summary of the content of a table
5865 * @cfg {Number} width Specifies the width of a table
5866 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5868 * @cfg {boolean} striped Should the rows be alternative striped
5869 * @cfg {boolean} bordered Add borders to the table
5870 * @cfg {boolean} hover Add hover highlighting
5871 * @cfg {boolean} condensed Format condensed
5872 * @cfg {boolean} responsive Format condensed
5873 * @cfg {Boolean} loadMask (true|false) default false
5874 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5875 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5876 * @cfg {Boolean} rowSelection (true|false) default false
5877 * @cfg {Boolean} cellSelection (true|false) default false
5878 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5879 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5880 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5884 * Create a new Table
5885 * @param {Object} config The config object
5888 Roo.bootstrap.Table = function(config){
5889 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5894 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5895 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5896 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5897 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5899 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5901 this.sm.grid = this;
5902 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5903 this.sm = this.selModel;
5904 this.sm.xmodule = this.xmodule || false;
5907 if (this.cm && typeof(this.cm.config) == 'undefined') {
5908 this.colModel = new Roo.grid.ColumnModel(this.cm);
5909 this.cm = this.colModel;
5910 this.cm.xmodule = this.xmodule || false;
5913 this.store= Roo.factory(this.store, Roo.data);
5914 this.ds = this.store;
5915 this.ds.xmodule = this.xmodule || false;
5918 if (this.footer && this.store) {
5919 this.footer.dataSource = this.ds;
5920 this.footer = Roo.factory(this.footer);
5927 * Fires when a cell is clicked
5928 * @param {Roo.bootstrap.Table} this
5929 * @param {Roo.Element} el
5930 * @param {Number} rowIndex
5931 * @param {Number} columnIndex
5932 * @param {Roo.EventObject} e
5936 * @event celldblclick
5937 * Fires when a cell is double clicked
5938 * @param {Roo.bootstrap.Table} this
5939 * @param {Roo.Element} el
5940 * @param {Number} rowIndex
5941 * @param {Number} columnIndex
5942 * @param {Roo.EventObject} e
5944 "celldblclick" : true,
5947 * Fires when a row is clicked
5948 * @param {Roo.bootstrap.Table} this
5949 * @param {Roo.Element} el
5950 * @param {Number} rowIndex
5951 * @param {Roo.EventObject} e
5955 * @event rowdblclick
5956 * Fires when a row is double clicked
5957 * @param {Roo.bootstrap.Table} this
5958 * @param {Roo.Element} el
5959 * @param {Number} rowIndex
5960 * @param {Roo.EventObject} e
5962 "rowdblclick" : true,
5965 * Fires when a mouseover occur
5966 * @param {Roo.bootstrap.Table} this
5967 * @param {Roo.Element} el
5968 * @param {Number} rowIndex
5969 * @param {Number} columnIndex
5970 * @param {Roo.EventObject} e
5975 * Fires when a mouseout occur
5976 * @param {Roo.bootstrap.Table} this
5977 * @param {Roo.Element} el
5978 * @param {Number} rowIndex
5979 * @param {Number} columnIndex
5980 * @param {Roo.EventObject} e
5985 * Fires when a row is rendered, so you can change add a style to it.
5986 * @param {Roo.bootstrap.Table} this
5987 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5991 * @event rowsrendered
5992 * Fires when all the rows have been rendered
5993 * @param {Roo.bootstrap.Table} this
5995 'rowsrendered' : true,
5997 * @event contextmenu
5998 * The raw contextmenu event for the entire grid.
5999 * @param {Roo.EventObject} e
6001 "contextmenu" : true,
6003 * @event rowcontextmenu
6004 * Fires when a row is right clicked
6005 * @param {Roo.bootstrap.Table} this
6006 * @param {Number} rowIndex
6007 * @param {Roo.EventObject} e
6009 "rowcontextmenu" : true,
6011 * @event cellcontextmenu
6012 * Fires when a cell is right clicked
6013 * @param {Roo.bootstrap.Table} this
6014 * @param {Number} rowIndex
6015 * @param {Number} cellIndex
6016 * @param {Roo.EventObject} e
6018 "cellcontextmenu" : true,
6020 * @event headercontextmenu
6021 * Fires when a header is right clicked
6022 * @param {Roo.bootstrap.Table} this
6023 * @param {Number} columnIndex
6024 * @param {Roo.EventObject} e
6026 "headercontextmenu" : true
6030 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6056 rowSelection : false,
6057 cellSelection : false,
6060 // Roo.Element - the tbody
6062 // Roo.Element - thead element
6065 container: false, // used by gridpanel...
6071 getAutoCreate : function()
6073 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6080 if (this.scrollBody) {
6081 cfg.cls += ' table-body-fixed';
6084 cfg.cls += ' table-striped';
6088 cfg.cls += ' table-hover';
6090 if (this.bordered) {
6091 cfg.cls += ' table-bordered';
6093 if (this.condensed) {
6094 cfg.cls += ' table-condensed';
6096 if (this.responsive) {
6097 cfg.cls += ' table-responsive';
6101 cfg.cls+= ' ' +this.cls;
6104 // this lot should be simplifed...
6107 cfg.align=this.align;
6110 cfg.bgcolor=this.bgcolor;
6113 cfg.border=this.border;
6115 if (this.cellpadding) {
6116 cfg.cellpadding=this.cellpadding;
6118 if (this.cellspacing) {
6119 cfg.cellspacing=this.cellspacing;
6122 cfg.frame=this.frame;
6125 cfg.rules=this.rules;
6127 if (this.sortable) {
6128 cfg.sortable=this.sortable;
6131 cfg.summary=this.summary;
6134 cfg.width=this.width;
6137 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6140 if(this.store || this.cm){
6141 if(this.headerShow){
6142 cfg.cn.push(this.renderHeader());
6145 cfg.cn.push(this.renderBody());
6147 if(this.footerShow){
6148 cfg.cn.push(this.renderFooter());
6150 // where does this come from?
6151 //cfg.cls+= ' TableGrid';
6154 return { cn : [ cfg ] };
6157 initEvents : function()
6159 if(!this.store || !this.cm){
6162 if (this.selModel) {
6163 this.selModel.initEvents();
6167 //Roo.log('initEvents with ds!!!!');
6169 this.mainBody = this.el.select('tbody', true).first();
6170 this.mainHead = this.el.select('thead', true).first();
6177 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6178 e.on('click', _this.sort, _this);
6181 this.mainBody.on("click", this.onClick, this);
6182 this.mainBody.on("dblclick", this.onDblClick, this);
6184 // why is this done????? = it breaks dialogs??
6185 //this.parent().el.setStyle('position', 'relative');
6189 this.footer.parentId = this.id;
6190 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6193 this.el.select('tfoot tr td').first().addClass('hide');
6197 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6199 this.store.on('load', this.onLoad, this);
6200 this.store.on('beforeload', this.onBeforeLoad, this);
6201 this.store.on('update', this.onUpdate, this);
6202 this.store.on('add', this.onAdd, this);
6203 this.store.on("clear", this.clear, this);
6205 this.el.on("contextmenu", this.onContextMenu, this);
6207 this.mainBody.on('scroll', this.onBodyScroll, this);
6209 this.cm.on("headerchange", this.onHeaderChange, this);
6211 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6215 onContextMenu : function(e, t)
6217 this.processEvent("contextmenu", e);
6220 processEvent : function(name, e)
6222 if (name != 'touchstart' ) {
6223 this.fireEvent(name, e);
6226 var t = e.getTarget();
6228 var cell = Roo.get(t);
6234 if(cell.findParent('tfoot', false, true)){
6238 if(cell.findParent('thead', false, true)){
6240 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6241 cell = Roo.get(t).findParent('th', false, true);
6243 Roo.log("failed to find th in thead?");
6244 Roo.log(e.getTarget());
6249 var cellIndex = cell.dom.cellIndex;
6251 var ename = name == 'touchstart' ? 'click' : name;
6252 this.fireEvent("header" + ename, this, cellIndex, e);
6257 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6258 cell = Roo.get(t).findParent('td', false, true);
6260 Roo.log("failed to find th in tbody?");
6261 Roo.log(e.getTarget());
6266 var row = cell.findParent('tr', false, true);
6267 var cellIndex = cell.dom.cellIndex;
6268 var rowIndex = row.dom.rowIndex - 1;
6272 this.fireEvent("row" + name, this, rowIndex, e);
6276 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6282 onMouseover : function(e, el)
6284 var cell = Roo.get(el);
6290 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6291 cell = cell.findParent('td', false, true);
6294 var row = cell.findParent('tr', false, true);
6295 var cellIndex = cell.dom.cellIndex;
6296 var rowIndex = row.dom.rowIndex - 1; // start from 0
6298 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6302 onMouseout : function(e, el)
6304 var cell = Roo.get(el);
6310 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6311 cell = cell.findParent('td', false, true);
6314 var row = cell.findParent('tr', false, true);
6315 var cellIndex = cell.dom.cellIndex;
6316 var rowIndex = row.dom.rowIndex - 1; // start from 0
6318 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6322 onClick : function(e, el)
6324 var cell = Roo.get(el);
6326 if(!cell || (!this.cellSelection && !this.rowSelection)){
6330 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6331 cell = cell.findParent('td', false, true);
6334 if(!cell || typeof(cell) == 'undefined'){
6338 var row = cell.findParent('tr', false, true);
6340 if(!row || typeof(row) == 'undefined'){
6344 var cellIndex = cell.dom.cellIndex;
6345 var rowIndex = this.getRowIndex(row);
6347 // why??? - should these not be based on SelectionModel?
6348 if(this.cellSelection){
6349 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6352 if(this.rowSelection){
6353 this.fireEvent('rowclick', this, row, rowIndex, e);
6359 onDblClick : function(e,el)
6361 var cell = Roo.get(el);
6363 if(!cell || (!this.cellSelection && !this.rowSelection)){
6367 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6368 cell = cell.findParent('td', false, true);
6371 if(!cell || typeof(cell) == 'undefined'){
6375 var row = cell.findParent('tr', false, true);
6377 if(!row || typeof(row) == 'undefined'){
6381 var cellIndex = cell.dom.cellIndex;
6382 var rowIndex = this.getRowIndex(row);
6384 if(this.cellSelection){
6385 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6388 if(this.rowSelection){
6389 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6393 sort : function(e,el)
6395 var col = Roo.get(el);
6397 if(!col.hasClass('sortable')){
6401 var sort = col.attr('sort');
6404 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6408 this.store.sortInfo = {field : sort, direction : dir};
6411 Roo.log("calling footer first");
6412 this.footer.onClick('first');
6415 this.store.load({ params : { start : 0 } });
6419 renderHeader : function()
6427 this.totalWidth = 0;
6429 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6431 var config = cm.config[i];
6435 cls : 'x-hcol-' + i,
6437 html: cm.getColumnHeader(i)
6442 if(typeof(config.sortable) != 'undefined' && config.sortable){
6444 c.html = '<i class="glyphicon"></i>' + c.html;
6447 if(typeof(config.lgHeader) != 'undefined'){
6448 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6451 if(typeof(config.mdHeader) != 'undefined'){
6452 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6455 if(typeof(config.smHeader) != 'undefined'){
6456 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6459 if(typeof(config.xsHeader) != 'undefined'){
6460 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6467 if(typeof(config.tooltip) != 'undefined'){
6468 c.tooltip = config.tooltip;
6471 if(typeof(config.colspan) != 'undefined'){
6472 c.colspan = config.colspan;
6475 if(typeof(config.hidden) != 'undefined' && config.hidden){
6476 c.style += ' display:none;';
6479 if(typeof(config.dataIndex) != 'undefined'){
6480 c.sort = config.dataIndex;
6485 if(typeof(config.align) != 'undefined' && config.align.length){
6486 c.style += ' text-align:' + config.align + ';';
6489 if(typeof(config.width) != 'undefined'){
6490 c.style += ' width:' + config.width + 'px;';
6491 this.totalWidth += config.width;
6493 this.totalWidth += 100; // assume minimum of 100 per column?
6496 if(typeof(config.cls) != 'undefined'){
6497 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6500 ['xs','sm','md','lg'].map(function(size){
6502 if(typeof(config[size]) == 'undefined'){
6506 if (!config[size]) { // 0 = hidden
6507 c.cls += ' hidden-' + size;
6511 c.cls += ' col-' + size + '-' + config[size];
6521 renderBody : function()
6531 colspan : this.cm.getColumnCount()
6541 renderFooter : function()
6551 colspan : this.cm.getColumnCount()
6565 // Roo.log('ds onload');
6570 var ds = this.store;
6572 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6573 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6574 if (_this.store.sortInfo) {
6576 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6577 e.select('i', true).addClass(['glyphicon-arrow-up']);
6580 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6581 e.select('i', true).addClass(['glyphicon-arrow-down']);
6586 var tbody = this.mainBody;
6588 if(ds.getCount() > 0){
6589 ds.data.each(function(d,rowIndex){
6590 var row = this.renderRow(cm, ds, rowIndex);
6592 tbody.createChild(row);
6596 if(row.cellObjects.length){
6597 Roo.each(row.cellObjects, function(r){
6598 _this.renderCellObject(r);
6605 Roo.each(this.el.select('tbody td', true).elements, function(e){
6606 e.on('mouseover', _this.onMouseover, _this);
6609 Roo.each(this.el.select('tbody td', true).elements, function(e){
6610 e.on('mouseout', _this.onMouseout, _this);
6612 this.fireEvent('rowsrendered', this);
6613 //if(this.loadMask){
6614 // this.maskEl.hide();
6621 onUpdate : function(ds,record)
6623 this.refreshRow(record);
6627 onRemove : function(ds, record, index, isUpdate){
6628 if(isUpdate !== true){
6629 this.fireEvent("beforerowremoved", this, index, record);
6631 var bt = this.mainBody.dom;
6633 var rows = this.el.select('tbody > tr', true).elements;
6635 if(typeof(rows[index]) != 'undefined'){
6636 bt.removeChild(rows[index].dom);
6639 // if(bt.rows[index]){
6640 // bt.removeChild(bt.rows[index]);
6643 if(isUpdate !== true){
6644 //this.stripeRows(index);
6645 //this.syncRowHeights(index, index);
6647 this.fireEvent("rowremoved", this, index, record);
6651 onAdd : function(ds, records, rowIndex)
6653 //Roo.log('on Add called');
6654 // - note this does not handle multiple adding very well..
6655 var bt = this.mainBody.dom;
6656 for (var i =0 ; i < records.length;i++) {
6657 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6658 //Roo.log(records[i]);
6659 //Roo.log(this.store.getAt(rowIndex+i));
6660 this.insertRow(this.store, rowIndex + i, false);
6667 refreshRow : function(record){
6668 var ds = this.store, index;
6669 if(typeof record == 'number'){
6671 record = ds.getAt(index);
6673 index = ds.indexOf(record);
6675 this.insertRow(ds, index, true);
6677 this.onRemove(ds, record, index+1, true);
6679 //this.syncRowHeights(index, index);
6681 this.fireEvent("rowupdated", this, index, record);
6684 insertRow : function(dm, rowIndex, isUpdate){
6687 this.fireEvent("beforerowsinserted", this, rowIndex);
6689 //var s = this.getScrollState();
6690 var row = this.renderRow(this.cm, this.store, rowIndex);
6691 // insert before rowIndex..
6692 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6696 if(row.cellObjects.length){
6697 Roo.each(row.cellObjects, function(r){
6698 _this.renderCellObject(r);
6703 this.fireEvent("rowsinserted", this, rowIndex);
6704 //this.syncRowHeights(firstRow, lastRow);
6705 //this.stripeRows(firstRow);
6712 getRowDom : function(rowIndex)
6714 var rows = this.el.select('tbody > tr', true).elements;
6716 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6719 // returns the object tree for a tr..
6722 renderRow : function(cm, ds, rowIndex)
6724 var d = ds.getAt(rowIndex);
6728 cls : 'x-row-' + rowIndex,
6732 var cellObjects = [];
6734 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6735 var config = cm.config[i];
6737 var renderer = cm.getRenderer(i);
6741 if(typeof(renderer) !== 'undefined'){
6742 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6744 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6745 // and are rendered into the cells after the row is rendered - using the id for the element.
6747 if(typeof(value) === 'object'){
6757 rowIndex : rowIndex,
6762 this.fireEvent('rowclass', this, rowcfg);
6766 cls : rowcfg.rowClass + ' x-col-' + i,
6768 html: (typeof(value) === 'object') ? '' : value
6775 if(typeof(config.colspan) != 'undefined'){
6776 td.colspan = config.colspan;
6779 if(typeof(config.hidden) != 'undefined' && config.hidden){
6780 td.style += ' display:none;';
6783 if(typeof(config.align) != 'undefined' && config.align.length){
6784 td.style += ' text-align:' + config.align + ';';
6787 if(typeof(config.width) != 'undefined'){
6788 td.style += ' width:' + config.width + 'px;';
6791 if(typeof(config.cursor) != 'undefined'){
6792 td.style += ' cursor:' + config.cursor + ';';
6795 if(typeof(config.cls) != 'undefined'){
6796 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6799 ['xs','sm','md','lg'].map(function(size){
6801 if(typeof(config[size]) == 'undefined'){
6805 if (!config[size]) { // 0 = hidden
6806 td.cls += ' hidden-' + size;
6810 td.cls += ' col-' + size + '-' + config[size];
6818 row.cellObjects = cellObjects;
6826 onBeforeLoad : function()
6828 //Roo.log('ds onBeforeLoad');
6832 //if(this.loadMask){
6833 // this.maskEl.show();
6841 this.el.select('tbody', true).first().dom.innerHTML = '';
6844 * Show or hide a row.
6845 * @param {Number} rowIndex to show or hide
6846 * @param {Boolean} state hide
6848 setRowVisibility : function(rowIndex, state)
6850 var bt = this.mainBody.dom;
6852 var rows = this.el.select('tbody > tr', true).elements;
6854 if(typeof(rows[rowIndex]) == 'undefined'){
6857 rows[rowIndex].dom.style.display = state ? '' : 'none';
6861 getSelectionModel : function(){
6863 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6865 return this.selModel;
6868 * Render the Roo.bootstrap object from renderder
6870 renderCellObject : function(r)
6874 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6876 var t = r.cfg.render(r.container);
6879 Roo.each(r.cfg.cn, function(c){
6881 container: t.getChildContainer(),
6884 _this.renderCellObject(child);
6889 getRowIndex : function(row)
6893 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6904 * Returns the grid's underlying element = used by panel.Grid
6905 * @return {Element} The element
6907 getGridEl : function(){
6911 * Forces a resize - used by panel.Grid
6912 * @return {Element} The element
6914 autoSize : function()
6916 //var ctr = Roo.get(this.container.dom.parentElement);
6917 var ctr = Roo.get(this.el.dom);
6919 var thd = this.getGridEl().select('thead',true).first();
6920 var tbd = this.getGridEl().select('tbody', true).first();
6921 var tfd = this.getGridEl().select('tfoot', true).first();
6923 var cw = ctr.getWidth();
6927 tbd.setSize(ctr.getWidth(),
6928 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6930 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6933 cw = Math.max(cw, this.totalWidth);
6934 this.getGridEl().select('tr',true).setWidth(cw);
6935 // resize 'expandable coloumn?
6937 return; // we doe not have a view in this design..
6940 onBodyScroll: function()
6942 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6944 this.mainHead.setStyle({
6945 'position' : 'relative',
6946 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6952 var scrollHeight = this.mainBody.dom.scrollHeight;
6954 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6956 var height = this.mainBody.getHeight();
6958 if(scrollHeight - height == scrollTop) {
6960 var total = this.ds.getTotalCount();
6962 if(this.footer.cursor + this.footer.pageSize < total){
6964 this.footer.ds.load({
6966 start : this.footer.cursor + this.footer.pageSize,
6967 limit : this.footer.pageSize
6977 onHeaderChange : function()
6979 var header = this.renderHeader();
6980 var table = this.el.select('table', true).first();
6982 this.mainHead.remove();
6983 this.mainHead = table.createChild(header, this.mainBody, false);
6986 onHiddenChange : function(colModel, colIndex, hidden)
6988 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6989 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6991 this.CSS.updateRule(thSelector, "display", "");
6992 this.CSS.updateRule(tdSelector, "display", "");
6995 this.CSS.updateRule(thSelector, "display", "none");
6996 this.CSS.updateRule(tdSelector, "display", "none");
6999 this.onHeaderChange();
7016 * @class Roo.bootstrap.TableCell
7017 * @extends Roo.bootstrap.Component
7018 * Bootstrap TableCell class
7019 * @cfg {String} html cell contain text
7020 * @cfg {String} cls cell class
7021 * @cfg {String} tag cell tag (td|th) default td
7022 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7023 * @cfg {String} align Aligns the content in a cell
7024 * @cfg {String} axis Categorizes cells
7025 * @cfg {String} bgcolor Specifies the background color of a cell
7026 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7027 * @cfg {Number} colspan Specifies the number of columns a cell should span
7028 * @cfg {String} headers Specifies one or more header cells a cell is related to
7029 * @cfg {Number} height Sets the height of a cell
7030 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7031 * @cfg {Number} rowspan Sets the number of rows a cell should span
7032 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7033 * @cfg {String} valign Vertical aligns the content in a cell
7034 * @cfg {Number} width Specifies the width of a cell
7037 * Create a new TableCell
7038 * @param {Object} config The config object
7041 Roo.bootstrap.TableCell = function(config){
7042 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7045 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7065 getAutoCreate : function(){
7066 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7086 cfg.align=this.align
7092 cfg.bgcolor=this.bgcolor
7095 cfg.charoff=this.charoff
7098 cfg.colspan=this.colspan
7101 cfg.headers=this.headers
7104 cfg.height=this.height
7107 cfg.nowrap=this.nowrap
7110 cfg.rowspan=this.rowspan
7113 cfg.scope=this.scope
7116 cfg.valign=this.valign
7119 cfg.width=this.width
7138 * @class Roo.bootstrap.TableRow
7139 * @extends Roo.bootstrap.Component
7140 * Bootstrap TableRow class
7141 * @cfg {String} cls row class
7142 * @cfg {String} align Aligns the content in a table row
7143 * @cfg {String} bgcolor Specifies a background color for a table row
7144 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7145 * @cfg {String} valign Vertical aligns the content in a table row
7148 * Create a new TableRow
7149 * @param {Object} config The config object
7152 Roo.bootstrap.TableRow = function(config){
7153 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7156 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7164 getAutoCreate : function(){
7165 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7175 cfg.align = this.align;
7178 cfg.bgcolor = this.bgcolor;
7181 cfg.charoff = this.charoff;
7184 cfg.valign = this.valign;
7202 * @class Roo.bootstrap.TableBody
7203 * @extends Roo.bootstrap.Component
7204 * Bootstrap TableBody class
7205 * @cfg {String} cls element class
7206 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7207 * @cfg {String} align Aligns the content inside the element
7208 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7209 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7212 * Create a new TableBody
7213 * @param {Object} config The config object
7216 Roo.bootstrap.TableBody = function(config){
7217 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7220 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7228 getAutoCreate : function(){
7229 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7243 cfg.align = this.align;
7246 cfg.charoff = this.charoff;
7249 cfg.valign = this.valign;
7256 // initEvents : function()
7263 // this.store = Roo.factory(this.store, Roo.data);
7264 // this.store.on('load', this.onLoad, this);
7266 // this.store.load();
7270 // onLoad: function ()
7272 // this.fireEvent('load', this);
7282 * Ext JS Library 1.1.1
7283 * Copyright(c) 2006-2007, Ext JS, LLC.
7285 * Originally Released Under LGPL - original licence link has changed is not relivant.
7288 * <script type="text/javascript">
7291 // as we use this in bootstrap.
7292 Roo.namespace('Roo.form');
7294 * @class Roo.form.Action
7295 * Internal Class used to handle form actions
7297 * @param {Roo.form.BasicForm} el The form element or its id
7298 * @param {Object} config Configuration options
7303 // define the action interface
7304 Roo.form.Action = function(form, options){
7306 this.options = options || {};
7309 * Client Validation Failed
7312 Roo.form.Action.CLIENT_INVALID = 'client';
7314 * Server Validation Failed
7317 Roo.form.Action.SERVER_INVALID = 'server';
7319 * Connect to Server Failed
7322 Roo.form.Action.CONNECT_FAILURE = 'connect';
7324 * Reading Data from Server Failed
7327 Roo.form.Action.LOAD_FAILURE = 'load';
7329 Roo.form.Action.prototype = {
7331 failureType : undefined,
7332 response : undefined,
7336 run : function(options){
7341 success : function(response){
7346 handleResponse : function(response){
7350 // default connection failure
7351 failure : function(response){
7353 this.response = response;
7354 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7355 this.form.afterAction(this, false);
7358 processResponse : function(response){
7359 this.response = response;
7360 if(!response.responseText){
7363 this.result = this.handleResponse(response);
7367 // utility functions used internally
7368 getUrl : function(appendParams){
7369 var url = this.options.url || this.form.url || this.form.el.dom.action;
7371 var p = this.getParams();
7373 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7379 getMethod : function(){
7380 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7383 getParams : function(){
7384 var bp = this.form.baseParams;
7385 var p = this.options.params;
7387 if(typeof p == "object"){
7388 p = Roo.urlEncode(Roo.applyIf(p, bp));
7389 }else if(typeof p == 'string' && bp){
7390 p += '&' + Roo.urlEncode(bp);
7393 p = Roo.urlEncode(bp);
7398 createCallback : function(){
7400 success: this.success,
7401 failure: this.failure,
7403 timeout: (this.form.timeout*1000),
7404 upload: this.form.fileUpload ? this.success : undefined
7409 Roo.form.Action.Submit = function(form, options){
7410 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7413 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7416 haveProgress : false,
7417 uploadComplete : false,
7419 // uploadProgress indicator.
7420 uploadProgress : function()
7422 if (!this.form.progressUrl) {
7426 if (!this.haveProgress) {
7427 Roo.MessageBox.progress("Uploading", "Uploading");
7429 if (this.uploadComplete) {
7430 Roo.MessageBox.hide();
7434 this.haveProgress = true;
7436 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7438 var c = new Roo.data.Connection();
7440 url : this.form.progressUrl,
7445 success : function(req){
7446 //console.log(data);
7450 rdata = Roo.decode(req.responseText)
7452 Roo.log("Invalid data from server..");
7456 if (!rdata || !rdata.success) {
7458 Roo.MessageBox.alert(Roo.encode(rdata));
7461 var data = rdata.data;
7463 if (this.uploadComplete) {
7464 Roo.MessageBox.hide();
7469 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7470 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7473 this.uploadProgress.defer(2000,this);
7476 failure: function(data) {
7477 Roo.log('progress url failed ');
7488 // run get Values on the form, so it syncs any secondary forms.
7489 this.form.getValues();
7491 var o = this.options;
7492 var method = this.getMethod();
7493 var isPost = method == 'POST';
7494 if(o.clientValidation === false || this.form.isValid()){
7496 if (this.form.progressUrl) {
7497 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7498 (new Date() * 1) + '' + Math.random());
7503 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7504 form:this.form.el.dom,
7505 url:this.getUrl(!isPost),
7507 params:isPost ? this.getParams() : null,
7508 isUpload: this.form.fileUpload
7511 this.uploadProgress();
7513 }else if (o.clientValidation !== false){ // client validation failed
7514 this.failureType = Roo.form.Action.CLIENT_INVALID;
7515 this.form.afterAction(this, false);
7519 success : function(response)
7521 this.uploadComplete= true;
7522 if (this.haveProgress) {
7523 Roo.MessageBox.hide();
7527 var result = this.processResponse(response);
7528 if(result === true || result.success){
7529 this.form.afterAction(this, true);
7533 this.form.markInvalid(result.errors);
7534 this.failureType = Roo.form.Action.SERVER_INVALID;
7536 this.form.afterAction(this, false);
7538 failure : function(response)
7540 this.uploadComplete= true;
7541 if (this.haveProgress) {
7542 Roo.MessageBox.hide();
7545 this.response = response;
7546 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7547 this.form.afterAction(this, false);
7550 handleResponse : function(response){
7551 if(this.form.errorReader){
7552 var rs = this.form.errorReader.read(response);
7555 for(var i = 0, len = rs.records.length; i < len; i++) {
7556 var r = rs.records[i];
7560 if(errors.length < 1){
7564 success : rs.success,
7570 ret = Roo.decode(response.responseText);
7574 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7584 Roo.form.Action.Load = function(form, options){
7585 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7586 this.reader = this.form.reader;
7589 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7594 Roo.Ajax.request(Roo.apply(
7595 this.createCallback(), {
7596 method:this.getMethod(),
7597 url:this.getUrl(false),
7598 params:this.getParams()
7602 success : function(response){
7604 var result = this.processResponse(response);
7605 if(result === true || !result.success || !result.data){
7606 this.failureType = Roo.form.Action.LOAD_FAILURE;
7607 this.form.afterAction(this, false);
7610 this.form.clearInvalid();
7611 this.form.setValues(result.data);
7612 this.form.afterAction(this, true);
7615 handleResponse : function(response){
7616 if(this.form.reader){
7617 var rs = this.form.reader.read(response);
7618 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7620 success : rs.success,
7624 return Roo.decode(response.responseText);
7628 Roo.form.Action.ACTION_TYPES = {
7629 'load' : Roo.form.Action.Load,
7630 'submit' : Roo.form.Action.Submit
7639 * @class Roo.bootstrap.Form
7640 * @extends Roo.bootstrap.Component
7641 * Bootstrap Form class
7642 * @cfg {String} method GET | POST (default POST)
7643 * @cfg {String} labelAlign top | left (default top)
7644 * @cfg {String} align left | right - for navbars
7645 * @cfg {Boolean} loadMask load mask when submit (default true)
7650 * @param {Object} config The config object
7654 Roo.bootstrap.Form = function(config){
7656 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7658 Roo.bootstrap.Form.popover.apply();
7662 * @event clientvalidation
7663 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7664 * @param {Form} this
7665 * @param {Boolean} valid true if the form has passed client-side validation
7667 clientvalidation: true,
7669 * @event beforeaction
7670 * Fires before any action is performed. Return false to cancel the action.
7671 * @param {Form} this
7672 * @param {Action} action The action to be performed
7676 * @event actionfailed
7677 * Fires when an action fails.
7678 * @param {Form} this
7679 * @param {Action} action The action that failed
7681 actionfailed : true,
7683 * @event actioncomplete
7684 * Fires when an action is completed.
7685 * @param {Form} this
7686 * @param {Action} action The action that completed
7688 actioncomplete : true
7692 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7695 * @cfg {String} method
7696 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7701 * The URL to use for form actions if one isn't supplied in the action options.
7704 * @cfg {Boolean} fileUpload
7705 * Set to true if this form is a file upload.
7709 * @cfg {Object} baseParams
7710 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7714 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7718 * @cfg {Sting} align (left|right) for navbar forms
7723 activeAction : null,
7726 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7727 * element by passing it or its id or mask the form itself by passing in true.
7730 waitMsgTarget : false,
7735 * @cfg {Boolean} errorMask (true|false) default false
7740 * @cfg {Number} maskOffset Default 100
7745 * @cfg {Boolean} maskBody
7749 getAutoCreate : function(){
7753 method : this.method || 'POST',
7754 id : this.id || Roo.id(),
7757 if (this.parent().xtype.match(/^Nav/)) {
7758 cfg.cls = 'navbar-form navbar-' + this.align;
7762 if (this.labelAlign == 'left' ) {
7763 cfg.cls += ' form-horizontal';
7769 initEvents : function()
7771 this.el.on('submit', this.onSubmit, this);
7772 // this was added as random key presses on the form where triggering form submit.
7773 this.el.on('keypress', function(e) {
7774 if (e.getCharCode() != 13) {
7777 // we might need to allow it for textareas.. and some other items.
7778 // check e.getTarget().
7780 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7784 Roo.log("keypress blocked");
7792 onSubmit : function(e){
7797 * Returns true if client-side validation on the form is successful.
7800 isValid : function(){
7801 var items = this.getItems();
7805 items.each(function(f){
7812 if(!target && f.el.isVisible(true)){
7818 if(this.errorMask && !valid){
7819 Roo.bootstrap.Form.popover.mask(this, target);
7826 * Returns true if any fields in this form have changed since their original load.
7829 isDirty : function(){
7831 var items = this.getItems();
7832 items.each(function(f){
7842 * Performs a predefined action (submit or load) or custom actions you define on this form.
7843 * @param {String} actionName The name of the action type
7844 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7845 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7846 * accept other config options):
7848 Property Type Description
7849 ---------------- --------------- ----------------------------------------------------------------------------------
7850 url String The url for the action (defaults to the form's url)
7851 method String The form method to use (defaults to the form's method, or POST if not defined)
7852 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7853 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7854 validate the form on the client (defaults to false)
7856 * @return {BasicForm} this
7858 doAction : function(action, options){
7859 if(typeof action == 'string'){
7860 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7862 if(this.fireEvent('beforeaction', this, action) !== false){
7863 this.beforeAction(action);
7864 action.run.defer(100, action);
7870 beforeAction : function(action){
7871 var o = action.options;
7876 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7878 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7881 // not really supported yet.. ??
7883 //if(this.waitMsgTarget === true){
7884 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7885 //}else if(this.waitMsgTarget){
7886 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7887 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7889 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7895 afterAction : function(action, success){
7896 this.activeAction = null;
7897 var o = action.options;
7902 Roo.get(document.body).unmask();
7908 //if(this.waitMsgTarget === true){
7909 // this.el.unmask();
7910 //}else if(this.waitMsgTarget){
7911 // this.waitMsgTarget.unmask();
7913 // Roo.MessageBox.updateProgress(1);
7914 // Roo.MessageBox.hide();
7921 Roo.callback(o.success, o.scope, [this, action]);
7922 this.fireEvent('actioncomplete', this, action);
7926 // failure condition..
7927 // we have a scenario where updates need confirming.
7928 // eg. if a locking scenario exists..
7929 // we look for { errors : { needs_confirm : true }} in the response.
7931 (typeof(action.result) != 'undefined') &&
7932 (typeof(action.result.errors) != 'undefined') &&
7933 (typeof(action.result.errors.needs_confirm) != 'undefined')
7936 Roo.log("not supported yet");
7939 Roo.MessageBox.confirm(
7940 "Change requires confirmation",
7941 action.result.errorMsg,
7946 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7956 Roo.callback(o.failure, o.scope, [this, action]);
7957 // show an error message if no failed handler is set..
7958 if (!this.hasListener('actionfailed')) {
7959 Roo.log("need to add dialog support");
7961 Roo.MessageBox.alert("Error",
7962 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7963 action.result.errorMsg :
7964 "Saving Failed, please check your entries or try again"
7969 this.fireEvent('actionfailed', this, action);
7974 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7975 * @param {String} id The value to search for
7978 findField : function(id){
7979 var items = this.getItems();
7980 var field = items.get(id);
7982 items.each(function(f){
7983 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7990 return field || null;
7993 * Mark fields in this form invalid in bulk.
7994 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7995 * @return {BasicForm} this
7997 markInvalid : function(errors){
7998 if(errors instanceof Array){
7999 for(var i = 0, len = errors.length; i < len; i++){
8000 var fieldError = errors[i];
8001 var f = this.findField(fieldError.id);
8003 f.markInvalid(fieldError.msg);
8009 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8010 field.markInvalid(errors[id]);
8014 //Roo.each(this.childForms || [], function (f) {
8015 // f.markInvalid(errors);
8022 * Set values for fields in this form in bulk.
8023 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8024 * @return {BasicForm} this
8026 setValues : function(values){
8027 if(values instanceof Array){ // array of objects
8028 for(var i = 0, len = values.length; i < len; i++){
8030 var f = this.findField(v.id);
8032 f.setValue(v.value);
8033 if(this.trackResetOnLoad){
8034 f.originalValue = f.getValue();
8038 }else{ // object hash
8041 if(typeof values[id] != 'function' && (field = this.findField(id))){
8043 if (field.setFromData &&
8045 field.displayField &&
8046 // combos' with local stores can
8047 // be queried via setValue()
8048 // to set their value..
8049 (field.store && !field.store.isLocal)
8053 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8054 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8055 field.setFromData(sd);
8057 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8059 field.setFromData(values);
8062 field.setValue(values[id]);
8066 if(this.trackResetOnLoad){
8067 field.originalValue = field.getValue();
8073 //Roo.each(this.childForms || [], function (f) {
8074 // f.setValues(values);
8081 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8082 * they are returned as an array.
8083 * @param {Boolean} asString
8086 getValues : function(asString){
8087 //if (this.childForms) {
8088 // copy values from the child forms
8089 // Roo.each(this.childForms, function (f) {
8090 // this.setValues(f.getValues());
8096 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8097 if(asString === true){
8100 return Roo.urlDecode(fs);
8104 * Returns the fields in this form as an object with key/value pairs.
8105 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8108 getFieldValues : function(with_hidden)
8110 var items = this.getItems();
8112 items.each(function(f){
8118 var v = f.getValue();
8120 if (f.inputType =='radio') {
8121 if (typeof(ret[f.getName()]) == 'undefined') {
8122 ret[f.getName()] = ''; // empty..
8125 if (!f.el.dom.checked) {
8133 if(f.xtype == 'MoneyField'){
8134 ret[f.currencyName] = f.getCurrency();
8137 // not sure if this supported any more..
8138 if ((typeof(v) == 'object') && f.getRawValue) {
8139 v = f.getRawValue() ; // dates..
8141 // combo boxes where name != hiddenName...
8142 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8143 ret[f.name] = f.getRawValue();
8145 ret[f.getName()] = v;
8152 * Clears all invalid messages in this form.
8153 * @return {BasicForm} this
8155 clearInvalid : function(){
8156 var items = this.getItems();
8158 items.each(function(f){
8167 * @return {BasicForm} this
8170 var items = this.getItems();
8171 items.each(function(f){
8175 Roo.each(this.childForms || [], function (f) {
8183 getItems : function()
8185 var r=new Roo.util.MixedCollection(false, function(o){
8186 return o.id || (o.id = Roo.id());
8188 var iter = function(el) {
8195 Roo.each(el.items,function(e) {
8204 hideFields : function(items)
8206 Roo.each(items, function(i){
8208 var f = this.findField(i);
8214 if(f.xtype == 'DateField'){
8215 f.setVisible(false);
8224 showFields : function(items)
8226 Roo.each(items, function(i){
8228 var f = this.findField(i);
8234 if(f.xtype == 'DateField'){
8246 Roo.apply(Roo.bootstrap.Form, {
8273 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8274 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8275 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8276 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8279 this.maskEl.top.enableDisplayMode("block");
8280 this.maskEl.left.enableDisplayMode("block");
8281 this.maskEl.bottom.enableDisplayMode("block");
8282 this.maskEl.right.enableDisplayMode("block");
8284 this.toolTip = new Roo.bootstrap.Tooltip({
8285 cls : 'roo-form-error-popover',
8287 'left' : ['r-l', [-2,0], 'right'],
8288 'right' : ['l-r', [2,0], 'left'],
8289 'bottom' : ['tl-bl', [0,2], 'top'],
8290 'top' : [ 'bl-tl', [0,-2], 'bottom']
8294 this.toolTip.render(Roo.get(document.body));
8296 this.toolTip.el.enableDisplayMode("block");
8298 Roo.get(document.body).on('click', function(){
8302 Roo.get(document.body).on('touchstart', function(){
8306 this.isApplied = true
8309 mask : function(form, target)
8313 this.target = target;
8315 if(!this.form.errorMask || !target.el){
8319 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8321 Roo.log(scrollable);
8323 var ot = this.target.el.calcOffsetsTo(scrollable);
8325 var scrollTo = ot[1] - this.form.maskOffset;
8327 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8329 scrollable.scrollTo('top', scrollTo);
8331 var box = this.target.el.getBox();
8333 var zIndex = Roo.bootstrap.Modal.zIndex++;
8336 this.maskEl.top.setStyle('position', 'absolute');
8337 this.maskEl.top.setStyle('z-index', zIndex);
8338 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8339 this.maskEl.top.setLeft(0);
8340 this.maskEl.top.setTop(0);
8341 this.maskEl.top.show();
8343 this.maskEl.left.setStyle('position', 'absolute');
8344 this.maskEl.left.setStyle('z-index', zIndex);
8345 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8346 this.maskEl.left.setLeft(0);
8347 this.maskEl.left.setTop(box.y - this.padding);
8348 this.maskEl.left.show();
8350 this.maskEl.bottom.setStyle('position', 'absolute');
8351 this.maskEl.bottom.setStyle('z-index', zIndex);
8352 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8353 this.maskEl.bottom.setLeft(0);
8354 this.maskEl.bottom.setTop(box.bottom + this.padding);
8355 this.maskEl.bottom.show();
8357 this.maskEl.right.setStyle('position', 'absolute');
8358 this.maskEl.right.setStyle('z-index', zIndex);
8359 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8360 this.maskEl.right.setLeft(box.right + this.padding);
8361 this.maskEl.right.setTop(box.y - this.padding);
8362 this.maskEl.right.show();
8364 this.toolTip.bindEl = this.target.el;
8366 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8368 var tip = this.target.blankText;
8370 if(this.target.getValue() !== '' ) {
8372 if (this.target.invalidText.length) {
8373 tip = this.target.invalidText;
8374 } else if (this.target.regexText.length){
8375 tip = this.target.regexText;
8379 this.toolTip.show(tip);
8381 this.intervalID = window.setInterval(function() {
8382 Roo.bootstrap.Form.popover.unmask();
8385 window.onwheel = function(){ return false;};
8387 (function(){ this.isMasked = true; }).defer(500, this);
8393 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8397 this.maskEl.top.setStyle('position', 'absolute');
8398 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8399 this.maskEl.top.hide();
8401 this.maskEl.left.setStyle('position', 'absolute');
8402 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8403 this.maskEl.left.hide();
8405 this.maskEl.bottom.setStyle('position', 'absolute');
8406 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8407 this.maskEl.bottom.hide();
8409 this.maskEl.right.setStyle('position', 'absolute');
8410 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8411 this.maskEl.right.hide();
8413 this.toolTip.hide();
8415 this.toolTip.el.hide();
8417 window.onwheel = function(){ return true;};
8419 if(this.intervalID){
8420 window.clearInterval(this.intervalID);
8421 this.intervalID = false;
8424 this.isMasked = false;
8434 * Ext JS Library 1.1.1
8435 * Copyright(c) 2006-2007, Ext JS, LLC.
8437 * Originally Released Under LGPL - original licence link has changed is not relivant.
8440 * <script type="text/javascript">
8443 * @class Roo.form.VTypes
8444 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8447 Roo.form.VTypes = function(){
8448 // closure these in so they are only created once.
8449 var alpha = /^[a-zA-Z_]+$/;
8450 var alphanum = /^[a-zA-Z0-9_]+$/;
8451 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8452 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8454 // All these messages and functions are configurable
8457 * The function used to validate email addresses
8458 * @param {String} value The email address
8460 'email' : function(v){
8461 return email.test(v);
8464 * The error text to display when the email validation function returns false
8467 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8469 * The keystroke filter mask to be applied on email input
8472 'emailMask' : /[a-z0-9_\.\-@]/i,
8475 * The function used to validate URLs
8476 * @param {String} value The URL
8478 'url' : function(v){
8482 * The error text to display when the url validation function returns false
8485 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8488 * The function used to validate alpha values
8489 * @param {String} value The value
8491 'alpha' : function(v){
8492 return alpha.test(v);
8495 * The error text to display when the alpha validation function returns false
8498 'alphaText' : 'This field should only contain letters and _',
8500 * The keystroke filter mask to be applied on alpha input
8503 'alphaMask' : /[a-z_]/i,
8506 * The function used to validate alphanumeric values
8507 * @param {String} value The value
8509 'alphanum' : function(v){
8510 return alphanum.test(v);
8513 * The error text to display when the alphanumeric validation function returns false
8516 'alphanumText' : 'This field should only contain letters, numbers and _',
8518 * The keystroke filter mask to be applied on alphanumeric input
8521 'alphanumMask' : /[a-z0-9_]/i
8531 * @class Roo.bootstrap.Input
8532 * @extends Roo.bootstrap.Component
8533 * Bootstrap Input class
8534 * @cfg {Boolean} disabled is it disabled
8535 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8536 * @cfg {String} name name of the input
8537 * @cfg {string} fieldLabel - the label associated
8538 * @cfg {string} placeholder - placeholder to put in text.
8539 * @cfg {string} before - input group add on before
8540 * @cfg {string} after - input group add on after
8541 * @cfg {string} size - (lg|sm) or leave empty..
8542 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8543 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8544 * @cfg {Number} md colspan out of 12 for computer-sized screens
8545 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8546 * @cfg {string} value default value of the input
8547 * @cfg {Number} labelWidth set the width of label
8548 * @cfg {Number} labellg set the width of label (1-12)
8549 * @cfg {Number} labelmd set the width of label (1-12)
8550 * @cfg {Number} labelsm set the width of label (1-12)
8551 * @cfg {Number} labelxs set the width of label (1-12)
8552 * @cfg {String} labelAlign (top|left)
8553 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8554 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8555 * @cfg {String} indicatorpos (left|right) default left
8556 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8557 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8559 * @cfg {String} align (left|center|right) Default left
8560 * @cfg {Boolean} forceFeedback (true|false) Default false
8563 * Create a new Input
8564 * @param {Object} config The config object
8567 Roo.bootstrap.Input = function(config){
8569 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8574 * Fires when this field receives input focus.
8575 * @param {Roo.form.Field} this
8580 * Fires when this field loses input focus.
8581 * @param {Roo.form.Field} this
8586 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8587 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8588 * @param {Roo.form.Field} this
8589 * @param {Roo.EventObject} e The event object
8594 * Fires just before the field blurs if the field value has changed.
8595 * @param {Roo.form.Field} this
8596 * @param {Mixed} newValue The new value
8597 * @param {Mixed} oldValue The original value
8602 * Fires after the field has been marked as invalid.
8603 * @param {Roo.form.Field} this
8604 * @param {String} msg The validation message
8609 * Fires after the field has been validated with no errors.
8610 * @param {Roo.form.Field} this
8615 * Fires after the key up
8616 * @param {Roo.form.Field} this
8617 * @param {Roo.EventObject} e The event Object
8623 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8625 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8626 automatic validation (defaults to "keyup").
8628 validationEvent : "keyup",
8630 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8632 validateOnBlur : true,
8634 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8636 validationDelay : 250,
8638 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8640 focusClass : "x-form-focus", // not needed???
8644 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8646 invalidClass : "has-warning",
8649 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8651 validClass : "has-success",
8654 * @cfg {Boolean} hasFeedback (true|false) default true
8659 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8661 invalidFeedbackClass : "glyphicon-warning-sign",
8664 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8666 validFeedbackClass : "glyphicon-ok",
8669 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8671 selectOnFocus : false,
8674 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8678 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8683 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8685 disableKeyFilter : false,
8688 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8692 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8696 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8698 blankText : "Please complete this mandatory field",
8701 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8705 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8707 maxLength : Number.MAX_VALUE,
8709 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8711 minLengthText : "The minimum length for this field is {0}",
8713 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8715 maxLengthText : "The maximum length for this field is {0}",
8719 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8720 * If available, this function will be called only after the basic validators all return true, and will be passed the
8721 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8725 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8726 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8727 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8731 * @cfg {String} regexText -- Depricated - use Invalid Text
8736 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8742 autocomplete: false,
8761 formatedValue : false,
8762 forceFeedback : false,
8764 indicatorpos : 'left',
8774 parentLabelAlign : function()
8777 while (parent.parent()) {
8778 parent = parent.parent();
8779 if (typeof(parent.labelAlign) !='undefined') {
8780 return parent.labelAlign;
8787 getAutoCreate : function()
8789 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8795 if(this.inputType != 'hidden'){
8796 cfg.cls = 'form-group' //input-group
8802 type : this.inputType,
8804 cls : 'form-control',
8805 placeholder : this.placeholder || '',
8806 autocomplete : this.autocomplete || 'new-password'
8809 if(this.capture.length){
8810 input.capture = this.capture;
8813 if(this.accept.length){
8814 input.accept = this.accept + "/*";
8818 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8821 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8822 input.maxLength = this.maxLength;
8825 if (this.disabled) {
8826 input.disabled=true;
8829 if (this.readOnly) {
8830 input.readonly=true;
8834 input.name = this.name;
8838 input.cls += ' input-' + this.size;
8842 ['xs','sm','md','lg'].map(function(size){
8843 if (settings[size]) {
8844 cfg.cls += ' col-' + size + '-' + settings[size];
8848 var inputblock = input;
8852 cls: 'glyphicon form-control-feedback'
8855 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8858 cls : 'has-feedback',
8866 if (this.before || this.after) {
8869 cls : 'input-group',
8873 if (this.before && typeof(this.before) == 'string') {
8875 inputblock.cn.push({
8877 cls : 'roo-input-before input-group-addon',
8881 if (this.before && typeof(this.before) == 'object') {
8882 this.before = Roo.factory(this.before);
8884 inputblock.cn.push({
8886 cls : 'roo-input-before input-group-' +
8887 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8891 inputblock.cn.push(input);
8893 if (this.after && typeof(this.after) == 'string') {
8894 inputblock.cn.push({
8896 cls : 'roo-input-after input-group-addon',
8900 if (this.after && typeof(this.after) == 'object') {
8901 this.after = Roo.factory(this.after);
8903 inputblock.cn.push({
8905 cls : 'roo-input-after input-group-' +
8906 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8910 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8911 inputblock.cls += ' has-feedback';
8912 inputblock.cn.push(feedback);
8916 if (align ==='left' && this.fieldLabel.length) {
8918 cfg.cls += ' roo-form-group-label-left';
8923 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8924 tooltip : 'This field is required'
8929 cls : 'control-label',
8930 html : this.fieldLabel
8941 var labelCfg = cfg.cn[1];
8942 var contentCfg = cfg.cn[2];
8944 if(this.indicatorpos == 'right'){
8949 cls : 'control-label',
8953 html : this.fieldLabel
8957 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8958 tooltip : 'This field is required'
8971 labelCfg = cfg.cn[0];
8972 contentCfg = cfg.cn[1];
8976 if(this.labelWidth > 12){
8977 labelCfg.style = "width: " + this.labelWidth + 'px';
8980 if(this.labelWidth < 13 && this.labelmd == 0){
8981 this.labelmd = this.labelWidth;
8984 if(this.labellg > 0){
8985 labelCfg.cls += ' col-lg-' + this.labellg;
8986 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8989 if(this.labelmd > 0){
8990 labelCfg.cls += ' col-md-' + this.labelmd;
8991 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8994 if(this.labelsm > 0){
8995 labelCfg.cls += ' col-sm-' + this.labelsm;
8996 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8999 if(this.labelxs > 0){
9000 labelCfg.cls += ' col-xs-' + this.labelxs;
9001 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9005 } else if ( this.fieldLabel.length) {
9010 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9011 tooltip : 'This field is required'
9015 //cls : 'input-group-addon',
9016 html : this.fieldLabel
9024 if(this.indicatorpos == 'right'){
9029 //cls : 'input-group-addon',
9030 html : this.fieldLabel
9035 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9036 tooltip : 'This field is required'
9056 if (this.parentType === 'Navbar' && this.parent().bar) {
9057 cfg.cls += ' navbar-form';
9060 if (this.parentType === 'NavGroup') {
9061 cfg.cls += ' navbar-form';
9069 * return the real input element.
9071 inputEl: function ()
9073 return this.el.select('input.form-control',true).first();
9076 tooltipEl : function()
9078 return this.inputEl();
9081 indicatorEl : function()
9083 var indicator = this.el.select('i.roo-required-indicator',true).first();
9093 setDisabled : function(v)
9095 var i = this.inputEl().dom;
9097 i.removeAttribute('disabled');
9101 i.setAttribute('disabled','true');
9103 initEvents : function()
9106 this.inputEl().on("keydown" , this.fireKey, this);
9107 this.inputEl().on("focus", this.onFocus, this);
9108 this.inputEl().on("blur", this.onBlur, this);
9110 this.inputEl().relayEvent('keyup', this);
9112 this.indicator = this.indicatorEl();
9115 this.indicator.addClass('invisible');
9118 // reference to original value for reset
9119 this.originalValue = this.getValue();
9120 //Roo.form.TextField.superclass.initEvents.call(this);
9121 if(this.validationEvent == 'keyup'){
9122 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9123 this.inputEl().on('keyup', this.filterValidation, this);
9125 else if(this.validationEvent !== false){
9126 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9129 if(this.selectOnFocus){
9130 this.on("focus", this.preFocus, this);
9133 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9134 this.inputEl().on("keypress", this.filterKeys, this);
9136 this.inputEl().relayEvent('keypress', this);
9139 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9140 this.el.on("click", this.autoSize, this);
9143 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9144 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9147 if (typeof(this.before) == 'object') {
9148 this.before.render(this.el.select('.roo-input-before',true).first());
9150 if (typeof(this.after) == 'object') {
9151 this.after.render(this.el.select('.roo-input-after',true).first());
9154 this.inputEl().on('change', this.onChange, this);
9157 filterValidation : function(e){
9158 if(!e.isNavKeyPress()){
9159 this.validationTask.delay(this.validationDelay);
9163 * Validates the field value
9164 * @return {Boolean} True if the value is valid, else false
9166 validate : function(){
9167 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9168 if(this.disabled || this.validateValue(this.getRawValue())){
9179 * Validates a value according to the field's validation rules and marks the field as invalid
9180 * if the validation fails
9181 * @param {Mixed} value The value to validate
9182 * @return {Boolean} True if the value is valid, else false
9184 validateValue : function(value)
9186 if(this.getVisibilityEl().hasClass('hidden')){
9190 if(value.length < 1) { // if it's blank
9191 if(this.allowBlank){
9197 if(value.length < this.minLength){
9200 if(value.length > this.maxLength){
9204 var vt = Roo.form.VTypes;
9205 if(!vt[this.vtype](value, this)){
9209 if(typeof this.validator == "function"){
9210 var msg = this.validator(value);
9214 if (typeof(msg) == 'string') {
9215 this.invalidText = msg;
9219 if(this.regex && !this.regex.test(value)){
9227 fireKey : function(e){
9228 //Roo.log('field ' + e.getKey());
9229 if(e.isNavKeyPress()){
9230 this.fireEvent("specialkey", this, e);
9233 focus : function (selectText){
9235 this.inputEl().focus();
9236 if(selectText === true){
9237 this.inputEl().dom.select();
9243 onFocus : function(){
9244 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9245 // this.el.addClass(this.focusClass);
9248 this.hasFocus = true;
9249 this.startValue = this.getValue();
9250 this.fireEvent("focus", this);
9254 beforeBlur : Roo.emptyFn,
9258 onBlur : function(){
9260 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9261 //this.el.removeClass(this.focusClass);
9263 this.hasFocus = false;
9264 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9267 var v = this.getValue();
9268 if(String(v) !== String(this.startValue)){
9269 this.fireEvent('change', this, v, this.startValue);
9271 this.fireEvent("blur", this);
9274 onChange : function(e)
9276 var v = this.getValue();
9277 if(String(v) !== String(this.startValue)){
9278 this.fireEvent('change', this, v, this.startValue);
9284 * Resets the current field value to the originally loaded value and clears any validation messages
9287 this.setValue(this.originalValue);
9291 * Returns the name of the field
9292 * @return {Mixed} name The name field
9294 getName: function(){
9298 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9299 * @return {Mixed} value The field value
9301 getValue : function(){
9303 var v = this.inputEl().getValue();
9308 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9309 * @return {Mixed} value The field value
9311 getRawValue : function(){
9312 var v = this.inputEl().getValue();
9318 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9319 * @param {Mixed} value The value to set
9321 setRawValue : function(v){
9322 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9325 selectText : function(start, end){
9326 var v = this.getRawValue();
9328 start = start === undefined ? 0 : start;
9329 end = end === undefined ? v.length : end;
9330 var d = this.inputEl().dom;
9331 if(d.setSelectionRange){
9332 d.setSelectionRange(start, end);
9333 }else if(d.createTextRange){
9334 var range = d.createTextRange();
9335 range.moveStart("character", start);
9336 range.moveEnd("character", v.length-end);
9343 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9344 * @param {Mixed} value The value to set
9346 setValue : function(v){
9349 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9355 processValue : function(value){
9356 if(this.stripCharsRe){
9357 var newValue = value.replace(this.stripCharsRe, '');
9358 if(newValue !== value){
9359 this.setRawValue(newValue);
9366 preFocus : function(){
9368 if(this.selectOnFocus){
9369 this.inputEl().dom.select();
9372 filterKeys : function(e){
9374 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9377 var c = e.getCharCode(), cc = String.fromCharCode(c);
9378 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9381 if(!this.maskRe.test(cc)){
9386 * Clear any invalid styles/messages for this field
9388 clearInvalid : function(){
9390 if(!this.el || this.preventMark){ // not rendered
9395 this.el.removeClass(this.invalidClass);
9397 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9399 var feedback = this.el.select('.form-control-feedback', true).first();
9402 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9407 this.fireEvent('valid', this);
9411 * Mark this field as valid
9413 markValid : function()
9415 if(!this.el || this.preventMark){ // not rendered...
9419 this.el.removeClass([this.invalidClass, this.validClass]);
9421 var feedback = this.el.select('.form-control-feedback', true).first();
9424 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9428 this.indicator.removeClass('visible');
9429 this.indicator.addClass('invisible');
9436 if(this.allowBlank && !this.getRawValue().length){
9440 this.el.addClass(this.validClass);
9442 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9444 var feedback = this.el.select('.form-control-feedback', true).first();
9447 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9448 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9453 this.fireEvent('valid', this);
9457 * Mark this field as invalid
9458 * @param {String} msg The validation message
9460 markInvalid : function(msg)
9462 if(!this.el || this.preventMark){ // not rendered
9466 this.el.removeClass([this.invalidClass, this.validClass]);
9468 var feedback = this.el.select('.form-control-feedback', true).first();
9471 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9478 if(this.allowBlank && !this.getRawValue().length){
9483 this.indicator.removeClass('invisible');
9484 this.indicator.addClass('visible');
9487 this.el.addClass(this.invalidClass);
9489 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9491 var feedback = this.el.select('.form-control-feedback', true).first();
9494 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9496 if(this.getValue().length || this.forceFeedback){
9497 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9504 this.fireEvent('invalid', this, msg);
9507 SafariOnKeyDown : function(event)
9509 // this is a workaround for a password hang bug on chrome/ webkit.
9510 if (this.inputEl().dom.type != 'password') {
9514 var isSelectAll = false;
9516 if(this.inputEl().dom.selectionEnd > 0){
9517 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9519 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9520 event.preventDefault();
9525 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9527 event.preventDefault();
9528 // this is very hacky as keydown always get's upper case.
9530 var cc = String.fromCharCode(event.getCharCode());
9531 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9535 adjustWidth : function(tag, w){
9536 tag = tag.toLowerCase();
9537 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9538 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9542 if(tag == 'textarea'){
9545 }else if(Roo.isOpera){
9549 if(tag == 'textarea'){
9557 setFieldLabel : function(v)
9564 var ar = this.el.select('label > span',true);
9566 if (ar.elements.length) {
9567 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9568 this.fieldLabel = v;
9572 var br = this.el.select('label',true);
9574 if(br.elements.length) {
9575 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9576 this.fieldLabel = v;
9580 Roo.log('Cannot Found any of label > span || label in input');
9584 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9585 this.fieldLabel = v;
9600 * @class Roo.bootstrap.TextArea
9601 * @extends Roo.bootstrap.Input
9602 * Bootstrap TextArea class
9603 * @cfg {Number} cols Specifies the visible width of a text area
9604 * @cfg {Number} rows Specifies the visible number of lines in a text area
9605 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9606 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9607 * @cfg {string} html text
9610 * Create a new TextArea
9611 * @param {Object} config The config object
9614 Roo.bootstrap.TextArea = function(config){
9615 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9619 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9629 getAutoCreate : function(){
9631 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9637 if(this.inputType != 'hidden'){
9638 cfg.cls = 'form-group' //input-group
9646 value : this.value || '',
9647 html: this.html || '',
9648 cls : 'form-control',
9649 placeholder : this.placeholder || ''
9653 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9654 input.maxLength = this.maxLength;
9658 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9662 input.cols = this.cols;
9665 if (this.readOnly) {
9666 input.readonly = true;
9670 input.name = this.name;
9674 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9678 ['xs','sm','md','lg'].map(function(size){
9679 if (settings[size]) {
9680 cfg.cls += ' col-' + size + '-' + settings[size];
9684 var inputblock = input;
9686 if(this.hasFeedback && !this.allowBlank){
9690 cls: 'glyphicon form-control-feedback'
9694 cls : 'has-feedback',
9703 if (this.before || this.after) {
9706 cls : 'input-group',
9710 inputblock.cn.push({
9712 cls : 'input-group-addon',
9717 inputblock.cn.push(input);
9719 if(this.hasFeedback && !this.allowBlank){
9720 inputblock.cls += ' has-feedback';
9721 inputblock.cn.push(feedback);
9725 inputblock.cn.push({
9727 cls : 'input-group-addon',
9734 if (align ==='left' && this.fieldLabel.length) {
9739 cls : 'control-label',
9740 html : this.fieldLabel
9751 if(this.labelWidth > 12){
9752 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9755 if(this.labelWidth < 13 && this.labelmd == 0){
9756 this.labelmd = this.labelWidth;
9759 if(this.labellg > 0){
9760 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9761 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9764 if(this.labelmd > 0){
9765 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9766 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9769 if(this.labelsm > 0){
9770 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9771 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9774 if(this.labelxs > 0){
9775 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9776 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9779 } else if ( this.fieldLabel.length) {
9784 //cls : 'input-group-addon',
9785 html : this.fieldLabel
9803 if (this.disabled) {
9804 input.disabled=true;
9811 * return the real textarea element.
9813 inputEl: function ()
9815 return this.el.select('textarea.form-control',true).first();
9819 * Clear any invalid styles/messages for this field
9821 clearInvalid : function()
9824 if(!this.el || this.preventMark){ // not rendered
9828 var label = this.el.select('label', true).first();
9829 var icon = this.el.select('i.fa-star', true).first();
9835 this.el.removeClass(this.invalidClass);
9837 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9839 var feedback = this.el.select('.form-control-feedback', true).first();
9842 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9847 this.fireEvent('valid', this);
9851 * Mark this field as valid
9853 markValid : function()
9855 if(!this.el || this.preventMark){ // not rendered
9859 this.el.removeClass([this.invalidClass, this.validClass]);
9861 var feedback = this.el.select('.form-control-feedback', true).first();
9864 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9867 if(this.disabled || this.allowBlank){
9871 var label = this.el.select('label', true).first();
9872 var icon = this.el.select('i.fa-star', true).first();
9878 this.el.addClass(this.validClass);
9880 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9882 var feedback = this.el.select('.form-control-feedback', true).first();
9885 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9886 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9891 this.fireEvent('valid', this);
9895 * Mark this field as invalid
9896 * @param {String} msg The validation message
9898 markInvalid : function(msg)
9900 if(!this.el || this.preventMark){ // not rendered
9904 this.el.removeClass([this.invalidClass, this.validClass]);
9906 var feedback = this.el.select('.form-control-feedback', true).first();
9909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9912 if(this.disabled || this.allowBlank){
9916 var label = this.el.select('label', true).first();
9917 var icon = this.el.select('i.fa-star', true).first();
9919 if(!this.getValue().length && label && !icon){
9920 this.el.createChild({
9922 cls : 'text-danger fa fa-lg fa-star',
9923 tooltip : 'This field is required',
9924 style : 'margin-right:5px;'
9928 this.el.addClass(this.invalidClass);
9930 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9932 var feedback = this.el.select('.form-control-feedback', true).first();
9935 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9937 if(this.getValue().length || this.forceFeedback){
9938 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9945 this.fireEvent('invalid', this, msg);
9953 * trigger field - base class for combo..
9958 * @class Roo.bootstrap.TriggerField
9959 * @extends Roo.bootstrap.Input
9960 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9961 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9962 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9963 * for which you can provide a custom implementation. For example:
9965 var trigger = new Roo.bootstrap.TriggerField();
9966 trigger.onTriggerClick = myTriggerFn;
9967 trigger.applyTo('my-field');
9970 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9971 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9972 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9973 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9974 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9977 * Create a new TriggerField.
9978 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9979 * to the base TextField)
9981 Roo.bootstrap.TriggerField = function(config){
9982 this.mimicing = false;
9983 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9986 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9988 * @cfg {String} triggerClass A CSS class to apply to the trigger
9991 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9996 * @cfg {Boolean} removable (true|false) special filter default false
10000 /** @cfg {Boolean} grow @hide */
10001 /** @cfg {Number} growMin @hide */
10002 /** @cfg {Number} growMax @hide */
10008 autoSize: Roo.emptyFn,
10012 deferHeight : true,
10015 actionMode : 'wrap',
10020 getAutoCreate : function(){
10022 var align = this.labelAlign || this.parentLabelAlign();
10027 cls: 'form-group' //input-group
10034 type : this.inputType,
10035 cls : 'form-control',
10036 autocomplete: 'new-password',
10037 placeholder : this.placeholder || ''
10041 input.name = this.name;
10044 input.cls += ' input-' + this.size;
10047 if (this.disabled) {
10048 input.disabled=true;
10051 var inputblock = input;
10053 if(this.hasFeedback && !this.allowBlank){
10057 cls: 'glyphicon form-control-feedback'
10060 if(this.removable && !this.editable && !this.tickable){
10062 cls : 'has-feedback',
10068 cls : 'roo-combo-removable-btn close'
10075 cls : 'has-feedback',
10084 if(this.removable && !this.editable && !this.tickable){
10086 cls : 'roo-removable',
10092 cls : 'roo-combo-removable-btn close'
10099 if (this.before || this.after) {
10102 cls : 'input-group',
10106 inputblock.cn.push({
10108 cls : 'input-group-addon',
10113 inputblock.cn.push(input);
10115 if(this.hasFeedback && !this.allowBlank){
10116 inputblock.cls += ' has-feedback';
10117 inputblock.cn.push(feedback);
10121 inputblock.cn.push({
10123 cls : 'input-group-addon',
10136 cls: 'form-hidden-field'
10150 cls: 'form-hidden-field'
10154 cls: 'roo-select2-choices',
10158 cls: 'roo-select2-search-field',
10171 cls: 'roo-select2-container input-group',
10176 // cls: 'typeahead typeahead-long dropdown-menu',
10177 // style: 'display:none'
10182 if(!this.multiple && this.showToggleBtn){
10188 if (this.caret != false) {
10191 cls: 'fa fa-' + this.caret
10198 cls : 'input-group-addon btn dropdown-toggle',
10203 cls: 'combobox-clear',
10217 combobox.cls += ' roo-select2-container-multi';
10220 if (align ==='left' && this.fieldLabel.length) {
10222 cfg.cls += ' roo-form-group-label-left';
10227 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10228 tooltip : 'This field is required'
10233 cls : 'control-label',
10234 html : this.fieldLabel
10246 var labelCfg = cfg.cn[1];
10247 var contentCfg = cfg.cn[2];
10249 if(this.indicatorpos == 'right'){
10254 cls : 'control-label',
10258 html : this.fieldLabel
10262 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10263 tooltip : 'This field is required'
10276 labelCfg = cfg.cn[0];
10277 contentCfg = cfg.cn[1];
10280 if(this.labelWidth > 12){
10281 labelCfg.style = "width: " + this.labelWidth + 'px';
10284 if(this.labelWidth < 13 && this.labelmd == 0){
10285 this.labelmd = this.labelWidth;
10288 if(this.labellg > 0){
10289 labelCfg.cls += ' col-lg-' + this.labellg;
10290 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10293 if(this.labelmd > 0){
10294 labelCfg.cls += ' col-md-' + this.labelmd;
10295 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10298 if(this.labelsm > 0){
10299 labelCfg.cls += ' col-sm-' + this.labelsm;
10300 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10303 if(this.labelxs > 0){
10304 labelCfg.cls += ' col-xs-' + this.labelxs;
10305 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10308 } else if ( this.fieldLabel.length) {
10309 // Roo.log(" label");
10313 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10314 tooltip : 'This field is required'
10318 //cls : 'input-group-addon',
10319 html : this.fieldLabel
10327 if(this.indicatorpos == 'right'){
10335 html : this.fieldLabel
10339 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10340 tooltip : 'This field is required'
10353 // Roo.log(" no label && no align");
10360 ['xs','sm','md','lg'].map(function(size){
10361 if (settings[size]) {
10362 cfg.cls += ' col-' + size + '-' + settings[size];
10373 onResize : function(w, h){
10374 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10375 // if(typeof w == 'number'){
10376 // var x = w - this.trigger.getWidth();
10377 // this.inputEl().setWidth(this.adjustWidth('input', x));
10378 // this.trigger.setStyle('left', x+'px');
10383 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10386 getResizeEl : function(){
10387 return this.inputEl();
10391 getPositionEl : function(){
10392 return this.inputEl();
10396 alignErrorIcon : function(){
10397 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10401 initEvents : function(){
10405 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10406 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10407 if(!this.multiple && this.showToggleBtn){
10408 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10409 if(this.hideTrigger){
10410 this.trigger.setDisplayed(false);
10412 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10416 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10419 if(this.removable && !this.editable && !this.tickable){
10420 var close = this.closeTriggerEl();
10423 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10424 close.on('click', this.removeBtnClick, this, close);
10428 //this.trigger.addClassOnOver('x-form-trigger-over');
10429 //this.trigger.addClassOnClick('x-form-trigger-click');
10432 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10436 closeTriggerEl : function()
10438 var close = this.el.select('.roo-combo-removable-btn', true).first();
10439 return close ? close : false;
10442 removeBtnClick : function(e, h, el)
10444 e.preventDefault();
10446 if(this.fireEvent("remove", this) !== false){
10448 this.fireEvent("afterremove", this)
10452 createList : function()
10454 this.list = Roo.get(document.body).createChild({
10456 cls: 'typeahead typeahead-long dropdown-menu',
10457 style: 'display:none'
10460 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10465 initTrigger : function(){
10470 onDestroy : function(){
10472 this.trigger.removeAllListeners();
10473 // this.trigger.remove();
10476 // this.wrap.remove();
10478 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10482 onFocus : function(){
10483 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10485 if(!this.mimicing){
10486 this.wrap.addClass('x-trigger-wrap-focus');
10487 this.mimicing = true;
10488 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10489 if(this.monitorTab){
10490 this.el.on("keydown", this.checkTab, this);
10497 checkTab : function(e){
10498 if(e.getKey() == e.TAB){
10499 this.triggerBlur();
10504 onBlur : function(){
10509 mimicBlur : function(e, t){
10511 if(!this.wrap.contains(t) && this.validateBlur()){
10512 this.triggerBlur();
10518 triggerBlur : function(){
10519 this.mimicing = false;
10520 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10521 if(this.monitorTab){
10522 this.el.un("keydown", this.checkTab, this);
10524 //this.wrap.removeClass('x-trigger-wrap-focus');
10525 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10529 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10530 validateBlur : function(e, t){
10535 onDisable : function(){
10536 this.inputEl().dom.disabled = true;
10537 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10539 // this.wrap.addClass('x-item-disabled');
10544 onEnable : function(){
10545 this.inputEl().dom.disabled = false;
10546 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10548 // this.el.removeClass('x-item-disabled');
10553 onShow : function(){
10554 var ae = this.getActionEl();
10557 ae.dom.style.display = '';
10558 ae.dom.style.visibility = 'visible';
10564 onHide : function(){
10565 var ae = this.getActionEl();
10566 ae.dom.style.display = 'none';
10570 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10571 * by an implementing function.
10573 * @param {EventObject} e
10575 onTriggerClick : Roo.emptyFn
10579 * Ext JS Library 1.1.1
10580 * Copyright(c) 2006-2007, Ext JS, LLC.
10582 * Originally Released Under LGPL - original licence link has changed is not relivant.
10585 * <script type="text/javascript">
10590 * @class Roo.data.SortTypes
10592 * Defines the default sorting (casting?) comparison functions used when sorting data.
10594 Roo.data.SortTypes = {
10596 * Default sort that does nothing
10597 * @param {Mixed} s The value being converted
10598 * @return {Mixed} The comparison value
10600 none : function(s){
10605 * The regular expression used to strip tags
10609 stripTagsRE : /<\/?[^>]+>/gi,
10612 * Strips all HTML tags to sort on text only
10613 * @param {Mixed} s The value being converted
10614 * @return {String} The comparison value
10616 asText : function(s){
10617 return String(s).replace(this.stripTagsRE, "");
10621 * Strips all HTML tags to sort on text only - Case insensitive
10622 * @param {Mixed} s The value being converted
10623 * @return {String} The comparison value
10625 asUCText : function(s){
10626 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10630 * Case insensitive string
10631 * @param {Mixed} s The value being converted
10632 * @return {String} The comparison value
10634 asUCString : function(s) {
10635 return String(s).toUpperCase();
10640 * @param {Mixed} s The value being converted
10641 * @return {Number} The comparison value
10643 asDate : function(s) {
10647 if(s instanceof Date){
10648 return s.getTime();
10650 return Date.parse(String(s));
10655 * @param {Mixed} s The value being converted
10656 * @return {Float} The comparison value
10658 asFloat : function(s) {
10659 var val = parseFloat(String(s).replace(/,/g, ""));
10668 * @param {Mixed} s The value being converted
10669 * @return {Number} The comparison value
10671 asInt : function(s) {
10672 var val = parseInt(String(s).replace(/,/g, ""));
10680 * Ext JS Library 1.1.1
10681 * Copyright(c) 2006-2007, Ext JS, LLC.
10683 * Originally Released Under LGPL - original licence link has changed is not relivant.
10686 * <script type="text/javascript">
10690 * @class Roo.data.Record
10691 * Instances of this class encapsulate both record <em>definition</em> information, and record
10692 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10693 * to access Records cached in an {@link Roo.data.Store} object.<br>
10695 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10696 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10699 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10701 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10702 * {@link #create}. The parameters are the same.
10703 * @param {Array} data An associative Array of data values keyed by the field name.
10704 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10705 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10706 * not specified an integer id is generated.
10708 Roo.data.Record = function(data, id){
10709 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10714 * Generate a constructor for a specific record layout.
10715 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10716 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10717 * Each field definition object may contain the following properties: <ul>
10718 * <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,
10719 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10720 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10721 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10722 * is being used, then this is a string containing the javascript expression to reference the data relative to
10723 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10724 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10725 * this may be omitted.</p></li>
10726 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10727 * <ul><li>auto (Default, implies no conversion)</li>
10732 * <li>date</li></ul></p></li>
10733 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10734 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10735 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10736 * by the Reader into an object that will be stored in the Record. It is passed the
10737 * following parameters:<ul>
10738 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10740 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10742 * <br>usage:<br><pre><code>
10743 var TopicRecord = Roo.data.Record.create(
10744 {name: 'title', mapping: 'topic_title'},
10745 {name: 'author', mapping: 'username'},
10746 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10747 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10748 {name: 'lastPoster', mapping: 'user2'},
10749 {name: 'excerpt', mapping: 'post_text'}
10752 var myNewRecord = new TopicRecord({
10753 title: 'Do my job please',
10756 lastPost: new Date(),
10757 lastPoster: 'Animal',
10758 excerpt: 'No way dude!'
10760 myStore.add(myNewRecord);
10765 Roo.data.Record.create = function(o){
10766 var f = function(){
10767 f.superclass.constructor.apply(this, arguments);
10769 Roo.extend(f, Roo.data.Record);
10770 var p = f.prototype;
10771 p.fields = new Roo.util.MixedCollection(false, function(field){
10774 for(var i = 0, len = o.length; i < len; i++){
10775 p.fields.add(new Roo.data.Field(o[i]));
10777 f.getField = function(name){
10778 return p.fields.get(name);
10783 Roo.data.Record.AUTO_ID = 1000;
10784 Roo.data.Record.EDIT = 'edit';
10785 Roo.data.Record.REJECT = 'reject';
10786 Roo.data.Record.COMMIT = 'commit';
10788 Roo.data.Record.prototype = {
10790 * Readonly flag - true if this record has been modified.
10799 join : function(store){
10800 this.store = store;
10804 * Set the named field to the specified value.
10805 * @param {String} name The name of the field to set.
10806 * @param {Object} value The value to set the field to.
10808 set : function(name, value){
10809 if(this.data[name] == value){
10813 if(!this.modified){
10814 this.modified = {};
10816 if(typeof this.modified[name] == 'undefined'){
10817 this.modified[name] = this.data[name];
10819 this.data[name] = value;
10820 if(!this.editing && this.store){
10821 this.store.afterEdit(this);
10826 * Get the value of the named field.
10827 * @param {String} name The name of the field to get the value of.
10828 * @return {Object} The value of the field.
10830 get : function(name){
10831 return this.data[name];
10835 beginEdit : function(){
10836 this.editing = true;
10837 this.modified = {};
10841 cancelEdit : function(){
10842 this.editing = false;
10843 delete this.modified;
10847 endEdit : function(){
10848 this.editing = false;
10849 if(this.dirty && this.store){
10850 this.store.afterEdit(this);
10855 * Usually called by the {@link Roo.data.Store} which owns the Record.
10856 * Rejects all changes made to the Record since either creation, or the last commit operation.
10857 * Modified fields are reverted to their original values.
10859 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10860 * of reject operations.
10862 reject : function(){
10863 var m = this.modified;
10865 if(typeof m[n] != "function"){
10866 this.data[n] = m[n];
10869 this.dirty = false;
10870 delete this.modified;
10871 this.editing = false;
10873 this.store.afterReject(this);
10878 * Usually called by the {@link Roo.data.Store} which owns the Record.
10879 * Commits all changes made to the Record since either creation, or the last commit operation.
10881 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10882 * of commit operations.
10884 commit : function(){
10885 this.dirty = false;
10886 delete this.modified;
10887 this.editing = false;
10889 this.store.afterCommit(this);
10894 hasError : function(){
10895 return this.error != null;
10899 clearError : function(){
10904 * Creates a copy of this record.
10905 * @param {String} id (optional) A new record id if you don't want to use this record's id
10908 copy : function(newId) {
10909 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10913 * Ext JS Library 1.1.1
10914 * Copyright(c) 2006-2007, Ext JS, LLC.
10916 * Originally Released Under LGPL - original licence link has changed is not relivant.
10919 * <script type="text/javascript">
10925 * @class Roo.data.Store
10926 * @extends Roo.util.Observable
10927 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10928 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10930 * 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
10931 * has no knowledge of the format of the data returned by the Proxy.<br>
10933 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10934 * instances from the data object. These records are cached and made available through accessor functions.
10936 * Creates a new Store.
10937 * @param {Object} config A config object containing the objects needed for the Store to access data,
10938 * and read the data into Records.
10940 Roo.data.Store = function(config){
10941 this.data = new Roo.util.MixedCollection(false);
10942 this.data.getKey = function(o){
10945 this.baseParams = {};
10947 this.paramNames = {
10952 "multisort" : "_multisort"
10955 if(config && config.data){
10956 this.inlineData = config.data;
10957 delete config.data;
10960 Roo.apply(this, config);
10962 if(this.reader){ // reader passed
10963 this.reader = Roo.factory(this.reader, Roo.data);
10964 this.reader.xmodule = this.xmodule || false;
10965 if(!this.recordType){
10966 this.recordType = this.reader.recordType;
10968 if(this.reader.onMetaChange){
10969 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10973 if(this.recordType){
10974 this.fields = this.recordType.prototype.fields;
10976 this.modified = [];
10980 * @event datachanged
10981 * Fires when the data cache has changed, and a widget which is using this Store
10982 * as a Record cache should refresh its view.
10983 * @param {Store} this
10985 datachanged : true,
10987 * @event metachange
10988 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10989 * @param {Store} this
10990 * @param {Object} meta The JSON metadata
10995 * Fires when Records have been added to the Store
10996 * @param {Store} this
10997 * @param {Roo.data.Record[]} records The array of Records added
10998 * @param {Number} index The index at which the record(s) were added
11003 * Fires when a Record has been removed from the Store
11004 * @param {Store} this
11005 * @param {Roo.data.Record} record The Record that was removed
11006 * @param {Number} index The index at which the record was removed
11011 * Fires when a Record has been updated
11012 * @param {Store} this
11013 * @param {Roo.data.Record} record The Record that was updated
11014 * @param {String} operation The update operation being performed. Value may be one of:
11016 Roo.data.Record.EDIT
11017 Roo.data.Record.REJECT
11018 Roo.data.Record.COMMIT
11024 * Fires when the data cache has been cleared.
11025 * @param {Store} this
11029 * @event beforeload
11030 * Fires before a request is made for a new data object. If the beforeload handler returns false
11031 * the load action will be canceled.
11032 * @param {Store} this
11033 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11037 * @event beforeloadadd
11038 * Fires after a new set of Records has been loaded.
11039 * @param {Store} this
11040 * @param {Roo.data.Record[]} records The Records that were loaded
11041 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11043 beforeloadadd : true,
11046 * Fires after a new set of Records has been loaded, before they are added to the store.
11047 * @param {Store} this
11048 * @param {Roo.data.Record[]} records The Records that were loaded
11049 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11050 * @params {Object} return from reader
11054 * @event loadexception
11055 * Fires if an exception occurs in the Proxy during loading.
11056 * Called with the signature of the Proxy's "loadexception" event.
11057 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11060 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11061 * @param {Object} load options
11062 * @param {Object} jsonData from your request (normally this contains the Exception)
11064 loadexception : true
11068 this.proxy = Roo.factory(this.proxy, Roo.data);
11069 this.proxy.xmodule = this.xmodule || false;
11070 this.relayEvents(this.proxy, ["loadexception"]);
11072 this.sortToggle = {};
11073 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11075 Roo.data.Store.superclass.constructor.call(this);
11077 if(this.inlineData){
11078 this.loadData(this.inlineData);
11079 delete this.inlineData;
11083 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11085 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11086 * without a remote query - used by combo/forms at present.
11090 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11093 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11096 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11097 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11100 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11101 * on any HTTP request
11104 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11107 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11111 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11112 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11114 remoteSort : false,
11117 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11118 * loaded or when a record is removed. (defaults to false).
11120 pruneModifiedRecords : false,
11123 lastOptions : null,
11126 * Add Records to the Store and fires the add event.
11127 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11129 add : function(records){
11130 records = [].concat(records);
11131 for(var i = 0, len = records.length; i < len; i++){
11132 records[i].join(this);
11134 var index = this.data.length;
11135 this.data.addAll(records);
11136 this.fireEvent("add", this, records, index);
11140 * Remove a Record from the Store and fires the remove event.
11141 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11143 remove : function(record){
11144 var index = this.data.indexOf(record);
11145 this.data.removeAt(index);
11147 if(this.pruneModifiedRecords){
11148 this.modified.remove(record);
11150 this.fireEvent("remove", this, record, index);
11154 * Remove all Records from the Store and fires the clear event.
11156 removeAll : function(){
11158 if(this.pruneModifiedRecords){
11159 this.modified = [];
11161 this.fireEvent("clear", this);
11165 * Inserts Records to the Store at the given index and fires the add event.
11166 * @param {Number} index The start index at which to insert the passed Records.
11167 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11169 insert : function(index, records){
11170 records = [].concat(records);
11171 for(var i = 0, len = records.length; i < len; i++){
11172 this.data.insert(index, records[i]);
11173 records[i].join(this);
11175 this.fireEvent("add", this, records, index);
11179 * Get the index within the cache of the passed Record.
11180 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11181 * @return {Number} The index of the passed Record. Returns -1 if not found.
11183 indexOf : function(record){
11184 return this.data.indexOf(record);
11188 * Get the index within the cache of the Record with the passed id.
11189 * @param {String} id The id of the Record to find.
11190 * @return {Number} The index of the Record. Returns -1 if not found.
11192 indexOfId : function(id){
11193 return this.data.indexOfKey(id);
11197 * Get the Record with the specified id.
11198 * @param {String} id The id of the Record to find.
11199 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11201 getById : function(id){
11202 return this.data.key(id);
11206 * Get the Record at the specified index.
11207 * @param {Number} index The index of the Record to find.
11208 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11210 getAt : function(index){
11211 return this.data.itemAt(index);
11215 * Returns a range of Records between specified indices.
11216 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11217 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11218 * @return {Roo.data.Record[]} An array of Records
11220 getRange : function(start, end){
11221 return this.data.getRange(start, end);
11225 storeOptions : function(o){
11226 o = Roo.apply({}, o);
11229 this.lastOptions = o;
11233 * Loads the Record cache from the configured Proxy using the configured Reader.
11235 * If using remote paging, then the first load call must specify the <em>start</em>
11236 * and <em>limit</em> properties in the options.params property to establish the initial
11237 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11239 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11240 * and this call will return before the new data has been loaded. Perform any post-processing
11241 * in a callback function, or in a "load" event handler.</strong>
11243 * @param {Object} options An object containing properties which control loading options:<ul>
11244 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11245 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11246 * passed the following arguments:<ul>
11247 * <li>r : Roo.data.Record[]</li>
11248 * <li>options: Options object from the load call</li>
11249 * <li>success: Boolean success indicator</li></ul></li>
11250 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11251 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11254 load : function(options){
11255 options = options || {};
11256 if(this.fireEvent("beforeload", this, options) !== false){
11257 this.storeOptions(options);
11258 var p = Roo.apply(options.params || {}, this.baseParams);
11259 // if meta was not loaded from remote source.. try requesting it.
11260 if (!this.reader.metaFromRemote) {
11261 p._requestMeta = 1;
11263 if(this.sortInfo && this.remoteSort){
11264 var pn = this.paramNames;
11265 p[pn["sort"]] = this.sortInfo.field;
11266 p[pn["dir"]] = this.sortInfo.direction;
11268 if (this.multiSort) {
11269 var pn = this.paramNames;
11270 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11273 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11278 * Reloads the Record cache from the configured Proxy using the configured Reader and
11279 * the options from the last load operation performed.
11280 * @param {Object} options (optional) An object containing properties which may override the options
11281 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11282 * the most recently used options are reused).
11284 reload : function(options){
11285 this.load(Roo.applyIf(options||{}, this.lastOptions));
11289 // Called as a callback by the Reader during a load operation.
11290 loadRecords : function(o, options, success){
11291 if(!o || success === false){
11292 if(success !== false){
11293 this.fireEvent("load", this, [], options, o);
11295 if(options.callback){
11296 options.callback.call(options.scope || this, [], options, false);
11300 // if data returned failure - throw an exception.
11301 if (o.success === false) {
11302 // show a message if no listener is registered.
11303 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11304 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11306 // loadmask wil be hooked into this..
11307 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11310 var r = o.records, t = o.totalRecords || r.length;
11312 this.fireEvent("beforeloadadd", this, r, options, o);
11314 if(!options || options.add !== true){
11315 if(this.pruneModifiedRecords){
11316 this.modified = [];
11318 for(var i = 0, len = r.length; i < len; i++){
11322 this.data = this.snapshot;
11323 delete this.snapshot;
11326 this.data.addAll(r);
11327 this.totalLength = t;
11329 this.fireEvent("datachanged", this);
11331 this.totalLength = Math.max(t, this.data.length+r.length);
11335 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11337 var e = new Roo.data.Record({});
11339 e.set(this.parent.displayField, this.parent.emptyTitle);
11340 e.set(this.parent.valueField, '');
11345 this.fireEvent("load", this, r, options, o);
11346 if(options.callback){
11347 options.callback.call(options.scope || this, r, options, true);
11353 * Loads data from a passed data block. A Reader which understands the format of the data
11354 * must have been configured in the constructor.
11355 * @param {Object} data The data block from which to read the Records. The format of the data expected
11356 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11357 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11359 loadData : function(o, append){
11360 var r = this.reader.readRecords(o);
11361 this.loadRecords(r, {add: append}, true);
11365 * Gets the number of cached records.
11367 * <em>If using paging, this may not be the total size of the dataset. If the data object
11368 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11369 * the data set size</em>
11371 getCount : function(){
11372 return this.data.length || 0;
11376 * Gets the total number of records in the dataset as returned by the server.
11378 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11379 * the dataset size</em>
11381 getTotalCount : function(){
11382 return this.totalLength || 0;
11386 * Returns the sort state of the Store as an object with two properties:
11388 field {String} The name of the field by which the Records are sorted
11389 direction {String} The sort order, "ASC" or "DESC"
11392 getSortState : function(){
11393 return this.sortInfo;
11397 applySort : function(){
11398 if(this.sortInfo && !this.remoteSort){
11399 var s = this.sortInfo, f = s.field;
11400 var st = this.fields.get(f).sortType;
11401 var fn = function(r1, r2){
11402 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11403 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11405 this.data.sort(s.direction, fn);
11406 if(this.snapshot && this.snapshot != this.data){
11407 this.snapshot.sort(s.direction, fn);
11413 * Sets the default sort column and order to be used by the next load operation.
11414 * @param {String} fieldName The name of the field to sort by.
11415 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11417 setDefaultSort : function(field, dir){
11418 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11422 * Sort the Records.
11423 * If remote sorting is used, the sort is performed on the server, and the cache is
11424 * reloaded. If local sorting is used, the cache is sorted internally.
11425 * @param {String} fieldName The name of the field to sort by.
11426 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11428 sort : function(fieldName, dir){
11429 var f = this.fields.get(fieldName);
11431 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11433 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11434 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11439 this.sortToggle[f.name] = dir;
11440 this.sortInfo = {field: f.name, direction: dir};
11441 if(!this.remoteSort){
11443 this.fireEvent("datachanged", this);
11445 this.load(this.lastOptions);
11450 * Calls the specified function for each of the Records in the cache.
11451 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11452 * Returning <em>false</em> aborts and exits the iteration.
11453 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11455 each : function(fn, scope){
11456 this.data.each(fn, scope);
11460 * Gets all records modified since the last commit. Modified records are persisted across load operations
11461 * (e.g., during paging).
11462 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11464 getModifiedRecords : function(){
11465 return this.modified;
11469 createFilterFn : function(property, value, anyMatch){
11470 if(!value.exec){ // not a regex
11471 value = String(value);
11472 if(value.length == 0){
11475 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11477 return function(r){
11478 return value.test(r.data[property]);
11483 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11484 * @param {String} property A field on your records
11485 * @param {Number} start The record index to start at (defaults to 0)
11486 * @param {Number} end The last record index to include (defaults to length - 1)
11487 * @return {Number} The sum
11489 sum : function(property, start, end){
11490 var rs = this.data.items, v = 0;
11491 start = start || 0;
11492 end = (end || end === 0) ? end : rs.length-1;
11494 for(var i = start; i <= end; i++){
11495 v += (rs[i].data[property] || 0);
11501 * Filter the records by a specified property.
11502 * @param {String} field A field on your records
11503 * @param {String/RegExp} value Either a string that the field
11504 * should start with or a RegExp to test against the field
11505 * @param {Boolean} anyMatch True to match any part not just the beginning
11507 filter : function(property, value, anyMatch){
11508 var fn = this.createFilterFn(property, value, anyMatch);
11509 return fn ? this.filterBy(fn) : this.clearFilter();
11513 * Filter by a function. The specified function will be called with each
11514 * record in this data source. If the function returns true the record is included,
11515 * otherwise it is filtered.
11516 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11517 * @param {Object} scope (optional) The scope of the function (defaults to this)
11519 filterBy : function(fn, scope){
11520 this.snapshot = this.snapshot || this.data;
11521 this.data = this.queryBy(fn, scope||this);
11522 this.fireEvent("datachanged", this);
11526 * Query the records by a specified property.
11527 * @param {String} field A field on your records
11528 * @param {String/RegExp} value Either a string that the field
11529 * should start with or a RegExp to test against the field
11530 * @param {Boolean} anyMatch True to match any part not just the beginning
11531 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11533 query : function(property, value, anyMatch){
11534 var fn = this.createFilterFn(property, value, anyMatch);
11535 return fn ? this.queryBy(fn) : this.data.clone();
11539 * Query by a function. The specified function will be called with each
11540 * record in this data source. If the function returns true the record is included
11542 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11543 * @param {Object} scope (optional) The scope of the function (defaults to this)
11544 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11546 queryBy : function(fn, scope){
11547 var data = this.snapshot || this.data;
11548 return data.filterBy(fn, scope||this);
11552 * Collects unique values for a particular dataIndex from this store.
11553 * @param {String} dataIndex The property to collect
11554 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11555 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11556 * @return {Array} An array of the unique values
11558 collect : function(dataIndex, allowNull, bypassFilter){
11559 var d = (bypassFilter === true && this.snapshot) ?
11560 this.snapshot.items : this.data.items;
11561 var v, sv, r = [], l = {};
11562 for(var i = 0, len = d.length; i < len; i++){
11563 v = d[i].data[dataIndex];
11565 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11574 * Revert to a view of the Record cache with no filtering applied.
11575 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11577 clearFilter : function(suppressEvent){
11578 if(this.snapshot && this.snapshot != this.data){
11579 this.data = this.snapshot;
11580 delete this.snapshot;
11581 if(suppressEvent !== true){
11582 this.fireEvent("datachanged", this);
11588 afterEdit : function(record){
11589 if(this.modified.indexOf(record) == -1){
11590 this.modified.push(record);
11592 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11596 afterReject : function(record){
11597 this.modified.remove(record);
11598 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11602 afterCommit : function(record){
11603 this.modified.remove(record);
11604 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11608 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11609 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11611 commitChanges : function(){
11612 var m = this.modified.slice(0);
11613 this.modified = [];
11614 for(var i = 0, len = m.length; i < len; i++){
11620 * Cancel outstanding changes on all changed records.
11622 rejectChanges : function(){
11623 var m = this.modified.slice(0);
11624 this.modified = [];
11625 for(var i = 0, len = m.length; i < len; i++){
11630 onMetaChange : function(meta, rtype, o){
11631 this.recordType = rtype;
11632 this.fields = rtype.prototype.fields;
11633 delete this.snapshot;
11634 this.sortInfo = meta.sortInfo || this.sortInfo;
11635 this.modified = [];
11636 this.fireEvent('metachange', this, this.reader.meta);
11639 moveIndex : function(data, type)
11641 var index = this.indexOf(data);
11643 var newIndex = index + type;
11647 this.insert(newIndex, data);
11652 * Ext JS Library 1.1.1
11653 * Copyright(c) 2006-2007, Ext JS, LLC.
11655 * Originally Released Under LGPL - original licence link has changed is not relivant.
11658 * <script type="text/javascript">
11662 * @class Roo.data.SimpleStore
11663 * @extends Roo.data.Store
11664 * Small helper class to make creating Stores from Array data easier.
11665 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11666 * @cfg {Array} fields An array of field definition objects, or field name strings.
11667 * @cfg {Array} data The multi-dimensional array of data
11669 * @param {Object} config
11671 Roo.data.SimpleStore = function(config){
11672 Roo.data.SimpleStore.superclass.constructor.call(this, {
11674 reader: new Roo.data.ArrayReader({
11677 Roo.data.Record.create(config.fields)
11679 proxy : new Roo.data.MemoryProxy(config.data)
11683 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11685 * Ext JS Library 1.1.1
11686 * Copyright(c) 2006-2007, Ext JS, LLC.
11688 * Originally Released Under LGPL - original licence link has changed is not relivant.
11691 * <script type="text/javascript">
11696 * @extends Roo.data.Store
11697 * @class Roo.data.JsonStore
11698 * Small helper class to make creating Stores for JSON data easier. <br/>
11700 var store = new Roo.data.JsonStore({
11701 url: 'get-images.php',
11703 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11706 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11707 * JsonReader and HttpProxy (unless inline data is provided).</b>
11708 * @cfg {Array} fields An array of field definition objects, or field name strings.
11710 * @param {Object} config
11712 Roo.data.JsonStore = function(c){
11713 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11714 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11715 reader: new Roo.data.JsonReader(c, c.fields)
11718 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11720 * Ext JS Library 1.1.1
11721 * Copyright(c) 2006-2007, Ext JS, LLC.
11723 * Originally Released Under LGPL - original licence link has changed is not relivant.
11726 * <script type="text/javascript">
11730 Roo.data.Field = function(config){
11731 if(typeof config == "string"){
11732 config = {name: config};
11734 Roo.apply(this, config);
11737 this.type = "auto";
11740 var st = Roo.data.SortTypes;
11741 // named sortTypes are supported, here we look them up
11742 if(typeof this.sortType == "string"){
11743 this.sortType = st[this.sortType];
11746 // set default sortType for strings and dates
11747 if(!this.sortType){
11750 this.sortType = st.asUCString;
11753 this.sortType = st.asDate;
11756 this.sortType = st.none;
11761 var stripRe = /[\$,%]/g;
11763 // prebuilt conversion function for this field, instead of
11764 // switching every time we're reading a value
11766 var cv, dateFormat = this.dateFormat;
11771 cv = function(v){ return v; };
11774 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11778 return v !== undefined && v !== null && v !== '' ?
11779 parseInt(String(v).replace(stripRe, ""), 10) : '';
11784 return v !== undefined && v !== null && v !== '' ?
11785 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11790 cv = function(v){ return v === true || v === "true" || v == 1; };
11797 if(v instanceof Date){
11801 if(dateFormat == "timestamp"){
11802 return new Date(v*1000);
11804 return Date.parseDate(v, dateFormat);
11806 var parsed = Date.parse(v);
11807 return parsed ? new Date(parsed) : null;
11816 Roo.data.Field.prototype = {
11824 * Ext JS Library 1.1.1
11825 * Copyright(c) 2006-2007, Ext JS, LLC.
11827 * Originally Released Under LGPL - original licence link has changed is not relivant.
11830 * <script type="text/javascript">
11833 // Base class for reading structured data from a data source. This class is intended to be
11834 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11837 * @class Roo.data.DataReader
11838 * Base class for reading structured data from a data source. This class is intended to be
11839 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11842 Roo.data.DataReader = function(meta, recordType){
11846 this.recordType = recordType instanceof Array ?
11847 Roo.data.Record.create(recordType) : recordType;
11850 Roo.data.DataReader.prototype = {
11852 * Create an empty record
11853 * @param {Object} data (optional) - overlay some values
11854 * @return {Roo.data.Record} record created.
11856 newRow : function(d) {
11858 this.recordType.prototype.fields.each(function(c) {
11860 case 'int' : da[c.name] = 0; break;
11861 case 'date' : da[c.name] = new Date(); break;
11862 case 'float' : da[c.name] = 0.0; break;
11863 case 'boolean' : da[c.name] = false; break;
11864 default : da[c.name] = ""; break;
11868 return new this.recordType(Roo.apply(da, d));
11873 * Ext JS Library 1.1.1
11874 * Copyright(c) 2006-2007, Ext JS, LLC.
11876 * Originally Released Under LGPL - original licence link has changed is not relivant.
11879 * <script type="text/javascript">
11883 * @class Roo.data.DataProxy
11884 * @extends Roo.data.Observable
11885 * This class is an abstract base class for implementations which provide retrieval of
11886 * unformatted data objects.<br>
11888 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11889 * (of the appropriate type which knows how to parse the data object) to provide a block of
11890 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11892 * Custom implementations must implement the load method as described in
11893 * {@link Roo.data.HttpProxy#load}.
11895 Roo.data.DataProxy = function(){
11898 * @event beforeload
11899 * Fires before a network request is made to retrieve a data object.
11900 * @param {Object} This DataProxy object.
11901 * @param {Object} params The params parameter to the load function.
11906 * Fires before the load method's callback is called.
11907 * @param {Object} This DataProxy object.
11908 * @param {Object} o The data object.
11909 * @param {Object} arg The callback argument object passed to the load function.
11913 * @event loadexception
11914 * Fires if an Exception occurs during data retrieval.
11915 * @param {Object} This DataProxy object.
11916 * @param {Object} o The data object.
11917 * @param {Object} arg The callback argument object passed to the load function.
11918 * @param {Object} e The Exception.
11920 loadexception : true
11922 Roo.data.DataProxy.superclass.constructor.call(this);
11925 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11928 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11932 * Ext JS Library 1.1.1
11933 * Copyright(c) 2006-2007, Ext JS, LLC.
11935 * Originally Released Under LGPL - original licence link has changed is not relivant.
11938 * <script type="text/javascript">
11941 * @class Roo.data.MemoryProxy
11942 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11943 * to the Reader when its load method is called.
11945 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11947 Roo.data.MemoryProxy = function(data){
11951 Roo.data.MemoryProxy.superclass.constructor.call(this);
11955 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11958 * Load data from the requested source (in this case an in-memory
11959 * data object passed to the constructor), read the data object into
11960 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11961 * process that block using the passed callback.
11962 * @param {Object} params This parameter is not used by the MemoryProxy class.
11963 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11964 * object into a block of Roo.data.Records.
11965 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11966 * The function must be passed <ul>
11967 * <li>The Record block object</li>
11968 * <li>The "arg" argument from the load function</li>
11969 * <li>A boolean success indicator</li>
11971 * @param {Object} scope The scope in which to call the callback
11972 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11974 load : function(params, reader, callback, scope, arg){
11975 params = params || {};
11978 result = reader.readRecords(this.data);
11980 this.fireEvent("loadexception", this, arg, null, e);
11981 callback.call(scope, null, arg, false);
11984 callback.call(scope, result, arg, true);
11988 update : function(params, records){
11993 * Ext JS Library 1.1.1
11994 * Copyright(c) 2006-2007, Ext JS, LLC.
11996 * Originally Released Under LGPL - original licence link has changed is not relivant.
11999 * <script type="text/javascript">
12002 * @class Roo.data.HttpProxy
12003 * @extends Roo.data.DataProxy
12004 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12005 * configured to reference a certain URL.<br><br>
12007 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12008 * from which the running page was served.<br><br>
12010 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12012 * Be aware that to enable the browser to parse an XML document, the server must set
12013 * the Content-Type header in the HTTP response to "text/xml".
12015 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12016 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12017 * will be used to make the request.
12019 Roo.data.HttpProxy = function(conn){
12020 Roo.data.HttpProxy.superclass.constructor.call(this);
12021 // is conn a conn config or a real conn?
12023 this.useAjax = !conn || !conn.events;
12027 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12028 // thse are take from connection...
12031 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12034 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12035 * extra parameters to each request made by this object. (defaults to undefined)
12038 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12039 * to each request made by this object. (defaults to undefined)
12042 * @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)
12045 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12048 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12054 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12058 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12059 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12060 * a finer-grained basis than the DataProxy events.
12062 getConnection : function(){
12063 return this.useAjax ? Roo.Ajax : this.conn;
12067 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12068 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12069 * process that block using the passed callback.
12070 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12071 * for the request to the remote server.
12072 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12073 * object into a block of Roo.data.Records.
12074 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12075 * The function must be passed <ul>
12076 * <li>The Record block object</li>
12077 * <li>The "arg" argument from the load function</li>
12078 * <li>A boolean success indicator</li>
12080 * @param {Object} scope The scope in which to call the callback
12081 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12083 load : function(params, reader, callback, scope, arg){
12084 if(this.fireEvent("beforeload", this, params) !== false){
12086 params : params || {},
12088 callback : callback,
12093 callback : this.loadResponse,
12097 Roo.applyIf(o, this.conn);
12098 if(this.activeRequest){
12099 Roo.Ajax.abort(this.activeRequest);
12101 this.activeRequest = Roo.Ajax.request(o);
12103 this.conn.request(o);
12106 callback.call(scope||this, null, arg, false);
12111 loadResponse : function(o, success, response){
12112 delete this.activeRequest;
12114 this.fireEvent("loadexception", this, o, response);
12115 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12120 result = o.reader.read(response);
12122 this.fireEvent("loadexception", this, o, response, e);
12123 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12127 this.fireEvent("load", this, o, o.request.arg);
12128 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12132 update : function(dataSet){
12137 updateResponse : function(dataSet){
12142 * Ext JS Library 1.1.1
12143 * Copyright(c) 2006-2007, Ext JS, LLC.
12145 * Originally Released Under LGPL - original licence link has changed is not relivant.
12148 * <script type="text/javascript">
12152 * @class Roo.data.ScriptTagProxy
12153 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12154 * other than the originating domain of the running page.<br><br>
12156 * <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
12157 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12159 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12160 * source code that is used as the source inside a <script> tag.<br><br>
12162 * In order for the browser to process the returned data, the server must wrap the data object
12163 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12164 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12165 * depending on whether the callback name was passed:
12168 boolean scriptTag = false;
12169 String cb = request.getParameter("callback");
12172 response.setContentType("text/javascript");
12174 response.setContentType("application/x-json");
12176 Writer out = response.getWriter();
12178 out.write(cb + "(");
12180 out.print(dataBlock.toJsonString());
12187 * @param {Object} config A configuration object.
12189 Roo.data.ScriptTagProxy = function(config){
12190 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12191 Roo.apply(this, config);
12192 this.head = document.getElementsByTagName("head")[0];
12195 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12197 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12199 * @cfg {String} url The URL from which to request the data object.
12202 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12206 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12207 * the server the name of the callback function set up by the load call to process the returned data object.
12208 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12209 * javascript output which calls this named function passing the data object as its only parameter.
12211 callbackParam : "callback",
12213 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12214 * name to the request.
12219 * Load data from the configured URL, read the data object into
12220 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12221 * process that block using the passed callback.
12222 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12223 * for the request to the remote server.
12224 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12225 * object into a block of Roo.data.Records.
12226 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12227 * The function must be passed <ul>
12228 * <li>The Record block object</li>
12229 * <li>The "arg" argument from the load function</li>
12230 * <li>A boolean success indicator</li>
12232 * @param {Object} scope The scope in which to call the callback
12233 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12235 load : function(params, reader, callback, scope, arg){
12236 if(this.fireEvent("beforeload", this, params) !== false){
12238 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12240 var url = this.url;
12241 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12243 url += "&_dc=" + (new Date().getTime());
12245 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12248 cb : "stcCallback"+transId,
12249 scriptId : "stcScript"+transId,
12253 callback : callback,
12259 window[trans.cb] = function(o){
12260 conn.handleResponse(o, trans);
12263 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12265 if(this.autoAbort !== false){
12269 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12271 var script = document.createElement("script");
12272 script.setAttribute("src", url);
12273 script.setAttribute("type", "text/javascript");
12274 script.setAttribute("id", trans.scriptId);
12275 this.head.appendChild(script);
12277 this.trans = trans;
12279 callback.call(scope||this, null, arg, false);
12284 isLoading : function(){
12285 return this.trans ? true : false;
12289 * Abort the current server request.
12291 abort : function(){
12292 if(this.isLoading()){
12293 this.destroyTrans(this.trans);
12298 destroyTrans : function(trans, isLoaded){
12299 this.head.removeChild(document.getElementById(trans.scriptId));
12300 clearTimeout(trans.timeoutId);
12302 window[trans.cb] = undefined;
12304 delete window[trans.cb];
12307 // if hasn't been loaded, wait for load to remove it to prevent script error
12308 window[trans.cb] = function(){
12309 window[trans.cb] = undefined;
12311 delete window[trans.cb];
12318 handleResponse : function(o, trans){
12319 this.trans = false;
12320 this.destroyTrans(trans, true);
12323 result = trans.reader.readRecords(o);
12325 this.fireEvent("loadexception", this, o, trans.arg, e);
12326 trans.callback.call(trans.scope||window, null, trans.arg, false);
12329 this.fireEvent("load", this, o, trans.arg);
12330 trans.callback.call(trans.scope||window, result, trans.arg, true);
12334 handleFailure : function(trans){
12335 this.trans = false;
12336 this.destroyTrans(trans, false);
12337 this.fireEvent("loadexception", this, null, trans.arg);
12338 trans.callback.call(trans.scope||window, null, trans.arg, false);
12342 * Ext JS Library 1.1.1
12343 * Copyright(c) 2006-2007, Ext JS, LLC.
12345 * Originally Released Under LGPL - original licence link has changed is not relivant.
12348 * <script type="text/javascript">
12352 * @class Roo.data.JsonReader
12353 * @extends Roo.data.DataReader
12354 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12355 * based on mappings in a provided Roo.data.Record constructor.
12357 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12358 * in the reply previously.
12363 var RecordDef = Roo.data.Record.create([
12364 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12365 {name: 'occupation'} // This field will use "occupation" as the mapping.
12367 var myReader = new Roo.data.JsonReader({
12368 totalProperty: "results", // The property which contains the total dataset size (optional)
12369 root: "rows", // The property which contains an Array of row objects
12370 id: "id" // The property within each row object that provides an ID for the record (optional)
12374 * This would consume a JSON file like this:
12376 { 'results': 2, 'rows': [
12377 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12378 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12381 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12382 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12383 * paged from the remote server.
12384 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12385 * @cfg {String} root name of the property which contains the Array of row objects.
12386 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12387 * @cfg {Array} fields Array of field definition objects
12389 * Create a new JsonReader
12390 * @param {Object} meta Metadata configuration options
12391 * @param {Object} recordType Either an Array of field definition objects,
12392 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12394 Roo.data.JsonReader = function(meta, recordType){
12397 // set some defaults:
12398 Roo.applyIf(meta, {
12399 totalProperty: 'total',
12400 successProperty : 'success',
12405 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12407 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12410 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12411 * Used by Store query builder to append _requestMeta to params.
12414 metaFromRemote : false,
12416 * This method is only used by a DataProxy which has retrieved data from a remote server.
12417 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12418 * @return {Object} data A data block which is used by an Roo.data.Store object as
12419 * a cache of Roo.data.Records.
12421 read : function(response){
12422 var json = response.responseText;
12424 var o = /* eval:var:o */ eval("("+json+")");
12426 throw {message: "JsonReader.read: Json object not found"};
12432 this.metaFromRemote = true;
12433 this.meta = o.metaData;
12434 this.recordType = Roo.data.Record.create(o.metaData.fields);
12435 this.onMetaChange(this.meta, this.recordType, o);
12437 return this.readRecords(o);
12440 // private function a store will implement
12441 onMetaChange : function(meta, recordType, o){
12448 simpleAccess: function(obj, subsc) {
12455 getJsonAccessor: function(){
12457 return function(expr) {
12459 return(re.test(expr))
12460 ? new Function("obj", "return obj." + expr)
12465 return Roo.emptyFn;
12470 * Create a data block containing Roo.data.Records from an XML document.
12471 * @param {Object} o An object which contains an Array of row objects in the property specified
12472 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12473 * which contains the total size of the dataset.
12474 * @return {Object} data A data block which is used by an Roo.data.Store object as
12475 * a cache of Roo.data.Records.
12477 readRecords : function(o){
12479 * After any data loads, the raw JSON data is available for further custom processing.
12483 var s = this.meta, Record = this.recordType,
12484 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12486 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12488 if(s.totalProperty) {
12489 this.getTotal = this.getJsonAccessor(s.totalProperty);
12491 if(s.successProperty) {
12492 this.getSuccess = this.getJsonAccessor(s.successProperty);
12494 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12496 var g = this.getJsonAccessor(s.id);
12497 this.getId = function(rec) {
12499 return (r === undefined || r === "") ? null : r;
12502 this.getId = function(){return null;};
12505 for(var jj = 0; jj < fl; jj++){
12507 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12508 this.ef[jj] = this.getJsonAccessor(map);
12512 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12513 if(s.totalProperty){
12514 var vt = parseInt(this.getTotal(o), 10);
12519 if(s.successProperty){
12520 var vs = this.getSuccess(o);
12521 if(vs === false || vs === 'false'){
12526 for(var i = 0; i < c; i++){
12529 var id = this.getId(n);
12530 for(var j = 0; j < fl; j++){
12532 var v = this.ef[j](n);
12534 Roo.log('missing convert for ' + f.name);
12538 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12540 var record = new Record(values, id);
12542 records[i] = record;
12548 totalRecords : totalRecords
12553 * Ext JS Library 1.1.1
12554 * Copyright(c) 2006-2007, Ext JS, LLC.
12556 * Originally Released Under LGPL - original licence link has changed is not relivant.
12559 * <script type="text/javascript">
12563 * @class Roo.data.ArrayReader
12564 * @extends Roo.data.DataReader
12565 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12566 * Each element of that Array represents a row of data fields. The
12567 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12568 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12572 var RecordDef = Roo.data.Record.create([
12573 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12574 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12576 var myReader = new Roo.data.ArrayReader({
12577 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12581 * This would consume an Array like this:
12583 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12585 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12587 * Create a new JsonReader
12588 * @param {Object} meta Metadata configuration options.
12589 * @param {Object} recordType Either an Array of field definition objects
12590 * as specified to {@link Roo.data.Record#create},
12591 * or an {@link Roo.data.Record} object
12592 * created using {@link Roo.data.Record#create}.
12594 Roo.data.ArrayReader = function(meta, recordType){
12595 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12598 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12600 * Create a data block containing Roo.data.Records from an XML document.
12601 * @param {Object} o An Array of row objects which represents the dataset.
12602 * @return {Object} data A data block which is used by an Roo.data.Store object as
12603 * a cache of Roo.data.Records.
12605 readRecords : function(o){
12606 var sid = this.meta ? this.meta.id : null;
12607 var recordType = this.recordType, fields = recordType.prototype.fields;
12610 for(var i = 0; i < root.length; i++){
12613 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12614 for(var j = 0, jlen = fields.length; j < jlen; j++){
12615 var f = fields.items[j];
12616 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12617 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12619 values[f.name] = v;
12621 var record = new recordType(values, id);
12623 records[records.length] = record;
12627 totalRecords : records.length
12636 * @class Roo.bootstrap.ComboBox
12637 * @extends Roo.bootstrap.TriggerField
12638 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12639 * @cfg {Boolean} append (true|false) default false
12640 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12641 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12642 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12643 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12644 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12645 * @cfg {Boolean} animate default true
12646 * @cfg {Boolean} emptyResultText only for touch device
12647 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12648 * @cfg {String} emptyTitle default ''
12650 * Create a new ComboBox.
12651 * @param {Object} config Configuration options
12653 Roo.bootstrap.ComboBox = function(config){
12654 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12658 * Fires when the dropdown list is expanded
12659 * @param {Roo.bootstrap.ComboBox} combo This combo box
12664 * Fires when the dropdown list is collapsed
12665 * @param {Roo.bootstrap.ComboBox} combo This combo box
12669 * @event beforeselect
12670 * Fires before a list item is selected. Return false to cancel the selection.
12671 * @param {Roo.bootstrap.ComboBox} combo This combo box
12672 * @param {Roo.data.Record} record The data record returned from the underlying store
12673 * @param {Number} index The index of the selected item in the dropdown list
12675 'beforeselect' : true,
12678 * Fires when a list item is selected
12679 * @param {Roo.bootstrap.ComboBox} combo This combo box
12680 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12681 * @param {Number} index The index of the selected item in the dropdown list
12685 * @event beforequery
12686 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12687 * The event object passed has these properties:
12688 * @param {Roo.bootstrap.ComboBox} combo This combo box
12689 * @param {String} query The query
12690 * @param {Boolean} forceAll true to force "all" query
12691 * @param {Boolean} cancel true to cancel the query
12692 * @param {Object} e The query event object
12694 'beforequery': true,
12697 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12698 * @param {Roo.bootstrap.ComboBox} combo This combo box
12703 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12704 * @param {Roo.bootstrap.ComboBox} combo This combo box
12705 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12710 * Fires when the remove value from the combobox array
12711 * @param {Roo.bootstrap.ComboBox} combo This combo box
12715 * @event afterremove
12716 * Fires when the remove value from the combobox array
12717 * @param {Roo.bootstrap.ComboBox} combo This combo box
12719 'afterremove' : true,
12721 * @event specialfilter
12722 * Fires when specialfilter
12723 * @param {Roo.bootstrap.ComboBox} combo This combo box
12725 'specialfilter' : true,
12728 * Fires when tick the element
12729 * @param {Roo.bootstrap.ComboBox} combo This combo box
12733 * @event touchviewdisplay
12734 * Fires when touch view require special display (default is using displayField)
12735 * @param {Roo.bootstrap.ComboBox} combo This combo box
12736 * @param {Object} cfg set html .
12738 'touchviewdisplay' : true
12743 this.tickItems = [];
12745 this.selectedIndex = -1;
12746 if(this.mode == 'local'){
12747 if(config.queryDelay === undefined){
12748 this.queryDelay = 10;
12750 if(config.minChars === undefined){
12756 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12759 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12760 * rendering into an Roo.Editor, defaults to false)
12763 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12764 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12767 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12770 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12771 * the dropdown list (defaults to undefined, with no header element)
12775 * @cfg {String/Roo.Template} tpl The template to use to render the output
12779 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12781 listWidth: undefined,
12783 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12784 * mode = 'remote' or 'text' if mode = 'local')
12786 displayField: undefined,
12789 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12790 * mode = 'remote' or 'value' if mode = 'local').
12791 * Note: use of a valueField requires the user make a selection
12792 * in order for a value to be mapped.
12794 valueField: undefined,
12796 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12801 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12802 * field's data value (defaults to the underlying DOM element's name)
12804 hiddenName: undefined,
12806 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12810 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12812 selectedClass: 'active',
12815 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12819 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12820 * anchor positions (defaults to 'tl-bl')
12822 listAlign: 'tl-bl?',
12824 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12828 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12829 * query specified by the allQuery config option (defaults to 'query')
12831 triggerAction: 'query',
12833 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12834 * (defaults to 4, does not apply if editable = false)
12838 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12839 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12843 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12844 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12848 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12849 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12853 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12854 * when editable = true (defaults to false)
12856 selectOnFocus:false,
12858 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12860 queryParam: 'query',
12862 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12863 * when mode = 'remote' (defaults to 'Loading...')
12865 loadingText: 'Loading...',
12867 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12871 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12875 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12876 * traditional select (defaults to true)
12880 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12884 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12888 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12889 * listWidth has a higher value)
12893 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12894 * allow the user to set arbitrary text into the field (defaults to false)
12896 forceSelection:false,
12898 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12899 * if typeAhead = true (defaults to 250)
12901 typeAheadDelay : 250,
12903 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12904 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12906 valueNotFoundText : undefined,
12908 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12910 blockFocus : false,
12913 * @cfg {Boolean} disableClear Disable showing of clear button.
12915 disableClear : false,
12917 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12919 alwaysQuery : false,
12922 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12927 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12929 invalidClass : "has-warning",
12932 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12934 validClass : "has-success",
12937 * @cfg {Boolean} specialFilter (true|false) special filter default false
12939 specialFilter : false,
12942 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12944 mobileTouchView : true,
12947 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12949 useNativeIOS : false,
12951 ios_options : false,
12963 btnPosition : 'right',
12964 triggerList : true,
12965 showToggleBtn : true,
12967 emptyResultText: 'Empty',
12968 triggerText : 'Select',
12971 // element that contains real text value.. (when hidden is used..)
12973 getAutoCreate : function()
12978 * Render classic select for iso
12981 if(Roo.isIOS && this.useNativeIOS){
12982 cfg = this.getAutoCreateNativeIOS();
12990 if(Roo.isTouch && this.mobileTouchView){
12991 cfg = this.getAutoCreateTouchView();
12998 if(!this.tickable){
12999 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13004 * ComboBox with tickable selections
13007 var align = this.labelAlign || this.parentLabelAlign();
13010 cls : 'form-group roo-combobox-tickable' //input-group
13013 var btn_text_select = '';
13014 var btn_text_done = '';
13015 var btn_text_cancel = '';
13017 if (this.btn_text_show) {
13018 btn_text_select = 'Select';
13019 btn_text_done = 'Done';
13020 btn_text_cancel = 'Cancel';
13025 cls : 'tickable-buttons',
13030 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13031 //html : this.triggerText
13032 html: btn_text_select
13038 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13040 html: btn_text_done
13046 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13048 html: btn_text_cancel
13054 buttons.cn.unshift({
13056 cls: 'roo-select2-search-field-input'
13062 Roo.each(buttons.cn, function(c){
13064 c.cls += ' btn-' + _this.size;
13067 if (_this.disabled) {
13078 cls: 'form-hidden-field'
13082 cls: 'roo-select2-choices',
13086 cls: 'roo-select2-search-field',
13097 cls: 'roo-select2-container input-group roo-select2-container-multi',
13102 // cls: 'typeahead typeahead-long dropdown-menu',
13103 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13108 if(this.hasFeedback && !this.allowBlank){
13112 cls: 'glyphicon form-control-feedback'
13115 combobox.cn.push(feedback);
13119 if (align ==='left' && this.fieldLabel.length) {
13121 cfg.cls += ' roo-form-group-label-left';
13126 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13127 tooltip : 'This field is required'
13132 cls : 'control-label',
13133 html : this.fieldLabel
13145 var labelCfg = cfg.cn[1];
13146 var contentCfg = cfg.cn[2];
13149 if(this.indicatorpos == 'right'){
13155 cls : 'control-label',
13159 html : this.fieldLabel
13163 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13164 tooltip : 'This field is required'
13179 labelCfg = cfg.cn[0];
13180 contentCfg = cfg.cn[1];
13184 if(this.labelWidth > 12){
13185 labelCfg.style = "width: " + this.labelWidth + 'px';
13188 if(this.labelWidth < 13 && this.labelmd == 0){
13189 this.labelmd = this.labelWidth;
13192 if(this.labellg > 0){
13193 labelCfg.cls += ' col-lg-' + this.labellg;
13194 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13197 if(this.labelmd > 0){
13198 labelCfg.cls += ' col-md-' + this.labelmd;
13199 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13202 if(this.labelsm > 0){
13203 labelCfg.cls += ' col-sm-' + this.labelsm;
13204 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13207 if(this.labelxs > 0){
13208 labelCfg.cls += ' col-xs-' + this.labelxs;
13209 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13213 } else if ( this.fieldLabel.length) {
13214 // Roo.log(" label");
13218 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13219 tooltip : 'This field is required'
13223 //cls : 'input-group-addon',
13224 html : this.fieldLabel
13229 if(this.indicatorpos == 'right'){
13233 //cls : 'input-group-addon',
13234 html : this.fieldLabel
13238 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13239 tooltip : 'This field is required'
13248 // Roo.log(" no label && no align");
13255 ['xs','sm','md','lg'].map(function(size){
13256 if (settings[size]) {
13257 cfg.cls += ' col-' + size + '-' + settings[size];
13265 _initEventsCalled : false,
13268 initEvents: function()
13270 if (this._initEventsCalled) { // as we call render... prevent looping...
13273 this._initEventsCalled = true;
13276 throw "can not find store for combo";
13279 this.indicator = this.indicatorEl();
13281 this.store = Roo.factory(this.store, Roo.data);
13282 this.store.parent = this;
13284 // if we are building from html. then this element is so complex, that we can not really
13285 // use the rendered HTML.
13286 // so we have to trash and replace the previous code.
13287 if (Roo.XComponent.build_from_html) {
13288 // remove this element....
13289 var e = this.el.dom, k=0;
13290 while (e ) { e = e.previousSibling; ++k;}
13295 this.rendered = false;
13297 this.render(this.parent().getChildContainer(true), k);
13300 if(Roo.isIOS && this.useNativeIOS){
13301 this.initIOSView();
13309 if(Roo.isTouch && this.mobileTouchView){
13310 this.initTouchView();
13315 this.initTickableEvents();
13319 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13321 if(this.hiddenName){
13323 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13325 this.hiddenField.dom.value =
13326 this.hiddenValue !== undefined ? this.hiddenValue :
13327 this.value !== undefined ? this.value : '';
13329 // prevent input submission
13330 this.el.dom.removeAttribute('name');
13331 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13336 // this.el.dom.setAttribute('autocomplete', 'off');
13339 var cls = 'x-combo-list';
13341 //this.list = new Roo.Layer({
13342 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13348 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13349 _this.list.setWidth(lw);
13352 this.list.on('mouseover', this.onViewOver, this);
13353 this.list.on('mousemove', this.onViewMove, this);
13354 this.list.on('scroll', this.onViewScroll, this);
13357 this.list.swallowEvent('mousewheel');
13358 this.assetHeight = 0;
13361 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13362 this.assetHeight += this.header.getHeight();
13365 this.innerList = this.list.createChild({cls:cls+'-inner'});
13366 this.innerList.on('mouseover', this.onViewOver, this);
13367 this.innerList.on('mousemove', this.onViewMove, this);
13368 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13370 if(this.allowBlank && !this.pageSize && !this.disableClear){
13371 this.footer = this.list.createChild({cls:cls+'-ft'});
13372 this.pageTb = new Roo.Toolbar(this.footer);
13376 this.footer = this.list.createChild({cls:cls+'-ft'});
13377 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13378 {pageSize: this.pageSize});
13382 if (this.pageTb && this.allowBlank && !this.disableClear) {
13384 this.pageTb.add(new Roo.Toolbar.Fill(), {
13385 cls: 'x-btn-icon x-btn-clear',
13387 handler: function()
13390 _this.clearValue();
13391 _this.onSelect(false, -1);
13396 this.assetHeight += this.footer.getHeight();
13401 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13404 this.view = new Roo.View(this.list, this.tpl, {
13405 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13407 //this.view.wrapEl.setDisplayed(false);
13408 this.view.on('click', this.onViewClick, this);
13411 this.store.on('beforeload', this.onBeforeLoad, this);
13412 this.store.on('load', this.onLoad, this);
13413 this.store.on('loadexception', this.onLoadException, this);
13415 if(this.resizable){
13416 this.resizer = new Roo.Resizable(this.list, {
13417 pinned:true, handles:'se'
13419 this.resizer.on('resize', function(r, w, h){
13420 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13421 this.listWidth = w;
13422 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13423 this.restrictHeight();
13425 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13428 if(!this.editable){
13429 this.editable = true;
13430 this.setEditable(false);
13435 if (typeof(this.events.add.listeners) != 'undefined') {
13437 this.addicon = this.wrap.createChild(
13438 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13440 this.addicon.on('click', function(e) {
13441 this.fireEvent('add', this);
13444 if (typeof(this.events.edit.listeners) != 'undefined') {
13446 this.editicon = this.wrap.createChild(
13447 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13448 if (this.addicon) {
13449 this.editicon.setStyle('margin-left', '40px');
13451 this.editicon.on('click', function(e) {
13453 // we fire even if inothing is selected..
13454 this.fireEvent('edit', this, this.lastData );
13460 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13461 "up" : function(e){
13462 this.inKeyMode = true;
13466 "down" : function(e){
13467 if(!this.isExpanded()){
13468 this.onTriggerClick();
13470 this.inKeyMode = true;
13475 "enter" : function(e){
13476 // this.onViewClick();
13480 if(this.fireEvent("specialkey", this, e)){
13481 this.onViewClick(false);
13487 "esc" : function(e){
13491 "tab" : function(e){
13494 if(this.fireEvent("specialkey", this, e)){
13495 this.onViewClick(false);
13503 doRelay : function(foo, bar, hname){
13504 if(hname == 'down' || this.scope.isExpanded()){
13505 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13514 this.queryDelay = Math.max(this.queryDelay || 10,
13515 this.mode == 'local' ? 10 : 250);
13518 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13520 if(this.typeAhead){
13521 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13523 if(this.editable !== false){
13524 this.inputEl().on("keyup", this.onKeyUp, this);
13526 if(this.forceSelection){
13527 this.inputEl().on('blur', this.doForce, this);
13531 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13532 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13536 initTickableEvents: function()
13540 if(this.hiddenName){
13542 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13544 this.hiddenField.dom.value =
13545 this.hiddenValue !== undefined ? this.hiddenValue :
13546 this.value !== undefined ? this.value : '';
13548 // prevent input submission
13549 this.el.dom.removeAttribute('name');
13550 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13555 // this.list = this.el.select('ul.dropdown-menu',true).first();
13557 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13558 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13559 if(this.triggerList){
13560 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13563 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13564 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13566 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13567 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13569 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13570 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13572 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13573 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13574 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13577 this.cancelBtn.hide();
13582 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13583 _this.list.setWidth(lw);
13586 this.list.on('mouseover', this.onViewOver, this);
13587 this.list.on('mousemove', this.onViewMove, this);
13589 this.list.on('scroll', this.onViewScroll, this);
13592 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>';
13595 this.view = new Roo.View(this.list, this.tpl, {
13596 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13599 //this.view.wrapEl.setDisplayed(false);
13600 this.view.on('click', this.onViewClick, this);
13604 this.store.on('beforeload', this.onBeforeLoad, this);
13605 this.store.on('load', this.onLoad, this);
13606 this.store.on('loadexception', this.onLoadException, this);
13609 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13610 "up" : function(e){
13611 this.inKeyMode = true;
13615 "down" : function(e){
13616 this.inKeyMode = true;
13620 "enter" : function(e){
13621 if(this.fireEvent("specialkey", this, e)){
13622 this.onViewClick(false);
13628 "esc" : function(e){
13629 this.onTickableFooterButtonClick(e, false, false);
13632 "tab" : function(e){
13633 this.fireEvent("specialkey", this, e);
13635 this.onTickableFooterButtonClick(e, false, false);
13642 doRelay : function(e, fn, key){
13643 if(this.scope.isExpanded()){
13644 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13653 this.queryDelay = Math.max(this.queryDelay || 10,
13654 this.mode == 'local' ? 10 : 250);
13657 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13659 if(this.typeAhead){
13660 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13663 if(this.editable !== false){
13664 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13667 this.indicator = this.indicatorEl();
13669 if(this.indicator){
13670 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13671 this.indicator.hide();
13676 onDestroy : function(){
13678 this.view.setStore(null);
13679 this.view.el.removeAllListeners();
13680 this.view.el.remove();
13681 this.view.purgeListeners();
13684 this.list.dom.innerHTML = '';
13688 this.store.un('beforeload', this.onBeforeLoad, this);
13689 this.store.un('load', this.onLoad, this);
13690 this.store.un('loadexception', this.onLoadException, this);
13692 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13696 fireKey : function(e){
13697 if(e.isNavKeyPress() && !this.list.isVisible()){
13698 this.fireEvent("specialkey", this, e);
13703 onResize: function(w, h){
13704 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13706 // if(typeof w != 'number'){
13707 // // we do not handle it!?!?
13710 // var tw = this.trigger.getWidth();
13711 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13712 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13714 // this.inputEl().setWidth( this.adjustWidth('input', x));
13716 // //this.trigger.setStyle('left', x+'px');
13718 // if(this.list && this.listWidth === undefined){
13719 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13720 // this.list.setWidth(lw);
13721 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13729 * Allow or prevent the user from directly editing the field text. If false is passed,
13730 * the user will only be able to select from the items defined in the dropdown list. This method
13731 * is the runtime equivalent of setting the 'editable' config option at config time.
13732 * @param {Boolean} value True to allow the user to directly edit the field text
13734 setEditable : function(value){
13735 if(value == this.editable){
13738 this.editable = value;
13740 this.inputEl().dom.setAttribute('readOnly', true);
13741 this.inputEl().on('mousedown', this.onTriggerClick, this);
13742 this.inputEl().addClass('x-combo-noedit');
13744 this.inputEl().dom.setAttribute('readOnly', false);
13745 this.inputEl().un('mousedown', this.onTriggerClick, this);
13746 this.inputEl().removeClass('x-combo-noedit');
13752 onBeforeLoad : function(combo,opts){
13753 if(!this.hasFocus){
13757 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13759 this.restrictHeight();
13760 this.selectedIndex = -1;
13764 onLoad : function(){
13766 this.hasQuery = false;
13768 if(!this.hasFocus){
13772 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13773 this.loading.hide();
13776 if(this.store.getCount() > 0){
13779 this.restrictHeight();
13780 if(this.lastQuery == this.allQuery){
13781 if(this.editable && !this.tickable){
13782 this.inputEl().dom.select();
13786 !this.selectByValue(this.value, true) &&
13789 !this.store.lastOptions ||
13790 typeof(this.store.lastOptions.add) == 'undefined' ||
13791 this.store.lastOptions.add != true
13794 this.select(0, true);
13797 if(this.autoFocus){
13800 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13801 this.taTask.delay(this.typeAheadDelay);
13805 this.onEmptyResults();
13811 onLoadException : function()
13813 this.hasQuery = false;
13815 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13816 this.loading.hide();
13819 if(this.tickable && this.editable){
13824 // only causes errors at present
13825 //Roo.log(this.store.reader.jsonData);
13826 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13828 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13834 onTypeAhead : function(){
13835 if(this.store.getCount() > 0){
13836 var r = this.store.getAt(0);
13837 var newValue = r.data[this.displayField];
13838 var len = newValue.length;
13839 var selStart = this.getRawValue().length;
13841 if(selStart != len){
13842 this.setRawValue(newValue);
13843 this.selectText(selStart, newValue.length);
13849 onSelect : function(record, index){
13851 if(this.fireEvent('beforeselect', this, record, index) !== false){
13853 this.setFromData(index > -1 ? record.data : false);
13856 this.fireEvent('select', this, record, index);
13861 * Returns the currently selected field value or empty string if no value is set.
13862 * @return {String} value The selected value
13864 getValue : function()
13866 if(Roo.isIOS && this.useNativeIOS){
13867 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13871 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13874 if(this.valueField){
13875 return typeof this.value != 'undefined' ? this.value : '';
13877 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13881 getRawValue : function()
13883 if(Roo.isIOS && this.useNativeIOS){
13884 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13887 var v = this.inputEl().getValue();
13893 * Clears any text/value currently set in the field
13895 clearValue : function(){
13897 if(this.hiddenField){
13898 this.hiddenField.dom.value = '';
13901 this.setRawValue('');
13902 this.lastSelectionText = '';
13903 this.lastData = false;
13905 var close = this.closeTriggerEl();
13916 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13917 * will be displayed in the field. If the value does not match the data value of an existing item,
13918 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13919 * Otherwise the field will be blank (although the value will still be set).
13920 * @param {String} value The value to match
13922 setValue : function(v)
13924 if(Roo.isIOS && this.useNativeIOS){
13925 this.setIOSValue(v);
13935 if(this.valueField){
13936 var r = this.findRecord(this.valueField, v);
13938 text = r.data[this.displayField];
13939 }else if(this.valueNotFoundText !== undefined){
13940 text = this.valueNotFoundText;
13943 this.lastSelectionText = text;
13944 if(this.hiddenField){
13945 this.hiddenField.dom.value = v;
13947 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13950 var close = this.closeTriggerEl();
13953 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13959 * @property {Object} the last set data for the element
13964 * Sets the value of the field based on a object which is related to the record format for the store.
13965 * @param {Object} value the value to set as. or false on reset?
13967 setFromData : function(o){
13974 var dv = ''; // display value
13975 var vv = ''; // value value..
13977 if (this.displayField) {
13978 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13980 // this is an error condition!!!
13981 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13984 if(this.valueField){
13985 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13988 var close = this.closeTriggerEl();
13991 if(dv.length || vv * 1 > 0){
13993 this.blockFocus=true;
13999 if(this.hiddenField){
14000 this.hiddenField.dom.value = vv;
14002 this.lastSelectionText = dv;
14003 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14007 // no hidden field.. - we store the value in 'value', but still display
14008 // display field!!!!
14009 this.lastSelectionText = dv;
14010 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14017 reset : function(){
14018 // overridden so that last data is reset..
14025 this.setValue(this.originalValue);
14026 //this.clearInvalid();
14027 this.lastData = false;
14029 this.view.clearSelections();
14035 findRecord : function(prop, value){
14037 if(this.store.getCount() > 0){
14038 this.store.each(function(r){
14039 if(r.data[prop] == value){
14049 getName: function()
14051 // returns hidden if it's set..
14052 if (!this.rendered) {return ''};
14053 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14057 onViewMove : function(e, t){
14058 this.inKeyMode = false;
14062 onViewOver : function(e, t){
14063 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14066 var item = this.view.findItemFromChild(t);
14069 var index = this.view.indexOf(item);
14070 this.select(index, false);
14075 onViewClick : function(view, doFocus, el, e)
14077 var index = this.view.getSelectedIndexes()[0];
14079 var r = this.store.getAt(index);
14083 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14090 Roo.each(this.tickItems, function(v,k){
14092 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14094 _this.tickItems.splice(k, 1);
14096 if(typeof(e) == 'undefined' && view == false){
14097 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14109 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14110 this.tickItems.push(r.data);
14113 if(typeof(e) == 'undefined' && view == false){
14114 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14121 this.onSelect(r, index);
14123 if(doFocus !== false && !this.blockFocus){
14124 this.inputEl().focus();
14129 restrictHeight : function(){
14130 //this.innerList.dom.style.height = '';
14131 //var inner = this.innerList.dom;
14132 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14133 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14134 //this.list.beginUpdate();
14135 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14136 this.list.alignTo(this.inputEl(), this.listAlign);
14137 this.list.alignTo(this.inputEl(), this.listAlign);
14138 //this.list.endUpdate();
14142 onEmptyResults : function(){
14144 if(this.tickable && this.editable){
14145 this.hasFocus = false;
14146 this.restrictHeight();
14154 * Returns true if the dropdown list is expanded, else false.
14156 isExpanded : function(){
14157 return this.list.isVisible();
14161 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14162 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14163 * @param {String} value The data value of the item to select
14164 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14165 * selected item if it is not currently in view (defaults to true)
14166 * @return {Boolean} True if the value matched an item in the list, else false
14168 selectByValue : function(v, scrollIntoView){
14169 if(v !== undefined && v !== null){
14170 var r = this.findRecord(this.valueField || this.displayField, v);
14172 this.select(this.store.indexOf(r), scrollIntoView);
14180 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14181 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14182 * @param {Number} index The zero-based index of the list item to select
14183 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14184 * selected item if it is not currently in view (defaults to true)
14186 select : function(index, scrollIntoView){
14187 this.selectedIndex = index;
14188 this.view.select(index);
14189 if(scrollIntoView !== false){
14190 var el = this.view.getNode(index);
14192 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14195 this.list.scrollChildIntoView(el, false);
14201 selectNext : function(){
14202 var ct = this.store.getCount();
14204 if(this.selectedIndex == -1){
14206 }else if(this.selectedIndex < ct-1){
14207 this.select(this.selectedIndex+1);
14213 selectPrev : function(){
14214 var ct = this.store.getCount();
14216 if(this.selectedIndex == -1){
14218 }else if(this.selectedIndex != 0){
14219 this.select(this.selectedIndex-1);
14225 onKeyUp : function(e){
14226 if(this.editable !== false && !e.isSpecialKey()){
14227 this.lastKey = e.getKey();
14228 this.dqTask.delay(this.queryDelay);
14233 validateBlur : function(){
14234 return !this.list || !this.list.isVisible();
14238 initQuery : function(){
14240 var v = this.getRawValue();
14242 if(this.tickable && this.editable){
14243 v = this.tickableInputEl().getValue();
14250 doForce : function(){
14251 if(this.inputEl().dom.value.length > 0){
14252 this.inputEl().dom.value =
14253 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14259 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14260 * query allowing the query action to be canceled if needed.
14261 * @param {String} query The SQL query to execute
14262 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14263 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14264 * saved in the current store (defaults to false)
14266 doQuery : function(q, forceAll){
14268 if(q === undefined || q === null){
14273 forceAll: forceAll,
14277 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14282 forceAll = qe.forceAll;
14283 if(forceAll === true || (q.length >= this.minChars)){
14285 this.hasQuery = true;
14287 if(this.lastQuery != q || this.alwaysQuery){
14288 this.lastQuery = q;
14289 if(this.mode == 'local'){
14290 this.selectedIndex = -1;
14292 this.store.clearFilter();
14295 if(this.specialFilter){
14296 this.fireEvent('specialfilter', this);
14301 this.store.filter(this.displayField, q);
14304 this.store.fireEvent("datachanged", this.store);
14311 this.store.baseParams[this.queryParam] = q;
14313 var options = {params : this.getParams(q)};
14316 options.add = true;
14317 options.params.start = this.page * this.pageSize;
14320 this.store.load(options);
14323 * this code will make the page width larger, at the beginning, the list not align correctly,
14324 * we should expand the list on onLoad
14325 * so command out it
14330 this.selectedIndex = -1;
14335 this.loadNext = false;
14339 getParams : function(q){
14341 //p[this.queryParam] = q;
14345 p.limit = this.pageSize;
14351 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14353 collapse : function(){
14354 if(!this.isExpanded()){
14360 this.hasFocus = false;
14364 this.cancelBtn.hide();
14365 this.trigger.show();
14368 this.tickableInputEl().dom.value = '';
14369 this.tickableInputEl().blur();
14374 Roo.get(document).un('mousedown', this.collapseIf, this);
14375 Roo.get(document).un('mousewheel', this.collapseIf, this);
14376 if (!this.editable) {
14377 Roo.get(document).un('keydown', this.listKeyPress, this);
14379 this.fireEvent('collapse', this);
14385 collapseIf : function(e){
14386 var in_combo = e.within(this.el);
14387 var in_list = e.within(this.list);
14388 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14390 if (in_combo || in_list || is_list) {
14391 //e.stopPropagation();
14396 this.onTickableFooterButtonClick(e, false, false);
14404 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14406 expand : function(){
14408 if(this.isExpanded() || !this.hasFocus){
14412 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14413 this.list.setWidth(lw);
14419 this.restrictHeight();
14423 this.tickItems = Roo.apply([], this.item);
14426 this.cancelBtn.show();
14427 this.trigger.hide();
14430 this.tickableInputEl().focus();
14435 Roo.get(document).on('mousedown', this.collapseIf, this);
14436 Roo.get(document).on('mousewheel', this.collapseIf, this);
14437 if (!this.editable) {
14438 Roo.get(document).on('keydown', this.listKeyPress, this);
14441 this.fireEvent('expand', this);
14445 // Implements the default empty TriggerField.onTriggerClick function
14446 onTriggerClick : function(e)
14448 Roo.log('trigger click');
14450 if(this.disabled || !this.triggerList){
14455 this.loadNext = false;
14457 if(this.isExpanded()){
14459 if (!this.blockFocus) {
14460 this.inputEl().focus();
14464 this.hasFocus = true;
14465 if(this.triggerAction == 'all') {
14466 this.doQuery(this.allQuery, true);
14468 this.doQuery(this.getRawValue());
14470 if (!this.blockFocus) {
14471 this.inputEl().focus();
14476 onTickableTriggerClick : function(e)
14483 this.loadNext = false;
14484 this.hasFocus = true;
14486 if(this.triggerAction == 'all') {
14487 this.doQuery(this.allQuery, true);
14489 this.doQuery(this.getRawValue());
14493 onSearchFieldClick : function(e)
14495 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14496 this.onTickableFooterButtonClick(e, false, false);
14500 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14505 this.loadNext = false;
14506 this.hasFocus = true;
14508 if(this.triggerAction == 'all') {
14509 this.doQuery(this.allQuery, true);
14511 this.doQuery(this.getRawValue());
14515 listKeyPress : function(e)
14517 //Roo.log('listkeypress');
14518 // scroll to first matching element based on key pres..
14519 if (e.isSpecialKey()) {
14522 var k = String.fromCharCode(e.getKey()).toUpperCase();
14525 var csel = this.view.getSelectedNodes();
14526 var cselitem = false;
14528 var ix = this.view.indexOf(csel[0]);
14529 cselitem = this.store.getAt(ix);
14530 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14536 this.store.each(function(v) {
14538 // start at existing selection.
14539 if (cselitem.id == v.id) {
14545 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14546 match = this.store.indexOf(v);
14552 if (match === false) {
14553 return true; // no more action?
14556 this.view.select(match);
14557 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14558 sn.scrollIntoView(sn.dom.parentNode, false);
14561 onViewScroll : function(e, t){
14563 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){
14567 this.hasQuery = true;
14569 this.loading = this.list.select('.loading', true).first();
14571 if(this.loading === null){
14572 this.list.createChild({
14574 cls: 'loading roo-select2-more-results roo-select2-active',
14575 html: 'Loading more results...'
14578 this.loading = this.list.select('.loading', true).first();
14580 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14582 this.loading.hide();
14585 this.loading.show();
14590 this.loadNext = true;
14592 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14597 addItem : function(o)
14599 var dv = ''; // display value
14601 if (this.displayField) {
14602 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14604 // this is an error condition!!!
14605 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14612 var choice = this.choices.createChild({
14614 cls: 'roo-select2-search-choice',
14623 cls: 'roo-select2-search-choice-close fa fa-times',
14628 }, this.searchField);
14630 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14632 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14640 this.inputEl().dom.value = '';
14645 onRemoveItem : function(e, _self, o)
14647 e.preventDefault();
14649 this.lastItem = Roo.apply([], this.item);
14651 var index = this.item.indexOf(o.data) * 1;
14654 Roo.log('not this item?!');
14658 this.item.splice(index, 1);
14663 this.fireEvent('remove', this, e);
14669 syncValue : function()
14671 if(!this.item.length){
14678 Roo.each(this.item, function(i){
14679 if(_this.valueField){
14680 value.push(i[_this.valueField]);
14687 this.value = value.join(',');
14689 if(this.hiddenField){
14690 this.hiddenField.dom.value = this.value;
14693 this.store.fireEvent("datachanged", this.store);
14698 clearItem : function()
14700 if(!this.multiple){
14706 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14714 if(this.tickable && !Roo.isTouch){
14715 this.view.refresh();
14719 inputEl: function ()
14721 if(Roo.isIOS && this.useNativeIOS){
14722 return this.el.select('select.roo-ios-select', true).first();
14725 if(Roo.isTouch && this.mobileTouchView){
14726 return this.el.select('input.form-control',true).first();
14730 return this.searchField;
14733 return this.el.select('input.form-control',true).first();
14736 onTickableFooterButtonClick : function(e, btn, el)
14738 e.preventDefault();
14740 this.lastItem = Roo.apply([], this.item);
14742 if(btn && btn.name == 'cancel'){
14743 this.tickItems = Roo.apply([], this.item);
14752 Roo.each(this.tickItems, function(o){
14760 validate : function()
14762 if(this.getVisibilityEl().hasClass('hidden')){
14766 var v = this.getRawValue();
14769 v = this.getValue();
14772 if(this.disabled || this.allowBlank || v.length){
14777 this.markInvalid();
14781 tickableInputEl : function()
14783 if(!this.tickable || !this.editable){
14784 return this.inputEl();
14787 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14791 getAutoCreateTouchView : function()
14796 cls: 'form-group' //input-group
14802 type : this.inputType,
14803 cls : 'form-control x-combo-noedit',
14804 autocomplete: 'new-password',
14805 placeholder : this.placeholder || '',
14810 input.name = this.name;
14814 input.cls += ' input-' + this.size;
14817 if (this.disabled) {
14818 input.disabled = true;
14829 inputblock.cls += ' input-group';
14831 inputblock.cn.unshift({
14833 cls : 'input-group-addon',
14838 if(this.removable && !this.multiple){
14839 inputblock.cls += ' roo-removable';
14841 inputblock.cn.push({
14844 cls : 'roo-combo-removable-btn close'
14848 if(this.hasFeedback && !this.allowBlank){
14850 inputblock.cls += ' has-feedback';
14852 inputblock.cn.push({
14854 cls: 'glyphicon form-control-feedback'
14861 inputblock.cls += (this.before) ? '' : ' input-group';
14863 inputblock.cn.push({
14865 cls : 'input-group-addon',
14876 cls: 'form-hidden-field'
14890 cls: 'form-hidden-field'
14894 cls: 'roo-select2-choices',
14898 cls: 'roo-select2-search-field',
14911 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14917 if(!this.multiple && this.showToggleBtn){
14924 if (this.caret != false) {
14927 cls: 'fa fa-' + this.caret
14934 cls : 'input-group-addon btn dropdown-toggle',
14939 cls: 'combobox-clear',
14953 combobox.cls += ' roo-select2-container-multi';
14956 var align = this.labelAlign || this.parentLabelAlign();
14958 if (align ==='left' && this.fieldLabel.length) {
14963 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14964 tooltip : 'This field is required'
14968 cls : 'control-label',
14969 html : this.fieldLabel
14980 var labelCfg = cfg.cn[1];
14981 var contentCfg = cfg.cn[2];
14984 if(this.indicatorpos == 'right'){
14989 cls : 'control-label',
14993 html : this.fieldLabel
14997 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14998 tooltip : 'This field is required'
15011 labelCfg = cfg.cn[0];
15012 contentCfg = cfg.cn[1];
15017 if(this.labelWidth > 12){
15018 labelCfg.style = "width: " + this.labelWidth + 'px';
15021 if(this.labelWidth < 13 && this.labelmd == 0){
15022 this.labelmd = this.labelWidth;
15025 if(this.labellg > 0){
15026 labelCfg.cls += ' col-lg-' + this.labellg;
15027 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15030 if(this.labelmd > 0){
15031 labelCfg.cls += ' col-md-' + this.labelmd;
15032 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15035 if(this.labelsm > 0){
15036 labelCfg.cls += ' col-sm-' + this.labelsm;
15037 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15040 if(this.labelxs > 0){
15041 labelCfg.cls += ' col-xs-' + this.labelxs;
15042 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15046 } else if ( this.fieldLabel.length) {
15050 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15051 tooltip : 'This field is required'
15055 cls : 'control-label',
15056 html : this.fieldLabel
15067 if(this.indicatorpos == 'right'){
15071 cls : 'control-label',
15072 html : this.fieldLabel,
15076 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15077 tooltip : 'This field is required'
15094 var settings = this;
15096 ['xs','sm','md','lg'].map(function(size){
15097 if (settings[size]) {
15098 cfg.cls += ' col-' + size + '-' + settings[size];
15105 initTouchView : function()
15107 this.renderTouchView();
15109 this.touchViewEl.on('scroll', function(){
15110 this.el.dom.scrollTop = 0;
15113 this.originalValue = this.getValue();
15115 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15117 this.inputEl().on("click", this.showTouchView, this);
15118 if (this.triggerEl) {
15119 this.triggerEl.on("click", this.showTouchView, this);
15123 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15124 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15126 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15128 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15129 this.store.on('load', this.onTouchViewLoad, this);
15130 this.store.on('loadexception', this.onTouchViewLoadException, this);
15132 if(this.hiddenName){
15134 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15136 this.hiddenField.dom.value =
15137 this.hiddenValue !== undefined ? this.hiddenValue :
15138 this.value !== undefined ? this.value : '';
15140 this.el.dom.removeAttribute('name');
15141 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15145 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15146 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15149 if(this.removable && !this.multiple){
15150 var close = this.closeTriggerEl();
15152 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15153 close.on('click', this.removeBtnClick, this, close);
15157 * fix the bug in Safari iOS8
15159 this.inputEl().on("focus", function(e){
15160 document.activeElement.blur();
15168 renderTouchView : function()
15170 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15171 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15173 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15174 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15176 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15177 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15178 this.touchViewBodyEl.setStyle('overflow', 'auto');
15180 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15181 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15183 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15184 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15188 showTouchView : function()
15194 this.touchViewHeaderEl.hide();
15196 if(this.modalTitle.length){
15197 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15198 this.touchViewHeaderEl.show();
15201 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15202 this.touchViewEl.show();
15204 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15206 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15207 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15209 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15211 if(this.modalTitle.length){
15212 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15215 this.touchViewBodyEl.setHeight(bodyHeight);
15219 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15221 this.touchViewEl.addClass('in');
15224 this.doTouchViewQuery();
15228 hideTouchView : function()
15230 this.touchViewEl.removeClass('in');
15234 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15236 this.touchViewEl.setStyle('display', 'none');
15241 setTouchViewValue : function()
15248 Roo.each(this.tickItems, function(o){
15253 this.hideTouchView();
15256 doTouchViewQuery : function()
15265 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15269 if(!this.alwaysQuery || this.mode == 'local'){
15270 this.onTouchViewLoad();
15277 onTouchViewBeforeLoad : function(combo,opts)
15283 onTouchViewLoad : function()
15285 if(this.store.getCount() < 1){
15286 this.onTouchViewEmptyResults();
15290 this.clearTouchView();
15292 var rawValue = this.getRawValue();
15294 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15296 this.tickItems = [];
15298 this.store.data.each(function(d, rowIndex){
15299 var row = this.touchViewListGroup.createChild(template);
15301 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15302 row.addClass(d.data.cls);
15305 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15308 html : d.data[this.displayField]
15311 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15312 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15315 row.removeClass('selected');
15316 if(!this.multiple && this.valueField &&
15317 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15320 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15321 row.addClass('selected');
15324 if(this.multiple && this.valueField &&
15325 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15329 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15330 this.tickItems.push(d.data);
15333 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15337 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15339 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15341 if(this.modalTitle.length){
15342 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15345 var listHeight = this.touchViewListGroup.getHeight();
15349 if(firstChecked && listHeight > bodyHeight){
15350 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15355 onTouchViewLoadException : function()
15357 this.hideTouchView();
15360 onTouchViewEmptyResults : function()
15362 this.clearTouchView();
15364 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15366 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15370 clearTouchView : function()
15372 this.touchViewListGroup.dom.innerHTML = '';
15375 onTouchViewClick : function(e, el, o)
15377 e.preventDefault();
15380 var rowIndex = o.rowIndex;
15382 var r = this.store.getAt(rowIndex);
15384 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15386 if(!this.multiple){
15387 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15388 c.dom.removeAttribute('checked');
15391 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15393 this.setFromData(r.data);
15395 var close = this.closeTriggerEl();
15401 this.hideTouchView();
15403 this.fireEvent('select', this, r, rowIndex);
15408 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15409 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15410 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15414 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15415 this.addItem(r.data);
15416 this.tickItems.push(r.data);
15420 getAutoCreateNativeIOS : function()
15423 cls: 'form-group' //input-group,
15428 cls : 'roo-ios-select'
15432 combobox.name = this.name;
15435 if (this.disabled) {
15436 combobox.disabled = true;
15439 var settings = this;
15441 ['xs','sm','md','lg'].map(function(size){
15442 if (settings[size]) {
15443 cfg.cls += ' col-' + size + '-' + settings[size];
15453 initIOSView : function()
15455 this.store.on('load', this.onIOSViewLoad, this);
15460 onIOSViewLoad : function()
15462 if(this.store.getCount() < 1){
15466 this.clearIOSView();
15468 if(this.allowBlank) {
15470 var default_text = '-- SELECT --';
15472 if(this.placeholder.length){
15473 default_text = this.placeholder;
15476 if(this.emptyTitle.length){
15477 default_text += ' - ' + this.emptyTitle + ' -';
15480 var opt = this.inputEl().createChild({
15483 html : default_text
15487 o[this.valueField] = 0;
15488 o[this.displayField] = default_text;
15490 this.ios_options.push({
15497 this.store.data.each(function(d, rowIndex){
15501 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15502 html = d.data[this.displayField];
15507 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15508 value = d.data[this.valueField];
15517 if(this.value == d.data[this.valueField]){
15518 option['selected'] = true;
15521 var opt = this.inputEl().createChild(option);
15523 this.ios_options.push({
15530 this.inputEl().on('change', function(){
15531 this.fireEvent('select', this);
15536 clearIOSView: function()
15538 this.inputEl().dom.innerHTML = '';
15540 this.ios_options = [];
15543 setIOSValue: function(v)
15547 if(!this.ios_options){
15551 Roo.each(this.ios_options, function(opts){
15553 opts.el.dom.removeAttribute('selected');
15555 if(opts.data[this.valueField] != v){
15559 opts.el.dom.setAttribute('selected', true);
15565 * @cfg {Boolean} grow
15569 * @cfg {Number} growMin
15573 * @cfg {Number} growMax
15582 Roo.apply(Roo.bootstrap.ComboBox, {
15586 cls: 'modal-header',
15608 cls: 'list-group-item',
15612 cls: 'roo-combobox-list-group-item-value'
15616 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15630 listItemCheckbox : {
15632 cls: 'list-group-item',
15636 cls: 'roo-combobox-list-group-item-value'
15640 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15656 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15661 cls: 'modal-footer',
15669 cls: 'col-xs-6 text-left',
15672 cls: 'btn btn-danger roo-touch-view-cancel',
15678 cls: 'col-xs-6 text-right',
15681 cls: 'btn btn-success roo-touch-view-ok',
15692 Roo.apply(Roo.bootstrap.ComboBox, {
15694 touchViewTemplate : {
15696 cls: 'modal fade roo-combobox-touch-view',
15700 cls: 'modal-dialog',
15701 style : 'position:fixed', // we have to fix position....
15705 cls: 'modal-content',
15707 Roo.bootstrap.ComboBox.header,
15708 Roo.bootstrap.ComboBox.body,
15709 Roo.bootstrap.ComboBox.footer
15718 * Ext JS Library 1.1.1
15719 * Copyright(c) 2006-2007, Ext JS, LLC.
15721 * Originally Released Under LGPL - original licence link has changed is not relivant.
15724 * <script type="text/javascript">
15729 * @extends Roo.util.Observable
15730 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15731 * This class also supports single and multi selection modes. <br>
15732 * Create a data model bound view:
15734 var store = new Roo.data.Store(...);
15736 var view = new Roo.View({
15738 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15740 singleSelect: true,
15741 selectedClass: "ydataview-selected",
15745 // listen for node click?
15746 view.on("click", function(vw, index, node, e){
15747 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15751 dataModel.load("foobar.xml");
15753 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15755 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15756 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15758 * Note: old style constructor is still suported (container, template, config)
15761 * Create a new View
15762 * @param {Object} config The config object
15765 Roo.View = function(config, depreciated_tpl, depreciated_config){
15767 this.parent = false;
15769 if (typeof(depreciated_tpl) == 'undefined') {
15770 // new way.. - universal constructor.
15771 Roo.apply(this, config);
15772 this.el = Roo.get(this.el);
15775 this.el = Roo.get(config);
15776 this.tpl = depreciated_tpl;
15777 Roo.apply(this, depreciated_config);
15779 this.wrapEl = this.el.wrap().wrap();
15780 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15783 if(typeof(this.tpl) == "string"){
15784 this.tpl = new Roo.Template(this.tpl);
15786 // support xtype ctors..
15787 this.tpl = new Roo.factory(this.tpl, Roo);
15791 this.tpl.compile();
15796 * @event beforeclick
15797 * Fires before a click is processed. Returns false to cancel the default action.
15798 * @param {Roo.View} this
15799 * @param {Number} index The index of the target node
15800 * @param {HTMLElement} node The target node
15801 * @param {Roo.EventObject} e The raw event object
15803 "beforeclick" : true,
15806 * Fires when a template node is clicked.
15807 * @param {Roo.View} this
15808 * @param {Number} index The index of the target node
15809 * @param {HTMLElement} node The target node
15810 * @param {Roo.EventObject} e The raw event object
15815 * Fires when a template node is double clicked.
15816 * @param {Roo.View} this
15817 * @param {Number} index The index of the target node
15818 * @param {HTMLElement} node The target node
15819 * @param {Roo.EventObject} e The raw event object
15823 * @event contextmenu
15824 * Fires when a template node is right clicked.
15825 * @param {Roo.View} this
15826 * @param {Number} index The index of the target node
15827 * @param {HTMLElement} node The target node
15828 * @param {Roo.EventObject} e The raw event object
15830 "contextmenu" : true,
15832 * @event selectionchange
15833 * Fires when the selected nodes change.
15834 * @param {Roo.View} this
15835 * @param {Array} selections Array of the selected nodes
15837 "selectionchange" : true,
15840 * @event beforeselect
15841 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15842 * @param {Roo.View} this
15843 * @param {HTMLElement} node The node to be selected
15844 * @param {Array} selections Array of currently selected nodes
15846 "beforeselect" : true,
15848 * @event preparedata
15849 * Fires on every row to render, to allow you to change the data.
15850 * @param {Roo.View} this
15851 * @param {Object} data to be rendered (change this)
15853 "preparedata" : true
15861 "click": this.onClick,
15862 "dblclick": this.onDblClick,
15863 "contextmenu": this.onContextMenu,
15867 this.selections = [];
15869 this.cmp = new Roo.CompositeElementLite([]);
15871 this.store = Roo.factory(this.store, Roo.data);
15872 this.setStore(this.store, true);
15875 if ( this.footer && this.footer.xtype) {
15877 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15879 this.footer.dataSource = this.store;
15880 this.footer.container = fctr;
15881 this.footer = Roo.factory(this.footer, Roo);
15882 fctr.insertFirst(this.el);
15884 // this is a bit insane - as the paging toolbar seems to detach the el..
15885 // dom.parentNode.parentNode.parentNode
15886 // they get detached?
15890 Roo.View.superclass.constructor.call(this);
15895 Roo.extend(Roo.View, Roo.util.Observable, {
15898 * @cfg {Roo.data.Store} store Data store to load data from.
15903 * @cfg {String|Roo.Element} el The container element.
15908 * @cfg {String|Roo.Template} tpl The template used by this View
15912 * @cfg {String} dataName the named area of the template to use as the data area
15913 * Works with domtemplates roo-name="name"
15917 * @cfg {String} selectedClass The css class to add to selected nodes
15919 selectedClass : "x-view-selected",
15921 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15926 * @cfg {String} text to display on mask (default Loading)
15930 * @cfg {Boolean} multiSelect Allow multiple selection
15932 multiSelect : false,
15934 * @cfg {Boolean} singleSelect Allow single selection
15936 singleSelect: false,
15939 * @cfg {Boolean} toggleSelect - selecting
15941 toggleSelect : false,
15944 * @cfg {Boolean} tickable - selecting
15949 * Returns the element this view is bound to.
15950 * @return {Roo.Element}
15952 getEl : function(){
15953 return this.wrapEl;
15959 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15961 refresh : function(){
15962 //Roo.log('refresh');
15965 // if we are using something like 'domtemplate', then
15966 // the what gets used is:
15967 // t.applySubtemplate(NAME, data, wrapping data..)
15968 // the outer template then get' applied with
15969 // the store 'extra data'
15970 // and the body get's added to the
15971 // roo-name="data" node?
15972 // <span class='roo-tpl-{name}'></span> ?????
15976 this.clearSelections();
15977 this.el.update("");
15979 var records = this.store.getRange();
15980 if(records.length < 1) {
15982 // is this valid?? = should it render a template??
15984 this.el.update(this.emptyText);
15988 if (this.dataName) {
15989 this.el.update(t.apply(this.store.meta)); //????
15990 el = this.el.child('.roo-tpl-' + this.dataName);
15993 for(var i = 0, len = records.length; i < len; i++){
15994 var data = this.prepareData(records[i].data, i, records[i]);
15995 this.fireEvent("preparedata", this, data, i, records[i]);
15997 var d = Roo.apply({}, data);
16000 Roo.apply(d, {'roo-id' : Roo.id()});
16004 Roo.each(this.parent.item, function(item){
16005 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16008 Roo.apply(d, {'roo-data-checked' : 'checked'});
16012 html[html.length] = Roo.util.Format.trim(
16014 t.applySubtemplate(this.dataName, d, this.store.meta) :
16021 el.update(html.join(""));
16022 this.nodes = el.dom.childNodes;
16023 this.updateIndexes(0);
16028 * Function to override to reformat the data that is sent to
16029 * the template for each node.
16030 * DEPRICATED - use the preparedata event handler.
16031 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16032 * a JSON object for an UpdateManager bound view).
16034 prepareData : function(data, index, record)
16036 this.fireEvent("preparedata", this, data, index, record);
16040 onUpdate : function(ds, record){
16041 // Roo.log('on update');
16042 this.clearSelections();
16043 var index = this.store.indexOf(record);
16044 var n = this.nodes[index];
16045 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16046 n.parentNode.removeChild(n);
16047 this.updateIndexes(index, index);
16053 onAdd : function(ds, records, index)
16055 //Roo.log(['on Add', ds, records, index] );
16056 this.clearSelections();
16057 if(this.nodes.length == 0){
16061 var n = this.nodes[index];
16062 for(var i = 0, len = records.length; i < len; i++){
16063 var d = this.prepareData(records[i].data, i, records[i]);
16065 this.tpl.insertBefore(n, d);
16068 this.tpl.append(this.el, d);
16071 this.updateIndexes(index);
16074 onRemove : function(ds, record, index){
16075 // Roo.log('onRemove');
16076 this.clearSelections();
16077 var el = this.dataName ?
16078 this.el.child('.roo-tpl-' + this.dataName) :
16081 el.dom.removeChild(this.nodes[index]);
16082 this.updateIndexes(index);
16086 * Refresh an individual node.
16087 * @param {Number} index
16089 refreshNode : function(index){
16090 this.onUpdate(this.store, this.store.getAt(index));
16093 updateIndexes : function(startIndex, endIndex){
16094 var ns = this.nodes;
16095 startIndex = startIndex || 0;
16096 endIndex = endIndex || ns.length - 1;
16097 for(var i = startIndex; i <= endIndex; i++){
16098 ns[i].nodeIndex = i;
16103 * Changes the data store this view uses and refresh the view.
16104 * @param {Store} store
16106 setStore : function(store, initial){
16107 if(!initial && this.store){
16108 this.store.un("datachanged", this.refresh);
16109 this.store.un("add", this.onAdd);
16110 this.store.un("remove", this.onRemove);
16111 this.store.un("update", this.onUpdate);
16112 this.store.un("clear", this.refresh);
16113 this.store.un("beforeload", this.onBeforeLoad);
16114 this.store.un("load", this.onLoad);
16115 this.store.un("loadexception", this.onLoad);
16119 store.on("datachanged", this.refresh, this);
16120 store.on("add", this.onAdd, this);
16121 store.on("remove", this.onRemove, this);
16122 store.on("update", this.onUpdate, this);
16123 store.on("clear", this.refresh, this);
16124 store.on("beforeload", this.onBeforeLoad, this);
16125 store.on("load", this.onLoad, this);
16126 store.on("loadexception", this.onLoad, this);
16134 * onbeforeLoad - masks the loading area.
16137 onBeforeLoad : function(store,opts)
16139 //Roo.log('onBeforeLoad');
16141 this.el.update("");
16143 this.el.mask(this.mask ? this.mask : "Loading" );
16145 onLoad : function ()
16152 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16153 * @param {HTMLElement} node
16154 * @return {HTMLElement} The template node
16156 findItemFromChild : function(node){
16157 var el = this.dataName ?
16158 this.el.child('.roo-tpl-' + this.dataName,true) :
16161 if(!node || node.parentNode == el){
16164 var p = node.parentNode;
16165 while(p && p != el){
16166 if(p.parentNode == el){
16175 onClick : function(e){
16176 var item = this.findItemFromChild(e.getTarget());
16178 var index = this.indexOf(item);
16179 if(this.onItemClick(item, index, e) !== false){
16180 this.fireEvent("click", this, index, item, e);
16183 this.clearSelections();
16188 onContextMenu : function(e){
16189 var item = this.findItemFromChild(e.getTarget());
16191 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16196 onDblClick : function(e){
16197 var item = this.findItemFromChild(e.getTarget());
16199 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16203 onItemClick : function(item, index, e)
16205 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16208 if (this.toggleSelect) {
16209 var m = this.isSelected(item) ? 'unselect' : 'select';
16212 _t[m](item, true, false);
16215 if(this.multiSelect || this.singleSelect){
16216 if(this.multiSelect && e.shiftKey && this.lastSelection){
16217 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16219 this.select(item, this.multiSelect && e.ctrlKey);
16220 this.lastSelection = item;
16223 if(!this.tickable){
16224 e.preventDefault();
16232 * Get the number of selected nodes.
16235 getSelectionCount : function(){
16236 return this.selections.length;
16240 * Get the currently selected nodes.
16241 * @return {Array} An array of HTMLElements
16243 getSelectedNodes : function(){
16244 return this.selections;
16248 * Get the indexes of the selected nodes.
16251 getSelectedIndexes : function(){
16252 var indexes = [], s = this.selections;
16253 for(var i = 0, len = s.length; i < len; i++){
16254 indexes.push(s[i].nodeIndex);
16260 * Clear all selections
16261 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16263 clearSelections : function(suppressEvent){
16264 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16265 this.cmp.elements = this.selections;
16266 this.cmp.removeClass(this.selectedClass);
16267 this.selections = [];
16268 if(!suppressEvent){
16269 this.fireEvent("selectionchange", this, this.selections);
16275 * Returns true if the passed node is selected
16276 * @param {HTMLElement/Number} node The node or node index
16277 * @return {Boolean}
16279 isSelected : function(node){
16280 var s = this.selections;
16284 node = this.getNode(node);
16285 return s.indexOf(node) !== -1;
16290 * @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
16291 * @param {Boolean} keepExisting (optional) true to keep existing selections
16292 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16294 select : function(nodeInfo, keepExisting, suppressEvent){
16295 if(nodeInfo instanceof Array){
16297 this.clearSelections(true);
16299 for(var i = 0, len = nodeInfo.length; i < len; i++){
16300 this.select(nodeInfo[i], true, true);
16304 var node = this.getNode(nodeInfo);
16305 if(!node || this.isSelected(node)){
16306 return; // already selected.
16309 this.clearSelections(true);
16312 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16313 Roo.fly(node).addClass(this.selectedClass);
16314 this.selections.push(node);
16315 if(!suppressEvent){
16316 this.fireEvent("selectionchange", this, this.selections);
16324 * @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
16325 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16326 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16328 unselect : function(nodeInfo, keepExisting, suppressEvent)
16330 if(nodeInfo instanceof Array){
16331 Roo.each(this.selections, function(s) {
16332 this.unselect(s, nodeInfo);
16336 var node = this.getNode(nodeInfo);
16337 if(!node || !this.isSelected(node)){
16338 //Roo.log("not selected");
16339 return; // not selected.
16343 Roo.each(this.selections, function(s) {
16345 Roo.fly(node).removeClass(this.selectedClass);
16352 this.selections= ns;
16353 this.fireEvent("selectionchange", this, this.selections);
16357 * Gets a template node.
16358 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16359 * @return {HTMLElement} The node or null if it wasn't found
16361 getNode : function(nodeInfo){
16362 if(typeof nodeInfo == "string"){
16363 return document.getElementById(nodeInfo);
16364 }else if(typeof nodeInfo == "number"){
16365 return this.nodes[nodeInfo];
16371 * Gets a range template nodes.
16372 * @param {Number} startIndex
16373 * @param {Number} endIndex
16374 * @return {Array} An array of nodes
16376 getNodes : function(start, end){
16377 var ns = this.nodes;
16378 start = start || 0;
16379 end = typeof end == "undefined" ? ns.length - 1 : end;
16382 for(var i = start; i <= end; i++){
16386 for(var i = start; i >= end; i--){
16394 * Finds the index of the passed node
16395 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16396 * @return {Number} The index of the node or -1
16398 indexOf : function(node){
16399 node = this.getNode(node);
16400 if(typeof node.nodeIndex == "number"){
16401 return node.nodeIndex;
16403 var ns = this.nodes;
16404 for(var i = 0, len = ns.length; i < len; i++){
16415 * based on jquery fullcalendar
16419 Roo.bootstrap = Roo.bootstrap || {};
16421 * @class Roo.bootstrap.Calendar
16422 * @extends Roo.bootstrap.Component
16423 * Bootstrap Calendar class
16424 * @cfg {Boolean} loadMask (true|false) default false
16425 * @cfg {Object} header generate the user specific header of the calendar, default false
16428 * Create a new Container
16429 * @param {Object} config The config object
16434 Roo.bootstrap.Calendar = function(config){
16435 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16439 * Fires when a date is selected
16440 * @param {DatePicker} this
16441 * @param {Date} date The selected date
16445 * @event monthchange
16446 * Fires when the displayed month changes
16447 * @param {DatePicker} this
16448 * @param {Date} date The selected month
16450 'monthchange': true,
16452 * @event evententer
16453 * Fires when mouse over an event
16454 * @param {Calendar} this
16455 * @param {event} Event
16457 'evententer': true,
16459 * @event eventleave
16460 * Fires when the mouse leaves an
16461 * @param {Calendar} this
16464 'eventleave': true,
16466 * @event eventclick
16467 * Fires when the mouse click an
16468 * @param {Calendar} this
16477 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16480 * @cfg {Number} startDay
16481 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16489 getAutoCreate : function(){
16492 var fc_button = function(name, corner, style, content ) {
16493 return Roo.apply({},{
16495 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16497 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16500 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16511 style : 'width:100%',
16518 cls : 'fc-header-left',
16520 fc_button('prev', 'left', 'arrow', '‹' ),
16521 fc_button('next', 'right', 'arrow', '›' ),
16522 { tag: 'span', cls: 'fc-header-space' },
16523 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16531 cls : 'fc-header-center',
16535 cls: 'fc-header-title',
16538 html : 'month / year'
16546 cls : 'fc-header-right',
16548 /* fc_button('month', 'left', '', 'month' ),
16549 fc_button('week', '', '', 'week' ),
16550 fc_button('day', 'right', '', 'day' )
16562 header = this.header;
16565 var cal_heads = function() {
16567 // fixme - handle this.
16569 for (var i =0; i < Date.dayNames.length; i++) {
16570 var d = Date.dayNames[i];
16573 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16574 html : d.substring(0,3)
16578 ret[0].cls += ' fc-first';
16579 ret[6].cls += ' fc-last';
16582 var cal_cell = function(n) {
16585 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16590 cls: 'fc-day-number',
16594 cls: 'fc-day-content',
16598 style: 'position: relative;' // height: 17px;
16610 var cal_rows = function() {
16613 for (var r = 0; r < 6; r++) {
16620 for (var i =0; i < Date.dayNames.length; i++) {
16621 var d = Date.dayNames[i];
16622 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16625 row.cn[0].cls+=' fc-first';
16626 row.cn[0].cn[0].style = 'min-height:90px';
16627 row.cn[6].cls+=' fc-last';
16631 ret[0].cls += ' fc-first';
16632 ret[4].cls += ' fc-prev-last';
16633 ret[5].cls += ' fc-last';
16640 cls: 'fc-border-separate',
16641 style : 'width:100%',
16649 cls : 'fc-first fc-last',
16667 cls : 'fc-content',
16668 style : "position: relative;",
16671 cls : 'fc-view fc-view-month fc-grid',
16672 style : 'position: relative',
16673 unselectable : 'on',
16676 cls : 'fc-event-container',
16677 style : 'position:absolute;z-index:8;top:0;left:0;'
16695 initEvents : function()
16698 throw "can not find store for calendar";
16704 style: "text-align:center",
16708 style: "background-color:white;width:50%;margin:250 auto",
16712 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16723 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16725 var size = this.el.select('.fc-content', true).first().getSize();
16726 this.maskEl.setSize(size.width, size.height);
16727 this.maskEl.enableDisplayMode("block");
16728 if(!this.loadMask){
16729 this.maskEl.hide();
16732 this.store = Roo.factory(this.store, Roo.data);
16733 this.store.on('load', this.onLoad, this);
16734 this.store.on('beforeload', this.onBeforeLoad, this);
16738 this.cells = this.el.select('.fc-day',true);
16739 //Roo.log(this.cells);
16740 this.textNodes = this.el.query('.fc-day-number');
16741 this.cells.addClassOnOver('fc-state-hover');
16743 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16744 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16745 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16746 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16748 this.on('monthchange', this.onMonthChange, this);
16750 this.update(new Date().clearTime());
16753 resize : function() {
16754 var sz = this.el.getSize();
16756 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16757 this.el.select('.fc-day-content div',true).setHeight(34);
16762 showPrevMonth : function(e){
16763 this.update(this.activeDate.add("mo", -1));
16765 showToday : function(e){
16766 this.update(new Date().clearTime());
16769 showNextMonth : function(e){
16770 this.update(this.activeDate.add("mo", 1));
16774 showPrevYear : function(){
16775 this.update(this.activeDate.add("y", -1));
16779 showNextYear : function(){
16780 this.update(this.activeDate.add("y", 1));
16785 update : function(date)
16787 var vd = this.activeDate;
16788 this.activeDate = date;
16789 // if(vd && this.el){
16790 // var t = date.getTime();
16791 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16792 // Roo.log('using add remove');
16794 // this.fireEvent('monthchange', this, date);
16796 // this.cells.removeClass("fc-state-highlight");
16797 // this.cells.each(function(c){
16798 // if(c.dateValue == t){
16799 // c.addClass("fc-state-highlight");
16800 // setTimeout(function(){
16801 // try{c.dom.firstChild.focus();}catch(e){}
16811 var days = date.getDaysInMonth();
16813 var firstOfMonth = date.getFirstDateOfMonth();
16814 var startingPos = firstOfMonth.getDay()-this.startDay;
16816 if(startingPos < this.startDay){
16820 var pm = date.add(Date.MONTH, -1);
16821 var prevStart = pm.getDaysInMonth()-startingPos;
16823 this.cells = this.el.select('.fc-day',true);
16824 this.textNodes = this.el.query('.fc-day-number');
16825 this.cells.addClassOnOver('fc-state-hover');
16827 var cells = this.cells.elements;
16828 var textEls = this.textNodes;
16830 Roo.each(cells, function(cell){
16831 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16834 days += startingPos;
16836 // convert everything to numbers so it's fast
16837 var day = 86400000;
16838 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16841 //Roo.log(prevStart);
16843 var today = new Date().clearTime().getTime();
16844 var sel = date.clearTime().getTime();
16845 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16846 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16847 var ddMatch = this.disabledDatesRE;
16848 var ddText = this.disabledDatesText;
16849 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16850 var ddaysText = this.disabledDaysText;
16851 var format = this.format;
16853 var setCellClass = function(cal, cell){
16857 //Roo.log('set Cell Class');
16859 var t = d.getTime();
16863 cell.dateValue = t;
16865 cell.className += " fc-today";
16866 cell.className += " fc-state-highlight";
16867 cell.title = cal.todayText;
16870 // disable highlight in other month..
16871 //cell.className += " fc-state-highlight";
16876 cell.className = " fc-state-disabled";
16877 cell.title = cal.minText;
16881 cell.className = " fc-state-disabled";
16882 cell.title = cal.maxText;
16886 if(ddays.indexOf(d.getDay()) != -1){
16887 cell.title = ddaysText;
16888 cell.className = " fc-state-disabled";
16891 if(ddMatch && format){
16892 var fvalue = d.dateFormat(format);
16893 if(ddMatch.test(fvalue)){
16894 cell.title = ddText.replace("%0", fvalue);
16895 cell.className = " fc-state-disabled";
16899 if (!cell.initialClassName) {
16900 cell.initialClassName = cell.dom.className;
16903 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16908 for(; i < startingPos; i++) {
16909 textEls[i].innerHTML = (++prevStart);
16910 d.setDate(d.getDate()+1);
16912 cells[i].className = "fc-past fc-other-month";
16913 setCellClass(this, cells[i]);
16918 for(; i < days; i++){
16919 intDay = i - startingPos + 1;
16920 textEls[i].innerHTML = (intDay);
16921 d.setDate(d.getDate()+1);
16923 cells[i].className = ''; // "x-date-active";
16924 setCellClass(this, cells[i]);
16928 for(; i < 42; i++) {
16929 textEls[i].innerHTML = (++extraDays);
16930 d.setDate(d.getDate()+1);
16932 cells[i].className = "fc-future fc-other-month";
16933 setCellClass(this, cells[i]);
16936 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16938 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16940 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16941 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16943 if(totalRows != 6){
16944 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16945 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16948 this.fireEvent('monthchange', this, date);
16952 if(!this.internalRender){
16953 var main = this.el.dom.firstChild;
16954 var w = main.offsetWidth;
16955 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16956 Roo.fly(main).setWidth(w);
16957 this.internalRender = true;
16958 // opera does not respect the auto grow header center column
16959 // then, after it gets a width opera refuses to recalculate
16960 // without a second pass
16961 if(Roo.isOpera && !this.secondPass){
16962 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16963 this.secondPass = true;
16964 this.update.defer(10, this, [date]);
16971 findCell : function(dt) {
16972 dt = dt.clearTime().getTime();
16974 this.cells.each(function(c){
16975 //Roo.log("check " +c.dateValue + '?=' + dt);
16976 if(c.dateValue == dt){
16986 findCells : function(ev) {
16987 var s = ev.start.clone().clearTime().getTime();
16989 var e= ev.end.clone().clearTime().getTime();
16992 this.cells.each(function(c){
16993 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16995 if(c.dateValue > e){
16998 if(c.dateValue < s){
17007 // findBestRow: function(cells)
17011 // for (var i =0 ; i < cells.length;i++) {
17012 // ret = Math.max(cells[i].rows || 0,ret);
17019 addItem : function(ev)
17021 // look for vertical location slot in
17022 var cells = this.findCells(ev);
17024 // ev.row = this.findBestRow(cells);
17026 // work out the location.
17030 for(var i =0; i < cells.length; i++) {
17032 cells[i].row = cells[0].row;
17035 cells[i].row = cells[i].row + 1;
17045 if (crow.start.getY() == cells[i].getY()) {
17047 crow.end = cells[i];
17064 cells[0].events.push(ev);
17066 this.calevents.push(ev);
17069 clearEvents: function() {
17071 if(!this.calevents){
17075 Roo.each(this.cells.elements, function(c){
17081 Roo.each(this.calevents, function(e) {
17082 Roo.each(e.els, function(el) {
17083 el.un('mouseenter' ,this.onEventEnter, this);
17084 el.un('mouseleave' ,this.onEventLeave, this);
17089 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17095 renderEvents: function()
17099 this.cells.each(function(c) {
17108 if(c.row != c.events.length){
17109 r = 4 - (4 - (c.row - c.events.length));
17112 c.events = ev.slice(0, r);
17113 c.more = ev.slice(r);
17115 if(c.more.length && c.more.length == 1){
17116 c.events.push(c.more.pop());
17119 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17123 this.cells.each(function(c) {
17125 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17128 for (var e = 0; e < c.events.length; e++){
17129 var ev = c.events[e];
17130 var rows = ev.rows;
17132 for(var i = 0; i < rows.length; i++) {
17134 // how many rows should it span..
17137 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17138 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17140 unselectable : "on",
17143 cls: 'fc-event-inner',
17147 // cls: 'fc-event-time',
17148 // html : cells.length > 1 ? '' : ev.time
17152 cls: 'fc-event-title',
17153 html : String.format('{0}', ev.title)
17160 cls: 'ui-resizable-handle ui-resizable-e',
17161 html : '  '
17168 cfg.cls += ' fc-event-start';
17170 if ((i+1) == rows.length) {
17171 cfg.cls += ' fc-event-end';
17174 var ctr = _this.el.select('.fc-event-container',true).first();
17175 var cg = ctr.createChild(cfg);
17177 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17178 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17180 var r = (c.more.length) ? 1 : 0;
17181 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17182 cg.setWidth(ebox.right - sbox.x -2);
17184 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17185 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17186 cg.on('click', _this.onEventClick, _this, ev);
17197 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17198 style : 'position: absolute',
17199 unselectable : "on",
17202 cls: 'fc-event-inner',
17206 cls: 'fc-event-title',
17214 cls: 'ui-resizable-handle ui-resizable-e',
17215 html : '  '
17221 var ctr = _this.el.select('.fc-event-container',true).first();
17222 var cg = ctr.createChild(cfg);
17224 var sbox = c.select('.fc-day-content',true).first().getBox();
17225 var ebox = c.select('.fc-day-content',true).first().getBox();
17227 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17228 cg.setWidth(ebox.right - sbox.x -2);
17230 cg.on('click', _this.onMoreEventClick, _this, c.more);
17240 onEventEnter: function (e, el,event,d) {
17241 this.fireEvent('evententer', this, el, event);
17244 onEventLeave: function (e, el,event,d) {
17245 this.fireEvent('eventleave', this, el, event);
17248 onEventClick: function (e, el,event,d) {
17249 this.fireEvent('eventclick', this, el, event);
17252 onMonthChange: function () {
17256 onMoreEventClick: function(e, el, more)
17260 this.calpopover.placement = 'right';
17261 this.calpopover.setTitle('More');
17263 this.calpopover.setContent('');
17265 var ctr = this.calpopover.el.select('.popover-content', true).first();
17267 Roo.each(more, function(m){
17269 cls : 'fc-event-hori fc-event-draggable',
17272 var cg = ctr.createChild(cfg);
17274 cg.on('click', _this.onEventClick, _this, m);
17277 this.calpopover.show(el);
17282 onLoad: function ()
17284 this.calevents = [];
17287 if(this.store.getCount() > 0){
17288 this.store.data.each(function(d){
17291 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17292 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17293 time : d.data.start_time,
17294 title : d.data.title,
17295 description : d.data.description,
17296 venue : d.data.venue
17301 this.renderEvents();
17303 if(this.calevents.length && this.loadMask){
17304 this.maskEl.hide();
17308 onBeforeLoad: function()
17310 this.clearEvents();
17312 this.maskEl.show();
17326 * @class Roo.bootstrap.Popover
17327 * @extends Roo.bootstrap.Component
17328 * Bootstrap Popover class
17329 * @cfg {String} html contents of the popover (or false to use children..)
17330 * @cfg {String} title of popover (or false to hide)
17331 * @cfg {String} placement how it is placed
17332 * @cfg {String} trigger click || hover (or false to trigger manually)
17333 * @cfg {String} over what (parent or false to trigger manually.)
17334 * @cfg {Number} delay - delay before showing
17337 * Create a new Popover
17338 * @param {Object} config The config object
17341 Roo.bootstrap.Popover = function(config){
17342 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17348 * After the popover show
17350 * @param {Roo.bootstrap.Popover} this
17355 * After the popover hide
17357 * @param {Roo.bootstrap.Popover} this
17363 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17365 title: 'Fill in a title',
17368 placement : 'right',
17369 trigger : 'hover', // hover
17375 can_build_overlaid : false,
17377 getChildContainer : function()
17379 return this.el.select('.popover-content',true).first();
17382 getAutoCreate : function(){
17385 cls : 'popover roo-dynamic',
17386 style: 'display:block',
17392 cls : 'popover-inner',
17396 cls: 'popover-title',
17400 cls : 'popover-content',
17411 setTitle: function(str)
17414 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17416 setContent: function(str)
17419 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17421 // as it get's added to the bottom of the page.
17422 onRender : function(ct, position)
17424 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17426 var cfg = Roo.apply({}, this.getAutoCreate());
17430 cfg.cls += ' ' + this.cls;
17433 cfg.style = this.style;
17435 //Roo.log("adding to ");
17436 this.el = Roo.get(document.body).createChild(cfg, position);
17437 // Roo.log(this.el);
17442 initEvents : function()
17444 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17445 this.el.enableDisplayMode('block');
17447 if (this.over === false) {
17450 if (this.triggers === false) {
17453 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17454 var triggers = this.trigger ? this.trigger.split(' ') : [];
17455 Roo.each(triggers, function(trigger) {
17457 if (trigger == 'click') {
17458 on_el.on('click', this.toggle, this);
17459 } else if (trigger != 'manual') {
17460 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17461 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17463 on_el.on(eventIn ,this.enter, this);
17464 on_el.on(eventOut, this.leave, this);
17475 toggle : function () {
17476 this.hoverState == 'in' ? this.leave() : this.enter();
17479 enter : function () {
17481 clearTimeout(this.timeout);
17483 this.hoverState = 'in';
17485 if (!this.delay || !this.delay.show) {
17490 this.timeout = setTimeout(function () {
17491 if (_t.hoverState == 'in') {
17494 }, this.delay.show)
17497 leave : function() {
17498 clearTimeout(this.timeout);
17500 this.hoverState = 'out';
17502 if (!this.delay || !this.delay.hide) {
17507 this.timeout = setTimeout(function () {
17508 if (_t.hoverState == 'out') {
17511 }, this.delay.hide)
17514 show : function (on_el)
17517 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17521 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17522 if (this.html !== false) {
17523 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17525 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17526 if (!this.title.length) {
17527 this.el.select('.popover-title',true).hide();
17530 var placement = typeof this.placement == 'function' ?
17531 this.placement.call(this, this.el, on_el) :
17534 var autoToken = /\s?auto?\s?/i;
17535 var autoPlace = autoToken.test(placement);
17537 placement = placement.replace(autoToken, '') || 'top';
17541 //this.el.setXY([0,0]);
17543 this.el.dom.style.display='block';
17544 this.el.addClass(placement);
17546 //this.el.appendTo(on_el);
17548 var p = this.getPosition();
17549 var box = this.el.getBox();
17554 var align = Roo.bootstrap.Popover.alignment[placement];
17557 this.el.alignTo(on_el, align[0],align[1]);
17558 //var arrow = this.el.select('.arrow',true).first();
17559 //arrow.set(align[2],
17561 this.el.addClass('in');
17564 if (this.el.hasClass('fade')) {
17568 this.hoverState = 'in';
17570 this.fireEvent('show', this);
17575 this.el.setXY([0,0]);
17576 this.el.removeClass('in');
17578 this.hoverState = null;
17580 this.fireEvent('hide', this);
17585 Roo.bootstrap.Popover.alignment = {
17586 'left' : ['r-l', [-10,0], 'right'],
17587 'right' : ['l-r', [10,0], 'left'],
17588 'bottom' : ['t-b', [0,10], 'top'],
17589 'top' : [ 'b-t', [0,-10], 'bottom']
17600 * @class Roo.bootstrap.Progress
17601 * @extends Roo.bootstrap.Component
17602 * Bootstrap Progress class
17603 * @cfg {Boolean} striped striped of the progress bar
17604 * @cfg {Boolean} active animated of the progress bar
17608 * Create a new Progress
17609 * @param {Object} config The config object
17612 Roo.bootstrap.Progress = function(config){
17613 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17616 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17621 getAutoCreate : function(){
17629 cfg.cls += ' progress-striped';
17633 cfg.cls += ' active';
17652 * @class Roo.bootstrap.ProgressBar
17653 * @extends Roo.bootstrap.Component
17654 * Bootstrap ProgressBar class
17655 * @cfg {Number} aria_valuenow aria-value now
17656 * @cfg {Number} aria_valuemin aria-value min
17657 * @cfg {Number} aria_valuemax aria-value max
17658 * @cfg {String} label label for the progress bar
17659 * @cfg {String} panel (success | info | warning | danger )
17660 * @cfg {String} role role of the progress bar
17661 * @cfg {String} sr_only text
17665 * Create a new ProgressBar
17666 * @param {Object} config The config object
17669 Roo.bootstrap.ProgressBar = function(config){
17670 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17673 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17677 aria_valuemax : 100,
17683 getAutoCreate : function()
17688 cls: 'progress-bar',
17689 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17701 cfg.role = this.role;
17704 if(this.aria_valuenow){
17705 cfg['aria-valuenow'] = this.aria_valuenow;
17708 if(this.aria_valuemin){
17709 cfg['aria-valuemin'] = this.aria_valuemin;
17712 if(this.aria_valuemax){
17713 cfg['aria-valuemax'] = this.aria_valuemax;
17716 if(this.label && !this.sr_only){
17717 cfg.html = this.label;
17721 cfg.cls += ' progress-bar-' + this.panel;
17727 update : function(aria_valuenow)
17729 this.aria_valuenow = aria_valuenow;
17731 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17746 * @class Roo.bootstrap.TabGroup
17747 * @extends Roo.bootstrap.Column
17748 * Bootstrap Column class
17749 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17750 * @cfg {Boolean} carousel true to make the group behave like a carousel
17751 * @cfg {Boolean} bullets show bullets for the panels
17752 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17753 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17754 * @cfg {Boolean} showarrow (true|false) show arrow default true
17757 * Create a new TabGroup
17758 * @param {Object} config The config object
17761 Roo.bootstrap.TabGroup = function(config){
17762 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17764 this.navId = Roo.id();
17767 Roo.bootstrap.TabGroup.register(this);
17771 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17774 transition : false,
17779 slideOnTouch : false,
17782 getAutoCreate : function()
17784 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17786 cfg.cls += ' tab-content';
17788 if (this.carousel) {
17789 cfg.cls += ' carousel slide';
17792 cls : 'carousel-inner',
17796 if(this.bullets && !Roo.isTouch){
17799 cls : 'carousel-bullets',
17803 if(this.bullets_cls){
17804 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17811 cfg.cn[0].cn.push(bullets);
17814 if(this.showarrow){
17815 cfg.cn[0].cn.push({
17817 class : 'carousel-arrow',
17821 class : 'carousel-prev',
17825 class : 'fa fa-chevron-left'
17831 class : 'carousel-next',
17835 class : 'fa fa-chevron-right'
17848 initEvents: function()
17850 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17851 // this.el.on("touchstart", this.onTouchStart, this);
17854 if(this.autoslide){
17857 this.slideFn = window.setInterval(function() {
17858 _this.showPanelNext();
17862 if(this.showarrow){
17863 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17864 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17870 // onTouchStart : function(e, el, o)
17872 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17876 // this.showPanelNext();
17880 getChildContainer : function()
17882 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17886 * register a Navigation item
17887 * @param {Roo.bootstrap.NavItem} the navitem to add
17889 register : function(item)
17891 this.tabs.push( item);
17892 item.navId = this.navId; // not really needed..
17897 getActivePanel : function()
17900 Roo.each(this.tabs, function(t) {
17910 getPanelByName : function(n)
17913 Roo.each(this.tabs, function(t) {
17914 if (t.tabId == n) {
17922 indexOfPanel : function(p)
17925 Roo.each(this.tabs, function(t,i) {
17926 if (t.tabId == p.tabId) {
17935 * show a specific panel
17936 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17937 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17939 showPanel : function (pan)
17941 if(this.transition || typeof(pan) == 'undefined'){
17942 Roo.log("waiting for the transitionend");
17946 if (typeof(pan) == 'number') {
17947 pan = this.tabs[pan];
17950 if (typeof(pan) == 'string') {
17951 pan = this.getPanelByName(pan);
17954 var cur = this.getActivePanel();
17957 Roo.log('pan or acitve pan is undefined');
17961 if (pan.tabId == this.getActivePanel().tabId) {
17965 if (false === cur.fireEvent('beforedeactivate')) {
17969 if(this.bullets > 0 && !Roo.isTouch){
17970 this.setActiveBullet(this.indexOfPanel(pan));
17973 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17975 this.transition = true;
17976 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17977 var lr = dir == 'next' ? 'left' : 'right';
17978 pan.el.addClass(dir); // or prev
17979 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17980 cur.el.addClass(lr); // or right
17981 pan.el.addClass(lr);
17984 cur.el.on('transitionend', function() {
17985 Roo.log("trans end?");
17987 pan.el.removeClass([lr,dir]);
17988 pan.setActive(true);
17990 cur.el.removeClass([lr]);
17991 cur.setActive(false);
17993 _this.transition = false;
17995 }, this, { single: true } );
18000 cur.setActive(false);
18001 pan.setActive(true);
18006 showPanelNext : function()
18008 var i = this.indexOfPanel(this.getActivePanel());
18010 if (i >= this.tabs.length - 1 && !this.autoslide) {
18014 if (i >= this.tabs.length - 1 && this.autoslide) {
18018 this.showPanel(this.tabs[i+1]);
18021 showPanelPrev : function()
18023 var i = this.indexOfPanel(this.getActivePanel());
18025 if (i < 1 && !this.autoslide) {
18029 if (i < 1 && this.autoslide) {
18030 i = this.tabs.length;
18033 this.showPanel(this.tabs[i-1]);
18037 addBullet: function()
18039 if(!this.bullets || Roo.isTouch){
18042 var ctr = this.el.select('.carousel-bullets',true).first();
18043 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18044 var bullet = ctr.createChild({
18045 cls : 'bullet bullet-' + i
18046 },ctr.dom.lastChild);
18051 bullet.on('click', (function(e, el, o, ii, t){
18053 e.preventDefault();
18055 this.showPanel(ii);
18057 if(this.autoslide && this.slideFn){
18058 clearInterval(this.slideFn);
18059 this.slideFn = window.setInterval(function() {
18060 _this.showPanelNext();
18064 }).createDelegate(this, [i, bullet], true));
18069 setActiveBullet : function(i)
18075 Roo.each(this.el.select('.bullet', true).elements, function(el){
18076 el.removeClass('selected');
18079 var bullet = this.el.select('.bullet-' + i, true).first();
18085 bullet.addClass('selected');
18096 Roo.apply(Roo.bootstrap.TabGroup, {
18100 * register a Navigation Group
18101 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18103 register : function(navgrp)
18105 this.groups[navgrp.navId] = navgrp;
18109 * fetch a Navigation Group based on the navigation ID
18110 * if one does not exist , it will get created.
18111 * @param {string} the navgroup to add
18112 * @returns {Roo.bootstrap.NavGroup} the navgroup
18114 get: function(navId) {
18115 if (typeof(this.groups[navId]) == 'undefined') {
18116 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18118 return this.groups[navId] ;
18133 * @class Roo.bootstrap.TabPanel
18134 * @extends Roo.bootstrap.Component
18135 * Bootstrap TabPanel class
18136 * @cfg {Boolean} active panel active
18137 * @cfg {String} html panel content
18138 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18139 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18140 * @cfg {String} href click to link..
18144 * Create a new TabPanel
18145 * @param {Object} config The config object
18148 Roo.bootstrap.TabPanel = function(config){
18149 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18153 * Fires when the active status changes
18154 * @param {Roo.bootstrap.TabPanel} this
18155 * @param {Boolean} state the new state
18160 * @event beforedeactivate
18161 * Fires before a tab is de-activated - can be used to do validation on a form.
18162 * @param {Roo.bootstrap.TabPanel} this
18163 * @return {Boolean} false if there is an error
18166 'beforedeactivate': true
18169 this.tabId = this.tabId || Roo.id();
18173 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18181 getAutoCreate : function(){
18184 // item is needed for carousel - not sure if it has any effect otherwise
18185 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18186 html: this.html || ''
18190 cfg.cls += ' active';
18194 cfg.tabId = this.tabId;
18201 initEvents: function()
18203 var p = this.parent();
18205 this.navId = this.navId || p.navId;
18207 if (typeof(this.navId) != 'undefined') {
18208 // not really needed.. but just in case.. parent should be a NavGroup.
18209 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18213 var i = tg.tabs.length - 1;
18215 if(this.active && tg.bullets > 0 && i < tg.bullets){
18216 tg.setActiveBullet(i);
18220 this.el.on('click', this.onClick, this);
18223 this.el.on("touchstart", this.onTouchStart, this);
18224 this.el.on("touchmove", this.onTouchMove, this);
18225 this.el.on("touchend", this.onTouchEnd, this);
18230 onRender : function(ct, position)
18232 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18235 setActive : function(state)
18237 Roo.log("panel - set active " + this.tabId + "=" + state);
18239 this.active = state;
18241 this.el.removeClass('active');
18243 } else if (!this.el.hasClass('active')) {
18244 this.el.addClass('active');
18247 this.fireEvent('changed', this, state);
18250 onClick : function(e)
18252 e.preventDefault();
18254 if(!this.href.length){
18258 window.location.href = this.href;
18267 onTouchStart : function(e)
18269 this.swiping = false;
18271 this.startX = e.browserEvent.touches[0].clientX;
18272 this.startY = e.browserEvent.touches[0].clientY;
18275 onTouchMove : function(e)
18277 this.swiping = true;
18279 this.endX = e.browserEvent.touches[0].clientX;
18280 this.endY = e.browserEvent.touches[0].clientY;
18283 onTouchEnd : function(e)
18290 var tabGroup = this.parent();
18292 if(this.endX > this.startX){ // swiping right
18293 tabGroup.showPanelPrev();
18297 if(this.startX > this.endX){ // swiping left
18298 tabGroup.showPanelNext();
18317 * @class Roo.bootstrap.DateField
18318 * @extends Roo.bootstrap.Input
18319 * Bootstrap DateField class
18320 * @cfg {Number} weekStart default 0
18321 * @cfg {String} viewMode default empty, (months|years)
18322 * @cfg {String} minViewMode default empty, (months|years)
18323 * @cfg {Number} startDate default -Infinity
18324 * @cfg {Number} endDate default Infinity
18325 * @cfg {Boolean} todayHighlight default false
18326 * @cfg {Boolean} todayBtn default false
18327 * @cfg {Boolean} calendarWeeks default false
18328 * @cfg {Object} daysOfWeekDisabled default empty
18329 * @cfg {Boolean} singleMode default false (true | false)
18331 * @cfg {Boolean} keyboardNavigation default true
18332 * @cfg {String} language default en
18335 * Create a new DateField
18336 * @param {Object} config The config object
18339 Roo.bootstrap.DateField = function(config){
18340 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18344 * Fires when this field show.
18345 * @param {Roo.bootstrap.DateField} this
18346 * @param {Mixed} date The date value
18351 * Fires when this field hide.
18352 * @param {Roo.bootstrap.DateField} this
18353 * @param {Mixed} date The date value
18358 * Fires when select a date.
18359 * @param {Roo.bootstrap.DateField} this
18360 * @param {Mixed} date The date value
18364 * @event beforeselect
18365 * Fires when before select a date.
18366 * @param {Roo.bootstrap.DateField} this
18367 * @param {Mixed} date The date value
18369 beforeselect : true
18373 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18376 * @cfg {String} format
18377 * The default date format string which can be overriden for localization support. The format must be
18378 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18382 * @cfg {String} altFormats
18383 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18384 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18386 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18394 todayHighlight : false,
18400 keyboardNavigation: true,
18402 calendarWeeks: false,
18404 startDate: -Infinity,
18408 daysOfWeekDisabled: [],
18412 singleMode : false,
18414 UTCDate: function()
18416 return new Date(Date.UTC.apply(Date, arguments));
18419 UTCToday: function()
18421 var today = new Date();
18422 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18425 getDate: function() {
18426 var d = this.getUTCDate();
18427 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18430 getUTCDate: function() {
18434 setDate: function(d) {
18435 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18438 setUTCDate: function(d) {
18440 this.setValue(this.formatDate(this.date));
18443 onRender: function(ct, position)
18446 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18448 this.language = this.language || 'en';
18449 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18450 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18452 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18453 this.format = this.format || 'm/d/y';
18454 this.isInline = false;
18455 this.isInput = true;
18456 this.component = this.el.select('.add-on', true).first() || false;
18457 this.component = (this.component && this.component.length === 0) ? false : this.component;
18458 this.hasInput = this.component && this.inputEl().length;
18460 if (typeof(this.minViewMode === 'string')) {
18461 switch (this.minViewMode) {
18463 this.minViewMode = 1;
18466 this.minViewMode = 2;
18469 this.minViewMode = 0;
18474 if (typeof(this.viewMode === 'string')) {
18475 switch (this.viewMode) {
18488 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18490 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18492 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18494 this.picker().on('mousedown', this.onMousedown, this);
18495 this.picker().on('click', this.onClick, this);
18497 this.picker().addClass('datepicker-dropdown');
18499 this.startViewMode = this.viewMode;
18501 if(this.singleMode){
18502 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18503 v.setVisibilityMode(Roo.Element.DISPLAY);
18507 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18508 v.setStyle('width', '189px');
18512 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18513 if(!this.calendarWeeks){
18518 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18519 v.attr('colspan', function(i, val){
18520 return parseInt(val) + 1;
18525 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18527 this.setStartDate(this.startDate);
18528 this.setEndDate(this.endDate);
18530 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18537 if(this.isInline) {
18542 picker : function()
18544 return this.pickerEl;
18545 // return this.el.select('.datepicker', true).first();
18548 fillDow: function()
18550 var dowCnt = this.weekStart;
18559 if(this.calendarWeeks){
18567 while (dowCnt < this.weekStart + 7) {
18571 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18575 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18578 fillMonths: function()
18581 var months = this.picker().select('>.datepicker-months td', true).first();
18583 months.dom.innerHTML = '';
18589 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18592 months.createChild(month);
18599 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;
18601 if (this.date < this.startDate) {
18602 this.viewDate = new Date(this.startDate);
18603 } else if (this.date > this.endDate) {
18604 this.viewDate = new Date(this.endDate);
18606 this.viewDate = new Date(this.date);
18614 var d = new Date(this.viewDate),
18615 year = d.getUTCFullYear(),
18616 month = d.getUTCMonth(),
18617 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18618 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18619 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18620 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18621 currentDate = this.date && this.date.valueOf(),
18622 today = this.UTCToday();
18624 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18626 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18628 // this.picker.select('>tfoot th.today').
18629 // .text(dates[this.language].today)
18630 // .toggle(this.todayBtn !== false);
18632 this.updateNavArrows();
18635 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18637 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18639 prevMonth.setUTCDate(day);
18641 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18643 var nextMonth = new Date(prevMonth);
18645 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18647 nextMonth = nextMonth.valueOf();
18649 var fillMonths = false;
18651 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18653 while(prevMonth.valueOf() < nextMonth) {
18656 if (prevMonth.getUTCDay() === this.weekStart) {
18658 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18666 if(this.calendarWeeks){
18667 // ISO 8601: First week contains first thursday.
18668 // ISO also states week starts on Monday, but we can be more abstract here.
18670 // Start of current week: based on weekstart/current date
18671 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18672 // Thursday of this week
18673 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18674 // First Thursday of year, year from thursday
18675 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18676 // Calendar week: ms between thursdays, div ms per day, div 7 days
18677 calWeek = (th - yth) / 864e5 / 7 + 1;
18679 fillMonths.cn.push({
18687 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18689 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18692 if (this.todayHighlight &&
18693 prevMonth.getUTCFullYear() == today.getFullYear() &&
18694 prevMonth.getUTCMonth() == today.getMonth() &&
18695 prevMonth.getUTCDate() == today.getDate()) {
18696 clsName += ' today';
18699 if (currentDate && prevMonth.valueOf() === currentDate) {
18700 clsName += ' active';
18703 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18704 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18705 clsName += ' disabled';
18708 fillMonths.cn.push({
18710 cls: 'day ' + clsName,
18711 html: prevMonth.getDate()
18714 prevMonth.setDate(prevMonth.getDate()+1);
18717 var currentYear = this.date && this.date.getUTCFullYear();
18718 var currentMonth = this.date && this.date.getUTCMonth();
18720 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18722 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18723 v.removeClass('active');
18725 if(currentYear === year && k === currentMonth){
18726 v.addClass('active');
18729 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18730 v.addClass('disabled');
18736 year = parseInt(year/10, 10) * 10;
18738 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18740 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18743 for (var i = -1; i < 11; i++) {
18744 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18746 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18754 showMode: function(dir)
18757 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18760 Roo.each(this.picker().select('>div',true).elements, function(v){
18761 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18764 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18769 if(this.isInline) {
18773 this.picker().removeClass(['bottom', 'top']);
18775 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18777 * place to the top of element!
18781 this.picker().addClass('top');
18782 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18787 this.picker().addClass('bottom');
18789 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18792 parseDate : function(value)
18794 if(!value || value instanceof Date){
18797 var v = Date.parseDate(value, this.format);
18798 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18799 v = Date.parseDate(value, 'Y-m-d');
18801 if(!v && this.altFormats){
18802 if(!this.altFormatsArray){
18803 this.altFormatsArray = this.altFormats.split("|");
18805 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18806 v = Date.parseDate(value, this.altFormatsArray[i]);
18812 formatDate : function(date, fmt)
18814 return (!date || !(date instanceof Date)) ?
18815 date : date.dateFormat(fmt || this.format);
18818 onFocus : function()
18820 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18824 onBlur : function()
18826 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18828 var d = this.inputEl().getValue();
18837 this.picker().show();
18841 this.fireEvent('show', this, this.date);
18846 if(this.isInline) {
18849 this.picker().hide();
18850 this.viewMode = this.startViewMode;
18853 this.fireEvent('hide', this, this.date);
18857 onMousedown: function(e)
18859 e.stopPropagation();
18860 e.preventDefault();
18865 Roo.bootstrap.DateField.superclass.keyup.call(this);
18869 setValue: function(v)
18871 if(this.fireEvent('beforeselect', this, v) !== false){
18872 var d = new Date(this.parseDate(v) ).clearTime();
18874 if(isNaN(d.getTime())){
18875 this.date = this.viewDate = '';
18876 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18880 v = this.formatDate(d);
18882 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18884 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18888 this.fireEvent('select', this, this.date);
18892 getValue: function()
18894 return this.formatDate(this.date);
18897 fireKey: function(e)
18899 if (!this.picker().isVisible()){
18900 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18906 var dateChanged = false,
18908 newDate, newViewDate;
18913 e.preventDefault();
18917 if (!this.keyboardNavigation) {
18920 dir = e.keyCode == 37 ? -1 : 1;
18923 newDate = this.moveYear(this.date, dir);
18924 newViewDate = this.moveYear(this.viewDate, dir);
18925 } else if (e.shiftKey){
18926 newDate = this.moveMonth(this.date, dir);
18927 newViewDate = this.moveMonth(this.viewDate, dir);
18929 newDate = new Date(this.date);
18930 newDate.setUTCDate(this.date.getUTCDate() + dir);
18931 newViewDate = new Date(this.viewDate);
18932 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18934 if (this.dateWithinRange(newDate)){
18935 this.date = newDate;
18936 this.viewDate = newViewDate;
18937 this.setValue(this.formatDate(this.date));
18939 e.preventDefault();
18940 dateChanged = true;
18945 if (!this.keyboardNavigation) {
18948 dir = e.keyCode == 38 ? -1 : 1;
18950 newDate = this.moveYear(this.date, dir);
18951 newViewDate = this.moveYear(this.viewDate, dir);
18952 } else if (e.shiftKey){
18953 newDate = this.moveMonth(this.date, dir);
18954 newViewDate = this.moveMonth(this.viewDate, dir);
18956 newDate = new Date(this.date);
18957 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18958 newViewDate = new Date(this.viewDate);
18959 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18961 if (this.dateWithinRange(newDate)){
18962 this.date = newDate;
18963 this.viewDate = newViewDate;
18964 this.setValue(this.formatDate(this.date));
18966 e.preventDefault();
18967 dateChanged = true;
18971 this.setValue(this.formatDate(this.date));
18973 e.preventDefault();
18976 this.setValue(this.formatDate(this.date));
18990 onClick: function(e)
18992 e.stopPropagation();
18993 e.preventDefault();
18995 var target = e.getTarget();
18997 if(target.nodeName.toLowerCase() === 'i'){
18998 target = Roo.get(target).dom.parentNode;
19001 var nodeName = target.nodeName;
19002 var className = target.className;
19003 var html = target.innerHTML;
19004 //Roo.log(nodeName);
19006 switch(nodeName.toLowerCase()) {
19008 switch(className) {
19014 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19015 switch(this.viewMode){
19017 this.viewDate = this.moveMonth(this.viewDate, dir);
19021 this.viewDate = this.moveYear(this.viewDate, dir);
19027 var date = new Date();
19028 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19030 this.setValue(this.formatDate(this.date));
19037 if (className.indexOf('disabled') < 0) {
19038 this.viewDate.setUTCDate(1);
19039 if (className.indexOf('month') > -1) {
19040 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19042 var year = parseInt(html, 10) || 0;
19043 this.viewDate.setUTCFullYear(year);
19047 if(this.singleMode){
19048 this.setValue(this.formatDate(this.viewDate));
19059 //Roo.log(className);
19060 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19061 var day = parseInt(html, 10) || 1;
19062 var year = this.viewDate.getUTCFullYear(),
19063 month = this.viewDate.getUTCMonth();
19065 if (className.indexOf('old') > -1) {
19072 } else if (className.indexOf('new') > -1) {
19080 //Roo.log([year,month,day]);
19081 this.date = this.UTCDate(year, month, day,0,0,0,0);
19082 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19084 //Roo.log(this.formatDate(this.date));
19085 this.setValue(this.formatDate(this.date));
19092 setStartDate: function(startDate)
19094 this.startDate = startDate || -Infinity;
19095 if (this.startDate !== -Infinity) {
19096 this.startDate = this.parseDate(this.startDate);
19099 this.updateNavArrows();
19102 setEndDate: function(endDate)
19104 this.endDate = endDate || Infinity;
19105 if (this.endDate !== Infinity) {
19106 this.endDate = this.parseDate(this.endDate);
19109 this.updateNavArrows();
19112 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19114 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19115 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19116 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19118 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19119 return parseInt(d, 10);
19122 this.updateNavArrows();
19125 updateNavArrows: function()
19127 if(this.singleMode){
19131 var d = new Date(this.viewDate),
19132 year = d.getUTCFullYear(),
19133 month = d.getUTCMonth();
19135 Roo.each(this.picker().select('.prev', true).elements, function(v){
19137 switch (this.viewMode) {
19140 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19146 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19153 Roo.each(this.picker().select('.next', true).elements, function(v){
19155 switch (this.viewMode) {
19158 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19164 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19172 moveMonth: function(date, dir)
19177 var new_date = new Date(date.valueOf()),
19178 day = new_date.getUTCDate(),
19179 month = new_date.getUTCMonth(),
19180 mag = Math.abs(dir),
19182 dir = dir > 0 ? 1 : -1;
19185 // If going back one month, make sure month is not current month
19186 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19188 return new_date.getUTCMonth() == month;
19190 // If going forward one month, make sure month is as expected
19191 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19193 return new_date.getUTCMonth() != new_month;
19195 new_month = month + dir;
19196 new_date.setUTCMonth(new_month);
19197 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19198 if (new_month < 0 || new_month > 11) {
19199 new_month = (new_month + 12) % 12;
19202 // For magnitudes >1, move one month at a time...
19203 for (var i=0; i<mag; i++) {
19204 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19205 new_date = this.moveMonth(new_date, dir);
19207 // ...then reset the day, keeping it in the new month
19208 new_month = new_date.getUTCMonth();
19209 new_date.setUTCDate(day);
19211 return new_month != new_date.getUTCMonth();
19214 // Common date-resetting loop -- if date is beyond end of month, make it
19217 new_date.setUTCDate(--day);
19218 new_date.setUTCMonth(new_month);
19223 moveYear: function(date, dir)
19225 return this.moveMonth(date, dir*12);
19228 dateWithinRange: function(date)
19230 return date >= this.startDate && date <= this.endDate;
19236 this.picker().remove();
19239 validateValue : function(value)
19241 if(this.getVisibilityEl().hasClass('hidden')){
19245 if(value.length < 1) {
19246 if(this.allowBlank){
19252 if(value.length < this.minLength){
19255 if(value.length > this.maxLength){
19259 var vt = Roo.form.VTypes;
19260 if(!vt[this.vtype](value, this)){
19264 if(typeof this.validator == "function"){
19265 var msg = this.validator(value);
19271 if(this.regex && !this.regex.test(value)){
19275 if(typeof(this.parseDate(value)) == 'undefined'){
19279 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19283 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19291 setVisible : function(visible)
19297 this.getEl().removeClass('hidden');
19303 this.getEl().addClass('hidden');
19308 Roo.apply(Roo.bootstrap.DateField, {
19319 html: '<i class="fa fa-arrow-left"/>'
19329 html: '<i class="fa fa-arrow-right"/>'
19371 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19372 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19373 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19374 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19375 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19388 navFnc: 'FullYear',
19393 navFnc: 'FullYear',
19398 Roo.apply(Roo.bootstrap.DateField, {
19402 cls: 'datepicker dropdown-menu roo-dynamic',
19406 cls: 'datepicker-days',
19410 cls: 'table-condensed',
19412 Roo.bootstrap.DateField.head,
19416 Roo.bootstrap.DateField.footer
19423 cls: 'datepicker-months',
19427 cls: 'table-condensed',
19429 Roo.bootstrap.DateField.head,
19430 Roo.bootstrap.DateField.content,
19431 Roo.bootstrap.DateField.footer
19438 cls: 'datepicker-years',
19442 cls: 'table-condensed',
19444 Roo.bootstrap.DateField.head,
19445 Roo.bootstrap.DateField.content,
19446 Roo.bootstrap.DateField.footer
19465 * @class Roo.bootstrap.TimeField
19466 * @extends Roo.bootstrap.Input
19467 * Bootstrap DateField class
19471 * Create a new TimeField
19472 * @param {Object} config The config object
19475 Roo.bootstrap.TimeField = function(config){
19476 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19480 * Fires when this field show.
19481 * @param {Roo.bootstrap.DateField} thisthis
19482 * @param {Mixed} date The date value
19487 * Fires when this field hide.
19488 * @param {Roo.bootstrap.DateField} this
19489 * @param {Mixed} date The date value
19494 * Fires when select a date.
19495 * @param {Roo.bootstrap.DateField} this
19496 * @param {Mixed} date The date value
19502 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19505 * @cfg {String} format
19506 * The default time format string which can be overriden for localization support. The format must be
19507 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19511 onRender: function(ct, position)
19514 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19516 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19518 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19520 this.pop = this.picker().select('>.datepicker-time',true).first();
19521 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19523 this.picker().on('mousedown', this.onMousedown, this);
19524 this.picker().on('click', this.onClick, this);
19526 this.picker().addClass('datepicker-dropdown');
19531 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19532 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19533 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19534 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19535 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19536 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19540 fireKey: function(e){
19541 if (!this.picker().isVisible()){
19542 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19548 e.preventDefault();
19556 this.onTogglePeriod();
19559 this.onIncrementMinutes();
19562 this.onDecrementMinutes();
19571 onClick: function(e) {
19572 e.stopPropagation();
19573 e.preventDefault();
19576 picker : function()
19578 return this.el.select('.datepicker', true).first();
19581 fillTime: function()
19583 var time = this.pop.select('tbody', true).first();
19585 time.dom.innerHTML = '';
19600 cls: 'hours-up glyphicon glyphicon-chevron-up'
19620 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19641 cls: 'timepicker-hour',
19656 cls: 'timepicker-minute',
19671 cls: 'btn btn-primary period',
19693 cls: 'hours-down glyphicon glyphicon-chevron-down'
19713 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19731 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19738 var hours = this.time.getHours();
19739 var minutes = this.time.getMinutes();
19752 hours = hours - 12;
19756 hours = '0' + hours;
19760 minutes = '0' + minutes;
19763 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19764 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19765 this.pop.select('button', true).first().dom.innerHTML = period;
19771 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19773 var cls = ['bottom'];
19775 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19782 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19787 this.picker().addClass(cls.join('-'));
19791 Roo.each(cls, function(c){
19793 _this.picker().setTop(_this.inputEl().getHeight());
19797 _this.picker().setTop(0 - _this.picker().getHeight());
19802 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19806 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19813 onFocus : function()
19815 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19819 onBlur : function()
19821 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19827 this.picker().show();
19832 this.fireEvent('show', this, this.date);
19837 this.picker().hide();
19840 this.fireEvent('hide', this, this.date);
19843 setTime : function()
19846 this.setValue(this.time.format(this.format));
19848 this.fireEvent('select', this, this.date);
19853 onMousedown: function(e){
19854 e.stopPropagation();
19855 e.preventDefault();
19858 onIncrementHours: function()
19860 Roo.log('onIncrementHours');
19861 this.time = this.time.add(Date.HOUR, 1);
19866 onDecrementHours: function()
19868 Roo.log('onDecrementHours');
19869 this.time = this.time.add(Date.HOUR, -1);
19873 onIncrementMinutes: function()
19875 Roo.log('onIncrementMinutes');
19876 this.time = this.time.add(Date.MINUTE, 1);
19880 onDecrementMinutes: function()
19882 Roo.log('onDecrementMinutes');
19883 this.time = this.time.add(Date.MINUTE, -1);
19887 onTogglePeriod: function()
19889 Roo.log('onTogglePeriod');
19890 this.time = this.time.add(Date.HOUR, 12);
19897 Roo.apply(Roo.bootstrap.TimeField, {
19927 cls: 'btn btn-info ok',
19939 Roo.apply(Roo.bootstrap.TimeField, {
19943 cls: 'datepicker dropdown-menu',
19947 cls: 'datepicker-time',
19951 cls: 'table-condensed',
19953 Roo.bootstrap.TimeField.content,
19954 Roo.bootstrap.TimeField.footer
19973 * @class Roo.bootstrap.MonthField
19974 * @extends Roo.bootstrap.Input
19975 * Bootstrap MonthField class
19977 * @cfg {String} language default en
19980 * Create a new MonthField
19981 * @param {Object} config The config object
19984 Roo.bootstrap.MonthField = function(config){
19985 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19990 * Fires when this field show.
19991 * @param {Roo.bootstrap.MonthField} this
19992 * @param {Mixed} date The date value
19997 * Fires when this field hide.
19998 * @param {Roo.bootstrap.MonthField} this
19999 * @param {Mixed} date The date value
20004 * Fires when select a date.
20005 * @param {Roo.bootstrap.MonthField} this
20006 * @param {String} oldvalue The old value
20007 * @param {String} newvalue The new value
20013 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20015 onRender: function(ct, position)
20018 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20020 this.language = this.language || 'en';
20021 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20022 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20024 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20025 this.isInline = false;
20026 this.isInput = true;
20027 this.component = this.el.select('.add-on', true).first() || false;
20028 this.component = (this.component && this.component.length === 0) ? false : this.component;
20029 this.hasInput = this.component && this.inputEL().length;
20031 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20033 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20035 this.picker().on('mousedown', this.onMousedown, this);
20036 this.picker().on('click', this.onClick, this);
20038 this.picker().addClass('datepicker-dropdown');
20040 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20041 v.setStyle('width', '189px');
20048 if(this.isInline) {
20054 setValue: function(v, suppressEvent)
20056 var o = this.getValue();
20058 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20062 if(suppressEvent !== true){
20063 this.fireEvent('select', this, o, v);
20068 getValue: function()
20073 onClick: function(e)
20075 e.stopPropagation();
20076 e.preventDefault();
20078 var target = e.getTarget();
20080 if(target.nodeName.toLowerCase() === 'i'){
20081 target = Roo.get(target).dom.parentNode;
20084 var nodeName = target.nodeName;
20085 var className = target.className;
20086 var html = target.innerHTML;
20088 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20092 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20094 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20100 picker : function()
20102 return this.pickerEl;
20105 fillMonths: function()
20108 var months = this.picker().select('>.datepicker-months td', true).first();
20110 months.dom.innerHTML = '';
20116 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20119 months.createChild(month);
20128 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20129 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20132 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20133 e.removeClass('active');
20135 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20136 e.addClass('active');
20143 if(this.isInline) {
20147 this.picker().removeClass(['bottom', 'top']);
20149 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20151 * place to the top of element!
20155 this.picker().addClass('top');
20156 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20161 this.picker().addClass('bottom');
20163 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20166 onFocus : function()
20168 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20172 onBlur : function()
20174 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20176 var d = this.inputEl().getValue();
20185 this.picker().show();
20186 this.picker().select('>.datepicker-months', true).first().show();
20190 this.fireEvent('show', this, this.date);
20195 if(this.isInline) {
20198 this.picker().hide();
20199 this.fireEvent('hide', this, this.date);
20203 onMousedown: function(e)
20205 e.stopPropagation();
20206 e.preventDefault();
20211 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20215 fireKey: function(e)
20217 if (!this.picker().isVisible()){
20218 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20229 e.preventDefault();
20233 dir = e.keyCode == 37 ? -1 : 1;
20235 this.vIndex = this.vIndex + dir;
20237 if(this.vIndex < 0){
20241 if(this.vIndex > 11){
20245 if(isNaN(this.vIndex)){
20249 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20255 dir = e.keyCode == 38 ? -1 : 1;
20257 this.vIndex = this.vIndex + dir * 4;
20259 if(this.vIndex < 0){
20263 if(this.vIndex > 11){
20267 if(isNaN(this.vIndex)){
20271 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20276 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20277 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20281 e.preventDefault();
20284 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20285 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20301 this.picker().remove();
20306 Roo.apply(Roo.bootstrap.MonthField, {
20325 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20326 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20331 Roo.apply(Roo.bootstrap.MonthField, {
20335 cls: 'datepicker dropdown-menu roo-dynamic',
20339 cls: 'datepicker-months',
20343 cls: 'table-condensed',
20345 Roo.bootstrap.DateField.content
20365 * @class Roo.bootstrap.CheckBox
20366 * @extends Roo.bootstrap.Input
20367 * Bootstrap CheckBox class
20369 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20370 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20371 * @cfg {String} boxLabel The text that appears beside the checkbox
20372 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20373 * @cfg {Boolean} checked initnal the element
20374 * @cfg {Boolean} inline inline the element (default false)
20375 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20376 * @cfg {String} tooltip label tooltip
20379 * Create a new CheckBox
20380 * @param {Object} config The config object
20383 Roo.bootstrap.CheckBox = function(config){
20384 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20389 * Fires when the element is checked or unchecked.
20390 * @param {Roo.bootstrap.CheckBox} this This input
20391 * @param {Boolean} checked The new checked value
20396 * Fires when the element is click.
20397 * @param {Roo.bootstrap.CheckBox} this This input
20404 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20406 inputType: 'checkbox',
20415 getAutoCreate : function()
20417 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20423 cfg.cls = 'form-group ' + this.inputType; //input-group
20426 cfg.cls += ' ' + this.inputType + '-inline';
20432 type : this.inputType,
20433 value : this.inputValue,
20434 cls : 'roo-' + this.inputType, //'form-box',
20435 placeholder : this.placeholder || ''
20439 if(this.inputType != 'radio'){
20443 cls : 'roo-hidden-value',
20444 value : this.checked ? this.inputValue : this.valueOff
20449 if (this.weight) { // Validity check?
20450 cfg.cls += " " + this.inputType + "-" + this.weight;
20453 if (this.disabled) {
20454 input.disabled=true;
20458 input.checked = this.checked;
20463 input.name = this.name;
20465 if(this.inputType != 'radio'){
20466 hidden.name = this.name;
20467 input.name = '_hidden_' + this.name;
20472 input.cls += ' input-' + this.size;
20477 ['xs','sm','md','lg'].map(function(size){
20478 if (settings[size]) {
20479 cfg.cls += ' col-' + size + '-' + settings[size];
20483 var inputblock = input;
20485 if (this.before || this.after) {
20488 cls : 'input-group',
20493 inputblock.cn.push({
20495 cls : 'input-group-addon',
20500 inputblock.cn.push(input);
20502 if(this.inputType != 'radio'){
20503 inputblock.cn.push(hidden);
20507 inputblock.cn.push({
20509 cls : 'input-group-addon',
20516 if (align ==='left' && this.fieldLabel.length) {
20517 // Roo.log("left and has label");
20522 cls : 'control-label',
20523 html : this.fieldLabel
20533 if(this.labelWidth > 12){
20534 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20537 if(this.labelWidth < 13 && this.labelmd == 0){
20538 this.labelmd = this.labelWidth;
20541 if(this.labellg > 0){
20542 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20543 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20546 if(this.labelmd > 0){
20547 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20548 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20551 if(this.labelsm > 0){
20552 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20553 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20556 if(this.labelxs > 0){
20557 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20558 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20561 } else if ( this.fieldLabel.length) {
20562 // Roo.log(" label");
20566 tag: this.boxLabel ? 'span' : 'label',
20568 cls: 'control-label box-input-label',
20569 //cls : 'input-group-addon',
20570 html : this.fieldLabel
20579 // Roo.log(" no label && no align");
20580 cfg.cn = [ inputblock ] ;
20586 var boxLabelCfg = {
20588 //'for': id, // box label is handled by onclick - so no for...
20590 html: this.boxLabel
20594 boxLabelCfg.tooltip = this.tooltip;
20597 cfg.cn.push(boxLabelCfg);
20600 if(this.inputType != 'radio'){
20601 cfg.cn.push(hidden);
20609 * return the real input element.
20611 inputEl: function ()
20613 return this.el.select('input.roo-' + this.inputType,true).first();
20615 hiddenEl: function ()
20617 return this.el.select('input.roo-hidden-value',true).first();
20620 labelEl: function()
20622 return this.el.select('label.control-label',true).first();
20624 /* depricated... */
20628 return this.labelEl();
20631 boxLabelEl: function()
20633 return this.el.select('label.box-label',true).first();
20636 initEvents : function()
20638 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20640 this.inputEl().on('click', this.onClick, this);
20642 if (this.boxLabel) {
20643 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20646 this.startValue = this.getValue();
20649 Roo.bootstrap.CheckBox.register(this);
20653 onClick : function(e)
20655 if(this.fireEvent('click', this, e) !== false){
20656 this.setChecked(!this.checked);
20661 setChecked : function(state,suppressEvent)
20663 this.startValue = this.getValue();
20665 if(this.inputType == 'radio'){
20667 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20668 e.dom.checked = false;
20671 this.inputEl().dom.checked = true;
20673 this.inputEl().dom.value = this.inputValue;
20675 if(suppressEvent !== true){
20676 this.fireEvent('check', this, true);
20684 this.checked = state;
20686 this.inputEl().dom.checked = state;
20689 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20691 if(suppressEvent !== true){
20692 this.fireEvent('check', this, state);
20698 getValue : function()
20700 if(this.inputType == 'radio'){
20701 return this.getGroupValue();
20704 return this.hiddenEl().dom.value;
20708 getGroupValue : function()
20710 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20714 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20717 setValue : function(v,suppressEvent)
20719 if(this.inputType == 'radio'){
20720 this.setGroupValue(v, suppressEvent);
20724 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20729 setGroupValue : function(v, suppressEvent)
20731 this.startValue = this.getValue();
20733 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20734 e.dom.checked = false;
20736 if(e.dom.value == v){
20737 e.dom.checked = true;
20741 if(suppressEvent !== true){
20742 this.fireEvent('check', this, true);
20750 validate : function()
20752 if(this.getVisibilityEl().hasClass('hidden')){
20758 (this.inputType == 'radio' && this.validateRadio()) ||
20759 (this.inputType == 'checkbox' && this.validateCheckbox())
20765 this.markInvalid();
20769 validateRadio : function()
20771 if(this.getVisibilityEl().hasClass('hidden')){
20775 if(this.allowBlank){
20781 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20782 if(!e.dom.checked){
20794 validateCheckbox : function()
20797 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20798 //return (this.getValue() == this.inputValue) ? true : false;
20801 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20809 for(var i in group){
20810 if(group[i].el.isVisible(true)){
20818 for(var i in group){
20823 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20830 * Mark this field as valid
20832 markValid : function()
20836 this.fireEvent('valid', this);
20838 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20841 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20848 if(this.inputType == 'radio'){
20849 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20850 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20851 e.findParent('.form-group', false, true).addClass(_this.validClass);
20858 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20859 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20863 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20869 for(var i in group){
20870 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20871 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20876 * Mark this field as invalid
20877 * @param {String} msg The validation message
20879 markInvalid : function(msg)
20881 if(this.allowBlank){
20887 this.fireEvent('invalid', this, msg);
20889 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20892 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20896 label.markInvalid();
20899 if(this.inputType == 'radio'){
20900 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20901 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20902 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20909 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20910 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20914 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20920 for(var i in group){
20921 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20922 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20927 clearInvalid : function()
20929 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20931 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20933 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20935 if (label && label.iconEl) {
20936 label.iconEl.removeClass(label.validClass);
20937 label.iconEl.removeClass(label.invalidClass);
20941 disable : function()
20943 if(this.inputType != 'radio'){
20944 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20951 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20952 _this.getActionEl().addClass(this.disabledClass);
20953 e.dom.disabled = true;
20957 this.disabled = true;
20958 this.fireEvent("disable", this);
20962 enable : function()
20964 if(this.inputType != 'radio'){
20965 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20972 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20973 _this.getActionEl().removeClass(this.disabledClass);
20974 e.dom.disabled = false;
20978 this.disabled = false;
20979 this.fireEvent("enable", this);
20983 setBoxLabel : function(v)
20988 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20994 Roo.apply(Roo.bootstrap.CheckBox, {
20999 * register a CheckBox Group
21000 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21002 register : function(checkbox)
21004 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21005 this.groups[checkbox.groupId] = {};
21008 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21012 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21016 * fetch a CheckBox Group based on the group ID
21017 * @param {string} the group ID
21018 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21020 get: function(groupId) {
21021 if (typeof(this.groups[groupId]) == 'undefined') {
21025 return this.groups[groupId] ;
21038 * @class Roo.bootstrap.Radio
21039 * @extends Roo.bootstrap.Component
21040 * Bootstrap Radio class
21041 * @cfg {String} boxLabel - the label associated
21042 * @cfg {String} value - the value of radio
21045 * Create a new Radio
21046 * @param {Object} config The config object
21048 Roo.bootstrap.Radio = function(config){
21049 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21053 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21059 getAutoCreate : function()
21063 cls : 'form-group radio',
21068 html : this.boxLabel
21076 initEvents : function()
21078 this.parent().register(this);
21080 this.el.on('click', this.onClick, this);
21084 onClick : function(e)
21086 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21087 this.setChecked(true);
21091 setChecked : function(state, suppressEvent)
21093 this.parent().setValue(this.value, suppressEvent);
21097 setBoxLabel : function(v)
21102 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21117 * @class Roo.bootstrap.SecurePass
21118 * @extends Roo.bootstrap.Input
21119 * Bootstrap SecurePass class
21123 * Create a new SecurePass
21124 * @param {Object} config The config object
21127 Roo.bootstrap.SecurePass = function (config) {
21128 // these go here, so the translation tool can replace them..
21130 PwdEmpty: "Please type a password, and then retype it to confirm.",
21131 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21132 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21133 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21134 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21135 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21136 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21137 TooWeak: "Your password is Too Weak."
21139 this.meterLabel = "Password strength:";
21140 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21141 this.meterClass = [
21142 "roo-password-meter-tooweak",
21143 "roo-password-meter-weak",
21144 "roo-password-meter-medium",
21145 "roo-password-meter-strong",
21146 "roo-password-meter-grey"
21151 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21154 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21156 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21158 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21159 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21160 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21161 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21162 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21163 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21164 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21174 * @cfg {String/Object} Label for the strength meter (defaults to
21175 * 'Password strength:')
21180 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21181 * ['Weak', 'Medium', 'Strong'])
21184 pwdStrengths: false,
21197 initEvents: function ()
21199 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21201 if (this.el.is('input[type=password]') && Roo.isSafari) {
21202 this.el.on('keydown', this.SafariOnKeyDown, this);
21205 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21208 onRender: function (ct, position)
21210 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21211 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21212 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21214 this.trigger.createChild({
21219 cls: 'roo-password-meter-grey col-xs-12',
21222 //width: this.meterWidth + 'px'
21226 cls: 'roo-password-meter-text'
21232 if (this.hideTrigger) {
21233 this.trigger.setDisplayed(false);
21235 this.setSize(this.width || '', this.height || '');
21238 onDestroy: function ()
21240 if (this.trigger) {
21241 this.trigger.removeAllListeners();
21242 this.trigger.remove();
21245 this.wrap.remove();
21247 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21250 checkStrength: function ()
21252 var pwd = this.inputEl().getValue();
21253 if (pwd == this._lastPwd) {
21258 if (this.ClientSideStrongPassword(pwd)) {
21260 } else if (this.ClientSideMediumPassword(pwd)) {
21262 } else if (this.ClientSideWeakPassword(pwd)) {
21268 Roo.log('strength1: ' + strength);
21270 //var pm = this.trigger.child('div/div/div').dom;
21271 var pm = this.trigger.child('div/div');
21272 pm.removeClass(this.meterClass);
21273 pm.addClass(this.meterClass[strength]);
21276 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21278 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21280 this._lastPwd = pwd;
21284 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21286 this._lastPwd = '';
21288 var pm = this.trigger.child('div/div');
21289 pm.removeClass(this.meterClass);
21290 pm.addClass('roo-password-meter-grey');
21293 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21296 this.inputEl().dom.type='password';
21299 validateValue: function (value)
21302 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21305 if (value.length == 0) {
21306 if (this.allowBlank) {
21307 this.clearInvalid();
21311 this.markInvalid(this.errors.PwdEmpty);
21312 this.errorMsg = this.errors.PwdEmpty;
21320 if ('[\x21-\x7e]*'.match(value)) {
21321 this.markInvalid(this.errors.PwdBadChar);
21322 this.errorMsg = this.errors.PwdBadChar;
21325 if (value.length < 6) {
21326 this.markInvalid(this.errors.PwdShort);
21327 this.errorMsg = this.errors.PwdShort;
21330 if (value.length > 16) {
21331 this.markInvalid(this.errors.PwdLong);
21332 this.errorMsg = this.errors.PwdLong;
21336 if (this.ClientSideStrongPassword(value)) {
21338 } else if (this.ClientSideMediumPassword(value)) {
21340 } else if (this.ClientSideWeakPassword(value)) {
21347 if (strength < 2) {
21348 //this.markInvalid(this.errors.TooWeak);
21349 this.errorMsg = this.errors.TooWeak;
21354 console.log('strength2: ' + strength);
21356 //var pm = this.trigger.child('div/div/div').dom;
21358 var pm = this.trigger.child('div/div');
21359 pm.removeClass(this.meterClass);
21360 pm.addClass(this.meterClass[strength]);
21362 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21364 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21366 this.errorMsg = '';
21370 CharacterSetChecks: function (type)
21373 this.fResult = false;
21376 isctype: function (character, type)
21379 case this.kCapitalLetter:
21380 if (character >= 'A' && character <= 'Z') {
21385 case this.kSmallLetter:
21386 if (character >= 'a' && character <= 'z') {
21392 if (character >= '0' && character <= '9') {
21397 case this.kPunctuation:
21398 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21409 IsLongEnough: function (pwd, size)
21411 return !(pwd == null || isNaN(size) || pwd.length < size);
21414 SpansEnoughCharacterSets: function (word, nb)
21416 if (!this.IsLongEnough(word, nb))
21421 var characterSetChecks = new Array(
21422 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21423 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21426 for (var index = 0; index < word.length; ++index) {
21427 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21428 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21429 characterSetChecks[nCharSet].fResult = true;
21436 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21437 if (characterSetChecks[nCharSet].fResult) {
21442 if (nCharSets < nb) {
21448 ClientSideStrongPassword: function (pwd)
21450 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21453 ClientSideMediumPassword: function (pwd)
21455 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21458 ClientSideWeakPassword: function (pwd)
21460 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21463 })//<script type="text/javascript">
21466 * Based Ext JS Library 1.1.1
21467 * Copyright(c) 2006-2007, Ext JS, LLC.
21473 * @class Roo.HtmlEditorCore
21474 * @extends Roo.Component
21475 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21477 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21480 Roo.HtmlEditorCore = function(config){
21483 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21488 * @event initialize
21489 * Fires when the editor is fully initialized (including the iframe)
21490 * @param {Roo.HtmlEditorCore} this
21495 * Fires when the editor is first receives the focus. Any insertion must wait
21496 * until after this event.
21497 * @param {Roo.HtmlEditorCore} this
21501 * @event beforesync
21502 * Fires before the textarea is updated with content from the editor iframe. Return false
21503 * to cancel the sync.
21504 * @param {Roo.HtmlEditorCore} this
21505 * @param {String} html
21509 * @event beforepush
21510 * Fires before the iframe editor is updated with content from the textarea. Return false
21511 * to cancel the push.
21512 * @param {Roo.HtmlEditorCore} this
21513 * @param {String} html
21518 * Fires when the textarea is updated with content from the editor iframe.
21519 * @param {Roo.HtmlEditorCore} this
21520 * @param {String} html
21525 * Fires when the iframe editor is updated with content from the textarea.
21526 * @param {Roo.HtmlEditorCore} this
21527 * @param {String} html
21532 * @event editorevent
21533 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21534 * @param {Roo.HtmlEditorCore} this
21540 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21542 // defaults : white / black...
21543 this.applyBlacklists();
21550 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21554 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21560 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21565 * @cfg {Number} height (in pixels)
21569 * @cfg {Number} width (in pixels)
21574 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21577 stylesheets: false,
21582 // private properties
21583 validationEvent : false,
21585 initialized : false,
21587 sourceEditMode : false,
21588 onFocus : Roo.emptyFn,
21590 hideMode:'offsets',
21594 // blacklist + whitelisted elements..
21601 * Protected method that will not generally be called directly. It
21602 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21603 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21605 getDocMarkup : function(){
21609 // inherit styels from page...??
21610 if (this.stylesheets === false) {
21612 Roo.get(document.head).select('style').each(function(node) {
21613 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21616 Roo.get(document.head).select('link').each(function(node) {
21617 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21620 } else if (!this.stylesheets.length) {
21622 st = '<style type="text/css">' +
21623 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21626 st = '<style type="text/css">' +
21631 st += '<style type="text/css">' +
21632 'IMG { cursor: pointer } ' +
21635 var cls = 'roo-htmleditor-body';
21637 if(this.bodyCls.length){
21638 cls += ' ' + this.bodyCls;
21641 return '<html><head>' + st +
21642 //<style type="text/css">' +
21643 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21645 ' </head><body class="' + cls + '"></body></html>';
21649 onRender : function(ct, position)
21652 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21653 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21656 this.el.dom.style.border = '0 none';
21657 this.el.dom.setAttribute('tabIndex', -1);
21658 this.el.addClass('x-hidden hide');
21662 if(Roo.isIE){ // fix IE 1px bogus margin
21663 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21667 this.frameId = Roo.id();
21671 var iframe = this.owner.wrap.createChild({
21673 cls: 'form-control', // bootstrap..
21675 name: this.frameId,
21676 frameBorder : 'no',
21677 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21682 this.iframe = iframe.dom;
21684 this.assignDocWin();
21686 this.doc.designMode = 'on';
21689 this.doc.write(this.getDocMarkup());
21693 var task = { // must defer to wait for browser to be ready
21695 //console.log("run task?" + this.doc.readyState);
21696 this.assignDocWin();
21697 if(this.doc.body || this.doc.readyState == 'complete'){
21699 this.doc.designMode="on";
21703 Roo.TaskMgr.stop(task);
21704 this.initEditor.defer(10, this);
21711 Roo.TaskMgr.start(task);
21716 onResize : function(w, h)
21718 Roo.log('resize: ' +w + ',' + h );
21719 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21723 if(typeof w == 'number'){
21725 this.iframe.style.width = w + 'px';
21727 if(typeof h == 'number'){
21729 this.iframe.style.height = h + 'px';
21731 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21738 * Toggles the editor between standard and source edit mode.
21739 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21741 toggleSourceEdit : function(sourceEditMode){
21743 this.sourceEditMode = sourceEditMode === true;
21745 if(this.sourceEditMode){
21747 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21750 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21751 //this.iframe.className = '';
21754 //this.setSize(this.owner.wrap.getSize());
21755 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21762 * Protected method that will not generally be called directly. If you need/want
21763 * custom HTML cleanup, this is the method you should override.
21764 * @param {String} html The HTML to be cleaned
21765 * return {String} The cleaned HTML
21767 cleanHtml : function(html){
21768 html = String(html);
21769 if(html.length > 5){
21770 if(Roo.isSafari){ // strip safari nonsense
21771 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21774 if(html == ' '){
21781 * HTML Editor -> Textarea
21782 * Protected method that will not generally be called directly. Syncs the contents
21783 * of the editor iframe with the textarea.
21785 syncValue : function(){
21786 if(this.initialized){
21787 var bd = (this.doc.body || this.doc.documentElement);
21788 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21789 var html = bd.innerHTML;
21791 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21792 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21794 html = '<div style="'+m[0]+'">' + html + '</div>';
21797 html = this.cleanHtml(html);
21798 // fix up the special chars.. normaly like back quotes in word...
21799 // however we do not want to do this with chinese..
21800 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21801 var cc = b.charCodeAt();
21803 (cc >= 0x4E00 && cc < 0xA000 ) ||
21804 (cc >= 0x3400 && cc < 0x4E00 ) ||
21805 (cc >= 0xf900 && cc < 0xfb00 )
21811 if(this.owner.fireEvent('beforesync', this, html) !== false){
21812 this.el.dom.value = html;
21813 this.owner.fireEvent('sync', this, html);
21819 * Protected method that will not generally be called directly. Pushes the value of the textarea
21820 * into the iframe editor.
21822 pushValue : function(){
21823 if(this.initialized){
21824 var v = this.el.dom.value.trim();
21826 // if(v.length < 1){
21830 if(this.owner.fireEvent('beforepush', this, v) !== false){
21831 var d = (this.doc.body || this.doc.documentElement);
21833 this.cleanUpPaste();
21834 this.el.dom.value = d.innerHTML;
21835 this.owner.fireEvent('push', this, v);
21841 deferFocus : function(){
21842 this.focus.defer(10, this);
21846 focus : function(){
21847 if(this.win && !this.sourceEditMode){
21854 assignDocWin: function()
21856 var iframe = this.iframe;
21859 this.doc = iframe.contentWindow.document;
21860 this.win = iframe.contentWindow;
21862 // if (!Roo.get(this.frameId)) {
21865 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21866 // this.win = Roo.get(this.frameId).dom.contentWindow;
21868 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21872 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21873 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21878 initEditor : function(){
21879 //console.log("INIT EDITOR");
21880 this.assignDocWin();
21884 this.doc.designMode="on";
21886 this.doc.write(this.getDocMarkup());
21889 var dbody = (this.doc.body || this.doc.documentElement);
21890 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21891 // this copies styles from the containing element into thsi one..
21892 // not sure why we need all of this..
21893 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21895 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21896 //ss['background-attachment'] = 'fixed'; // w3c
21897 dbody.bgProperties = 'fixed'; // ie
21898 //Roo.DomHelper.applyStyles(dbody, ss);
21899 Roo.EventManager.on(this.doc, {
21900 //'mousedown': this.onEditorEvent,
21901 'mouseup': this.onEditorEvent,
21902 'dblclick': this.onEditorEvent,
21903 'click': this.onEditorEvent,
21904 'keyup': this.onEditorEvent,
21909 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21911 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21912 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21914 this.initialized = true;
21916 this.owner.fireEvent('initialize', this);
21921 onDestroy : function(){
21927 //for (var i =0; i < this.toolbars.length;i++) {
21928 // // fixme - ask toolbars for heights?
21929 // this.toolbars[i].onDestroy();
21932 //this.wrap.dom.innerHTML = '';
21933 //this.wrap.remove();
21938 onFirstFocus : function(){
21940 this.assignDocWin();
21943 this.activated = true;
21946 if(Roo.isGecko){ // prevent silly gecko errors
21948 var s = this.win.getSelection();
21949 if(!s.focusNode || s.focusNode.nodeType != 3){
21950 var r = s.getRangeAt(0);
21951 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21956 this.execCmd('useCSS', true);
21957 this.execCmd('styleWithCSS', false);
21960 this.owner.fireEvent('activate', this);
21964 adjustFont: function(btn){
21965 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21966 //if(Roo.isSafari){ // safari
21969 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21970 if(Roo.isSafari){ // safari
21971 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21972 v = (v < 10) ? 10 : v;
21973 v = (v > 48) ? 48 : v;
21974 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21979 v = Math.max(1, v+adjust);
21981 this.execCmd('FontSize', v );
21984 onEditorEvent : function(e)
21986 this.owner.fireEvent('editorevent', this, e);
21987 // this.updateToolbar();
21988 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21991 insertTag : function(tg)
21993 // could be a bit smarter... -> wrap the current selected tRoo..
21994 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21996 range = this.createRange(this.getSelection());
21997 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21998 wrappingNode.appendChild(range.extractContents());
21999 range.insertNode(wrappingNode);
22006 this.execCmd("formatblock", tg);
22010 insertText : function(txt)
22014 var range = this.createRange();
22015 range.deleteContents();
22016 //alert(Sender.getAttribute('label'));
22018 range.insertNode(this.doc.createTextNode(txt));
22024 * Executes a Midas editor command on the editor document and performs necessary focus and
22025 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22026 * @param {String} cmd The Midas command
22027 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22029 relayCmd : function(cmd, value){
22031 this.execCmd(cmd, value);
22032 this.owner.fireEvent('editorevent', this);
22033 //this.updateToolbar();
22034 this.owner.deferFocus();
22038 * Executes a Midas editor command directly on the editor document.
22039 * For visual commands, you should use {@link #relayCmd} instead.
22040 * <b>This should only be called after the editor is initialized.</b>
22041 * @param {String} cmd The Midas command
22042 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22044 execCmd : function(cmd, value){
22045 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22052 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22054 * @param {String} text | dom node..
22056 insertAtCursor : function(text)
22059 if(!this.activated){
22065 var r = this.doc.selection.createRange();
22076 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22080 // from jquery ui (MIT licenced)
22082 var win = this.win;
22084 if (win.getSelection && win.getSelection().getRangeAt) {
22085 range = win.getSelection().getRangeAt(0);
22086 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22087 range.insertNode(node);
22088 } else if (win.document.selection && win.document.selection.createRange) {
22089 // no firefox support
22090 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22091 win.document.selection.createRange().pasteHTML(txt);
22093 // no firefox support
22094 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22095 this.execCmd('InsertHTML', txt);
22104 mozKeyPress : function(e){
22106 var c = e.getCharCode(), cmd;
22109 c = String.fromCharCode(c).toLowerCase();
22123 this.cleanUpPaste.defer(100, this);
22131 e.preventDefault();
22139 fixKeys : function(){ // load time branching for fastest keydown performance
22141 return function(e){
22142 var k = e.getKey(), r;
22145 r = this.doc.selection.createRange();
22148 r.pasteHTML('    ');
22155 r = this.doc.selection.createRange();
22157 var target = r.parentElement();
22158 if(!target || target.tagName.toLowerCase() != 'li'){
22160 r.pasteHTML('<br />');
22166 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22167 this.cleanUpPaste.defer(100, this);
22173 }else if(Roo.isOpera){
22174 return function(e){
22175 var k = e.getKey();
22179 this.execCmd('InsertHTML','    ');
22182 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22183 this.cleanUpPaste.defer(100, this);
22188 }else if(Roo.isSafari){
22189 return function(e){
22190 var k = e.getKey();
22194 this.execCmd('InsertText','\t');
22198 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22199 this.cleanUpPaste.defer(100, this);
22207 getAllAncestors: function()
22209 var p = this.getSelectedNode();
22212 a.push(p); // push blank onto stack..
22213 p = this.getParentElement();
22217 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22221 a.push(this.doc.body);
22225 lastSelNode : false,
22228 getSelection : function()
22230 this.assignDocWin();
22231 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22234 getSelectedNode: function()
22236 // this may only work on Gecko!!!
22238 // should we cache this!!!!
22243 var range = this.createRange(this.getSelection()).cloneRange();
22246 var parent = range.parentElement();
22248 var testRange = range.duplicate();
22249 testRange.moveToElementText(parent);
22250 if (testRange.inRange(range)) {
22253 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22256 parent = parent.parentElement;
22261 // is ancestor a text element.
22262 var ac = range.commonAncestorContainer;
22263 if (ac.nodeType == 3) {
22264 ac = ac.parentNode;
22267 var ar = ac.childNodes;
22270 var other_nodes = [];
22271 var has_other_nodes = false;
22272 for (var i=0;i<ar.length;i++) {
22273 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22276 // fullly contained node.
22278 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22283 // probably selected..
22284 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22285 other_nodes.push(ar[i]);
22289 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22294 has_other_nodes = true;
22296 if (!nodes.length && other_nodes.length) {
22297 nodes= other_nodes;
22299 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22305 createRange: function(sel)
22307 // this has strange effects when using with
22308 // top toolbar - not sure if it's a great idea.
22309 //this.editor.contentWindow.focus();
22310 if (typeof sel != "undefined") {
22312 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22314 return this.doc.createRange();
22317 return this.doc.createRange();
22320 getParentElement: function()
22323 this.assignDocWin();
22324 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22326 var range = this.createRange(sel);
22329 var p = range.commonAncestorContainer;
22330 while (p.nodeType == 3) { // text node
22341 * Range intersection.. the hard stuff...
22345 * [ -- selected range --- ]
22349 * if end is before start or hits it. fail.
22350 * if start is after end or hits it fail.
22352 * if either hits (but other is outside. - then it's not
22358 // @see http://www.thismuchiknow.co.uk/?p=64.
22359 rangeIntersectsNode : function(range, node)
22361 var nodeRange = node.ownerDocument.createRange();
22363 nodeRange.selectNode(node);
22365 nodeRange.selectNodeContents(node);
22368 var rangeStartRange = range.cloneRange();
22369 rangeStartRange.collapse(true);
22371 var rangeEndRange = range.cloneRange();
22372 rangeEndRange.collapse(false);
22374 var nodeStartRange = nodeRange.cloneRange();
22375 nodeStartRange.collapse(true);
22377 var nodeEndRange = nodeRange.cloneRange();
22378 nodeEndRange.collapse(false);
22380 return rangeStartRange.compareBoundaryPoints(
22381 Range.START_TO_START, nodeEndRange) == -1 &&
22382 rangeEndRange.compareBoundaryPoints(
22383 Range.START_TO_START, nodeStartRange) == 1;
22387 rangeCompareNode : function(range, node)
22389 var nodeRange = node.ownerDocument.createRange();
22391 nodeRange.selectNode(node);
22393 nodeRange.selectNodeContents(node);
22397 range.collapse(true);
22399 nodeRange.collapse(true);
22401 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22402 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22404 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22406 var nodeIsBefore = ss == 1;
22407 var nodeIsAfter = ee == -1;
22409 if (nodeIsBefore && nodeIsAfter) {
22412 if (!nodeIsBefore && nodeIsAfter) {
22413 return 1; //right trailed.
22416 if (nodeIsBefore && !nodeIsAfter) {
22417 return 2; // left trailed.
22423 // private? - in a new class?
22424 cleanUpPaste : function()
22426 // cleans up the whole document..
22427 Roo.log('cleanuppaste');
22429 this.cleanUpChildren(this.doc.body);
22430 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22431 if (clean != this.doc.body.innerHTML) {
22432 this.doc.body.innerHTML = clean;
22437 cleanWordChars : function(input) {// change the chars to hex code
22438 var he = Roo.HtmlEditorCore;
22440 var output = input;
22441 Roo.each(he.swapCodes, function(sw) {
22442 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22444 output = output.replace(swapper, sw[1]);
22451 cleanUpChildren : function (n)
22453 if (!n.childNodes.length) {
22456 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22457 this.cleanUpChild(n.childNodes[i]);
22464 cleanUpChild : function (node)
22467 //console.log(node);
22468 if (node.nodeName == "#text") {
22469 // clean up silly Windows -- stuff?
22472 if (node.nodeName == "#comment") {
22473 node.parentNode.removeChild(node);
22474 // clean up silly Windows -- stuff?
22477 var lcname = node.tagName.toLowerCase();
22478 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22479 // whitelist of tags..
22481 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22483 node.parentNode.removeChild(node);
22488 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22490 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22491 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22493 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22494 // remove_keep_children = true;
22497 if (remove_keep_children) {
22498 this.cleanUpChildren(node);
22499 // inserts everything just before this node...
22500 while (node.childNodes.length) {
22501 var cn = node.childNodes[0];
22502 node.removeChild(cn);
22503 node.parentNode.insertBefore(cn, node);
22505 node.parentNode.removeChild(node);
22509 if (!node.attributes || !node.attributes.length) {
22510 this.cleanUpChildren(node);
22514 function cleanAttr(n,v)
22517 if (v.match(/^\./) || v.match(/^\//)) {
22520 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22523 if (v.match(/^#/)) {
22526 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22527 node.removeAttribute(n);
22531 var cwhite = this.cwhite;
22532 var cblack = this.cblack;
22534 function cleanStyle(n,v)
22536 if (v.match(/expression/)) { //XSS?? should we even bother..
22537 node.removeAttribute(n);
22541 var parts = v.split(/;/);
22544 Roo.each(parts, function(p) {
22545 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22549 var l = p.split(':').shift().replace(/\s+/g,'');
22550 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22552 if ( cwhite.length && cblack.indexOf(l) > -1) {
22553 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22554 //node.removeAttribute(n);
22558 // only allow 'c whitelisted system attributes'
22559 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22560 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22561 //node.removeAttribute(n);
22571 if (clean.length) {
22572 node.setAttribute(n, clean.join(';'));
22574 node.removeAttribute(n);
22580 for (var i = node.attributes.length-1; i > -1 ; i--) {
22581 var a = node.attributes[i];
22584 if (a.name.toLowerCase().substr(0,2)=='on') {
22585 node.removeAttribute(a.name);
22588 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22589 node.removeAttribute(a.name);
22592 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22593 cleanAttr(a.name,a.value); // fixme..
22596 if (a.name == 'style') {
22597 cleanStyle(a.name,a.value);
22600 /// clean up MS crap..
22601 // tecnically this should be a list of valid class'es..
22604 if (a.name == 'class') {
22605 if (a.value.match(/^Mso/)) {
22606 node.className = '';
22609 if (a.value.match(/^body$/)) {
22610 node.className = '';
22621 this.cleanUpChildren(node);
22627 * Clean up MS wordisms...
22629 cleanWord : function(node)
22634 this.cleanWord(this.doc.body);
22637 if (node.nodeName == "#text") {
22638 // clean up silly Windows -- stuff?
22641 if (node.nodeName == "#comment") {
22642 node.parentNode.removeChild(node);
22643 // clean up silly Windows -- stuff?
22647 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22648 node.parentNode.removeChild(node);
22652 // remove - but keep children..
22653 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22654 while (node.childNodes.length) {
22655 var cn = node.childNodes[0];
22656 node.removeChild(cn);
22657 node.parentNode.insertBefore(cn, node);
22659 node.parentNode.removeChild(node);
22660 this.iterateChildren(node, this.cleanWord);
22664 if (node.className.length) {
22666 var cn = node.className.split(/\W+/);
22668 Roo.each(cn, function(cls) {
22669 if (cls.match(/Mso[a-zA-Z]+/)) {
22674 node.className = cna.length ? cna.join(' ') : '';
22676 node.removeAttribute("class");
22680 if (node.hasAttribute("lang")) {
22681 node.removeAttribute("lang");
22684 if (node.hasAttribute("style")) {
22686 var styles = node.getAttribute("style").split(";");
22688 Roo.each(styles, function(s) {
22689 if (!s.match(/:/)) {
22692 var kv = s.split(":");
22693 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22696 // what ever is left... we allow.
22699 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22700 if (!nstyle.length) {
22701 node.removeAttribute('style');
22704 this.iterateChildren(node, this.cleanWord);
22710 * iterateChildren of a Node, calling fn each time, using this as the scole..
22711 * @param {DomNode} node node to iterate children of.
22712 * @param {Function} fn method of this class to call on each item.
22714 iterateChildren : function(node, fn)
22716 if (!node.childNodes.length) {
22719 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22720 fn.call(this, node.childNodes[i])
22726 * cleanTableWidths.
22728 * Quite often pasting from word etc.. results in tables with column and widths.
22729 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22732 cleanTableWidths : function(node)
22737 this.cleanTableWidths(this.doc.body);
22742 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22745 Roo.log(node.tagName);
22746 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22747 this.iterateChildren(node, this.cleanTableWidths);
22750 if (node.hasAttribute('width')) {
22751 node.removeAttribute('width');
22755 if (node.hasAttribute("style")) {
22758 var styles = node.getAttribute("style").split(";");
22760 Roo.each(styles, function(s) {
22761 if (!s.match(/:/)) {
22764 var kv = s.split(":");
22765 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22768 // what ever is left... we allow.
22771 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22772 if (!nstyle.length) {
22773 node.removeAttribute('style');
22777 this.iterateChildren(node, this.cleanTableWidths);
22785 domToHTML : function(currentElement, depth, nopadtext) {
22787 depth = depth || 0;
22788 nopadtext = nopadtext || false;
22790 if (!currentElement) {
22791 return this.domToHTML(this.doc.body);
22794 //Roo.log(currentElement);
22796 var allText = false;
22797 var nodeName = currentElement.nodeName;
22798 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22800 if (nodeName == '#text') {
22802 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22807 if (nodeName != 'BODY') {
22810 // Prints the node tagName, such as <A>, <IMG>, etc
22813 for(i = 0; i < currentElement.attributes.length;i++) {
22815 var aname = currentElement.attributes.item(i).name;
22816 if (!currentElement.attributes.item(i).value.length) {
22819 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22822 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22831 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22834 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22839 // Traverse the tree
22841 var currentElementChild = currentElement.childNodes.item(i);
22842 var allText = true;
22843 var innerHTML = '';
22845 while (currentElementChild) {
22846 // Formatting code (indent the tree so it looks nice on the screen)
22847 var nopad = nopadtext;
22848 if (lastnode == 'SPAN') {
22852 if (currentElementChild.nodeName == '#text') {
22853 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22854 toadd = nopadtext ? toadd : toadd.trim();
22855 if (!nopad && toadd.length > 80) {
22856 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22858 innerHTML += toadd;
22861 currentElementChild = currentElement.childNodes.item(i);
22867 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22869 // Recursively traverse the tree structure of the child node
22870 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22871 lastnode = currentElementChild.nodeName;
22873 currentElementChild=currentElement.childNodes.item(i);
22879 // The remaining code is mostly for formatting the tree
22880 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22885 ret+= "</"+tagName+">";
22891 applyBlacklists : function()
22893 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22894 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22898 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22899 if (b.indexOf(tag) > -1) {
22902 this.white.push(tag);
22906 Roo.each(w, function(tag) {
22907 if (b.indexOf(tag) > -1) {
22910 if (this.white.indexOf(tag) > -1) {
22913 this.white.push(tag);
22918 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22919 if (w.indexOf(tag) > -1) {
22922 this.black.push(tag);
22926 Roo.each(b, function(tag) {
22927 if (w.indexOf(tag) > -1) {
22930 if (this.black.indexOf(tag) > -1) {
22933 this.black.push(tag);
22938 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22939 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22943 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22944 if (b.indexOf(tag) > -1) {
22947 this.cwhite.push(tag);
22951 Roo.each(w, function(tag) {
22952 if (b.indexOf(tag) > -1) {
22955 if (this.cwhite.indexOf(tag) > -1) {
22958 this.cwhite.push(tag);
22963 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22964 if (w.indexOf(tag) > -1) {
22967 this.cblack.push(tag);
22971 Roo.each(b, function(tag) {
22972 if (w.indexOf(tag) > -1) {
22975 if (this.cblack.indexOf(tag) > -1) {
22978 this.cblack.push(tag);
22983 setStylesheets : function(stylesheets)
22985 if(typeof(stylesheets) == 'string'){
22986 Roo.get(this.iframe.contentDocument.head).createChild({
22988 rel : 'stylesheet',
22997 Roo.each(stylesheets, function(s) {
23002 Roo.get(_this.iframe.contentDocument.head).createChild({
23004 rel : 'stylesheet',
23013 removeStylesheets : function()
23017 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23022 setStyle : function(style)
23024 Roo.get(this.iframe.contentDocument.head).createChild({
23033 // hide stuff that is not compatible
23047 * @event specialkey
23051 * @cfg {String} fieldClass @hide
23054 * @cfg {String} focusClass @hide
23057 * @cfg {String} autoCreate @hide
23060 * @cfg {String} inputType @hide
23063 * @cfg {String} invalidClass @hide
23066 * @cfg {String} invalidText @hide
23069 * @cfg {String} msgFx @hide
23072 * @cfg {String} validateOnBlur @hide
23076 Roo.HtmlEditorCore.white = [
23077 'area', 'br', 'img', 'input', 'hr', 'wbr',
23079 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23080 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23081 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23082 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23083 'table', 'ul', 'xmp',
23085 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23088 'dir', 'menu', 'ol', 'ul', 'dl',
23094 Roo.HtmlEditorCore.black = [
23095 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23097 'base', 'basefont', 'bgsound', 'blink', 'body',
23098 'frame', 'frameset', 'head', 'html', 'ilayer',
23099 'iframe', 'layer', 'link', 'meta', 'object',
23100 'script', 'style' ,'title', 'xml' // clean later..
23102 Roo.HtmlEditorCore.clean = [
23103 'script', 'style', 'title', 'xml'
23105 Roo.HtmlEditorCore.remove = [
23110 Roo.HtmlEditorCore.ablack = [
23114 Roo.HtmlEditorCore.aclean = [
23115 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23119 Roo.HtmlEditorCore.pwhite= [
23120 'http', 'https', 'mailto'
23123 // white listed style attributes.
23124 Roo.HtmlEditorCore.cwhite= [
23125 // 'text-align', /// default is to allow most things..
23131 // black listed style attributes.
23132 Roo.HtmlEditorCore.cblack= [
23133 // 'font-size' -- this can be set by the project
23137 Roo.HtmlEditorCore.swapCodes =[
23156 * @class Roo.bootstrap.HtmlEditor
23157 * @extends Roo.bootstrap.TextArea
23158 * Bootstrap HtmlEditor class
23161 * Create a new HtmlEditor
23162 * @param {Object} config The config object
23165 Roo.bootstrap.HtmlEditor = function(config){
23166 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23167 if (!this.toolbars) {
23168 this.toolbars = [];
23171 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23174 * @event initialize
23175 * Fires when the editor is fully initialized (including the iframe)
23176 * @param {HtmlEditor} this
23181 * Fires when the editor is first receives the focus. Any insertion must wait
23182 * until after this event.
23183 * @param {HtmlEditor} this
23187 * @event beforesync
23188 * Fires before the textarea is updated with content from the editor iframe. Return false
23189 * to cancel the sync.
23190 * @param {HtmlEditor} this
23191 * @param {String} html
23195 * @event beforepush
23196 * Fires before the iframe editor is updated with content from the textarea. Return false
23197 * to cancel the push.
23198 * @param {HtmlEditor} this
23199 * @param {String} html
23204 * Fires when the textarea is updated with content from the editor iframe.
23205 * @param {HtmlEditor} this
23206 * @param {String} html
23211 * Fires when the iframe editor is updated with content from the textarea.
23212 * @param {HtmlEditor} this
23213 * @param {String} html
23217 * @event editmodechange
23218 * Fires when the editor switches edit modes
23219 * @param {HtmlEditor} this
23220 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23222 editmodechange: true,
23224 * @event editorevent
23225 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23226 * @param {HtmlEditor} this
23230 * @event firstfocus
23231 * Fires when on first focus - needed by toolbars..
23232 * @param {HtmlEditor} this
23237 * Auto save the htmlEditor value as a file into Events
23238 * @param {HtmlEditor} this
23242 * @event savedpreview
23243 * preview the saved version of htmlEditor
23244 * @param {HtmlEditor} this
23251 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23255 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23260 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23265 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23270 * @cfg {Number} height (in pixels)
23274 * @cfg {Number} width (in pixels)
23279 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23282 stylesheets: false,
23287 // private properties
23288 validationEvent : false,
23290 initialized : false,
23293 onFocus : Roo.emptyFn,
23295 hideMode:'offsets',
23297 tbContainer : false,
23301 toolbarContainer :function() {
23302 return this.wrap.select('.x-html-editor-tb',true).first();
23306 * Protected method that will not generally be called directly. It
23307 * is called when the editor creates its toolbar. Override this method if you need to
23308 * add custom toolbar buttons.
23309 * @param {HtmlEditor} editor
23311 createToolbar : function(){
23312 Roo.log('renewing');
23313 Roo.log("create toolbars");
23315 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23316 this.toolbars[0].render(this.toolbarContainer());
23320 // if (!editor.toolbars || !editor.toolbars.length) {
23321 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23324 // for (var i =0 ; i < editor.toolbars.length;i++) {
23325 // editor.toolbars[i] = Roo.factory(
23326 // typeof(editor.toolbars[i]) == 'string' ?
23327 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23328 // Roo.bootstrap.HtmlEditor);
23329 // editor.toolbars[i].init(editor);
23335 onRender : function(ct, position)
23337 // Roo.log("Call onRender: " + this.xtype);
23339 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23341 this.wrap = this.inputEl().wrap({
23342 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23345 this.editorcore.onRender(ct, position);
23347 if (this.resizable) {
23348 this.resizeEl = new Roo.Resizable(this.wrap, {
23352 minHeight : this.height,
23353 height: this.height,
23354 handles : this.resizable,
23357 resize : function(r, w, h) {
23358 _t.onResize(w,h); // -something
23364 this.createToolbar(this);
23367 if(!this.width && this.resizable){
23368 this.setSize(this.wrap.getSize());
23370 if (this.resizeEl) {
23371 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23372 // should trigger onReize..
23378 onResize : function(w, h)
23380 Roo.log('resize: ' +w + ',' + h );
23381 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23385 if(this.inputEl() ){
23386 if(typeof w == 'number'){
23387 var aw = w - this.wrap.getFrameWidth('lr');
23388 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23391 if(typeof h == 'number'){
23392 var tbh = -11; // fixme it needs to tool bar size!
23393 for (var i =0; i < this.toolbars.length;i++) {
23394 // fixme - ask toolbars for heights?
23395 tbh += this.toolbars[i].el.getHeight();
23396 //if (this.toolbars[i].footer) {
23397 // tbh += this.toolbars[i].footer.el.getHeight();
23405 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23406 ah -= 5; // knock a few pixes off for look..
23407 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23411 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23412 this.editorcore.onResize(ew,eh);
23417 * Toggles the editor between standard and source edit mode.
23418 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23420 toggleSourceEdit : function(sourceEditMode)
23422 this.editorcore.toggleSourceEdit(sourceEditMode);
23424 if(this.editorcore.sourceEditMode){
23425 Roo.log('editor - showing textarea');
23428 // Roo.log(this.syncValue());
23430 this.inputEl().removeClass(['hide', 'x-hidden']);
23431 this.inputEl().dom.removeAttribute('tabIndex');
23432 this.inputEl().focus();
23434 Roo.log('editor - hiding textarea');
23436 // Roo.log(this.pushValue());
23439 this.inputEl().addClass(['hide', 'x-hidden']);
23440 this.inputEl().dom.setAttribute('tabIndex', -1);
23441 //this.deferFocus();
23444 if(this.resizable){
23445 this.setSize(this.wrap.getSize());
23448 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23451 // private (for BoxComponent)
23452 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23454 // private (for BoxComponent)
23455 getResizeEl : function(){
23459 // private (for BoxComponent)
23460 getPositionEl : function(){
23465 initEvents : function(){
23466 this.originalValue = this.getValue();
23470 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23473 // markInvalid : Roo.emptyFn,
23475 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23478 // clearInvalid : Roo.emptyFn,
23480 setValue : function(v){
23481 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23482 this.editorcore.pushValue();
23487 deferFocus : function(){
23488 this.focus.defer(10, this);
23492 focus : function(){
23493 this.editorcore.focus();
23499 onDestroy : function(){
23505 for (var i =0; i < this.toolbars.length;i++) {
23506 // fixme - ask toolbars for heights?
23507 this.toolbars[i].onDestroy();
23510 this.wrap.dom.innerHTML = '';
23511 this.wrap.remove();
23516 onFirstFocus : function(){
23517 //Roo.log("onFirstFocus");
23518 this.editorcore.onFirstFocus();
23519 for (var i =0; i < this.toolbars.length;i++) {
23520 this.toolbars[i].onFirstFocus();
23526 syncValue : function()
23528 this.editorcore.syncValue();
23531 pushValue : function()
23533 this.editorcore.pushValue();
23537 // hide stuff that is not compatible
23551 * @event specialkey
23555 * @cfg {String} fieldClass @hide
23558 * @cfg {String} focusClass @hide
23561 * @cfg {String} autoCreate @hide
23564 * @cfg {String} inputType @hide
23567 * @cfg {String} invalidClass @hide
23570 * @cfg {String} invalidText @hide
23573 * @cfg {String} msgFx @hide
23576 * @cfg {String} validateOnBlur @hide
23585 Roo.namespace('Roo.bootstrap.htmleditor');
23587 * @class Roo.bootstrap.HtmlEditorToolbar1
23592 new Roo.bootstrap.HtmlEditor({
23595 new Roo.bootstrap.HtmlEditorToolbar1({
23596 disable : { fonts: 1 , format: 1, ..., ... , ...],
23602 * @cfg {Object} disable List of elements to disable..
23603 * @cfg {Array} btns List of additional buttons.
23607 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23610 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23613 Roo.apply(this, config);
23615 // default disabled, based on 'good practice'..
23616 this.disable = this.disable || {};
23617 Roo.applyIf(this.disable, {
23620 specialElements : true
23622 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23624 this.editor = config.editor;
23625 this.editorcore = config.editor.editorcore;
23627 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23629 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23630 // dont call parent... till later.
23632 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23637 editorcore : false,
23642 "h1","h2","h3","h4","h5","h6",
23644 "abbr", "acronym", "address", "cite", "samp", "var",
23648 onRender : function(ct, position)
23650 // Roo.log("Call onRender: " + this.xtype);
23652 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23654 this.el.dom.style.marginBottom = '0';
23656 var editorcore = this.editorcore;
23657 var editor= this.editor;
23660 var btn = function(id,cmd , toggle, handler, html){
23662 var event = toggle ? 'toggle' : 'click';
23667 xns: Roo.bootstrap,
23670 enableToggle:toggle !== false,
23672 pressed : toggle ? false : null,
23675 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23676 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23682 // var cb_box = function...
23687 xns: Roo.bootstrap,
23688 glyphicon : 'font',
23692 xns: Roo.bootstrap,
23696 Roo.each(this.formats, function(f) {
23697 style.menu.items.push({
23699 xns: Roo.bootstrap,
23700 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23705 editorcore.insertTag(this.tagname);
23712 children.push(style);
23714 btn('bold',false,true);
23715 btn('italic',false,true);
23716 btn('align-left', 'justifyleft',true);
23717 btn('align-center', 'justifycenter',true);
23718 btn('align-right' , 'justifyright',true);
23719 btn('link', false, false, function(btn) {
23720 //Roo.log("create link?");
23721 var url = prompt(this.createLinkText, this.defaultLinkValue);
23722 if(url && url != 'http:/'+'/'){
23723 this.editorcore.relayCmd('createlink', url);
23726 btn('list','insertunorderedlist',true);
23727 btn('pencil', false,true, function(btn){
23729 this.toggleSourceEdit(btn.pressed);
23732 if (this.editor.btns.length > 0) {
23733 for (var i = 0; i<this.editor.btns.length; i++) {
23734 children.push(this.editor.btns[i]);
23742 xns: Roo.bootstrap,
23747 xns: Roo.bootstrap,
23752 cog.menu.items.push({
23754 xns: Roo.bootstrap,
23755 html : Clean styles,
23760 editorcore.insertTag(this.tagname);
23769 this.xtype = 'NavSimplebar';
23771 for(var i=0;i< children.length;i++) {
23773 this.buttons.add(this.addxtypeChild(children[i]));
23777 editor.on('editorevent', this.updateToolbar, this);
23779 onBtnClick : function(id)
23781 this.editorcore.relayCmd(id);
23782 this.editorcore.focus();
23786 * Protected method that will not generally be called directly. It triggers
23787 * a toolbar update by reading the markup state of the current selection in the editor.
23789 updateToolbar: function(){
23791 if(!this.editorcore.activated){
23792 this.editor.onFirstFocus(); // is this neeed?
23796 var btns = this.buttons;
23797 var doc = this.editorcore.doc;
23798 btns.get('bold').setActive(doc.queryCommandState('bold'));
23799 btns.get('italic').setActive(doc.queryCommandState('italic'));
23800 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23802 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23803 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23804 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23806 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23807 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23810 var ans = this.editorcore.getAllAncestors();
23811 if (this.formatCombo) {
23814 var store = this.formatCombo.store;
23815 this.formatCombo.setValue("");
23816 for (var i =0; i < ans.length;i++) {
23817 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23819 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23827 // hides menus... - so this cant be on a menu...
23828 Roo.bootstrap.MenuMgr.hideAll();
23830 Roo.bootstrap.MenuMgr.hideAll();
23831 //this.editorsyncValue();
23833 onFirstFocus: function() {
23834 this.buttons.each(function(item){
23838 toggleSourceEdit : function(sourceEditMode){
23841 if(sourceEditMode){
23842 Roo.log("disabling buttons");
23843 this.buttons.each( function(item){
23844 if(item.cmd != 'pencil'){
23850 Roo.log("enabling buttons");
23851 if(this.editorcore.initialized){
23852 this.buttons.each( function(item){
23858 Roo.log("calling toggole on editor");
23859 // tell the editor that it's been pressed..
23860 this.editor.toggleSourceEdit(sourceEditMode);
23870 * @class Roo.bootstrap.Table.AbstractSelectionModel
23871 * @extends Roo.util.Observable
23872 * Abstract base class for grid SelectionModels. It provides the interface that should be
23873 * implemented by descendant classes. This class should not be directly instantiated.
23876 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23877 this.locked = false;
23878 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23882 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23883 /** @ignore Called by the grid automatically. Do not call directly. */
23884 init : function(grid){
23890 * Locks the selections.
23893 this.locked = true;
23897 * Unlocks the selections.
23899 unlock : function(){
23900 this.locked = false;
23904 * Returns true if the selections are locked.
23905 * @return {Boolean}
23907 isLocked : function(){
23908 return this.locked;
23912 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23913 * @class Roo.bootstrap.Table.RowSelectionModel
23914 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23915 * It supports multiple selections and keyboard selection/navigation.
23917 * @param {Object} config
23920 Roo.bootstrap.Table.RowSelectionModel = function(config){
23921 Roo.apply(this, config);
23922 this.selections = new Roo.util.MixedCollection(false, function(o){
23927 this.lastActive = false;
23931 * @event selectionchange
23932 * Fires when the selection changes
23933 * @param {SelectionModel} this
23935 "selectionchange" : true,
23937 * @event afterselectionchange
23938 * Fires after the selection changes (eg. by key press or clicking)
23939 * @param {SelectionModel} this
23941 "afterselectionchange" : true,
23943 * @event beforerowselect
23944 * Fires when a row is selected being selected, return false to cancel.
23945 * @param {SelectionModel} this
23946 * @param {Number} rowIndex The selected index
23947 * @param {Boolean} keepExisting False if other selections will be cleared
23949 "beforerowselect" : true,
23952 * Fires when a row is selected.
23953 * @param {SelectionModel} this
23954 * @param {Number} rowIndex The selected index
23955 * @param {Roo.data.Record} r The record
23957 "rowselect" : true,
23959 * @event rowdeselect
23960 * Fires when a row is deselected.
23961 * @param {SelectionModel} this
23962 * @param {Number} rowIndex The selected index
23964 "rowdeselect" : true
23966 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23967 this.locked = false;
23970 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23972 * @cfg {Boolean} singleSelect
23973 * True to allow selection of only one row at a time (defaults to false)
23975 singleSelect : false,
23978 initEvents : function()
23981 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23982 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23983 //}else{ // allow click to work like normal
23984 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23986 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23987 this.grid.on("rowclick", this.handleMouseDown, this);
23989 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23990 "up" : function(e){
23992 this.selectPrevious(e.shiftKey);
23993 }else if(this.last !== false && this.lastActive !== false){
23994 var last = this.last;
23995 this.selectRange(this.last, this.lastActive-1);
23996 this.grid.getView().focusRow(this.lastActive);
23997 if(last !== false){
24001 this.selectFirstRow();
24003 this.fireEvent("afterselectionchange", this);
24005 "down" : function(e){
24007 this.selectNext(e.shiftKey);
24008 }else if(this.last !== false && this.lastActive !== false){
24009 var last = this.last;
24010 this.selectRange(this.last, this.lastActive+1);
24011 this.grid.getView().focusRow(this.lastActive);
24012 if(last !== false){
24016 this.selectFirstRow();
24018 this.fireEvent("afterselectionchange", this);
24022 this.grid.store.on('load', function(){
24023 this.selections.clear();
24026 var view = this.grid.view;
24027 view.on("refresh", this.onRefresh, this);
24028 view.on("rowupdated", this.onRowUpdated, this);
24029 view.on("rowremoved", this.onRemove, this);
24034 onRefresh : function()
24036 var ds = this.grid.store, i, v = this.grid.view;
24037 var s = this.selections;
24038 s.each(function(r){
24039 if((i = ds.indexOfId(r.id)) != -1){
24048 onRemove : function(v, index, r){
24049 this.selections.remove(r);
24053 onRowUpdated : function(v, index, r){
24054 if(this.isSelected(r)){
24055 v.onRowSelect(index);
24061 * @param {Array} records The records to select
24062 * @param {Boolean} keepExisting (optional) True to keep existing selections
24064 selectRecords : function(records, keepExisting)
24067 this.clearSelections();
24069 var ds = this.grid.store;
24070 for(var i = 0, len = records.length; i < len; i++){
24071 this.selectRow(ds.indexOf(records[i]), true);
24076 * Gets the number of selected rows.
24079 getCount : function(){
24080 return this.selections.length;
24084 * Selects the first row in the grid.
24086 selectFirstRow : function(){
24091 * Select the last row.
24092 * @param {Boolean} keepExisting (optional) True to keep existing selections
24094 selectLastRow : function(keepExisting){
24095 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24096 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24100 * Selects the row immediately following the last selected row.
24101 * @param {Boolean} keepExisting (optional) True to keep existing selections
24103 selectNext : function(keepExisting)
24105 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24106 this.selectRow(this.last+1, keepExisting);
24107 this.grid.getView().focusRow(this.last);
24112 * Selects the row that precedes the last selected row.
24113 * @param {Boolean} keepExisting (optional) True to keep existing selections
24115 selectPrevious : function(keepExisting){
24117 this.selectRow(this.last-1, keepExisting);
24118 this.grid.getView().focusRow(this.last);
24123 * Returns the selected records
24124 * @return {Array} Array of selected records
24126 getSelections : function(){
24127 return [].concat(this.selections.items);
24131 * Returns the first selected record.
24134 getSelected : function(){
24135 return this.selections.itemAt(0);
24140 * Clears all selections.
24142 clearSelections : function(fast)
24148 var ds = this.grid.store;
24149 var s = this.selections;
24150 s.each(function(r){
24151 this.deselectRow(ds.indexOfId(r.id));
24155 this.selections.clear();
24162 * Selects all rows.
24164 selectAll : function(){
24168 this.selections.clear();
24169 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24170 this.selectRow(i, true);
24175 * Returns True if there is a selection.
24176 * @return {Boolean}
24178 hasSelection : function(){
24179 return this.selections.length > 0;
24183 * Returns True if the specified row is selected.
24184 * @param {Number/Record} record The record or index of the record to check
24185 * @return {Boolean}
24187 isSelected : function(index){
24188 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24189 return (r && this.selections.key(r.id) ? true : false);
24193 * Returns True if the specified record id is selected.
24194 * @param {String} id The id of record to check
24195 * @return {Boolean}
24197 isIdSelected : function(id){
24198 return (this.selections.key(id) ? true : false);
24203 handleMouseDBClick : function(e, t){
24207 handleMouseDown : function(e, t)
24209 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24210 if(this.isLocked() || rowIndex < 0 ){
24213 if(e.shiftKey && this.last !== false){
24214 var last = this.last;
24215 this.selectRange(last, rowIndex, e.ctrlKey);
24216 this.last = last; // reset the last
24220 var isSelected = this.isSelected(rowIndex);
24221 //Roo.log("select row:" + rowIndex);
24223 this.deselectRow(rowIndex);
24225 this.selectRow(rowIndex, true);
24229 if(e.button !== 0 && isSelected){
24230 alert('rowIndex 2: ' + rowIndex);
24231 view.focusRow(rowIndex);
24232 }else if(e.ctrlKey && isSelected){
24233 this.deselectRow(rowIndex);
24234 }else if(!isSelected){
24235 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24236 view.focusRow(rowIndex);
24240 this.fireEvent("afterselectionchange", this);
24243 handleDragableRowClick : function(grid, rowIndex, e)
24245 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24246 this.selectRow(rowIndex, false);
24247 grid.view.focusRow(rowIndex);
24248 this.fireEvent("afterselectionchange", this);
24253 * Selects multiple rows.
24254 * @param {Array} rows Array of the indexes of the row to select
24255 * @param {Boolean} keepExisting (optional) True to keep existing selections
24257 selectRows : function(rows, keepExisting){
24259 this.clearSelections();
24261 for(var i = 0, len = rows.length; i < len; i++){
24262 this.selectRow(rows[i], true);
24267 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24268 * @param {Number} startRow The index of the first row in the range
24269 * @param {Number} endRow The index of the last row in the range
24270 * @param {Boolean} keepExisting (optional) True to retain existing selections
24272 selectRange : function(startRow, endRow, keepExisting){
24277 this.clearSelections();
24279 if(startRow <= endRow){
24280 for(var i = startRow; i <= endRow; i++){
24281 this.selectRow(i, true);
24284 for(var i = startRow; i >= endRow; i--){
24285 this.selectRow(i, true);
24291 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24292 * @param {Number} startRow The index of the first row in the range
24293 * @param {Number} endRow The index of the last row in the range
24295 deselectRange : function(startRow, endRow, preventViewNotify){
24299 for(var i = startRow; i <= endRow; i++){
24300 this.deselectRow(i, preventViewNotify);
24306 * @param {Number} row The index of the row to select
24307 * @param {Boolean} keepExisting (optional) True to keep existing selections
24309 selectRow : function(index, keepExisting, preventViewNotify)
24311 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24314 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24315 if(!keepExisting || this.singleSelect){
24316 this.clearSelections();
24319 var r = this.grid.store.getAt(index);
24320 //console.log('selectRow - record id :' + r.id);
24322 this.selections.add(r);
24323 this.last = this.lastActive = index;
24324 if(!preventViewNotify){
24325 var proxy = new Roo.Element(
24326 this.grid.getRowDom(index)
24328 proxy.addClass('bg-info info');
24330 this.fireEvent("rowselect", this, index, r);
24331 this.fireEvent("selectionchange", this);
24337 * @param {Number} row The index of the row to deselect
24339 deselectRow : function(index, preventViewNotify)
24344 if(this.last == index){
24347 if(this.lastActive == index){
24348 this.lastActive = false;
24351 var r = this.grid.store.getAt(index);
24356 this.selections.remove(r);
24357 //.console.log('deselectRow - record id :' + r.id);
24358 if(!preventViewNotify){
24360 var proxy = new Roo.Element(
24361 this.grid.getRowDom(index)
24363 proxy.removeClass('bg-info info');
24365 this.fireEvent("rowdeselect", this, index);
24366 this.fireEvent("selectionchange", this);
24370 restoreLast : function(){
24372 this.last = this._last;
24377 acceptsNav : function(row, col, cm){
24378 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24382 onEditorKey : function(field, e){
24383 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24388 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24390 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24392 }else if(k == e.ENTER && !e.ctrlKey){
24396 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24398 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24400 }else if(k == e.ESC){
24404 g.startEditing(newCell[0], newCell[1]);
24410 * Ext JS Library 1.1.1
24411 * Copyright(c) 2006-2007, Ext JS, LLC.
24413 * Originally Released Under LGPL - original licence link has changed is not relivant.
24416 * <script type="text/javascript">
24420 * @class Roo.bootstrap.PagingToolbar
24421 * @extends Roo.bootstrap.NavSimplebar
24422 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24424 * Create a new PagingToolbar
24425 * @param {Object} config The config object
24426 * @param {Roo.data.Store} store
24428 Roo.bootstrap.PagingToolbar = function(config)
24430 // old args format still supported... - xtype is prefered..
24431 // created from xtype...
24433 this.ds = config.dataSource;
24435 if (config.store && !this.ds) {
24436 this.store= Roo.factory(config.store, Roo.data);
24437 this.ds = this.store;
24438 this.ds.xmodule = this.xmodule || false;
24441 this.toolbarItems = [];
24442 if (config.items) {
24443 this.toolbarItems = config.items;
24446 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24451 this.bind(this.ds);
24454 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24458 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24460 * @cfg {Roo.data.Store} dataSource
24461 * The underlying data store providing the paged data
24464 * @cfg {String/HTMLElement/Element} container
24465 * container The id or element that will contain the toolbar
24468 * @cfg {Boolean} displayInfo
24469 * True to display the displayMsg (defaults to false)
24472 * @cfg {Number} pageSize
24473 * The number of records to display per page (defaults to 20)
24477 * @cfg {String} displayMsg
24478 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24480 displayMsg : 'Displaying {0} - {1} of {2}',
24482 * @cfg {String} emptyMsg
24483 * The message to display when no records are found (defaults to "No data to display")
24485 emptyMsg : 'No data to display',
24487 * Customizable piece of the default paging text (defaults to "Page")
24490 beforePageText : "Page",
24492 * Customizable piece of the default paging text (defaults to "of %0")
24495 afterPageText : "of {0}",
24497 * Customizable piece of the default paging text (defaults to "First Page")
24500 firstText : "First Page",
24502 * Customizable piece of the default paging text (defaults to "Previous Page")
24505 prevText : "Previous Page",
24507 * Customizable piece of the default paging text (defaults to "Next Page")
24510 nextText : "Next Page",
24512 * Customizable piece of the default paging text (defaults to "Last Page")
24515 lastText : "Last Page",
24517 * Customizable piece of the default paging text (defaults to "Refresh")
24520 refreshText : "Refresh",
24524 onRender : function(ct, position)
24526 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24527 this.navgroup.parentId = this.id;
24528 this.navgroup.onRender(this.el, null);
24529 // add the buttons to the navgroup
24531 if(this.displayInfo){
24532 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24533 this.displayEl = this.el.select('.x-paging-info', true).first();
24534 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24535 // this.displayEl = navel.el.select('span',true).first();
24541 Roo.each(_this.buttons, function(e){ // this might need to use render????
24542 Roo.factory(e).render(_this.el);
24546 Roo.each(_this.toolbarItems, function(e) {
24547 _this.navgroup.addItem(e);
24551 this.first = this.navgroup.addItem({
24552 tooltip: this.firstText,
24554 icon : 'fa fa-backward',
24556 preventDefault: true,
24557 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24560 this.prev = this.navgroup.addItem({
24561 tooltip: this.prevText,
24563 icon : 'fa fa-step-backward',
24565 preventDefault: true,
24566 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24568 //this.addSeparator();
24571 var field = this.navgroup.addItem( {
24573 cls : 'x-paging-position',
24575 html : this.beforePageText +
24576 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24577 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24580 this.field = field.el.select('input', true).first();
24581 this.field.on("keydown", this.onPagingKeydown, this);
24582 this.field.on("focus", function(){this.dom.select();});
24585 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24586 //this.field.setHeight(18);
24587 //this.addSeparator();
24588 this.next = this.navgroup.addItem({
24589 tooltip: this.nextText,
24591 html : ' <i class="fa fa-step-forward">',
24593 preventDefault: true,
24594 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24596 this.last = this.navgroup.addItem({
24597 tooltip: this.lastText,
24598 icon : 'fa fa-forward',
24601 preventDefault: true,
24602 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24604 //this.addSeparator();
24605 this.loading = this.navgroup.addItem({
24606 tooltip: this.refreshText,
24607 icon: 'fa fa-refresh',
24608 preventDefault: true,
24609 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24615 updateInfo : function(){
24616 if(this.displayEl){
24617 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24618 var msg = count == 0 ?
24622 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24624 this.displayEl.update(msg);
24629 onLoad : function(ds, r, o)
24631 this.cursor = o.params.start ? o.params.start : 0;
24633 var d = this.getPageData(),
24638 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24639 this.field.dom.value = ap;
24640 this.first.setDisabled(ap == 1);
24641 this.prev.setDisabled(ap == 1);
24642 this.next.setDisabled(ap == ps);
24643 this.last.setDisabled(ap == ps);
24644 this.loading.enable();
24649 getPageData : function(){
24650 var total = this.ds.getTotalCount();
24653 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24654 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24659 onLoadError : function(){
24660 this.loading.enable();
24664 onPagingKeydown : function(e){
24665 var k = e.getKey();
24666 var d = this.getPageData();
24668 var v = this.field.dom.value, pageNum;
24669 if(!v || isNaN(pageNum = parseInt(v, 10))){
24670 this.field.dom.value = d.activePage;
24673 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24674 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24677 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))
24679 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24680 this.field.dom.value = pageNum;
24681 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24684 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24686 var v = this.field.dom.value, pageNum;
24687 var increment = (e.shiftKey) ? 10 : 1;
24688 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24691 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24692 this.field.dom.value = d.activePage;
24695 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24697 this.field.dom.value = parseInt(v, 10) + increment;
24698 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24699 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24706 beforeLoad : function(){
24708 this.loading.disable();
24713 onClick : function(which){
24722 ds.load({params:{start: 0, limit: this.pageSize}});
24725 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24728 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24731 var total = ds.getTotalCount();
24732 var extra = total % this.pageSize;
24733 var lastStart = extra ? (total - extra) : total-this.pageSize;
24734 ds.load({params:{start: lastStart, limit: this.pageSize}});
24737 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24743 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24744 * @param {Roo.data.Store} store The data store to unbind
24746 unbind : function(ds){
24747 ds.un("beforeload", this.beforeLoad, this);
24748 ds.un("load", this.onLoad, this);
24749 ds.un("loadexception", this.onLoadError, this);
24750 ds.un("remove", this.updateInfo, this);
24751 ds.un("add", this.updateInfo, this);
24752 this.ds = undefined;
24756 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24757 * @param {Roo.data.Store} store The data store to bind
24759 bind : function(ds){
24760 ds.on("beforeload", this.beforeLoad, this);
24761 ds.on("load", this.onLoad, this);
24762 ds.on("loadexception", this.onLoadError, this);
24763 ds.on("remove", this.updateInfo, this);
24764 ds.on("add", this.updateInfo, this);
24775 * @class Roo.bootstrap.MessageBar
24776 * @extends Roo.bootstrap.Component
24777 * Bootstrap MessageBar class
24778 * @cfg {String} html contents of the MessageBar
24779 * @cfg {String} weight (info | success | warning | danger) default info
24780 * @cfg {String} beforeClass insert the bar before the given class
24781 * @cfg {Boolean} closable (true | false) default false
24782 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24785 * Create a new Element
24786 * @param {Object} config The config object
24789 Roo.bootstrap.MessageBar = function(config){
24790 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24793 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24799 beforeClass: 'bootstrap-sticky-wrap',
24801 getAutoCreate : function(){
24805 cls: 'alert alert-dismissable alert-' + this.weight,
24810 html: this.html || ''
24816 cfg.cls += ' alert-messages-fixed';
24830 onRender : function(ct, position)
24832 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24835 var cfg = Roo.apply({}, this.getAutoCreate());
24839 cfg.cls += ' ' + this.cls;
24842 cfg.style = this.style;
24844 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24846 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24849 this.el.select('>button.close').on('click', this.hide, this);
24855 if (!this.rendered) {
24861 this.fireEvent('show', this);
24867 if (!this.rendered) {
24873 this.fireEvent('hide', this);
24876 update : function()
24878 // var e = this.el.dom.firstChild;
24880 // if(this.closable){
24881 // e = e.nextSibling;
24884 // e.data = this.html || '';
24886 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24902 * @class Roo.bootstrap.Graph
24903 * @extends Roo.bootstrap.Component
24904 * Bootstrap Graph class
24908 @cfg {String} graphtype bar | vbar | pie
24909 @cfg {number} g_x coodinator | centre x (pie)
24910 @cfg {number} g_y coodinator | centre y (pie)
24911 @cfg {number} g_r radius (pie)
24912 @cfg {number} g_height height of the chart (respected by all elements in the set)
24913 @cfg {number} g_width width of the chart (respected by all elements in the set)
24914 @cfg {Object} title The title of the chart
24917 -opts (object) options for the chart
24919 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24920 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24922 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.
24923 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24925 o stretch (boolean)
24927 -opts (object) options for the pie
24930 o startAngle (number)
24931 o endAngle (number)
24935 * Create a new Input
24936 * @param {Object} config The config object
24939 Roo.bootstrap.Graph = function(config){
24940 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24946 * The img click event for the img.
24947 * @param {Roo.EventObject} e
24953 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24964 //g_colors: this.colors,
24971 getAutoCreate : function(){
24982 onRender : function(ct,position){
24985 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24987 if (typeof(Raphael) == 'undefined') {
24988 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24992 this.raphael = Raphael(this.el.dom);
24994 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24995 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24996 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24997 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24999 r.text(160, 10, "Single Series Chart").attr(txtattr);
25000 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25001 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25002 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25004 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25005 r.barchart(330, 10, 300, 220, data1);
25006 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25007 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25010 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25011 // r.barchart(30, 30, 560, 250, xdata, {
25012 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25013 // axis : "0 0 1 1",
25014 // axisxlabels : xdata
25015 // //yvalues : cols,
25018 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25020 // this.load(null,xdata,{
25021 // axis : "0 0 1 1",
25022 // axisxlabels : xdata
25027 load : function(graphtype,xdata,opts)
25029 this.raphael.clear();
25031 graphtype = this.graphtype;
25036 var r = this.raphael,
25037 fin = function () {
25038 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25040 fout = function () {
25041 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25043 pfin = function() {
25044 this.sector.stop();
25045 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25048 this.label[0].stop();
25049 this.label[0].attr({ r: 7.5 });
25050 this.label[1].attr({ "font-weight": 800 });
25053 pfout = function() {
25054 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25057 this.label[0].animate({ r: 5 }, 500, "bounce");
25058 this.label[1].attr({ "font-weight": 400 });
25064 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25067 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25070 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25071 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25073 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25080 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25085 setTitle: function(o)
25090 initEvents: function() {
25093 this.el.on('click', this.onClick, this);
25097 onClick : function(e)
25099 Roo.log('img onclick');
25100 this.fireEvent('click', this, e);
25112 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25115 * @class Roo.bootstrap.dash.NumberBox
25116 * @extends Roo.bootstrap.Component
25117 * Bootstrap NumberBox class
25118 * @cfg {String} headline Box headline
25119 * @cfg {String} content Box content
25120 * @cfg {String} icon Box icon
25121 * @cfg {String} footer Footer text
25122 * @cfg {String} fhref Footer href
25125 * Create a new NumberBox
25126 * @param {Object} config The config object
25130 Roo.bootstrap.dash.NumberBox = function(config){
25131 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25135 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25144 getAutoCreate : function(){
25148 cls : 'small-box ',
25156 cls : 'roo-headline',
25157 html : this.headline
25161 cls : 'roo-content',
25162 html : this.content
25176 cls : 'ion ' + this.icon
25185 cls : 'small-box-footer',
25186 href : this.fhref || '#',
25190 cfg.cn.push(footer);
25197 onRender : function(ct,position){
25198 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25205 setHeadline: function (value)
25207 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25210 setFooter: function (value, href)
25212 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25215 this.el.select('a.small-box-footer',true).first().attr('href', href);
25220 setContent: function (value)
25222 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25225 initEvents: function()
25239 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25242 * @class Roo.bootstrap.dash.TabBox
25243 * @extends Roo.bootstrap.Component
25244 * Bootstrap TabBox class
25245 * @cfg {String} title Title of the TabBox
25246 * @cfg {String} icon Icon of the TabBox
25247 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25248 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25251 * Create a new TabBox
25252 * @param {Object} config The config object
25256 Roo.bootstrap.dash.TabBox = function(config){
25257 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25262 * When a pane is added
25263 * @param {Roo.bootstrap.dash.TabPane} pane
25267 * @event activatepane
25268 * When a pane is activated
25269 * @param {Roo.bootstrap.dash.TabPane} pane
25271 "activatepane" : true
25279 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25284 tabScrollable : false,
25286 getChildContainer : function()
25288 return this.el.select('.tab-content', true).first();
25291 getAutoCreate : function(){
25295 cls: 'pull-left header',
25303 cls: 'fa ' + this.icon
25309 cls: 'nav nav-tabs pull-right',
25315 if(this.tabScrollable){
25322 cls: 'nav nav-tabs pull-right',
25333 cls: 'nav-tabs-custom',
25338 cls: 'tab-content no-padding',
25346 initEvents : function()
25348 //Roo.log('add add pane handler');
25349 this.on('addpane', this.onAddPane, this);
25352 * Updates the box title
25353 * @param {String} html to set the title to.
25355 setTitle : function(value)
25357 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25359 onAddPane : function(pane)
25361 this.panes.push(pane);
25362 //Roo.log('addpane');
25364 // tabs are rendere left to right..
25365 if(!this.showtabs){
25369 var ctr = this.el.select('.nav-tabs', true).first();
25372 var existing = ctr.select('.nav-tab',true);
25373 var qty = existing.getCount();;
25376 var tab = ctr.createChild({
25378 cls : 'nav-tab' + (qty ? '' : ' active'),
25386 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25389 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25391 pane.el.addClass('active');
25396 onTabClick : function(ev,un,ob,pane)
25398 //Roo.log('tab - prev default');
25399 ev.preventDefault();
25402 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25403 pane.tab.addClass('active');
25404 //Roo.log(pane.title);
25405 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25406 // technically we should have a deactivate event.. but maybe add later.
25407 // and it should not de-activate the selected tab...
25408 this.fireEvent('activatepane', pane);
25409 pane.el.addClass('active');
25410 pane.fireEvent('activate');
25415 getActivePane : function()
25418 Roo.each(this.panes, function(p) {
25419 if(p.el.hasClass('active')){
25440 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25442 * @class Roo.bootstrap.TabPane
25443 * @extends Roo.bootstrap.Component
25444 * Bootstrap TabPane class
25445 * @cfg {Boolean} active (false | true) Default false
25446 * @cfg {String} title title of panel
25450 * Create a new TabPane
25451 * @param {Object} config The config object
25454 Roo.bootstrap.dash.TabPane = function(config){
25455 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25461 * When a pane is activated
25462 * @param {Roo.bootstrap.dash.TabPane} pane
25469 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25474 // the tabBox that this is attached to.
25477 getAutoCreate : function()
25485 cfg.cls += ' active';
25490 initEvents : function()
25492 //Roo.log('trigger add pane handler');
25493 this.parent().fireEvent('addpane', this)
25497 * Updates the tab title
25498 * @param {String} html to set the title to.
25500 setTitle: function(str)
25506 this.tab.select('a', true).first().dom.innerHTML = str;
25523 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25526 * @class Roo.bootstrap.menu.Menu
25527 * @extends Roo.bootstrap.Component
25528 * Bootstrap Menu class - container for Menu
25529 * @cfg {String} html Text of the menu
25530 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25531 * @cfg {String} icon Font awesome icon
25532 * @cfg {String} pos Menu align to (top | bottom) default bottom
25536 * Create a new Menu
25537 * @param {Object} config The config object
25541 Roo.bootstrap.menu.Menu = function(config){
25542 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25546 * @event beforeshow
25547 * Fires before this menu is displayed
25548 * @param {Roo.bootstrap.menu.Menu} this
25552 * @event beforehide
25553 * Fires before this menu is hidden
25554 * @param {Roo.bootstrap.menu.Menu} this
25559 * Fires after this menu is displayed
25560 * @param {Roo.bootstrap.menu.Menu} this
25565 * Fires after this menu is hidden
25566 * @param {Roo.bootstrap.menu.Menu} this
25571 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25572 * @param {Roo.bootstrap.menu.Menu} this
25573 * @param {Roo.EventObject} e
25580 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25584 weight : 'default',
25589 getChildContainer : function() {
25590 if(this.isSubMenu){
25594 return this.el.select('ul.dropdown-menu', true).first();
25597 getAutoCreate : function()
25602 cls : 'roo-menu-text',
25610 cls : 'fa ' + this.icon
25621 cls : 'dropdown-button btn btn-' + this.weight,
25626 cls : 'dropdown-toggle btn btn-' + this.weight,
25636 cls : 'dropdown-menu'
25642 if(this.pos == 'top'){
25643 cfg.cls += ' dropup';
25646 if(this.isSubMenu){
25649 cls : 'dropdown-menu'
25656 onRender : function(ct, position)
25658 this.isSubMenu = ct.hasClass('dropdown-submenu');
25660 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25663 initEvents : function()
25665 if(this.isSubMenu){
25669 this.hidden = true;
25671 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25672 this.triggerEl.on('click', this.onTriggerPress, this);
25674 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25675 this.buttonEl.on('click', this.onClick, this);
25681 if(this.isSubMenu){
25685 return this.el.select('ul.dropdown-menu', true).first();
25688 onClick : function(e)
25690 this.fireEvent("click", this, e);
25693 onTriggerPress : function(e)
25695 if (this.isVisible()) {
25702 isVisible : function(){
25703 return !this.hidden;
25708 this.fireEvent("beforeshow", this);
25710 this.hidden = false;
25711 this.el.addClass('open');
25713 Roo.get(document).on("mouseup", this.onMouseUp, this);
25715 this.fireEvent("show", this);
25722 this.fireEvent("beforehide", this);
25724 this.hidden = true;
25725 this.el.removeClass('open');
25727 Roo.get(document).un("mouseup", this.onMouseUp);
25729 this.fireEvent("hide", this);
25732 onMouseUp : function()
25746 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25749 * @class Roo.bootstrap.menu.Item
25750 * @extends Roo.bootstrap.Component
25751 * Bootstrap MenuItem class
25752 * @cfg {Boolean} submenu (true | false) default false
25753 * @cfg {String} html text of the item
25754 * @cfg {String} href the link
25755 * @cfg {Boolean} disable (true | false) default false
25756 * @cfg {Boolean} preventDefault (true | false) default true
25757 * @cfg {String} icon Font awesome icon
25758 * @cfg {String} pos Submenu align to (left | right) default right
25762 * Create a new Item
25763 * @param {Object} config The config object
25767 Roo.bootstrap.menu.Item = function(config){
25768 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25772 * Fires when the mouse is hovering over this menu
25773 * @param {Roo.bootstrap.menu.Item} this
25774 * @param {Roo.EventObject} e
25779 * Fires when the mouse exits this menu
25780 * @param {Roo.bootstrap.menu.Item} this
25781 * @param {Roo.EventObject} e
25787 * The raw click event for the entire grid.
25788 * @param {Roo.EventObject} e
25794 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25799 preventDefault: true,
25804 getAutoCreate : function()
25809 cls : 'roo-menu-item-text',
25817 cls : 'fa ' + this.icon
25826 href : this.href || '#',
25833 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25837 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25839 if(this.pos == 'left'){
25840 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25847 initEvents : function()
25849 this.el.on('mouseover', this.onMouseOver, this);
25850 this.el.on('mouseout', this.onMouseOut, this);
25852 this.el.select('a', true).first().on('click', this.onClick, this);
25856 onClick : function(e)
25858 if(this.preventDefault){
25859 e.preventDefault();
25862 this.fireEvent("click", this, e);
25865 onMouseOver : function(e)
25867 if(this.submenu && this.pos == 'left'){
25868 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25871 this.fireEvent("mouseover", this, e);
25874 onMouseOut : function(e)
25876 this.fireEvent("mouseout", this, e);
25888 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25891 * @class Roo.bootstrap.menu.Separator
25892 * @extends Roo.bootstrap.Component
25893 * Bootstrap Separator class
25896 * Create a new Separator
25897 * @param {Object} config The config object
25901 Roo.bootstrap.menu.Separator = function(config){
25902 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25905 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25907 getAutoCreate : function(){
25928 * @class Roo.bootstrap.Tooltip
25929 * Bootstrap Tooltip class
25930 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25931 * to determine which dom element triggers the tooltip.
25933 * It needs to add support for additional attributes like tooltip-position
25936 * Create a new Toolti
25937 * @param {Object} config The config object
25940 Roo.bootstrap.Tooltip = function(config){
25941 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25943 this.alignment = Roo.bootstrap.Tooltip.alignment;
25945 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25946 this.alignment = config.alignment;
25951 Roo.apply(Roo.bootstrap.Tooltip, {
25953 * @function init initialize tooltip monitoring.
25957 currentTip : false,
25958 currentRegion : false,
25964 Roo.get(document).on('mouseover', this.enter ,this);
25965 Roo.get(document).on('mouseout', this.leave, this);
25968 this.currentTip = new Roo.bootstrap.Tooltip();
25971 enter : function(ev)
25973 var dom = ev.getTarget();
25975 //Roo.log(['enter',dom]);
25976 var el = Roo.fly(dom);
25977 if (this.currentEl) {
25979 //Roo.log(this.currentEl);
25980 //Roo.log(this.currentEl.contains(dom));
25981 if (this.currentEl == el) {
25984 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25990 if (this.currentTip.el) {
25991 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25995 if(!el || el.dom == document){
26001 // you can not look for children, as if el is the body.. then everythign is the child..
26002 if (!el.attr('tooltip')) { //
26003 if (!el.select("[tooltip]").elements.length) {
26006 // is the mouse over this child...?
26007 bindEl = el.select("[tooltip]").first();
26008 var xy = ev.getXY();
26009 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26010 //Roo.log("not in region.");
26013 //Roo.log("child element over..");
26016 this.currentEl = bindEl;
26017 this.currentTip.bind(bindEl);
26018 this.currentRegion = Roo.lib.Region.getRegion(dom);
26019 this.currentTip.enter();
26022 leave : function(ev)
26024 var dom = ev.getTarget();
26025 //Roo.log(['leave',dom]);
26026 if (!this.currentEl) {
26031 if (dom != this.currentEl.dom) {
26034 var xy = ev.getXY();
26035 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26038 // only activate leave if mouse cursor is outside... bounding box..
26043 if (this.currentTip) {
26044 this.currentTip.leave();
26046 //Roo.log('clear currentEl');
26047 this.currentEl = false;
26052 'left' : ['r-l', [-2,0], 'right'],
26053 'right' : ['l-r', [2,0], 'left'],
26054 'bottom' : ['t-b', [0,2], 'top'],
26055 'top' : [ 'b-t', [0,-2], 'bottom']
26061 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26066 delay : null, // can be { show : 300 , hide: 500}
26070 hoverState : null, //???
26072 placement : 'bottom',
26076 getAutoCreate : function(){
26083 cls : 'tooltip-arrow'
26086 cls : 'tooltip-inner'
26093 bind : function(el)
26099 enter : function () {
26101 if (this.timeout != null) {
26102 clearTimeout(this.timeout);
26105 this.hoverState = 'in';
26106 //Roo.log("enter - show");
26107 if (!this.delay || !this.delay.show) {
26112 this.timeout = setTimeout(function () {
26113 if (_t.hoverState == 'in') {
26116 }, this.delay.show);
26120 clearTimeout(this.timeout);
26122 this.hoverState = 'out';
26123 if (!this.delay || !this.delay.hide) {
26129 this.timeout = setTimeout(function () {
26130 //Roo.log("leave - timeout");
26132 if (_t.hoverState == 'out') {
26134 Roo.bootstrap.Tooltip.currentEl = false;
26139 show : function (msg)
26142 this.render(document.body);
26145 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26147 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26149 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26151 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26153 var placement = typeof this.placement == 'function' ?
26154 this.placement.call(this, this.el, on_el) :
26157 var autoToken = /\s?auto?\s?/i;
26158 var autoPlace = autoToken.test(placement);
26160 placement = placement.replace(autoToken, '') || 'top';
26164 //this.el.setXY([0,0]);
26166 //this.el.dom.style.display='block';
26168 //this.el.appendTo(on_el);
26170 var p = this.getPosition();
26171 var box = this.el.getBox();
26177 var align = this.alignment[placement];
26179 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26181 if(placement == 'top' || placement == 'bottom'){
26183 placement = 'right';
26186 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26187 placement = 'left';
26190 var scroll = Roo.select('body', true).first().getScroll();
26192 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26198 this.el.alignTo(this.bindEl, align[0],align[1]);
26199 //var arrow = this.el.select('.arrow',true).first();
26200 //arrow.set(align[2],
26202 this.el.addClass(placement);
26204 this.el.addClass('in fade');
26206 this.hoverState = null;
26208 if (this.el.hasClass('fade')) {
26219 //this.el.setXY([0,0]);
26220 this.el.removeClass('in');
26236 * @class Roo.bootstrap.LocationPicker
26237 * @extends Roo.bootstrap.Component
26238 * Bootstrap LocationPicker class
26239 * @cfg {Number} latitude Position when init default 0
26240 * @cfg {Number} longitude Position when init default 0
26241 * @cfg {Number} zoom default 15
26242 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26243 * @cfg {Boolean} mapTypeControl default false
26244 * @cfg {Boolean} disableDoubleClickZoom default false
26245 * @cfg {Boolean} scrollwheel default true
26246 * @cfg {Boolean} streetViewControl default false
26247 * @cfg {Number} radius default 0
26248 * @cfg {String} locationName
26249 * @cfg {Boolean} draggable default true
26250 * @cfg {Boolean} enableAutocomplete default false
26251 * @cfg {Boolean} enableReverseGeocode default true
26252 * @cfg {String} markerTitle
26255 * Create a new LocationPicker
26256 * @param {Object} config The config object
26260 Roo.bootstrap.LocationPicker = function(config){
26262 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26267 * Fires when the picker initialized.
26268 * @param {Roo.bootstrap.LocationPicker} this
26269 * @param {Google Location} location
26273 * @event positionchanged
26274 * Fires when the picker position changed.
26275 * @param {Roo.bootstrap.LocationPicker} this
26276 * @param {Google Location} location
26278 positionchanged : true,
26281 * Fires when the map resize.
26282 * @param {Roo.bootstrap.LocationPicker} this
26287 * Fires when the map show.
26288 * @param {Roo.bootstrap.LocationPicker} this
26293 * Fires when the map hide.
26294 * @param {Roo.bootstrap.LocationPicker} this
26299 * Fires when click the map.
26300 * @param {Roo.bootstrap.LocationPicker} this
26301 * @param {Map event} e
26305 * @event mapRightClick
26306 * Fires when right click the map.
26307 * @param {Roo.bootstrap.LocationPicker} this
26308 * @param {Map event} e
26310 mapRightClick : true,
26312 * @event markerClick
26313 * Fires when click the marker.
26314 * @param {Roo.bootstrap.LocationPicker} this
26315 * @param {Map event} e
26317 markerClick : true,
26319 * @event markerRightClick
26320 * Fires when right click the marker.
26321 * @param {Roo.bootstrap.LocationPicker} this
26322 * @param {Map event} e
26324 markerRightClick : true,
26326 * @event OverlayViewDraw
26327 * Fires when OverlayView Draw
26328 * @param {Roo.bootstrap.LocationPicker} this
26330 OverlayViewDraw : true,
26332 * @event OverlayViewOnAdd
26333 * Fires when OverlayView Draw
26334 * @param {Roo.bootstrap.LocationPicker} this
26336 OverlayViewOnAdd : true,
26338 * @event OverlayViewOnRemove
26339 * Fires when OverlayView Draw
26340 * @param {Roo.bootstrap.LocationPicker} this
26342 OverlayViewOnRemove : true,
26344 * @event OverlayViewShow
26345 * Fires when OverlayView Draw
26346 * @param {Roo.bootstrap.LocationPicker} this
26347 * @param {Pixel} cpx
26349 OverlayViewShow : true,
26351 * @event OverlayViewHide
26352 * Fires when OverlayView Draw
26353 * @param {Roo.bootstrap.LocationPicker} this
26355 OverlayViewHide : true,
26357 * @event loadexception
26358 * Fires when load google lib failed.
26359 * @param {Roo.bootstrap.LocationPicker} this
26361 loadexception : true
26366 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26368 gMapContext: false,
26374 mapTypeControl: false,
26375 disableDoubleClickZoom: false,
26377 streetViewControl: false,
26381 enableAutocomplete: false,
26382 enableReverseGeocode: true,
26385 getAutoCreate: function()
26390 cls: 'roo-location-picker'
26396 initEvents: function(ct, position)
26398 if(!this.el.getWidth() || this.isApplied()){
26402 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26407 initial: function()
26409 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26410 this.fireEvent('loadexception', this);
26414 if(!this.mapTypeId){
26415 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26418 this.gMapContext = this.GMapContext();
26420 this.initOverlayView();
26422 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26426 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26427 _this.setPosition(_this.gMapContext.marker.position);
26430 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26431 _this.fireEvent('mapClick', this, event);
26435 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26436 _this.fireEvent('mapRightClick', this, event);
26440 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26441 _this.fireEvent('markerClick', this, event);
26445 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26446 _this.fireEvent('markerRightClick', this, event);
26450 this.setPosition(this.gMapContext.location);
26452 this.fireEvent('initial', this, this.gMapContext.location);
26455 initOverlayView: function()
26459 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26463 _this.fireEvent('OverlayViewDraw', _this);
26468 _this.fireEvent('OverlayViewOnAdd', _this);
26471 onRemove: function()
26473 _this.fireEvent('OverlayViewOnRemove', _this);
26476 show: function(cpx)
26478 _this.fireEvent('OverlayViewShow', _this, cpx);
26483 _this.fireEvent('OverlayViewHide', _this);
26489 fromLatLngToContainerPixel: function(event)
26491 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26494 isApplied: function()
26496 return this.getGmapContext() == false ? false : true;
26499 getGmapContext: function()
26501 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26504 GMapContext: function()
26506 var position = new google.maps.LatLng(this.latitude, this.longitude);
26508 var _map = new google.maps.Map(this.el.dom, {
26511 mapTypeId: this.mapTypeId,
26512 mapTypeControl: this.mapTypeControl,
26513 disableDoubleClickZoom: this.disableDoubleClickZoom,
26514 scrollwheel: this.scrollwheel,
26515 streetViewControl: this.streetViewControl,
26516 locationName: this.locationName,
26517 draggable: this.draggable,
26518 enableAutocomplete: this.enableAutocomplete,
26519 enableReverseGeocode: this.enableReverseGeocode
26522 var _marker = new google.maps.Marker({
26523 position: position,
26525 title: this.markerTitle,
26526 draggable: this.draggable
26533 location: position,
26534 radius: this.radius,
26535 locationName: this.locationName,
26536 addressComponents: {
26537 formatted_address: null,
26538 addressLine1: null,
26539 addressLine2: null,
26541 streetNumber: null,
26545 stateOrProvince: null
26548 domContainer: this.el.dom,
26549 geodecoder: new google.maps.Geocoder()
26553 drawCircle: function(center, radius, options)
26555 if (this.gMapContext.circle != null) {
26556 this.gMapContext.circle.setMap(null);
26560 options = Roo.apply({}, options, {
26561 strokeColor: "#0000FF",
26562 strokeOpacity: .35,
26564 fillColor: "#0000FF",
26568 options.map = this.gMapContext.map;
26569 options.radius = radius;
26570 options.center = center;
26571 this.gMapContext.circle = new google.maps.Circle(options);
26572 return this.gMapContext.circle;
26578 setPosition: function(location)
26580 this.gMapContext.location = location;
26581 this.gMapContext.marker.setPosition(location);
26582 this.gMapContext.map.panTo(location);
26583 this.drawCircle(location, this.gMapContext.radius, {});
26587 if (this.gMapContext.settings.enableReverseGeocode) {
26588 this.gMapContext.geodecoder.geocode({
26589 latLng: this.gMapContext.location
26590 }, function(results, status) {
26592 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26593 _this.gMapContext.locationName = results[0].formatted_address;
26594 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26596 _this.fireEvent('positionchanged', this, location);
26603 this.fireEvent('positionchanged', this, location);
26608 google.maps.event.trigger(this.gMapContext.map, "resize");
26610 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26612 this.fireEvent('resize', this);
26615 setPositionByLatLng: function(latitude, longitude)
26617 this.setPosition(new google.maps.LatLng(latitude, longitude));
26620 getCurrentPosition: function()
26623 latitude: this.gMapContext.location.lat(),
26624 longitude: this.gMapContext.location.lng()
26628 getAddressName: function()
26630 return this.gMapContext.locationName;
26633 getAddressComponents: function()
26635 return this.gMapContext.addressComponents;
26638 address_component_from_google_geocode: function(address_components)
26642 for (var i = 0; i < address_components.length; i++) {
26643 var component = address_components[i];
26644 if (component.types.indexOf("postal_code") >= 0) {
26645 result.postalCode = component.short_name;
26646 } else if (component.types.indexOf("street_number") >= 0) {
26647 result.streetNumber = component.short_name;
26648 } else if (component.types.indexOf("route") >= 0) {
26649 result.streetName = component.short_name;
26650 } else if (component.types.indexOf("neighborhood") >= 0) {
26651 result.city = component.short_name;
26652 } else if (component.types.indexOf("locality") >= 0) {
26653 result.city = component.short_name;
26654 } else if (component.types.indexOf("sublocality") >= 0) {
26655 result.district = component.short_name;
26656 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26657 result.stateOrProvince = component.short_name;
26658 } else if (component.types.indexOf("country") >= 0) {
26659 result.country = component.short_name;
26663 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26664 result.addressLine2 = "";
26668 setZoomLevel: function(zoom)
26670 this.gMapContext.map.setZoom(zoom);
26683 this.fireEvent('show', this);
26694 this.fireEvent('hide', this);
26699 Roo.apply(Roo.bootstrap.LocationPicker, {
26701 OverlayView : function(map, options)
26703 options = options || {};
26717 * @class Roo.bootstrap.Alert
26718 * @extends Roo.bootstrap.Component
26719 * Bootstrap Alert class
26720 * @cfg {String} title The title of alert
26721 * @cfg {String} html The content of alert
26722 * @cfg {String} weight ( success | info | warning | danger )
26723 * @cfg {String} faicon font-awesomeicon
26726 * Create a new alert
26727 * @param {Object} config The config object
26731 Roo.bootstrap.Alert = function(config){
26732 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26736 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26743 getAutoCreate : function()
26752 cls : 'roo-alert-icon'
26757 cls : 'roo-alert-title',
26762 cls : 'roo-alert-text',
26769 cfg.cn[0].cls += ' fa ' + this.faicon;
26773 cfg.cls += ' alert-' + this.weight;
26779 initEvents: function()
26781 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26784 setTitle : function(str)
26786 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26789 setText : function(str)
26791 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26794 setWeight : function(weight)
26797 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26800 this.weight = weight;
26802 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26805 setIcon : function(icon)
26808 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26811 this.faicon = icon;
26813 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26834 * @class Roo.bootstrap.UploadCropbox
26835 * @extends Roo.bootstrap.Component
26836 * Bootstrap UploadCropbox class
26837 * @cfg {String} emptyText show when image has been loaded
26838 * @cfg {String} rotateNotify show when image too small to rotate
26839 * @cfg {Number} errorTimeout default 3000
26840 * @cfg {Number} minWidth default 300
26841 * @cfg {Number} minHeight default 300
26842 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26843 * @cfg {Boolean} isDocument (true|false) default false
26844 * @cfg {String} url action url
26845 * @cfg {String} paramName default 'imageUpload'
26846 * @cfg {String} method default POST
26847 * @cfg {Boolean} loadMask (true|false) default true
26848 * @cfg {Boolean} loadingText default 'Loading...'
26851 * Create a new UploadCropbox
26852 * @param {Object} config The config object
26855 Roo.bootstrap.UploadCropbox = function(config){
26856 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26860 * @event beforeselectfile
26861 * Fire before select file
26862 * @param {Roo.bootstrap.UploadCropbox} this
26864 "beforeselectfile" : true,
26867 * Fire after initEvent
26868 * @param {Roo.bootstrap.UploadCropbox} this
26873 * Fire after initEvent
26874 * @param {Roo.bootstrap.UploadCropbox} this
26875 * @param {String} data
26880 * Fire when preparing the file data
26881 * @param {Roo.bootstrap.UploadCropbox} this
26882 * @param {Object} file
26887 * Fire when get exception
26888 * @param {Roo.bootstrap.UploadCropbox} this
26889 * @param {XMLHttpRequest} xhr
26891 "exception" : true,
26893 * @event beforeloadcanvas
26894 * Fire before load the canvas
26895 * @param {Roo.bootstrap.UploadCropbox} this
26896 * @param {String} src
26898 "beforeloadcanvas" : true,
26901 * Fire when trash image
26902 * @param {Roo.bootstrap.UploadCropbox} this
26907 * Fire when download the image
26908 * @param {Roo.bootstrap.UploadCropbox} this
26912 * @event footerbuttonclick
26913 * Fire when footerbuttonclick
26914 * @param {Roo.bootstrap.UploadCropbox} this
26915 * @param {String} type
26917 "footerbuttonclick" : true,
26921 * @param {Roo.bootstrap.UploadCropbox} this
26926 * Fire when rotate the image
26927 * @param {Roo.bootstrap.UploadCropbox} this
26928 * @param {String} pos
26933 * Fire when inspect the file
26934 * @param {Roo.bootstrap.UploadCropbox} this
26935 * @param {Object} file
26940 * Fire when xhr upload the file
26941 * @param {Roo.bootstrap.UploadCropbox} this
26942 * @param {Object} data
26947 * Fire when arrange the file data
26948 * @param {Roo.bootstrap.UploadCropbox} this
26949 * @param {Object} formData
26954 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26957 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26959 emptyText : 'Click to upload image',
26960 rotateNotify : 'Image is too small to rotate',
26961 errorTimeout : 3000,
26975 cropType : 'image/jpeg',
26977 canvasLoaded : false,
26978 isDocument : false,
26980 paramName : 'imageUpload',
26982 loadingText : 'Loading...',
26985 getAutoCreate : function()
26989 cls : 'roo-upload-cropbox',
26993 cls : 'roo-upload-cropbox-selector',
26998 cls : 'roo-upload-cropbox-body',
26999 style : 'cursor:pointer',
27003 cls : 'roo-upload-cropbox-preview'
27007 cls : 'roo-upload-cropbox-thumb'
27011 cls : 'roo-upload-cropbox-empty-notify',
27012 html : this.emptyText
27016 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27017 html : this.rotateNotify
27023 cls : 'roo-upload-cropbox-footer',
27026 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27036 onRender : function(ct, position)
27038 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27040 if (this.buttons.length) {
27042 Roo.each(this.buttons, function(bb) {
27044 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27046 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27052 this.maskEl = this.el;
27056 initEvents : function()
27058 this.urlAPI = (window.createObjectURL && window) ||
27059 (window.URL && URL.revokeObjectURL && URL) ||
27060 (window.webkitURL && webkitURL);
27062 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27063 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27065 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27066 this.selectorEl.hide();
27068 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27069 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27071 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27072 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27073 this.thumbEl.hide();
27075 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27076 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27078 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27079 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27080 this.errorEl.hide();
27082 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27083 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27084 this.footerEl.hide();
27086 this.setThumbBoxSize();
27092 this.fireEvent('initial', this);
27099 window.addEventListener("resize", function() { _this.resize(); } );
27101 this.bodyEl.on('click', this.beforeSelectFile, this);
27104 this.bodyEl.on('touchstart', this.onTouchStart, this);
27105 this.bodyEl.on('touchmove', this.onTouchMove, this);
27106 this.bodyEl.on('touchend', this.onTouchEnd, this);
27110 this.bodyEl.on('mousedown', this.onMouseDown, this);
27111 this.bodyEl.on('mousemove', this.onMouseMove, this);
27112 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27113 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27114 Roo.get(document).on('mouseup', this.onMouseUp, this);
27117 this.selectorEl.on('change', this.onFileSelected, this);
27123 this.baseScale = 1;
27125 this.baseRotate = 1;
27126 this.dragable = false;
27127 this.pinching = false;
27130 this.cropData = false;
27131 this.notifyEl.dom.innerHTML = this.emptyText;
27133 this.selectorEl.dom.value = '';
27137 resize : function()
27139 if(this.fireEvent('resize', this) != false){
27140 this.setThumbBoxPosition();
27141 this.setCanvasPosition();
27145 onFooterButtonClick : function(e, el, o, type)
27148 case 'rotate-left' :
27149 this.onRotateLeft(e);
27151 case 'rotate-right' :
27152 this.onRotateRight(e);
27155 this.beforeSelectFile(e);
27170 this.fireEvent('footerbuttonclick', this, type);
27173 beforeSelectFile : function(e)
27175 e.preventDefault();
27177 if(this.fireEvent('beforeselectfile', this) != false){
27178 this.selectorEl.dom.click();
27182 onFileSelected : function(e)
27184 e.preventDefault();
27186 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27190 var file = this.selectorEl.dom.files[0];
27192 if(this.fireEvent('inspect', this, file) != false){
27193 this.prepare(file);
27198 trash : function(e)
27200 this.fireEvent('trash', this);
27203 download : function(e)
27205 this.fireEvent('download', this);
27208 loadCanvas : function(src)
27210 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27214 this.imageEl = document.createElement('img');
27218 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27220 this.imageEl.src = src;
27224 onLoadCanvas : function()
27226 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27227 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27229 this.bodyEl.un('click', this.beforeSelectFile, this);
27231 this.notifyEl.hide();
27232 this.thumbEl.show();
27233 this.footerEl.show();
27235 this.baseRotateLevel();
27237 if(this.isDocument){
27238 this.setThumbBoxSize();
27241 this.setThumbBoxPosition();
27243 this.baseScaleLevel();
27249 this.canvasLoaded = true;
27252 this.maskEl.unmask();
27257 setCanvasPosition : function()
27259 if(!this.canvasEl){
27263 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27264 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27266 this.previewEl.setLeft(pw);
27267 this.previewEl.setTop(ph);
27271 onMouseDown : function(e)
27275 this.dragable = true;
27276 this.pinching = false;
27278 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27279 this.dragable = false;
27283 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27284 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27288 onMouseMove : function(e)
27292 if(!this.canvasLoaded){
27296 if (!this.dragable){
27300 var minX = Math.ceil(this.thumbEl.getLeft(true));
27301 var minY = Math.ceil(this.thumbEl.getTop(true));
27303 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27304 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27306 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27307 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27309 x = x - this.mouseX;
27310 y = y - this.mouseY;
27312 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27313 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27315 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27316 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27318 this.previewEl.setLeft(bgX);
27319 this.previewEl.setTop(bgY);
27321 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27322 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27325 onMouseUp : function(e)
27329 this.dragable = false;
27332 onMouseWheel : function(e)
27336 this.startScale = this.scale;
27338 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27340 if(!this.zoomable()){
27341 this.scale = this.startScale;
27350 zoomable : function()
27352 var minScale = this.thumbEl.getWidth() / this.minWidth;
27354 if(this.minWidth < this.minHeight){
27355 minScale = this.thumbEl.getHeight() / this.minHeight;
27358 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27359 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27363 (this.rotate == 0 || this.rotate == 180) &&
27365 width > this.imageEl.OriginWidth ||
27366 height > this.imageEl.OriginHeight ||
27367 (width < this.minWidth && height < this.minHeight)
27375 (this.rotate == 90 || this.rotate == 270) &&
27377 width > this.imageEl.OriginWidth ||
27378 height > this.imageEl.OriginHeight ||
27379 (width < this.minHeight && height < this.minWidth)
27386 !this.isDocument &&
27387 (this.rotate == 0 || this.rotate == 180) &&
27389 width < this.minWidth ||
27390 width > this.imageEl.OriginWidth ||
27391 height < this.minHeight ||
27392 height > this.imageEl.OriginHeight
27399 !this.isDocument &&
27400 (this.rotate == 90 || this.rotate == 270) &&
27402 width < this.minHeight ||
27403 width > this.imageEl.OriginWidth ||
27404 height < this.minWidth ||
27405 height > this.imageEl.OriginHeight
27415 onRotateLeft : function(e)
27417 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27419 var minScale = this.thumbEl.getWidth() / this.minWidth;
27421 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27422 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27424 this.startScale = this.scale;
27426 while (this.getScaleLevel() < minScale){
27428 this.scale = this.scale + 1;
27430 if(!this.zoomable()){
27435 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27436 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27441 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27448 this.scale = this.startScale;
27450 this.onRotateFail();
27455 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27457 if(this.isDocument){
27458 this.setThumbBoxSize();
27459 this.setThumbBoxPosition();
27460 this.setCanvasPosition();
27465 this.fireEvent('rotate', this, 'left');
27469 onRotateRight : function(e)
27471 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27473 var minScale = this.thumbEl.getWidth() / this.minWidth;
27475 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27476 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27478 this.startScale = this.scale;
27480 while (this.getScaleLevel() < minScale){
27482 this.scale = this.scale + 1;
27484 if(!this.zoomable()){
27489 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27490 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27495 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27502 this.scale = this.startScale;
27504 this.onRotateFail();
27509 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27511 if(this.isDocument){
27512 this.setThumbBoxSize();
27513 this.setThumbBoxPosition();
27514 this.setCanvasPosition();
27519 this.fireEvent('rotate', this, 'right');
27522 onRotateFail : function()
27524 this.errorEl.show(true);
27528 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27533 this.previewEl.dom.innerHTML = '';
27535 var canvasEl = document.createElement("canvas");
27537 var contextEl = canvasEl.getContext("2d");
27539 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27540 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27541 var center = this.imageEl.OriginWidth / 2;
27543 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27544 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27545 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27546 center = this.imageEl.OriginHeight / 2;
27549 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27551 contextEl.translate(center, center);
27552 contextEl.rotate(this.rotate * Math.PI / 180);
27554 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27556 this.canvasEl = document.createElement("canvas");
27558 this.contextEl = this.canvasEl.getContext("2d");
27560 switch (this.rotate) {
27563 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27564 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27566 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27571 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27572 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27574 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27575 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);
27579 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27584 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27585 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27587 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27588 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);
27592 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);
27597 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27598 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27600 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27601 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27605 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);
27612 this.previewEl.appendChild(this.canvasEl);
27614 this.setCanvasPosition();
27619 if(!this.canvasLoaded){
27623 var imageCanvas = document.createElement("canvas");
27625 var imageContext = imageCanvas.getContext("2d");
27627 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27628 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27630 var center = imageCanvas.width / 2;
27632 imageContext.translate(center, center);
27634 imageContext.rotate(this.rotate * Math.PI / 180);
27636 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27638 var canvas = document.createElement("canvas");
27640 var context = canvas.getContext("2d");
27642 canvas.width = this.minWidth;
27643 canvas.height = this.minHeight;
27645 switch (this.rotate) {
27648 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27649 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27651 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27652 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27654 var targetWidth = this.minWidth - 2 * x;
27655 var targetHeight = this.minHeight - 2 * y;
27659 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27660 scale = targetWidth / width;
27663 if(x > 0 && y == 0){
27664 scale = targetHeight / height;
27667 if(x > 0 && y > 0){
27668 scale = targetWidth / width;
27670 if(width < height){
27671 scale = targetHeight / height;
27675 context.scale(scale, scale);
27677 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27678 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27680 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27681 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27683 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27688 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27689 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27691 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27692 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27694 var targetWidth = this.minWidth - 2 * x;
27695 var targetHeight = this.minHeight - 2 * y;
27699 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27700 scale = targetWidth / width;
27703 if(x > 0 && y == 0){
27704 scale = targetHeight / height;
27707 if(x > 0 && y > 0){
27708 scale = targetWidth / width;
27710 if(width < height){
27711 scale = targetHeight / height;
27715 context.scale(scale, scale);
27717 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27718 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27720 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27721 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27723 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27725 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27730 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27731 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27733 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27734 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27736 var targetWidth = this.minWidth - 2 * x;
27737 var targetHeight = this.minHeight - 2 * y;
27741 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27742 scale = targetWidth / width;
27745 if(x > 0 && y == 0){
27746 scale = targetHeight / height;
27749 if(x > 0 && y > 0){
27750 scale = targetWidth / width;
27752 if(width < height){
27753 scale = targetHeight / height;
27757 context.scale(scale, scale);
27759 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27760 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27762 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27763 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27765 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27766 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27768 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27773 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27774 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27776 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27777 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27779 var targetWidth = this.minWidth - 2 * x;
27780 var targetHeight = this.minHeight - 2 * y;
27784 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27785 scale = targetWidth / width;
27788 if(x > 0 && y == 0){
27789 scale = targetHeight / height;
27792 if(x > 0 && y > 0){
27793 scale = targetWidth / width;
27795 if(width < height){
27796 scale = targetHeight / height;
27800 context.scale(scale, scale);
27802 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27803 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27805 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27806 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27808 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27810 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27817 this.cropData = canvas.toDataURL(this.cropType);
27819 if(this.fireEvent('crop', this, this.cropData) !== false){
27820 this.process(this.file, this.cropData);
27827 setThumbBoxSize : function()
27831 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27832 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27833 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27835 this.minWidth = width;
27836 this.minHeight = height;
27838 if(this.rotate == 90 || this.rotate == 270){
27839 this.minWidth = height;
27840 this.minHeight = width;
27845 width = Math.ceil(this.minWidth * height / this.minHeight);
27847 if(this.minWidth > this.minHeight){
27849 height = Math.ceil(this.minHeight * width / this.minWidth);
27852 this.thumbEl.setStyle({
27853 width : width + 'px',
27854 height : height + 'px'
27861 setThumbBoxPosition : function()
27863 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27864 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27866 this.thumbEl.setLeft(x);
27867 this.thumbEl.setTop(y);
27871 baseRotateLevel : function()
27873 this.baseRotate = 1;
27876 typeof(this.exif) != 'undefined' &&
27877 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27878 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27880 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27883 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27887 baseScaleLevel : function()
27891 if(this.isDocument){
27893 if(this.baseRotate == 6 || this.baseRotate == 8){
27895 height = this.thumbEl.getHeight();
27896 this.baseScale = height / this.imageEl.OriginWidth;
27898 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27899 width = this.thumbEl.getWidth();
27900 this.baseScale = width / this.imageEl.OriginHeight;
27906 height = this.thumbEl.getHeight();
27907 this.baseScale = height / this.imageEl.OriginHeight;
27909 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27910 width = this.thumbEl.getWidth();
27911 this.baseScale = width / this.imageEl.OriginWidth;
27917 if(this.baseRotate == 6 || this.baseRotate == 8){
27919 width = this.thumbEl.getHeight();
27920 this.baseScale = width / this.imageEl.OriginHeight;
27922 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27923 height = this.thumbEl.getWidth();
27924 this.baseScale = height / this.imageEl.OriginHeight;
27927 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27928 height = this.thumbEl.getWidth();
27929 this.baseScale = height / this.imageEl.OriginHeight;
27931 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27932 width = this.thumbEl.getHeight();
27933 this.baseScale = width / this.imageEl.OriginWidth;
27940 width = this.thumbEl.getWidth();
27941 this.baseScale = width / this.imageEl.OriginWidth;
27943 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27944 height = this.thumbEl.getHeight();
27945 this.baseScale = height / this.imageEl.OriginHeight;
27948 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27950 height = this.thumbEl.getHeight();
27951 this.baseScale = height / this.imageEl.OriginHeight;
27953 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27954 width = this.thumbEl.getWidth();
27955 this.baseScale = width / this.imageEl.OriginWidth;
27963 getScaleLevel : function()
27965 return this.baseScale * Math.pow(1.1, this.scale);
27968 onTouchStart : function(e)
27970 if(!this.canvasLoaded){
27971 this.beforeSelectFile(e);
27975 var touches = e.browserEvent.touches;
27981 if(touches.length == 1){
27982 this.onMouseDown(e);
27986 if(touches.length != 2){
27992 for(var i = 0, finger; finger = touches[i]; i++){
27993 coords.push(finger.pageX, finger.pageY);
27996 var x = Math.pow(coords[0] - coords[2], 2);
27997 var y = Math.pow(coords[1] - coords[3], 2);
27999 this.startDistance = Math.sqrt(x + y);
28001 this.startScale = this.scale;
28003 this.pinching = true;
28004 this.dragable = false;
28008 onTouchMove : function(e)
28010 if(!this.pinching && !this.dragable){
28014 var touches = e.browserEvent.touches;
28021 this.onMouseMove(e);
28027 for(var i = 0, finger; finger = touches[i]; i++){
28028 coords.push(finger.pageX, finger.pageY);
28031 var x = Math.pow(coords[0] - coords[2], 2);
28032 var y = Math.pow(coords[1] - coords[3], 2);
28034 this.endDistance = Math.sqrt(x + y);
28036 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28038 if(!this.zoomable()){
28039 this.scale = this.startScale;
28047 onTouchEnd : function(e)
28049 this.pinching = false;
28050 this.dragable = false;
28054 process : function(file, crop)
28057 this.maskEl.mask(this.loadingText);
28060 this.xhr = new XMLHttpRequest();
28062 file.xhr = this.xhr;
28064 this.xhr.open(this.method, this.url, true);
28067 "Accept": "application/json",
28068 "Cache-Control": "no-cache",
28069 "X-Requested-With": "XMLHttpRequest"
28072 for (var headerName in headers) {
28073 var headerValue = headers[headerName];
28075 this.xhr.setRequestHeader(headerName, headerValue);
28081 this.xhr.onload = function()
28083 _this.xhrOnLoad(_this.xhr);
28086 this.xhr.onerror = function()
28088 _this.xhrOnError(_this.xhr);
28091 var formData = new FormData();
28093 formData.append('returnHTML', 'NO');
28096 formData.append('crop', crop);
28099 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28100 formData.append(this.paramName, file, file.name);
28103 if(typeof(file.filename) != 'undefined'){
28104 formData.append('filename', file.filename);
28107 if(typeof(file.mimetype) != 'undefined'){
28108 formData.append('mimetype', file.mimetype);
28111 if(this.fireEvent('arrange', this, formData) != false){
28112 this.xhr.send(formData);
28116 xhrOnLoad : function(xhr)
28119 this.maskEl.unmask();
28122 if (xhr.readyState !== 4) {
28123 this.fireEvent('exception', this, xhr);
28127 var response = Roo.decode(xhr.responseText);
28129 if(!response.success){
28130 this.fireEvent('exception', this, xhr);
28134 var response = Roo.decode(xhr.responseText);
28136 this.fireEvent('upload', this, response);
28140 xhrOnError : function()
28143 this.maskEl.unmask();
28146 Roo.log('xhr on error');
28148 var response = Roo.decode(xhr.responseText);
28154 prepare : function(file)
28157 this.maskEl.mask(this.loadingText);
28163 if(typeof(file) === 'string'){
28164 this.loadCanvas(file);
28168 if(!file || !this.urlAPI){
28173 this.cropType = file.type;
28177 if(this.fireEvent('prepare', this, this.file) != false){
28179 var reader = new FileReader();
28181 reader.onload = function (e) {
28182 if (e.target.error) {
28183 Roo.log(e.target.error);
28187 var buffer = e.target.result,
28188 dataView = new DataView(buffer),
28190 maxOffset = dataView.byteLength - 4,
28194 if (dataView.getUint16(0) === 0xffd8) {
28195 while (offset < maxOffset) {
28196 markerBytes = dataView.getUint16(offset);
28198 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28199 markerLength = dataView.getUint16(offset + 2) + 2;
28200 if (offset + markerLength > dataView.byteLength) {
28201 Roo.log('Invalid meta data: Invalid segment size.');
28205 if(markerBytes == 0xffe1){
28206 _this.parseExifData(
28213 offset += markerLength;
28223 var url = _this.urlAPI.createObjectURL(_this.file);
28225 _this.loadCanvas(url);
28230 reader.readAsArrayBuffer(this.file);
28236 parseExifData : function(dataView, offset, length)
28238 var tiffOffset = offset + 10,
28242 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28243 // No Exif data, might be XMP data instead
28247 // Check for the ASCII code for "Exif" (0x45786966):
28248 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28249 // No Exif data, might be XMP data instead
28252 if (tiffOffset + 8 > dataView.byteLength) {
28253 Roo.log('Invalid Exif data: Invalid segment size.');
28256 // Check for the two null bytes:
28257 if (dataView.getUint16(offset + 8) !== 0x0000) {
28258 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28261 // Check the byte alignment:
28262 switch (dataView.getUint16(tiffOffset)) {
28264 littleEndian = true;
28267 littleEndian = false;
28270 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28273 // Check for the TIFF tag marker (0x002A):
28274 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28275 Roo.log('Invalid Exif data: Missing TIFF marker.');
28278 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28279 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28281 this.parseExifTags(
28284 tiffOffset + dirOffset,
28289 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28294 if (dirOffset + 6 > dataView.byteLength) {
28295 Roo.log('Invalid Exif data: Invalid directory offset.');
28298 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28299 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28300 if (dirEndOffset + 4 > dataView.byteLength) {
28301 Roo.log('Invalid Exif data: Invalid directory size.');
28304 for (i = 0; i < tagsNumber; i += 1) {
28308 dirOffset + 2 + 12 * i, // tag offset
28312 // Return the offset to the next directory:
28313 return dataView.getUint32(dirEndOffset, littleEndian);
28316 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28318 var tag = dataView.getUint16(offset, littleEndian);
28320 this.exif[tag] = this.getExifValue(
28324 dataView.getUint16(offset + 2, littleEndian), // tag type
28325 dataView.getUint32(offset + 4, littleEndian), // tag length
28330 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28332 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28341 Roo.log('Invalid Exif data: Invalid tag type.');
28345 tagSize = tagType.size * length;
28346 // Determine if the value is contained in the dataOffset bytes,
28347 // or if the value at the dataOffset is a pointer to the actual data:
28348 dataOffset = tagSize > 4 ?
28349 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28350 if (dataOffset + tagSize > dataView.byteLength) {
28351 Roo.log('Invalid Exif data: Invalid data offset.');
28354 if (length === 1) {
28355 return tagType.getValue(dataView, dataOffset, littleEndian);
28358 for (i = 0; i < length; i += 1) {
28359 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28362 if (tagType.ascii) {
28364 // Concatenate the chars:
28365 for (i = 0; i < values.length; i += 1) {
28367 // Ignore the terminating NULL byte(s):
28368 if (c === '\u0000') {
28380 Roo.apply(Roo.bootstrap.UploadCropbox, {
28382 'Orientation': 0x0112
28386 1: 0, //'top-left',
28388 3: 180, //'bottom-right',
28389 // 4: 'bottom-left',
28391 6: 90, //'right-top',
28392 // 7: 'right-bottom',
28393 8: 270 //'left-bottom'
28397 // byte, 8-bit unsigned int:
28399 getValue: function (dataView, dataOffset) {
28400 return dataView.getUint8(dataOffset);
28404 // ascii, 8-bit byte:
28406 getValue: function (dataView, dataOffset) {
28407 return String.fromCharCode(dataView.getUint8(dataOffset));
28412 // short, 16 bit int:
28414 getValue: function (dataView, dataOffset, littleEndian) {
28415 return dataView.getUint16(dataOffset, littleEndian);
28419 // long, 32 bit int:
28421 getValue: function (dataView, dataOffset, littleEndian) {
28422 return dataView.getUint32(dataOffset, littleEndian);
28426 // rational = two long values, first is numerator, second is denominator:
28428 getValue: function (dataView, dataOffset, littleEndian) {
28429 return dataView.getUint32(dataOffset, littleEndian) /
28430 dataView.getUint32(dataOffset + 4, littleEndian);
28434 // slong, 32 bit signed int:
28436 getValue: function (dataView, dataOffset, littleEndian) {
28437 return dataView.getInt32(dataOffset, littleEndian);
28441 // srational, two slongs, first is numerator, second is denominator:
28443 getValue: function (dataView, dataOffset, littleEndian) {
28444 return dataView.getInt32(dataOffset, littleEndian) /
28445 dataView.getInt32(dataOffset + 4, littleEndian);
28455 cls : 'btn-group roo-upload-cropbox-rotate-left',
28456 action : 'rotate-left',
28460 cls : 'btn btn-default',
28461 html : '<i class="fa fa-undo"></i>'
28467 cls : 'btn-group roo-upload-cropbox-picture',
28468 action : 'picture',
28472 cls : 'btn btn-default',
28473 html : '<i class="fa fa-picture-o"></i>'
28479 cls : 'btn-group roo-upload-cropbox-rotate-right',
28480 action : 'rotate-right',
28484 cls : 'btn btn-default',
28485 html : '<i class="fa fa-repeat"></i>'
28493 cls : 'btn-group roo-upload-cropbox-rotate-left',
28494 action : 'rotate-left',
28498 cls : 'btn btn-default',
28499 html : '<i class="fa fa-undo"></i>'
28505 cls : 'btn-group roo-upload-cropbox-download',
28506 action : 'download',
28510 cls : 'btn btn-default',
28511 html : '<i class="fa fa-download"></i>'
28517 cls : 'btn-group roo-upload-cropbox-crop',
28522 cls : 'btn btn-default',
28523 html : '<i class="fa fa-crop"></i>'
28529 cls : 'btn-group roo-upload-cropbox-trash',
28534 cls : 'btn btn-default',
28535 html : '<i class="fa fa-trash"></i>'
28541 cls : 'btn-group roo-upload-cropbox-rotate-right',
28542 action : 'rotate-right',
28546 cls : 'btn btn-default',
28547 html : '<i class="fa fa-repeat"></i>'
28555 cls : 'btn-group roo-upload-cropbox-rotate-left',
28556 action : 'rotate-left',
28560 cls : 'btn btn-default',
28561 html : '<i class="fa fa-undo"></i>'
28567 cls : 'btn-group roo-upload-cropbox-rotate-right',
28568 action : 'rotate-right',
28572 cls : 'btn btn-default',
28573 html : '<i class="fa fa-repeat"></i>'
28586 * @class Roo.bootstrap.DocumentManager
28587 * @extends Roo.bootstrap.Component
28588 * Bootstrap DocumentManager class
28589 * @cfg {String} paramName default 'imageUpload'
28590 * @cfg {String} toolTipName default 'filename'
28591 * @cfg {String} method default POST
28592 * @cfg {String} url action url
28593 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28594 * @cfg {Boolean} multiple multiple upload default true
28595 * @cfg {Number} thumbSize default 300
28596 * @cfg {String} fieldLabel
28597 * @cfg {Number} labelWidth default 4
28598 * @cfg {String} labelAlign (left|top) default left
28599 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28600 * @cfg {Number} labellg set the width of label (1-12)
28601 * @cfg {Number} labelmd set the width of label (1-12)
28602 * @cfg {Number} labelsm set the width of label (1-12)
28603 * @cfg {Number} labelxs set the width of label (1-12)
28606 * Create a new DocumentManager
28607 * @param {Object} config The config object
28610 Roo.bootstrap.DocumentManager = function(config){
28611 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28614 this.delegates = [];
28619 * Fire when initial the DocumentManager
28620 * @param {Roo.bootstrap.DocumentManager} this
28625 * inspect selected file
28626 * @param {Roo.bootstrap.DocumentManager} this
28627 * @param {File} file
28632 * Fire when xhr load exception
28633 * @param {Roo.bootstrap.DocumentManager} this
28634 * @param {XMLHttpRequest} xhr
28636 "exception" : true,
28638 * @event afterupload
28639 * Fire when xhr load exception
28640 * @param {Roo.bootstrap.DocumentManager} this
28641 * @param {XMLHttpRequest} xhr
28643 "afterupload" : true,
28646 * prepare the form data
28647 * @param {Roo.bootstrap.DocumentManager} this
28648 * @param {Object} formData
28653 * Fire when remove the file
28654 * @param {Roo.bootstrap.DocumentManager} this
28655 * @param {Object} file
28660 * Fire after refresh the file
28661 * @param {Roo.bootstrap.DocumentManager} this
28666 * Fire after click the image
28667 * @param {Roo.bootstrap.DocumentManager} this
28668 * @param {Object} file
28673 * Fire when upload a image and editable set to true
28674 * @param {Roo.bootstrap.DocumentManager} this
28675 * @param {Object} file
28679 * @event beforeselectfile
28680 * Fire before select file
28681 * @param {Roo.bootstrap.DocumentManager} this
28683 "beforeselectfile" : true,
28686 * Fire before process file
28687 * @param {Roo.bootstrap.DocumentManager} this
28688 * @param {Object} file
28692 * @event previewrendered
28693 * Fire when preview rendered
28694 * @param {Roo.bootstrap.DocumentManager} this
28695 * @param {Object} file
28697 "previewrendered" : true
28702 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28711 paramName : 'imageUpload',
28712 toolTipName : 'filename',
28715 labelAlign : 'left',
28725 getAutoCreate : function()
28727 var managerWidget = {
28729 cls : 'roo-document-manager',
28733 cls : 'roo-document-manager-selector',
28738 cls : 'roo-document-manager-uploader',
28742 cls : 'roo-document-manager-upload-btn',
28743 html : '<i class="fa fa-plus"></i>'
28754 cls : 'column col-md-12',
28759 if(this.fieldLabel.length){
28764 cls : 'column col-md-12',
28765 html : this.fieldLabel
28769 cls : 'column col-md-12',
28774 if(this.labelAlign == 'left'){
28779 html : this.fieldLabel
28788 if(this.labelWidth > 12){
28789 content[0].style = "width: " + this.labelWidth + 'px';
28792 if(this.labelWidth < 13 && this.labelmd == 0){
28793 this.labelmd = this.labelWidth;
28796 if(this.labellg > 0){
28797 content[0].cls += ' col-lg-' + this.labellg;
28798 content[1].cls += ' col-lg-' + (12 - this.labellg);
28801 if(this.labelmd > 0){
28802 content[0].cls += ' col-md-' + this.labelmd;
28803 content[1].cls += ' col-md-' + (12 - this.labelmd);
28806 if(this.labelsm > 0){
28807 content[0].cls += ' col-sm-' + this.labelsm;
28808 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28811 if(this.labelxs > 0){
28812 content[0].cls += ' col-xs-' + this.labelxs;
28813 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28821 cls : 'row clearfix',
28829 initEvents : function()
28831 this.managerEl = this.el.select('.roo-document-manager', true).first();
28832 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28834 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28835 this.selectorEl.hide();
28838 this.selectorEl.attr('multiple', 'multiple');
28841 this.selectorEl.on('change', this.onFileSelected, this);
28843 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28844 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28846 this.uploader.on('click', this.onUploaderClick, this);
28848 this.renderProgressDialog();
28852 window.addEventListener("resize", function() { _this.refresh(); } );
28854 this.fireEvent('initial', this);
28857 renderProgressDialog : function()
28861 this.progressDialog = new Roo.bootstrap.Modal({
28862 cls : 'roo-document-manager-progress-dialog',
28863 allow_close : false,
28873 btnclick : function() {
28874 _this.uploadCancel();
28880 this.progressDialog.render(Roo.get(document.body));
28882 this.progress = new Roo.bootstrap.Progress({
28883 cls : 'roo-document-manager-progress',
28888 this.progress.render(this.progressDialog.getChildContainer());
28890 this.progressBar = new Roo.bootstrap.ProgressBar({
28891 cls : 'roo-document-manager-progress-bar',
28894 aria_valuemax : 12,
28898 this.progressBar.render(this.progress.getChildContainer());
28901 onUploaderClick : function(e)
28903 e.preventDefault();
28905 if(this.fireEvent('beforeselectfile', this) != false){
28906 this.selectorEl.dom.click();
28911 onFileSelected : function(e)
28913 e.preventDefault();
28915 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28919 Roo.each(this.selectorEl.dom.files, function(file){
28920 if(this.fireEvent('inspect', this, file) != false){
28921 this.files.push(file);
28931 this.selectorEl.dom.value = '';
28933 if(!this.files || !this.files.length){
28937 if(this.boxes > 0 && this.files.length > this.boxes){
28938 this.files = this.files.slice(0, this.boxes);
28941 this.uploader.show();
28943 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28944 this.uploader.hide();
28953 Roo.each(this.files, function(file){
28955 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28956 var f = this.renderPreview(file);
28961 if(file.type.indexOf('image') != -1){
28962 this.delegates.push(
28964 _this.process(file);
28965 }).createDelegate(this)
28973 _this.process(file);
28974 }).createDelegate(this)
28979 this.files = files;
28981 this.delegates = this.delegates.concat(docs);
28983 if(!this.delegates.length){
28988 this.progressBar.aria_valuemax = this.delegates.length;
28995 arrange : function()
28997 if(!this.delegates.length){
28998 this.progressDialog.hide();
29003 var delegate = this.delegates.shift();
29005 this.progressDialog.show();
29007 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29009 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29014 refresh : function()
29016 this.uploader.show();
29018 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29019 this.uploader.hide();
29022 Roo.isTouch ? this.closable(false) : this.closable(true);
29024 this.fireEvent('refresh', this);
29027 onRemove : function(e, el, o)
29029 e.preventDefault();
29031 this.fireEvent('remove', this, o);
29035 remove : function(o)
29039 Roo.each(this.files, function(file){
29040 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29049 this.files = files;
29056 Roo.each(this.files, function(file){
29061 file.target.remove();
29070 onClick : function(e, el, o)
29072 e.preventDefault();
29074 this.fireEvent('click', this, o);
29078 closable : function(closable)
29080 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29082 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29094 xhrOnLoad : function(xhr)
29096 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29100 if (xhr.readyState !== 4) {
29102 this.fireEvent('exception', this, xhr);
29106 var response = Roo.decode(xhr.responseText);
29108 if(!response.success){
29110 this.fireEvent('exception', this, xhr);
29114 var file = this.renderPreview(response.data);
29116 this.files.push(file);
29120 this.fireEvent('afterupload', this, xhr);
29124 xhrOnError : function(xhr)
29126 Roo.log('xhr on error');
29128 var response = Roo.decode(xhr.responseText);
29135 process : function(file)
29137 if(this.fireEvent('process', this, file) !== false){
29138 if(this.editable && file.type.indexOf('image') != -1){
29139 this.fireEvent('edit', this, file);
29143 this.uploadStart(file, false);
29150 uploadStart : function(file, crop)
29152 this.xhr = new XMLHttpRequest();
29154 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29159 file.xhr = this.xhr;
29161 this.managerEl.createChild({
29163 cls : 'roo-document-manager-loading',
29167 tooltip : file.name,
29168 cls : 'roo-document-manager-thumb',
29169 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29175 this.xhr.open(this.method, this.url, true);
29178 "Accept": "application/json",
29179 "Cache-Control": "no-cache",
29180 "X-Requested-With": "XMLHttpRequest"
29183 for (var headerName in headers) {
29184 var headerValue = headers[headerName];
29186 this.xhr.setRequestHeader(headerName, headerValue);
29192 this.xhr.onload = function()
29194 _this.xhrOnLoad(_this.xhr);
29197 this.xhr.onerror = function()
29199 _this.xhrOnError(_this.xhr);
29202 var formData = new FormData();
29204 formData.append('returnHTML', 'NO');
29207 formData.append('crop', crop);
29210 formData.append(this.paramName, file, file.name);
29217 if(this.fireEvent('prepare', this, formData, options) != false){
29219 if(options.manually){
29223 this.xhr.send(formData);
29227 this.uploadCancel();
29230 uploadCancel : function()
29236 this.delegates = [];
29238 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29245 renderPreview : function(file)
29247 if(typeof(file.target) != 'undefined' && file.target){
29251 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29253 var previewEl = this.managerEl.createChild({
29255 cls : 'roo-document-manager-preview',
29259 tooltip : file[this.toolTipName],
29260 cls : 'roo-document-manager-thumb',
29261 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29266 html : '<i class="fa fa-times-circle"></i>'
29271 var close = previewEl.select('button.close', true).first();
29273 close.on('click', this.onRemove, this, file);
29275 file.target = previewEl;
29277 var image = previewEl.select('img', true).first();
29281 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29283 image.on('click', this.onClick, this, file);
29285 this.fireEvent('previewrendered', this, file);
29291 onPreviewLoad : function(file, image)
29293 if(typeof(file.target) == 'undefined' || !file.target){
29297 var width = image.dom.naturalWidth || image.dom.width;
29298 var height = image.dom.naturalHeight || image.dom.height;
29300 if(width > height){
29301 file.target.addClass('wide');
29305 file.target.addClass('tall');
29310 uploadFromSource : function(file, crop)
29312 this.xhr = new XMLHttpRequest();
29314 this.managerEl.createChild({
29316 cls : 'roo-document-manager-loading',
29320 tooltip : file.name,
29321 cls : 'roo-document-manager-thumb',
29322 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29328 this.xhr.open(this.method, this.url, true);
29331 "Accept": "application/json",
29332 "Cache-Control": "no-cache",
29333 "X-Requested-With": "XMLHttpRequest"
29336 for (var headerName in headers) {
29337 var headerValue = headers[headerName];
29339 this.xhr.setRequestHeader(headerName, headerValue);
29345 this.xhr.onload = function()
29347 _this.xhrOnLoad(_this.xhr);
29350 this.xhr.onerror = function()
29352 _this.xhrOnError(_this.xhr);
29355 var formData = new FormData();
29357 formData.append('returnHTML', 'NO');
29359 formData.append('crop', crop);
29361 if(typeof(file.filename) != 'undefined'){
29362 formData.append('filename', file.filename);
29365 if(typeof(file.mimetype) != 'undefined'){
29366 formData.append('mimetype', file.mimetype);
29371 if(this.fireEvent('prepare', this, formData) != false){
29372 this.xhr.send(formData);
29382 * @class Roo.bootstrap.DocumentViewer
29383 * @extends Roo.bootstrap.Component
29384 * Bootstrap DocumentViewer class
29385 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29386 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29389 * Create a new DocumentViewer
29390 * @param {Object} config The config object
29393 Roo.bootstrap.DocumentViewer = function(config){
29394 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29399 * Fire after initEvent
29400 * @param {Roo.bootstrap.DocumentViewer} this
29406 * @param {Roo.bootstrap.DocumentViewer} this
29411 * Fire after download button
29412 * @param {Roo.bootstrap.DocumentViewer} this
29417 * Fire after trash button
29418 * @param {Roo.bootstrap.DocumentViewer} this
29425 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29427 showDownload : true,
29431 getAutoCreate : function()
29435 cls : 'roo-document-viewer',
29439 cls : 'roo-document-viewer-body',
29443 cls : 'roo-document-viewer-thumb',
29447 cls : 'roo-document-viewer-image'
29455 cls : 'roo-document-viewer-footer',
29458 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29462 cls : 'btn-group roo-document-viewer-download',
29466 cls : 'btn btn-default',
29467 html : '<i class="fa fa-download"></i>'
29473 cls : 'btn-group roo-document-viewer-trash',
29477 cls : 'btn btn-default',
29478 html : '<i class="fa fa-trash"></i>'
29491 initEvents : function()
29493 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29494 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29496 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29497 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29499 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29500 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29502 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29503 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29505 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29506 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29508 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29509 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29511 this.bodyEl.on('click', this.onClick, this);
29512 this.downloadBtn.on('click', this.onDownload, this);
29513 this.trashBtn.on('click', this.onTrash, this);
29515 this.downloadBtn.hide();
29516 this.trashBtn.hide();
29518 if(this.showDownload){
29519 this.downloadBtn.show();
29522 if(this.showTrash){
29523 this.trashBtn.show();
29526 if(!this.showDownload && !this.showTrash) {
29527 this.footerEl.hide();
29532 initial : function()
29534 this.fireEvent('initial', this);
29538 onClick : function(e)
29540 e.preventDefault();
29542 this.fireEvent('click', this);
29545 onDownload : function(e)
29547 e.preventDefault();
29549 this.fireEvent('download', this);
29552 onTrash : function(e)
29554 e.preventDefault();
29556 this.fireEvent('trash', this);
29568 * @class Roo.bootstrap.NavProgressBar
29569 * @extends Roo.bootstrap.Component
29570 * Bootstrap NavProgressBar class
29573 * Create a new nav progress bar
29574 * @param {Object} config The config object
29577 Roo.bootstrap.NavProgressBar = function(config){
29578 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29580 this.bullets = this.bullets || [];
29582 // Roo.bootstrap.NavProgressBar.register(this);
29586 * Fires when the active item changes
29587 * @param {Roo.bootstrap.NavProgressBar} this
29588 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29589 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29596 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29601 getAutoCreate : function()
29603 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29607 cls : 'roo-navigation-bar-group',
29611 cls : 'roo-navigation-top-bar'
29615 cls : 'roo-navigation-bullets-bar',
29619 cls : 'roo-navigation-bar'
29626 cls : 'roo-navigation-bottom-bar'
29636 initEvents: function()
29641 onRender : function(ct, position)
29643 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29645 if(this.bullets.length){
29646 Roo.each(this.bullets, function(b){
29655 addItem : function(cfg)
29657 var item = new Roo.bootstrap.NavProgressItem(cfg);
29659 item.parentId = this.id;
29660 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29663 var top = new Roo.bootstrap.Element({
29665 cls : 'roo-navigation-bar-text'
29668 var bottom = new Roo.bootstrap.Element({
29670 cls : 'roo-navigation-bar-text'
29673 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29674 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29676 var topText = new Roo.bootstrap.Element({
29678 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29681 var bottomText = new Roo.bootstrap.Element({
29683 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29686 topText.onRender(top.el, null);
29687 bottomText.onRender(bottom.el, null);
29690 item.bottomEl = bottom;
29693 this.barItems.push(item);
29698 getActive : function()
29700 var active = false;
29702 Roo.each(this.barItems, function(v){
29704 if (!v.isActive()) {
29716 setActiveItem : function(item)
29720 Roo.each(this.barItems, function(v){
29721 if (v.rid == item.rid) {
29725 if (v.isActive()) {
29726 v.setActive(false);
29731 item.setActive(true);
29733 this.fireEvent('changed', this, item, prev);
29736 getBarItem: function(rid)
29740 Roo.each(this.barItems, function(e) {
29741 if (e.rid != rid) {
29752 indexOfItem : function(item)
29756 Roo.each(this.barItems, function(v, i){
29758 if (v.rid != item.rid) {
29769 setActiveNext : function()
29771 var i = this.indexOfItem(this.getActive());
29773 if (i > this.barItems.length) {
29777 this.setActiveItem(this.barItems[i+1]);
29780 setActivePrev : function()
29782 var i = this.indexOfItem(this.getActive());
29788 this.setActiveItem(this.barItems[i-1]);
29791 format : function()
29793 if(!this.barItems.length){
29797 var width = 100 / this.barItems.length;
29799 Roo.each(this.barItems, function(i){
29800 i.el.setStyle('width', width + '%');
29801 i.topEl.el.setStyle('width', width + '%');
29802 i.bottomEl.el.setStyle('width', width + '%');
29811 * Nav Progress Item
29816 * @class Roo.bootstrap.NavProgressItem
29817 * @extends Roo.bootstrap.Component
29818 * Bootstrap NavProgressItem class
29819 * @cfg {String} rid the reference id
29820 * @cfg {Boolean} active (true|false) Is item active default false
29821 * @cfg {Boolean} disabled (true|false) Is item active default false
29822 * @cfg {String} html
29823 * @cfg {String} position (top|bottom) text position default bottom
29824 * @cfg {String} icon show icon instead of number
29827 * Create a new NavProgressItem
29828 * @param {Object} config The config object
29830 Roo.bootstrap.NavProgressItem = function(config){
29831 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29836 * The raw click event for the entire grid.
29837 * @param {Roo.bootstrap.NavProgressItem} this
29838 * @param {Roo.EventObject} e
29845 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29851 position : 'bottom',
29854 getAutoCreate : function()
29856 var iconCls = 'roo-navigation-bar-item-icon';
29858 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29862 cls: 'roo-navigation-bar-item',
29872 cfg.cls += ' active';
29875 cfg.cls += ' disabled';
29881 disable : function()
29883 this.setDisabled(true);
29886 enable : function()
29888 this.setDisabled(false);
29891 initEvents: function()
29893 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29895 this.iconEl.on('click', this.onClick, this);
29898 onClick : function(e)
29900 e.preventDefault();
29906 if(this.fireEvent('click', this, e) === false){
29910 this.parent().setActiveItem(this);
29913 isActive: function ()
29915 return this.active;
29918 setActive : function(state)
29920 if(this.active == state){
29924 this.active = state;
29927 this.el.addClass('active');
29931 this.el.removeClass('active');
29936 setDisabled : function(state)
29938 if(this.disabled == state){
29942 this.disabled = state;
29945 this.el.addClass('disabled');
29949 this.el.removeClass('disabled');
29952 tooltipEl : function()
29954 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29967 * @class Roo.bootstrap.FieldLabel
29968 * @extends Roo.bootstrap.Component
29969 * Bootstrap FieldLabel class
29970 * @cfg {String} html contents of the element
29971 * @cfg {String} tag tag of the element default label
29972 * @cfg {String} cls class of the element
29973 * @cfg {String} target label target
29974 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29975 * @cfg {String} invalidClass default "text-warning"
29976 * @cfg {String} validClass default "text-success"
29977 * @cfg {String} iconTooltip default "This field is required"
29978 * @cfg {String} indicatorpos (left|right) default left
29981 * Create a new FieldLabel
29982 * @param {Object} config The config object
29985 Roo.bootstrap.FieldLabel = function(config){
29986 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29991 * Fires after the field has been marked as invalid.
29992 * @param {Roo.form.FieldLabel} this
29993 * @param {String} msg The validation message
29998 * Fires after the field has been validated with no errors.
29999 * @param {Roo.form.FieldLabel} this
30005 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30012 invalidClass : 'has-warning',
30013 validClass : 'has-success',
30014 iconTooltip : 'This field is required',
30015 indicatorpos : 'left',
30017 getAutoCreate : function(){
30021 cls : 'roo-bootstrap-field-label ' + this.cls,
30026 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30027 tooltip : this.iconTooltip
30036 if(this.indicatorpos == 'right'){
30039 cls : 'roo-bootstrap-field-label ' + this.cls,
30048 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30049 tooltip : this.iconTooltip
30058 initEvents: function()
30060 Roo.bootstrap.Element.superclass.initEvents.call(this);
30062 this.indicator = this.indicatorEl();
30064 if(this.indicator){
30065 this.indicator.removeClass('visible');
30066 this.indicator.addClass('invisible');
30069 Roo.bootstrap.FieldLabel.register(this);
30072 indicatorEl : function()
30074 var indicator = this.el.select('i.roo-required-indicator',true).first();
30085 * Mark this field as valid
30087 markValid : function()
30089 if(this.indicator){
30090 this.indicator.removeClass('visible');
30091 this.indicator.addClass('invisible');
30094 this.el.removeClass(this.invalidClass);
30096 this.el.addClass(this.validClass);
30098 this.fireEvent('valid', this);
30102 * Mark this field as invalid
30103 * @param {String} msg The validation message
30105 markInvalid : function(msg)
30107 if(this.indicator){
30108 this.indicator.removeClass('invisible');
30109 this.indicator.addClass('visible');
30112 this.el.removeClass(this.validClass);
30114 this.el.addClass(this.invalidClass);
30116 this.fireEvent('invalid', this, msg);
30122 Roo.apply(Roo.bootstrap.FieldLabel, {
30127 * register a FieldLabel Group
30128 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30130 register : function(label)
30132 if(this.groups.hasOwnProperty(label.target)){
30136 this.groups[label.target] = label;
30140 * fetch a FieldLabel Group based on the target
30141 * @param {string} target
30142 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30144 get: function(target) {
30145 if (typeof(this.groups[target]) == 'undefined') {
30149 return this.groups[target] ;
30158 * page DateSplitField.
30164 * @class Roo.bootstrap.DateSplitField
30165 * @extends Roo.bootstrap.Component
30166 * Bootstrap DateSplitField class
30167 * @cfg {string} fieldLabel - the label associated
30168 * @cfg {Number} labelWidth set the width of label (0-12)
30169 * @cfg {String} labelAlign (top|left)
30170 * @cfg {Boolean} dayAllowBlank (true|false) default false
30171 * @cfg {Boolean} monthAllowBlank (true|false) default false
30172 * @cfg {Boolean} yearAllowBlank (true|false) default false
30173 * @cfg {string} dayPlaceholder
30174 * @cfg {string} monthPlaceholder
30175 * @cfg {string} yearPlaceholder
30176 * @cfg {string} dayFormat default 'd'
30177 * @cfg {string} monthFormat default 'm'
30178 * @cfg {string} yearFormat default 'Y'
30179 * @cfg {Number} labellg set the width of label (1-12)
30180 * @cfg {Number} labelmd set the width of label (1-12)
30181 * @cfg {Number} labelsm set the width of label (1-12)
30182 * @cfg {Number} labelxs set the width of label (1-12)
30186 * Create a new DateSplitField
30187 * @param {Object} config The config object
30190 Roo.bootstrap.DateSplitField = function(config){
30191 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30197 * getting the data of years
30198 * @param {Roo.bootstrap.DateSplitField} this
30199 * @param {Object} years
30204 * getting the data of days
30205 * @param {Roo.bootstrap.DateSplitField} this
30206 * @param {Object} days
30211 * Fires after the field has been marked as invalid.
30212 * @param {Roo.form.Field} this
30213 * @param {String} msg The validation message
30218 * Fires after the field has been validated with no errors.
30219 * @param {Roo.form.Field} this
30225 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30228 labelAlign : 'top',
30230 dayAllowBlank : false,
30231 monthAllowBlank : false,
30232 yearAllowBlank : false,
30233 dayPlaceholder : '',
30234 monthPlaceholder : '',
30235 yearPlaceholder : '',
30239 isFormField : true,
30245 getAutoCreate : function()
30249 cls : 'row roo-date-split-field-group',
30254 cls : 'form-hidden-field roo-date-split-field-group-value',
30260 var labelCls = 'col-md-12';
30261 var contentCls = 'col-md-4';
30263 if(this.fieldLabel){
30267 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30271 html : this.fieldLabel
30276 if(this.labelAlign == 'left'){
30278 if(this.labelWidth > 12){
30279 label.style = "width: " + this.labelWidth + 'px';
30282 if(this.labelWidth < 13 && this.labelmd == 0){
30283 this.labelmd = this.labelWidth;
30286 if(this.labellg > 0){
30287 labelCls = ' col-lg-' + this.labellg;
30288 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30291 if(this.labelmd > 0){
30292 labelCls = ' col-md-' + this.labelmd;
30293 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30296 if(this.labelsm > 0){
30297 labelCls = ' col-sm-' + this.labelsm;
30298 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30301 if(this.labelxs > 0){
30302 labelCls = ' col-xs-' + this.labelxs;
30303 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30307 label.cls += ' ' + labelCls;
30309 cfg.cn.push(label);
30312 Roo.each(['day', 'month', 'year'], function(t){
30315 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30322 inputEl: function ()
30324 return this.el.select('.roo-date-split-field-group-value', true).first();
30327 onRender : function(ct, position)
30331 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30333 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30335 this.dayField = new Roo.bootstrap.ComboBox({
30336 allowBlank : this.dayAllowBlank,
30337 alwaysQuery : true,
30338 displayField : 'value',
30341 forceSelection : true,
30343 placeholder : this.dayPlaceholder,
30344 selectOnFocus : true,
30345 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30346 triggerAction : 'all',
30348 valueField : 'value',
30349 store : new Roo.data.SimpleStore({
30350 data : (function() {
30352 _this.fireEvent('days', _this, days);
30355 fields : [ 'value' ]
30358 select : function (_self, record, index)
30360 _this.setValue(_this.getValue());
30365 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30367 this.monthField = new Roo.bootstrap.MonthField({
30368 after : '<i class=\"fa fa-calendar\"></i>',
30369 allowBlank : this.monthAllowBlank,
30370 placeholder : this.monthPlaceholder,
30373 render : function (_self)
30375 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30376 e.preventDefault();
30380 select : function (_self, oldvalue, newvalue)
30382 _this.setValue(_this.getValue());
30387 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30389 this.yearField = new Roo.bootstrap.ComboBox({
30390 allowBlank : this.yearAllowBlank,
30391 alwaysQuery : true,
30392 displayField : 'value',
30395 forceSelection : true,
30397 placeholder : this.yearPlaceholder,
30398 selectOnFocus : true,
30399 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30400 triggerAction : 'all',
30402 valueField : 'value',
30403 store : new Roo.data.SimpleStore({
30404 data : (function() {
30406 _this.fireEvent('years', _this, years);
30409 fields : [ 'value' ]
30412 select : function (_self, record, index)
30414 _this.setValue(_this.getValue());
30419 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30422 setValue : function(v, format)
30424 this.inputEl.dom.value = v;
30426 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30428 var d = Date.parseDate(v, f);
30435 this.setDay(d.format(this.dayFormat));
30436 this.setMonth(d.format(this.monthFormat));
30437 this.setYear(d.format(this.yearFormat));
30444 setDay : function(v)
30446 this.dayField.setValue(v);
30447 this.inputEl.dom.value = this.getValue();
30452 setMonth : function(v)
30454 this.monthField.setValue(v, true);
30455 this.inputEl.dom.value = this.getValue();
30460 setYear : function(v)
30462 this.yearField.setValue(v);
30463 this.inputEl.dom.value = this.getValue();
30468 getDay : function()
30470 return this.dayField.getValue();
30473 getMonth : function()
30475 return this.monthField.getValue();
30478 getYear : function()
30480 return this.yearField.getValue();
30483 getValue : function()
30485 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30487 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30497 this.inputEl.dom.value = '';
30502 validate : function()
30504 var d = this.dayField.validate();
30505 var m = this.monthField.validate();
30506 var y = this.yearField.validate();
30511 (!this.dayAllowBlank && !d) ||
30512 (!this.monthAllowBlank && !m) ||
30513 (!this.yearAllowBlank && !y)
30518 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30527 this.markInvalid();
30532 markValid : function()
30535 var label = this.el.select('label', true).first();
30536 var icon = this.el.select('i.fa-star', true).first();
30542 this.fireEvent('valid', this);
30546 * Mark this field as invalid
30547 * @param {String} msg The validation message
30549 markInvalid : function(msg)
30552 var label = this.el.select('label', true).first();
30553 var icon = this.el.select('i.fa-star', true).first();
30555 if(label && !icon){
30556 this.el.select('.roo-date-split-field-label', true).createChild({
30558 cls : 'text-danger fa fa-lg fa-star',
30559 tooltip : 'This field is required',
30560 style : 'margin-right:5px;'
30564 this.fireEvent('invalid', this, msg);
30567 clearInvalid : function()
30569 var label = this.el.select('label', true).first();
30570 var icon = this.el.select('i.fa-star', true).first();
30576 this.fireEvent('valid', this);
30579 getName: function()
30589 * http://masonry.desandro.com
30591 * The idea is to render all the bricks based on vertical width...
30593 * The original code extends 'outlayer' - we might need to use that....
30599 * @class Roo.bootstrap.LayoutMasonry
30600 * @extends Roo.bootstrap.Component
30601 * Bootstrap Layout Masonry class
30604 * Create a new Element
30605 * @param {Object} config The config object
30608 Roo.bootstrap.LayoutMasonry = function(config){
30610 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30614 Roo.bootstrap.LayoutMasonry.register(this);
30620 * Fire after layout the items
30621 * @param {Roo.bootstrap.LayoutMasonry} this
30622 * @param {Roo.EventObject} e
30629 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30632 * @cfg {Boolean} isLayoutInstant = no animation?
30634 isLayoutInstant : false, // needed?
30637 * @cfg {Number} boxWidth width of the columns
30642 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30647 * @cfg {Number} padWidth padding below box..
30652 * @cfg {Number} gutter gutter width..
30657 * @cfg {Number} maxCols maximum number of columns
30663 * @cfg {Boolean} isAutoInitial defalut true
30665 isAutoInitial : true,
30670 * @cfg {Boolean} isHorizontal defalut false
30672 isHorizontal : false,
30674 currentSize : null,
30680 bricks: null, //CompositeElement
30684 _isLayoutInited : false,
30686 // isAlternative : false, // only use for vertical layout...
30689 * @cfg {Number} alternativePadWidth padding below box..
30691 alternativePadWidth : 50,
30693 selectedBrick : [],
30695 getAutoCreate : function(){
30697 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30701 cls: 'blog-masonary-wrapper ' + this.cls,
30703 cls : 'mas-boxes masonary'
30710 getChildContainer: function( )
30712 if (this.boxesEl) {
30713 return this.boxesEl;
30716 this.boxesEl = this.el.select('.mas-boxes').first();
30718 return this.boxesEl;
30722 initEvents : function()
30726 if(this.isAutoInitial){
30727 Roo.log('hook children rendered');
30728 this.on('childrenrendered', function() {
30729 Roo.log('children rendered');
30735 initial : function()
30737 this.selectedBrick = [];
30739 this.currentSize = this.el.getBox(true);
30741 Roo.EventManager.onWindowResize(this.resize, this);
30743 if(!this.isAutoInitial){
30751 //this.layout.defer(500,this);
30755 resize : function()
30757 var cs = this.el.getBox(true);
30760 this.currentSize.width == cs.width &&
30761 this.currentSize.x == cs.x &&
30762 this.currentSize.height == cs.height &&
30763 this.currentSize.y == cs.y
30765 Roo.log("no change in with or X or Y");
30769 this.currentSize = cs;
30775 layout : function()
30777 this._resetLayout();
30779 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30781 this.layoutItems( isInstant );
30783 this._isLayoutInited = true;
30785 this.fireEvent('layout', this);
30789 _resetLayout : function()
30791 if(this.isHorizontal){
30792 this.horizontalMeasureColumns();
30796 this.verticalMeasureColumns();
30800 verticalMeasureColumns : function()
30802 this.getContainerWidth();
30804 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30805 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30809 var boxWidth = this.boxWidth + this.padWidth;
30811 if(this.containerWidth < this.boxWidth){
30812 boxWidth = this.containerWidth
30815 var containerWidth = this.containerWidth;
30817 var cols = Math.floor(containerWidth / boxWidth);
30819 this.cols = Math.max( cols, 1 );
30821 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30823 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30825 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30827 this.colWidth = boxWidth + avail - this.padWidth;
30829 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30830 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30833 horizontalMeasureColumns : function()
30835 this.getContainerWidth();
30837 var boxWidth = this.boxWidth;
30839 if(this.containerWidth < boxWidth){
30840 boxWidth = this.containerWidth;
30843 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30845 this.el.setHeight(boxWidth);
30849 getContainerWidth : function()
30851 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30854 layoutItems : function( isInstant )
30856 Roo.log(this.bricks);
30858 var items = Roo.apply([], this.bricks);
30860 if(this.isHorizontal){
30861 this._horizontalLayoutItems( items , isInstant );
30865 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30866 // this._verticalAlternativeLayoutItems( items , isInstant );
30870 this._verticalLayoutItems( items , isInstant );
30874 _verticalLayoutItems : function ( items , isInstant)
30876 if ( !items || !items.length ) {
30881 ['xs', 'xs', 'xs', 'tall'],
30882 ['xs', 'xs', 'tall'],
30883 ['xs', 'xs', 'sm'],
30884 ['xs', 'xs', 'xs'],
30890 ['sm', 'xs', 'xs'],
30894 ['tall', 'xs', 'xs', 'xs'],
30895 ['tall', 'xs', 'xs'],
30907 Roo.each(items, function(item, k){
30909 switch (item.size) {
30910 // these layouts take up a full box,
30921 boxes.push([item]);
30944 var filterPattern = function(box, length)
30952 var pattern = box.slice(0, length);
30956 Roo.each(pattern, function(i){
30957 format.push(i.size);
30960 Roo.each(standard, function(s){
30962 if(String(s) != String(format)){
30971 if(!match && length == 1){
30976 filterPattern(box, length - 1);
30980 queue.push(pattern);
30982 box = box.slice(length, box.length);
30984 filterPattern(box, 4);
30990 Roo.each(boxes, function(box, k){
30996 if(box.length == 1){
31001 filterPattern(box, 4);
31005 this._processVerticalLayoutQueue( queue, isInstant );
31009 // _verticalAlternativeLayoutItems : function( items , isInstant )
31011 // if ( !items || !items.length ) {
31015 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31019 _horizontalLayoutItems : function ( items , isInstant)
31021 if ( !items || !items.length || items.length < 3) {
31027 var eItems = items.slice(0, 3);
31029 items = items.slice(3, items.length);
31032 ['xs', 'xs', 'xs', 'wide'],
31033 ['xs', 'xs', 'wide'],
31034 ['xs', 'xs', 'sm'],
31035 ['xs', 'xs', 'xs'],
31041 ['sm', 'xs', 'xs'],
31045 ['wide', 'xs', 'xs', 'xs'],
31046 ['wide', 'xs', 'xs'],
31059 Roo.each(items, function(item, k){
31061 switch (item.size) {
31072 boxes.push([item]);
31096 var filterPattern = function(box, length)
31104 var pattern = box.slice(0, length);
31108 Roo.each(pattern, function(i){
31109 format.push(i.size);
31112 Roo.each(standard, function(s){
31114 if(String(s) != String(format)){
31123 if(!match && length == 1){
31128 filterPattern(box, length - 1);
31132 queue.push(pattern);
31134 box = box.slice(length, box.length);
31136 filterPattern(box, 4);
31142 Roo.each(boxes, function(box, k){
31148 if(box.length == 1){
31153 filterPattern(box, 4);
31160 var pos = this.el.getBox(true);
31164 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31166 var hit_end = false;
31168 Roo.each(queue, function(box){
31172 Roo.each(box, function(b){
31174 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31184 Roo.each(box, function(b){
31186 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31189 mx = Math.max(mx, b.x);
31193 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31197 Roo.each(box, function(b){
31199 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31213 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31216 /** Sets position of item in DOM
31217 * @param {Element} item
31218 * @param {Number} x - horizontal position
31219 * @param {Number} y - vertical position
31220 * @param {Boolean} isInstant - disables transitions
31222 _processVerticalLayoutQueue : function( queue, isInstant )
31224 var pos = this.el.getBox(true);
31229 for (var i = 0; i < this.cols; i++){
31233 Roo.each(queue, function(box, k){
31235 var col = k % this.cols;
31237 Roo.each(box, function(b,kk){
31239 b.el.position('absolute');
31241 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31242 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31244 if(b.size == 'md-left' || b.size == 'md-right'){
31245 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31246 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31249 b.el.setWidth(width);
31250 b.el.setHeight(height);
31252 b.el.select('iframe',true).setSize(width,height);
31256 for (var i = 0; i < this.cols; i++){
31258 if(maxY[i] < maxY[col]){
31263 col = Math.min(col, i);
31267 x = pos.x + col * (this.colWidth + this.padWidth);
31271 var positions = [];
31273 switch (box.length){
31275 positions = this.getVerticalOneBoxColPositions(x, y, box);
31278 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31281 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31284 positions = this.getVerticalFourBoxColPositions(x, y, box);
31290 Roo.each(box, function(b,kk){
31292 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31294 var sz = b.el.getSize();
31296 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31304 for (var i = 0; i < this.cols; i++){
31305 mY = Math.max(mY, maxY[i]);
31308 this.el.setHeight(mY - pos.y);
31312 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31314 // var pos = this.el.getBox(true);
31317 // var maxX = pos.right;
31319 // var maxHeight = 0;
31321 // Roo.each(items, function(item, k){
31325 // item.el.position('absolute');
31327 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31329 // item.el.setWidth(width);
31331 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31333 // item.el.setHeight(height);
31336 // item.el.setXY([x, y], isInstant ? false : true);
31338 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31341 // y = y + height + this.alternativePadWidth;
31343 // maxHeight = maxHeight + height + this.alternativePadWidth;
31347 // this.el.setHeight(maxHeight);
31351 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31353 var pos = this.el.getBox(true);
31358 var maxX = pos.right;
31360 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31362 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31364 Roo.each(queue, function(box, k){
31366 Roo.each(box, function(b, kk){
31368 b.el.position('absolute');
31370 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31371 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31373 if(b.size == 'md-left' || b.size == 'md-right'){
31374 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31375 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31378 b.el.setWidth(width);
31379 b.el.setHeight(height);
31387 var positions = [];
31389 switch (box.length){
31391 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31394 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31397 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31400 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31406 Roo.each(box, function(b,kk){
31408 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31410 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31418 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31420 Roo.each(eItems, function(b,k){
31422 b.size = (k == 0) ? 'sm' : 'xs';
31423 b.x = (k == 0) ? 2 : 1;
31424 b.y = (k == 0) ? 2 : 1;
31426 b.el.position('absolute');
31428 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31430 b.el.setWidth(width);
31432 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31434 b.el.setHeight(height);
31438 var positions = [];
31441 x : maxX - this.unitWidth * 2 - this.gutter,
31446 x : maxX - this.unitWidth,
31447 y : minY + (this.unitWidth + this.gutter) * 2
31451 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31455 Roo.each(eItems, function(b,k){
31457 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31463 getVerticalOneBoxColPositions : function(x, y, box)
31467 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31469 if(box[0].size == 'md-left'){
31473 if(box[0].size == 'md-right'){
31478 x : x + (this.unitWidth + this.gutter) * rand,
31485 getVerticalTwoBoxColPositions : function(x, y, box)
31489 if(box[0].size == 'xs'){
31493 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31497 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31511 x : x + (this.unitWidth + this.gutter) * 2,
31512 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31519 getVerticalThreeBoxColPositions : function(x, y, box)
31523 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31531 x : x + (this.unitWidth + this.gutter) * 1,
31536 x : x + (this.unitWidth + this.gutter) * 2,
31544 if(box[0].size == 'xs' && box[1].size == 'xs'){
31553 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31557 x : x + (this.unitWidth + this.gutter) * 1,
31571 x : x + (this.unitWidth + this.gutter) * 2,
31576 x : x + (this.unitWidth + this.gutter) * 2,
31577 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31584 getVerticalFourBoxColPositions : function(x, y, box)
31588 if(box[0].size == 'xs'){
31597 y : y + (this.unitHeight + this.gutter) * 1
31602 y : y + (this.unitHeight + this.gutter) * 2
31606 x : x + (this.unitWidth + this.gutter) * 1,
31620 x : x + (this.unitWidth + this.gutter) * 2,
31625 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31626 y : y + (this.unitHeight + this.gutter) * 1
31630 x : x + (this.unitWidth + this.gutter) * 2,
31631 y : y + (this.unitWidth + this.gutter) * 2
31638 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31642 if(box[0].size == 'md-left'){
31644 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31651 if(box[0].size == 'md-right'){
31653 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31654 y : minY + (this.unitWidth + this.gutter) * 1
31660 var rand = Math.floor(Math.random() * (4 - box[0].y));
31663 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31664 y : minY + (this.unitWidth + this.gutter) * rand
31671 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31675 if(box[0].size == 'xs'){
31678 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31683 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31684 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31692 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31697 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31698 y : minY + (this.unitWidth + this.gutter) * 2
31705 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31709 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31712 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31717 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31718 y : minY + (this.unitWidth + this.gutter) * 1
31722 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31723 y : minY + (this.unitWidth + this.gutter) * 2
31730 if(box[0].size == 'xs' && box[1].size == 'xs'){
31733 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31738 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31743 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31744 y : minY + (this.unitWidth + this.gutter) * 1
31752 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31757 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31758 y : minY + (this.unitWidth + this.gutter) * 2
31762 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31763 y : minY + (this.unitWidth + this.gutter) * 2
31770 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31774 if(box[0].size == 'xs'){
31777 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31782 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31787 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),
31792 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31793 y : minY + (this.unitWidth + this.gutter) * 1
31801 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31806 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31807 y : minY + (this.unitWidth + this.gutter) * 2
31811 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31812 y : minY + (this.unitWidth + this.gutter) * 2
31816 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),
31817 y : minY + (this.unitWidth + this.gutter) * 2
31825 * remove a Masonry Brick
31826 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31828 removeBrick : function(brick_id)
31834 for (var i = 0; i<this.bricks.length; i++) {
31835 if (this.bricks[i].id == brick_id) {
31836 this.bricks.splice(i,1);
31837 this.el.dom.removeChild(Roo.get(brick_id).dom);
31844 * adds a Masonry Brick
31845 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31847 addBrick : function(cfg)
31849 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31850 //this.register(cn);
31851 cn.parentId = this.id;
31852 cn.onRender(this.el, null);
31857 * register a Masonry Brick
31858 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31861 register : function(brick)
31863 this.bricks.push(brick);
31864 brick.masonryId = this.id;
31868 * clear all the Masonry Brick
31870 clearAll : function()
31873 //this.getChildContainer().dom.innerHTML = "";
31874 this.el.dom.innerHTML = '';
31877 getSelected : function()
31879 if (!this.selectedBrick) {
31883 return this.selectedBrick;
31887 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31891 * register a Masonry Layout
31892 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31895 register : function(layout)
31897 this.groups[layout.id] = layout;
31900 * fetch a Masonry Layout based on the masonry layout ID
31901 * @param {string} the masonry layout to add
31902 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31905 get: function(layout_id) {
31906 if (typeof(this.groups[layout_id]) == 'undefined') {
31909 return this.groups[layout_id] ;
31921 * http://masonry.desandro.com
31923 * The idea is to render all the bricks based on vertical width...
31925 * The original code extends 'outlayer' - we might need to use that....
31931 * @class Roo.bootstrap.LayoutMasonryAuto
31932 * @extends Roo.bootstrap.Component
31933 * Bootstrap Layout Masonry class
31936 * Create a new Element
31937 * @param {Object} config The config object
31940 Roo.bootstrap.LayoutMasonryAuto = function(config){
31941 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31944 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31947 * @cfg {Boolean} isFitWidth - resize the width..
31949 isFitWidth : false, // options..
31951 * @cfg {Boolean} isOriginLeft = left align?
31953 isOriginLeft : true,
31955 * @cfg {Boolean} isOriginTop = top align?
31957 isOriginTop : false,
31959 * @cfg {Boolean} isLayoutInstant = no animation?
31961 isLayoutInstant : false, // needed?
31963 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31965 isResizingContainer : true,
31967 * @cfg {Number} columnWidth width of the columns
31973 * @cfg {Number} maxCols maximum number of columns
31978 * @cfg {Number} padHeight padding below box..
31984 * @cfg {Boolean} isAutoInitial defalut true
31987 isAutoInitial : true,
31993 initialColumnWidth : 0,
31994 currentSize : null,
31996 colYs : null, // array.
32003 bricks: null, //CompositeElement
32004 cols : 0, // array?
32005 // element : null, // wrapped now this.el
32006 _isLayoutInited : null,
32009 getAutoCreate : function(){
32013 cls: 'blog-masonary-wrapper ' + this.cls,
32015 cls : 'mas-boxes masonary'
32022 getChildContainer: function( )
32024 if (this.boxesEl) {
32025 return this.boxesEl;
32028 this.boxesEl = this.el.select('.mas-boxes').first();
32030 return this.boxesEl;
32034 initEvents : function()
32038 if(this.isAutoInitial){
32039 Roo.log('hook children rendered');
32040 this.on('childrenrendered', function() {
32041 Roo.log('children rendered');
32048 initial : function()
32050 this.reloadItems();
32052 this.currentSize = this.el.getBox(true);
32054 /// was window resize... - let's see if this works..
32055 Roo.EventManager.onWindowResize(this.resize, this);
32057 if(!this.isAutoInitial){
32062 this.layout.defer(500,this);
32065 reloadItems: function()
32067 this.bricks = this.el.select('.masonry-brick', true);
32069 this.bricks.each(function(b) {
32070 //Roo.log(b.getSize());
32071 if (!b.attr('originalwidth')) {
32072 b.attr('originalwidth', b.getSize().width);
32077 Roo.log(this.bricks.elements.length);
32080 resize : function()
32083 var cs = this.el.getBox(true);
32085 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32086 Roo.log("no change in with or X");
32089 this.currentSize = cs;
32093 layout : function()
32096 this._resetLayout();
32097 //this._manageStamps();
32099 // don't animate first layout
32100 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32101 this.layoutItems( isInstant );
32103 // flag for initalized
32104 this._isLayoutInited = true;
32107 layoutItems : function( isInstant )
32109 //var items = this._getItemsForLayout( this.items );
32110 // original code supports filtering layout items.. we just ignore it..
32112 this._layoutItems( this.bricks , isInstant );
32114 this._postLayout();
32116 _layoutItems : function ( items , isInstant)
32118 //this.fireEvent( 'layout', this, items );
32121 if ( !items || !items.elements.length ) {
32122 // no items, emit event with empty array
32127 items.each(function(item) {
32128 Roo.log("layout item");
32130 // get x/y object from method
32131 var position = this._getItemLayoutPosition( item );
32133 position.item = item;
32134 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32135 queue.push( position );
32138 this._processLayoutQueue( queue );
32140 /** Sets position of item in DOM
32141 * @param {Element} item
32142 * @param {Number} x - horizontal position
32143 * @param {Number} y - vertical position
32144 * @param {Boolean} isInstant - disables transitions
32146 _processLayoutQueue : function( queue )
32148 for ( var i=0, len = queue.length; i < len; i++ ) {
32149 var obj = queue[i];
32150 obj.item.position('absolute');
32151 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32157 * Any logic you want to do after each layout,
32158 * i.e. size the container
32160 _postLayout : function()
32162 this.resizeContainer();
32165 resizeContainer : function()
32167 if ( !this.isResizingContainer ) {
32170 var size = this._getContainerSize();
32172 this.el.setSize(size.width,size.height);
32173 this.boxesEl.setSize(size.width,size.height);
32179 _resetLayout : function()
32181 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32182 this.colWidth = this.el.getWidth();
32183 //this.gutter = this.el.getWidth();
32185 this.measureColumns();
32191 this.colYs.push( 0 );
32197 measureColumns : function()
32199 this.getContainerWidth();
32200 // if columnWidth is 0, default to outerWidth of first item
32201 if ( !this.columnWidth ) {
32202 var firstItem = this.bricks.first();
32203 Roo.log(firstItem);
32204 this.columnWidth = this.containerWidth;
32205 if (firstItem && firstItem.attr('originalwidth') ) {
32206 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32208 // columnWidth fall back to item of first element
32209 Roo.log("set column width?");
32210 this.initialColumnWidth = this.columnWidth ;
32212 // if first elem has no width, default to size of container
32217 if (this.initialColumnWidth) {
32218 this.columnWidth = this.initialColumnWidth;
32223 // column width is fixed at the top - however if container width get's smaller we should
32226 // this bit calcs how man columns..
32228 var columnWidth = this.columnWidth += this.gutter;
32230 // calculate columns
32231 var containerWidth = this.containerWidth + this.gutter;
32233 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32234 // fix rounding errors, typically with gutters
32235 var excess = columnWidth - containerWidth % columnWidth;
32238 // if overshoot is less than a pixel, round up, otherwise floor it
32239 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32240 cols = Math[ mathMethod ]( cols );
32241 this.cols = Math.max( cols, 1 );
32242 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32244 // padding positioning..
32245 var totalColWidth = this.cols * this.columnWidth;
32246 var padavail = this.containerWidth - totalColWidth;
32247 // so for 2 columns - we need 3 'pads'
32249 var padNeeded = (1+this.cols) * this.padWidth;
32251 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32253 this.columnWidth += padExtra
32254 //this.padWidth = Math.floor(padavail / ( this.cols));
32256 // adjust colum width so that padding is fixed??
32258 // we have 3 columns ... total = width * 3
32259 // we have X left over... that should be used by
32261 //if (this.expandC) {
32269 getContainerWidth : function()
32271 /* // container is parent if fit width
32272 var container = this.isFitWidth ? this.element.parentNode : this.element;
32273 // check that this.size and size are there
32274 // IE8 triggers resize on body size change, so they might not be
32276 var size = getSize( container ); //FIXME
32277 this.containerWidth = size && size.innerWidth; //FIXME
32280 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32284 _getItemLayoutPosition : function( item ) // what is item?
32286 // we resize the item to our columnWidth..
32288 item.setWidth(this.columnWidth);
32289 item.autoBoxAdjust = false;
32291 var sz = item.getSize();
32293 // how many columns does this brick span
32294 var remainder = this.containerWidth % this.columnWidth;
32296 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32297 // round if off by 1 pixel, otherwise use ceil
32298 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32299 colSpan = Math.min( colSpan, this.cols );
32301 // normally this should be '1' as we dont' currently allow multi width columns..
32303 var colGroup = this._getColGroup( colSpan );
32304 // get the minimum Y value from the columns
32305 var minimumY = Math.min.apply( Math, colGroup );
32306 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32308 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32310 // position the brick
32312 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32313 y: this.currentSize.y + minimumY + this.padHeight
32317 // apply setHeight to necessary columns
32318 var setHeight = minimumY + sz.height + this.padHeight;
32319 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32321 var setSpan = this.cols + 1 - colGroup.length;
32322 for ( var i = 0; i < setSpan; i++ ) {
32323 this.colYs[ shortColIndex + i ] = setHeight ;
32330 * @param {Number} colSpan - number of columns the element spans
32331 * @returns {Array} colGroup
32333 _getColGroup : function( colSpan )
32335 if ( colSpan < 2 ) {
32336 // if brick spans only one column, use all the column Ys
32341 // how many different places could this brick fit horizontally
32342 var groupCount = this.cols + 1 - colSpan;
32343 // for each group potential horizontal position
32344 for ( var i = 0; i < groupCount; i++ ) {
32345 // make an array of colY values for that one group
32346 var groupColYs = this.colYs.slice( i, i + colSpan );
32347 // and get the max value of the array
32348 colGroup[i] = Math.max.apply( Math, groupColYs );
32353 _manageStamp : function( stamp )
32355 var stampSize = stamp.getSize();
32356 var offset = stamp.getBox();
32357 // get the columns that this stamp affects
32358 var firstX = this.isOriginLeft ? offset.x : offset.right;
32359 var lastX = firstX + stampSize.width;
32360 var firstCol = Math.floor( firstX / this.columnWidth );
32361 firstCol = Math.max( 0, firstCol );
32363 var lastCol = Math.floor( lastX / this.columnWidth );
32364 // lastCol should not go over if multiple of columnWidth #425
32365 lastCol -= lastX % this.columnWidth ? 0 : 1;
32366 lastCol = Math.min( this.cols - 1, lastCol );
32368 // set colYs to bottom of the stamp
32369 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32372 for ( var i = firstCol; i <= lastCol; i++ ) {
32373 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32378 _getContainerSize : function()
32380 this.maxY = Math.max.apply( Math, this.colYs );
32385 if ( this.isFitWidth ) {
32386 size.width = this._getContainerFitWidth();
32392 _getContainerFitWidth : function()
32394 var unusedCols = 0;
32395 // count unused columns
32398 if ( this.colYs[i] !== 0 ) {
32403 // fit container to columns that have been used
32404 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32407 needsResizeLayout : function()
32409 var previousWidth = this.containerWidth;
32410 this.getContainerWidth();
32411 return previousWidth !== this.containerWidth;
32426 * @class Roo.bootstrap.MasonryBrick
32427 * @extends Roo.bootstrap.Component
32428 * Bootstrap MasonryBrick class
32431 * Create a new MasonryBrick
32432 * @param {Object} config The config object
32435 Roo.bootstrap.MasonryBrick = function(config){
32437 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32439 Roo.bootstrap.MasonryBrick.register(this);
32445 * When a MasonryBrick is clcik
32446 * @param {Roo.bootstrap.MasonryBrick} this
32447 * @param {Roo.EventObject} e
32453 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32456 * @cfg {String} title
32460 * @cfg {String} html
32464 * @cfg {String} bgimage
32468 * @cfg {String} videourl
32472 * @cfg {String} cls
32476 * @cfg {String} href
32480 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32485 * @cfg {String} placetitle (center|bottom)
32490 * @cfg {Boolean} isFitContainer defalut true
32492 isFitContainer : true,
32495 * @cfg {Boolean} preventDefault defalut false
32497 preventDefault : false,
32500 * @cfg {Boolean} inverse defalut false
32502 maskInverse : false,
32504 getAutoCreate : function()
32506 if(!this.isFitContainer){
32507 return this.getSplitAutoCreate();
32510 var cls = 'masonry-brick masonry-brick-full';
32512 if(this.href.length){
32513 cls += ' masonry-brick-link';
32516 if(this.bgimage.length){
32517 cls += ' masonry-brick-image';
32520 if(this.maskInverse){
32521 cls += ' mask-inverse';
32524 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32525 cls += ' enable-mask';
32529 cls += ' masonry-' + this.size + '-brick';
32532 if(this.placetitle.length){
32534 switch (this.placetitle) {
32536 cls += ' masonry-center-title';
32539 cls += ' masonry-bottom-title';
32546 if(!this.html.length && !this.bgimage.length){
32547 cls += ' masonry-center-title';
32550 if(!this.html.length && this.bgimage.length){
32551 cls += ' masonry-bottom-title';
32556 cls += ' ' + this.cls;
32560 tag: (this.href.length) ? 'a' : 'div',
32565 cls: 'masonry-brick-mask'
32569 cls: 'masonry-brick-paragraph',
32575 if(this.href.length){
32576 cfg.href = this.href;
32579 var cn = cfg.cn[1].cn;
32581 if(this.title.length){
32584 cls: 'masonry-brick-title',
32589 if(this.html.length){
32592 cls: 'masonry-brick-text',
32597 if (!this.title.length && !this.html.length) {
32598 cfg.cn[1].cls += ' hide';
32601 if(this.bgimage.length){
32604 cls: 'masonry-brick-image-view',
32609 if(this.videourl.length){
32610 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32611 // youtube support only?
32614 cls: 'masonry-brick-image-view',
32617 allowfullscreen : true
32625 getSplitAutoCreate : function()
32627 var cls = 'masonry-brick masonry-brick-split';
32629 if(this.href.length){
32630 cls += ' masonry-brick-link';
32633 if(this.bgimage.length){
32634 cls += ' masonry-brick-image';
32638 cls += ' masonry-' + this.size + '-brick';
32641 switch (this.placetitle) {
32643 cls += ' masonry-center-title';
32646 cls += ' masonry-bottom-title';
32649 if(!this.bgimage.length){
32650 cls += ' masonry-center-title';
32653 if(this.bgimage.length){
32654 cls += ' masonry-bottom-title';
32660 cls += ' ' + this.cls;
32664 tag: (this.href.length) ? 'a' : 'div',
32669 cls: 'masonry-brick-split-head',
32673 cls: 'masonry-brick-paragraph',
32680 cls: 'masonry-brick-split-body',
32686 if(this.href.length){
32687 cfg.href = this.href;
32690 if(this.title.length){
32691 cfg.cn[0].cn[0].cn.push({
32693 cls: 'masonry-brick-title',
32698 if(this.html.length){
32699 cfg.cn[1].cn.push({
32701 cls: 'masonry-brick-text',
32706 if(this.bgimage.length){
32707 cfg.cn[0].cn.push({
32709 cls: 'masonry-brick-image-view',
32714 if(this.videourl.length){
32715 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32716 // youtube support only?
32717 cfg.cn[0].cn.cn.push({
32719 cls: 'masonry-brick-image-view',
32722 allowfullscreen : true
32729 initEvents: function()
32731 switch (this.size) {
32764 this.el.on('touchstart', this.onTouchStart, this);
32765 this.el.on('touchmove', this.onTouchMove, this);
32766 this.el.on('touchend', this.onTouchEnd, this);
32767 this.el.on('contextmenu', this.onContextMenu, this);
32769 this.el.on('mouseenter' ,this.enter, this);
32770 this.el.on('mouseleave', this.leave, this);
32771 this.el.on('click', this.onClick, this);
32774 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32775 this.parent().bricks.push(this);
32780 onClick: function(e, el)
32782 var time = this.endTimer - this.startTimer;
32783 // Roo.log(e.preventDefault());
32786 e.preventDefault();
32791 if(!this.preventDefault){
32795 e.preventDefault();
32797 if (this.activeClass != '') {
32798 this.selectBrick();
32801 this.fireEvent('click', this, e);
32804 enter: function(e, el)
32806 e.preventDefault();
32808 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32812 if(this.bgimage.length && this.html.length){
32813 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32817 leave: function(e, el)
32819 e.preventDefault();
32821 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32825 if(this.bgimage.length && this.html.length){
32826 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32830 onTouchStart: function(e, el)
32832 // e.preventDefault();
32834 this.touchmoved = false;
32836 if(!this.isFitContainer){
32840 if(!this.bgimage.length || !this.html.length){
32844 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32846 this.timer = new Date().getTime();
32850 onTouchMove: function(e, el)
32852 this.touchmoved = true;
32855 onContextMenu : function(e,el)
32857 e.preventDefault();
32858 e.stopPropagation();
32862 onTouchEnd: function(e, el)
32864 // e.preventDefault();
32866 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32873 if(!this.bgimage.length || !this.html.length){
32875 if(this.href.length){
32876 window.location.href = this.href;
32882 if(!this.isFitContainer){
32886 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32888 window.location.href = this.href;
32891 //selection on single brick only
32892 selectBrick : function() {
32894 if (!this.parentId) {
32898 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32899 var index = m.selectedBrick.indexOf(this.id);
32902 m.selectedBrick.splice(index,1);
32903 this.el.removeClass(this.activeClass);
32907 for(var i = 0; i < m.selectedBrick.length; i++) {
32908 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32909 b.el.removeClass(b.activeClass);
32912 m.selectedBrick = [];
32914 m.selectedBrick.push(this.id);
32915 this.el.addClass(this.activeClass);
32919 isSelected : function(){
32920 return this.el.hasClass(this.activeClass);
32925 Roo.apply(Roo.bootstrap.MasonryBrick, {
32928 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32930 * register a Masonry Brick
32931 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32934 register : function(brick)
32936 //this.groups[brick.id] = brick;
32937 this.groups.add(brick.id, brick);
32940 * fetch a masonry brick based on the masonry brick ID
32941 * @param {string} the masonry brick to add
32942 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32945 get: function(brick_id)
32947 // if (typeof(this.groups[brick_id]) == 'undefined') {
32950 // return this.groups[brick_id] ;
32952 if(this.groups.key(brick_id)) {
32953 return this.groups.key(brick_id);
32971 * @class Roo.bootstrap.Brick
32972 * @extends Roo.bootstrap.Component
32973 * Bootstrap Brick class
32976 * Create a new Brick
32977 * @param {Object} config The config object
32980 Roo.bootstrap.Brick = function(config){
32981 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32987 * When a Brick is click
32988 * @param {Roo.bootstrap.Brick} this
32989 * @param {Roo.EventObject} e
32995 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32998 * @cfg {String} title
33002 * @cfg {String} html
33006 * @cfg {String} bgimage
33010 * @cfg {String} cls
33014 * @cfg {String} href
33018 * @cfg {String} video
33022 * @cfg {Boolean} square
33026 getAutoCreate : function()
33028 var cls = 'roo-brick';
33030 if(this.href.length){
33031 cls += ' roo-brick-link';
33034 if(this.bgimage.length){
33035 cls += ' roo-brick-image';
33038 if(!this.html.length && !this.bgimage.length){
33039 cls += ' roo-brick-center-title';
33042 if(!this.html.length && this.bgimage.length){
33043 cls += ' roo-brick-bottom-title';
33047 cls += ' ' + this.cls;
33051 tag: (this.href.length) ? 'a' : 'div',
33056 cls: 'roo-brick-paragraph',
33062 if(this.href.length){
33063 cfg.href = this.href;
33066 var cn = cfg.cn[0].cn;
33068 if(this.title.length){
33071 cls: 'roo-brick-title',
33076 if(this.html.length){
33079 cls: 'roo-brick-text',
33086 if(this.bgimage.length){
33089 cls: 'roo-brick-image-view',
33097 initEvents: function()
33099 if(this.title.length || this.html.length){
33100 this.el.on('mouseenter' ,this.enter, this);
33101 this.el.on('mouseleave', this.leave, this);
33104 Roo.EventManager.onWindowResize(this.resize, this);
33106 if(this.bgimage.length){
33107 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33108 this.imageEl.on('load', this.onImageLoad, this);
33115 onImageLoad : function()
33120 resize : function()
33122 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33124 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33126 if(this.bgimage.length){
33127 var image = this.el.select('.roo-brick-image-view', true).first();
33129 image.setWidth(paragraph.getWidth());
33132 image.setHeight(paragraph.getWidth());
33135 this.el.setHeight(image.getHeight());
33136 paragraph.setHeight(image.getHeight());
33142 enter: function(e, el)
33144 e.preventDefault();
33146 if(this.bgimage.length){
33147 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33148 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33152 leave: function(e, el)
33154 e.preventDefault();
33156 if(this.bgimage.length){
33157 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33158 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33173 * @class Roo.bootstrap.NumberField
33174 * @extends Roo.bootstrap.Input
33175 * Bootstrap NumberField class
33181 * Create a new NumberField
33182 * @param {Object} config The config object
33185 Roo.bootstrap.NumberField = function(config){
33186 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33189 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33192 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33194 allowDecimals : true,
33196 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33198 decimalSeparator : ".",
33200 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33202 decimalPrecision : 2,
33204 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33206 allowNegative : true,
33209 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33213 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33215 minValue : Number.NEGATIVE_INFINITY,
33217 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33219 maxValue : Number.MAX_VALUE,
33221 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33223 minText : "The minimum value for this field is {0}",
33225 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33227 maxText : "The maximum value for this field is {0}",
33229 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33230 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33232 nanText : "{0} is not a valid number",
33234 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33238 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33240 thousandsDelimiter : false,
33242 * @cfg {String} valueAlign alignment of value
33244 valueAlign : "left",
33246 getAutoCreate : function()
33248 var hiddenInput = {
33252 cls: 'hidden-number-input'
33256 hiddenInput.name = this.name;
33261 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33263 this.name = hiddenInput.name;
33265 if(cfg.cn.length > 0) {
33266 cfg.cn.push(hiddenInput);
33273 initEvents : function()
33275 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33277 var allowed = "0123456789";
33279 if(this.allowDecimals){
33280 allowed += this.decimalSeparator;
33283 if(this.allowNegative){
33287 if(this.thousandsDelimiter) {
33291 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33293 var keyPress = function(e){
33295 var k = e.getKey();
33297 var c = e.getCharCode();
33300 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33301 allowed.indexOf(String.fromCharCode(c)) === -1
33307 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33311 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33316 this.el.on("keypress", keyPress, this);
33319 validateValue : function(value)
33322 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33326 var num = this.parseValue(value);
33329 this.markInvalid(String.format(this.nanText, value));
33333 if(num < this.minValue){
33334 this.markInvalid(String.format(this.minText, this.minValue));
33338 if(num > this.maxValue){
33339 this.markInvalid(String.format(this.maxText, this.maxValue));
33346 getValue : function()
33348 var v = this.hiddenEl().getValue();
33350 return this.fixPrecision(this.parseValue(v));
33353 parseValue : function(value)
33355 if(this.thousandsDelimiter) {
33357 r = new RegExp(",", "g");
33358 value = value.replace(r, "");
33361 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33362 return isNaN(value) ? '' : value;
33365 fixPrecision : function(value)
33367 if(this.thousandsDelimiter) {
33369 r = new RegExp(",", "g");
33370 value = value.replace(r, "");
33373 var nan = isNaN(value);
33375 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33376 return nan ? '' : value;
33378 return parseFloat(value).toFixed(this.decimalPrecision);
33381 setValue : function(v)
33383 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33389 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33391 this.inputEl().dom.value = (v == '') ? '' :
33392 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33394 if(!this.allowZero && v === '0') {
33395 this.hiddenEl().dom.value = '';
33396 this.inputEl().dom.value = '';
33403 decimalPrecisionFcn : function(v)
33405 return Math.floor(v);
33408 beforeBlur : function()
33414 var v = this.parseValue(this.getRawValue());
33421 hiddenEl : function()
33423 return this.el.select('input.hidden-number-input',true).first();
33435 * @class Roo.bootstrap.DocumentSlider
33436 * @extends Roo.bootstrap.Component
33437 * Bootstrap DocumentSlider class
33440 * Create a new DocumentViewer
33441 * @param {Object} config The config object
33444 Roo.bootstrap.DocumentSlider = function(config){
33445 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33452 * Fire after initEvent
33453 * @param {Roo.bootstrap.DocumentSlider} this
33458 * Fire after update
33459 * @param {Roo.bootstrap.DocumentSlider} this
33465 * @param {Roo.bootstrap.DocumentSlider} this
33471 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33477 getAutoCreate : function()
33481 cls : 'roo-document-slider',
33485 cls : 'roo-document-slider-header',
33489 cls : 'roo-document-slider-header-title'
33495 cls : 'roo-document-slider-body',
33499 cls : 'roo-document-slider-prev',
33503 cls : 'fa fa-chevron-left'
33509 cls : 'roo-document-slider-thumb',
33513 cls : 'roo-document-slider-image'
33519 cls : 'roo-document-slider-next',
33523 cls : 'fa fa-chevron-right'
33535 initEvents : function()
33537 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33538 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33540 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33541 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33543 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33544 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33546 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33547 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33549 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33550 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33552 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33553 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33555 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33556 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33558 this.thumbEl.on('click', this.onClick, this);
33560 this.prevIndicator.on('click', this.prev, this);
33562 this.nextIndicator.on('click', this.next, this);
33566 initial : function()
33568 if(this.files.length){
33569 this.indicator = 1;
33573 this.fireEvent('initial', this);
33576 update : function()
33578 this.imageEl.attr('src', this.files[this.indicator - 1]);
33580 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33582 this.prevIndicator.show();
33584 if(this.indicator == 1){
33585 this.prevIndicator.hide();
33588 this.nextIndicator.show();
33590 if(this.indicator == this.files.length){
33591 this.nextIndicator.hide();
33594 this.thumbEl.scrollTo('top');
33596 this.fireEvent('update', this);
33599 onClick : function(e)
33601 e.preventDefault();
33603 this.fireEvent('click', this);
33608 e.preventDefault();
33610 this.indicator = Math.max(1, this.indicator - 1);
33617 e.preventDefault();
33619 this.indicator = Math.min(this.files.length, this.indicator + 1);
33633 * @class Roo.bootstrap.RadioSet
33634 * @extends Roo.bootstrap.Input
33635 * Bootstrap RadioSet class
33636 * @cfg {String} indicatorpos (left|right) default left
33637 * @cfg {Boolean} inline (true|false) inline the element (default true)
33638 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33640 * Create a new RadioSet
33641 * @param {Object} config The config object
33644 Roo.bootstrap.RadioSet = function(config){
33646 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33650 Roo.bootstrap.RadioSet.register(this);
33655 * Fires when the element is checked or unchecked.
33656 * @param {Roo.bootstrap.RadioSet} this This radio
33657 * @param {Roo.bootstrap.Radio} item The checked item
33662 * Fires when the element is click.
33663 * @param {Roo.bootstrap.RadioSet} this This radio set
33664 * @param {Roo.bootstrap.Radio} item The checked item
33665 * @param {Roo.EventObject} e The event object
33672 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33680 indicatorpos : 'left',
33682 getAutoCreate : function()
33686 cls : 'roo-radio-set-label',
33690 html : this.fieldLabel
33695 if(this.indicatorpos == 'left'){
33698 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33699 tooltip : 'This field is required'
33704 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33705 tooltip : 'This field is required'
33711 cls : 'roo-radio-set-items'
33714 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33716 if (align === 'left' && this.fieldLabel.length) {
33719 cls : "roo-radio-set-right",
33725 if(this.labelWidth > 12){
33726 label.style = "width: " + this.labelWidth + 'px';
33729 if(this.labelWidth < 13 && this.labelmd == 0){
33730 this.labelmd = this.labelWidth;
33733 if(this.labellg > 0){
33734 label.cls += ' col-lg-' + this.labellg;
33735 items.cls += ' col-lg-' + (12 - this.labellg);
33738 if(this.labelmd > 0){
33739 label.cls += ' col-md-' + this.labelmd;
33740 items.cls += ' col-md-' + (12 - this.labelmd);
33743 if(this.labelsm > 0){
33744 label.cls += ' col-sm-' + this.labelsm;
33745 items.cls += ' col-sm-' + (12 - this.labelsm);
33748 if(this.labelxs > 0){
33749 label.cls += ' col-xs-' + this.labelxs;
33750 items.cls += ' col-xs-' + (12 - this.labelxs);
33756 cls : 'roo-radio-set',
33760 cls : 'roo-radio-set-input',
33763 value : this.value ? this.value : ''
33770 if(this.weight.length){
33771 cfg.cls += ' roo-radio-' + this.weight;
33775 cfg.cls += ' roo-radio-set-inline';
33779 ['xs','sm','md','lg'].map(function(size){
33780 if (settings[size]) {
33781 cfg.cls += ' col-' + size + '-' + settings[size];
33789 initEvents : function()
33791 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33792 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33794 if(!this.fieldLabel.length){
33795 this.labelEl.hide();
33798 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33799 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33801 this.indicator = this.indicatorEl();
33803 if(this.indicator){
33804 this.indicator.addClass('invisible');
33807 this.originalValue = this.getValue();
33811 inputEl: function ()
33813 return this.el.select('.roo-radio-set-input', true).first();
33816 getChildContainer : function()
33818 return this.itemsEl;
33821 register : function(item)
33823 this.radioes.push(item);
33827 validate : function()
33829 if(this.getVisibilityEl().hasClass('hidden')){
33835 Roo.each(this.radioes, function(i){
33844 if(this.allowBlank) {
33848 if(this.disabled || valid){
33853 this.markInvalid();
33858 markValid : function()
33860 if(this.labelEl.isVisible(true)){
33861 this.indicatorEl().removeClass('visible');
33862 this.indicatorEl().addClass('invisible');
33865 this.el.removeClass([this.invalidClass, this.validClass]);
33866 this.el.addClass(this.validClass);
33868 this.fireEvent('valid', this);
33871 markInvalid : function(msg)
33873 if(this.allowBlank || this.disabled){
33877 if(this.labelEl.isVisible(true)){
33878 this.indicatorEl().removeClass('invisible');
33879 this.indicatorEl().addClass('visible');
33882 this.el.removeClass([this.invalidClass, this.validClass]);
33883 this.el.addClass(this.invalidClass);
33885 this.fireEvent('invalid', this, msg);
33889 setValue : function(v, suppressEvent)
33891 if(this.value === v){
33898 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33901 Roo.each(this.radioes, function(i){
33903 i.el.removeClass('checked');
33906 Roo.each(this.radioes, function(i){
33908 if(i.value === v || i.value.toString() === v.toString()){
33910 i.el.addClass('checked');
33912 if(suppressEvent !== true){
33913 this.fireEvent('check', this, i);
33924 clearInvalid : function(){
33926 if(!this.el || this.preventMark){
33930 this.el.removeClass([this.invalidClass]);
33932 this.fireEvent('valid', this);
33937 Roo.apply(Roo.bootstrap.RadioSet, {
33941 register : function(set)
33943 this.groups[set.name] = set;
33946 get: function(name)
33948 if (typeof(this.groups[name]) == 'undefined') {
33952 return this.groups[name] ;
33958 * Ext JS Library 1.1.1
33959 * Copyright(c) 2006-2007, Ext JS, LLC.
33961 * Originally Released Under LGPL - original licence link has changed is not relivant.
33964 * <script type="text/javascript">
33969 * @class Roo.bootstrap.SplitBar
33970 * @extends Roo.util.Observable
33971 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33975 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33976 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33977 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33978 split.minSize = 100;
33979 split.maxSize = 600;
33980 split.animate = true;
33981 split.on('moved', splitterMoved);
33984 * Create a new SplitBar
33985 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33986 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33987 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33988 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33989 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33990 position of the SplitBar).
33992 Roo.bootstrap.SplitBar = function(cfg){
33997 // dragElement : elm
33998 // resizingElement: el,
34000 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34001 // placement : Roo.bootstrap.SplitBar.LEFT ,
34002 // existingProxy ???
34005 this.el = Roo.get(cfg.dragElement, true);
34006 this.el.dom.unselectable = "on";
34008 this.resizingEl = Roo.get(cfg.resizingElement, true);
34012 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34013 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34016 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34019 * The minimum size of the resizing element. (Defaults to 0)
34025 * The maximum size of the resizing element. (Defaults to 2000)
34028 this.maxSize = 2000;
34031 * Whether to animate the transition to the new size
34034 this.animate = false;
34037 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34040 this.useShim = false;
34045 if(!cfg.existingProxy){
34047 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34049 this.proxy = Roo.get(cfg.existingProxy).dom;
34052 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34055 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34058 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34061 this.dragSpecs = {};
34064 * @private The adapter to use to positon and resize elements
34066 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34067 this.adapter.init(this);
34069 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34071 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34072 this.el.addClass("roo-splitbar-h");
34075 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34076 this.el.addClass("roo-splitbar-v");
34082 * Fires when the splitter is moved (alias for {@link #event-moved})
34083 * @param {Roo.bootstrap.SplitBar} this
34084 * @param {Number} newSize the new width or height
34089 * Fires when the splitter is moved
34090 * @param {Roo.bootstrap.SplitBar} this
34091 * @param {Number} newSize the new width or height
34095 * @event beforeresize
34096 * Fires before the splitter is dragged
34097 * @param {Roo.bootstrap.SplitBar} this
34099 "beforeresize" : true,
34101 "beforeapply" : true
34104 Roo.util.Observable.call(this);
34107 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34108 onStartProxyDrag : function(x, y){
34109 this.fireEvent("beforeresize", this);
34111 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34113 o.enableDisplayMode("block");
34114 // all splitbars share the same overlay
34115 Roo.bootstrap.SplitBar.prototype.overlay = o;
34117 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34118 this.overlay.show();
34119 Roo.get(this.proxy).setDisplayed("block");
34120 var size = this.adapter.getElementSize(this);
34121 this.activeMinSize = this.getMinimumSize();;
34122 this.activeMaxSize = this.getMaximumSize();;
34123 var c1 = size - this.activeMinSize;
34124 var c2 = Math.max(this.activeMaxSize - size, 0);
34125 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34126 this.dd.resetConstraints();
34127 this.dd.setXConstraint(
34128 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34129 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34131 this.dd.setYConstraint(0, 0);
34133 this.dd.resetConstraints();
34134 this.dd.setXConstraint(0, 0);
34135 this.dd.setYConstraint(
34136 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34137 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34140 this.dragSpecs.startSize = size;
34141 this.dragSpecs.startPoint = [x, y];
34142 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34146 * @private Called after the drag operation by the DDProxy
34148 onEndProxyDrag : function(e){
34149 Roo.get(this.proxy).setDisplayed(false);
34150 var endPoint = Roo.lib.Event.getXY(e);
34152 this.overlay.hide();
34155 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34156 newSize = this.dragSpecs.startSize +
34157 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34158 endPoint[0] - this.dragSpecs.startPoint[0] :
34159 this.dragSpecs.startPoint[0] - endPoint[0]
34162 newSize = this.dragSpecs.startSize +
34163 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34164 endPoint[1] - this.dragSpecs.startPoint[1] :
34165 this.dragSpecs.startPoint[1] - endPoint[1]
34168 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34169 if(newSize != this.dragSpecs.startSize){
34170 if(this.fireEvent('beforeapply', this, newSize) !== false){
34171 this.adapter.setElementSize(this, newSize);
34172 this.fireEvent("moved", this, newSize);
34173 this.fireEvent("resize", this, newSize);
34179 * Get the adapter this SplitBar uses
34180 * @return The adapter object
34182 getAdapter : function(){
34183 return this.adapter;
34187 * Set the adapter this SplitBar uses
34188 * @param {Object} adapter A SplitBar adapter object
34190 setAdapter : function(adapter){
34191 this.adapter = adapter;
34192 this.adapter.init(this);
34196 * Gets the minimum size for the resizing element
34197 * @return {Number} The minimum size
34199 getMinimumSize : function(){
34200 return this.minSize;
34204 * Sets the minimum size for the resizing element
34205 * @param {Number} minSize The minimum size
34207 setMinimumSize : function(minSize){
34208 this.minSize = minSize;
34212 * Gets the maximum size for the resizing element
34213 * @return {Number} The maximum size
34215 getMaximumSize : function(){
34216 return this.maxSize;
34220 * Sets the maximum size for the resizing element
34221 * @param {Number} maxSize The maximum size
34223 setMaximumSize : function(maxSize){
34224 this.maxSize = maxSize;
34228 * Sets the initialize size for the resizing element
34229 * @param {Number} size The initial size
34231 setCurrentSize : function(size){
34232 var oldAnimate = this.animate;
34233 this.animate = false;
34234 this.adapter.setElementSize(this, size);
34235 this.animate = oldAnimate;
34239 * Destroy this splitbar.
34240 * @param {Boolean} removeEl True to remove the element
34242 destroy : function(removeEl){
34244 this.shim.remove();
34247 this.proxy.parentNode.removeChild(this.proxy);
34255 * @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.
34257 Roo.bootstrap.SplitBar.createProxy = function(dir){
34258 var proxy = new Roo.Element(document.createElement("div"));
34259 proxy.unselectable();
34260 var cls = 'roo-splitbar-proxy';
34261 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34262 document.body.appendChild(proxy.dom);
34267 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34268 * Default Adapter. It assumes the splitter and resizing element are not positioned
34269 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34271 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34274 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34275 // do nothing for now
34276 init : function(s){
34280 * Called before drag operations to get the current size of the resizing element.
34281 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34283 getElementSize : function(s){
34284 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34285 return s.resizingEl.getWidth();
34287 return s.resizingEl.getHeight();
34292 * Called after drag operations to set the size of the resizing element.
34293 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34294 * @param {Number} newSize The new size to set
34295 * @param {Function} onComplete A function to be invoked when resizing is complete
34297 setElementSize : function(s, newSize, onComplete){
34298 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34300 s.resizingEl.setWidth(newSize);
34302 onComplete(s, newSize);
34305 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34310 s.resizingEl.setHeight(newSize);
34312 onComplete(s, newSize);
34315 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34322 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34323 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34324 * Adapter that moves the splitter element to align with the resized sizing element.
34325 * Used with an absolute positioned SplitBar.
34326 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34327 * document.body, make sure you assign an id to the body element.
34329 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34330 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34331 this.container = Roo.get(container);
34334 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34335 init : function(s){
34336 this.basic.init(s);
34339 getElementSize : function(s){
34340 return this.basic.getElementSize(s);
34343 setElementSize : function(s, newSize, onComplete){
34344 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34347 moveSplitter : function(s){
34348 var yes = Roo.bootstrap.SplitBar;
34349 switch(s.placement){
34351 s.el.setX(s.resizingEl.getRight());
34354 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34357 s.el.setY(s.resizingEl.getBottom());
34360 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34367 * Orientation constant - Create a vertical SplitBar
34371 Roo.bootstrap.SplitBar.VERTICAL = 1;
34374 * Orientation constant - Create a horizontal SplitBar
34378 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34381 * Placement constant - The resizing element is to the left of the splitter element
34385 Roo.bootstrap.SplitBar.LEFT = 1;
34388 * Placement constant - The resizing element is to the right of the splitter element
34392 Roo.bootstrap.SplitBar.RIGHT = 2;
34395 * Placement constant - The resizing element is positioned above the splitter element
34399 Roo.bootstrap.SplitBar.TOP = 3;
34402 * Placement constant - The resizing element is positioned under splitter element
34406 Roo.bootstrap.SplitBar.BOTTOM = 4;
34407 Roo.namespace("Roo.bootstrap.layout");/*
34409 * Ext JS Library 1.1.1
34410 * Copyright(c) 2006-2007, Ext JS, LLC.
34412 * Originally Released Under LGPL - original licence link has changed is not relivant.
34415 * <script type="text/javascript">
34419 * @class Roo.bootstrap.layout.Manager
34420 * @extends Roo.bootstrap.Component
34421 * Base class for layout managers.
34423 Roo.bootstrap.layout.Manager = function(config)
34425 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34431 /** false to disable window resize monitoring @type Boolean */
34432 this.monitorWindowResize = true;
34437 * Fires when a layout is performed.
34438 * @param {Roo.LayoutManager} this
34442 * @event regionresized
34443 * Fires when the user resizes a region.
34444 * @param {Roo.LayoutRegion} region The resized region
34445 * @param {Number} newSize The new size (width for east/west, height for north/south)
34447 "regionresized" : true,
34449 * @event regioncollapsed
34450 * Fires when a region is collapsed.
34451 * @param {Roo.LayoutRegion} region The collapsed region
34453 "regioncollapsed" : true,
34455 * @event regionexpanded
34456 * Fires when a region is expanded.
34457 * @param {Roo.LayoutRegion} region The expanded region
34459 "regionexpanded" : true
34461 this.updating = false;
34464 this.el = Roo.get(config.el);
34470 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34475 monitorWindowResize : true,
34481 onRender : function(ct, position)
34484 this.el = Roo.get(ct);
34487 //this.fireEvent('render',this);
34491 initEvents: function()
34495 // ie scrollbar fix
34496 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34497 document.body.scroll = "no";
34498 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34499 this.el.position('relative');
34501 this.id = this.el.id;
34502 this.el.addClass("roo-layout-container");
34503 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34504 if(this.el.dom != document.body ) {
34505 this.el.on('resize', this.layout,this);
34506 this.el.on('show', this.layout,this);
34512 * Returns true if this layout is currently being updated
34513 * @return {Boolean}
34515 isUpdating : function(){
34516 return this.updating;
34520 * Suspend the LayoutManager from doing auto-layouts while
34521 * making multiple add or remove calls
34523 beginUpdate : function(){
34524 this.updating = true;
34528 * Restore auto-layouts and optionally disable the manager from performing a layout
34529 * @param {Boolean} noLayout true to disable a layout update
34531 endUpdate : function(noLayout){
34532 this.updating = false;
34538 layout: function(){
34542 onRegionResized : function(region, newSize){
34543 this.fireEvent("regionresized", region, newSize);
34547 onRegionCollapsed : function(region){
34548 this.fireEvent("regioncollapsed", region);
34551 onRegionExpanded : function(region){
34552 this.fireEvent("regionexpanded", region);
34556 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34557 * performs box-model adjustments.
34558 * @return {Object} The size as an object {width: (the width), height: (the height)}
34560 getViewSize : function()
34563 if(this.el.dom != document.body){
34564 size = this.el.getSize();
34566 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34568 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34569 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34574 * Returns the Element this layout is bound to.
34575 * @return {Roo.Element}
34577 getEl : function(){
34582 * Returns the specified region.
34583 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34584 * @return {Roo.LayoutRegion}
34586 getRegion : function(target){
34587 return this.regions[target.toLowerCase()];
34590 onWindowResize : function(){
34591 if(this.monitorWindowResize){
34598 * Ext JS Library 1.1.1
34599 * Copyright(c) 2006-2007, Ext JS, LLC.
34601 * Originally Released Under LGPL - original licence link has changed is not relivant.
34604 * <script type="text/javascript">
34607 * @class Roo.bootstrap.layout.Border
34608 * @extends Roo.bootstrap.layout.Manager
34609 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34610 * please see: examples/bootstrap/nested.html<br><br>
34612 <b>The container the layout is rendered into can be either the body element or any other element.
34613 If it is not the body element, the container needs to either be an absolute positioned element,
34614 or you will need to add "position:relative" to the css of the container. You will also need to specify
34615 the container size if it is not the body element.</b>
34618 * Create a new Border
34619 * @param {Object} config Configuration options
34621 Roo.bootstrap.layout.Border = function(config){
34622 config = config || {};
34623 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34627 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34628 if(config[region]){
34629 config[region].region = region;
34630 this.addRegion(config[region]);
34636 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34638 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34640 * Creates and adds a new region if it doesn't already exist.
34641 * @param {String} target The target region key (north, south, east, west or center).
34642 * @param {Object} config The regions config object
34643 * @return {BorderLayoutRegion} The new region
34645 addRegion : function(config)
34647 if(!this.regions[config.region]){
34648 var r = this.factory(config);
34649 this.bindRegion(r);
34651 return this.regions[config.region];
34655 bindRegion : function(r){
34656 this.regions[r.config.region] = r;
34658 r.on("visibilitychange", this.layout, this);
34659 r.on("paneladded", this.layout, this);
34660 r.on("panelremoved", this.layout, this);
34661 r.on("invalidated", this.layout, this);
34662 r.on("resized", this.onRegionResized, this);
34663 r.on("collapsed", this.onRegionCollapsed, this);
34664 r.on("expanded", this.onRegionExpanded, this);
34668 * Performs a layout update.
34670 layout : function()
34672 if(this.updating) {
34676 // render all the rebions if they have not been done alreayd?
34677 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34678 if(this.regions[region] && !this.regions[region].bodyEl){
34679 this.regions[region].onRender(this.el)
34683 var size = this.getViewSize();
34684 var w = size.width;
34685 var h = size.height;
34690 //var x = 0, y = 0;
34692 var rs = this.regions;
34693 var north = rs["north"];
34694 var south = rs["south"];
34695 var west = rs["west"];
34696 var east = rs["east"];
34697 var center = rs["center"];
34698 //if(this.hideOnLayout){ // not supported anymore
34699 //c.el.setStyle("display", "none");
34701 if(north && north.isVisible()){
34702 var b = north.getBox();
34703 var m = north.getMargins();
34704 b.width = w - (m.left+m.right);
34707 centerY = b.height + b.y + m.bottom;
34708 centerH -= centerY;
34709 north.updateBox(this.safeBox(b));
34711 if(south && south.isVisible()){
34712 var b = south.getBox();
34713 var m = south.getMargins();
34714 b.width = w - (m.left+m.right);
34716 var totalHeight = (b.height + m.top + m.bottom);
34717 b.y = h - totalHeight + m.top;
34718 centerH -= totalHeight;
34719 south.updateBox(this.safeBox(b));
34721 if(west && west.isVisible()){
34722 var b = west.getBox();
34723 var m = west.getMargins();
34724 b.height = centerH - (m.top+m.bottom);
34726 b.y = centerY + m.top;
34727 var totalWidth = (b.width + m.left + m.right);
34728 centerX += totalWidth;
34729 centerW -= totalWidth;
34730 west.updateBox(this.safeBox(b));
34732 if(east && east.isVisible()){
34733 var b = east.getBox();
34734 var m = east.getMargins();
34735 b.height = centerH - (m.top+m.bottom);
34736 var totalWidth = (b.width + m.left + m.right);
34737 b.x = w - totalWidth + m.left;
34738 b.y = centerY + m.top;
34739 centerW -= totalWidth;
34740 east.updateBox(this.safeBox(b));
34743 var m = center.getMargins();
34745 x: centerX + m.left,
34746 y: centerY + m.top,
34747 width: centerW - (m.left+m.right),
34748 height: centerH - (m.top+m.bottom)
34750 //if(this.hideOnLayout){
34751 //center.el.setStyle("display", "block");
34753 center.updateBox(this.safeBox(centerBox));
34756 this.fireEvent("layout", this);
34760 safeBox : function(box){
34761 box.width = Math.max(0, box.width);
34762 box.height = Math.max(0, box.height);
34767 * Adds a ContentPanel (or subclass) to this layout.
34768 * @param {String} target The target region key (north, south, east, west or center).
34769 * @param {Roo.ContentPanel} panel The panel to add
34770 * @return {Roo.ContentPanel} The added panel
34772 add : function(target, panel){
34774 target = target.toLowerCase();
34775 return this.regions[target].add(panel);
34779 * Remove a ContentPanel (or subclass) to this layout.
34780 * @param {String} target The target region key (north, south, east, west or center).
34781 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34782 * @return {Roo.ContentPanel} The removed panel
34784 remove : function(target, panel){
34785 target = target.toLowerCase();
34786 return this.regions[target].remove(panel);
34790 * Searches all regions for a panel with the specified id
34791 * @param {String} panelId
34792 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34794 findPanel : function(panelId){
34795 var rs = this.regions;
34796 for(var target in rs){
34797 if(typeof rs[target] != "function"){
34798 var p = rs[target].getPanel(panelId);
34808 * Searches all regions for a panel with the specified id and activates (shows) it.
34809 * @param {String/ContentPanel} panelId The panels id or the panel itself
34810 * @return {Roo.ContentPanel} The shown panel or null
34812 showPanel : function(panelId) {
34813 var rs = this.regions;
34814 for(var target in rs){
34815 var r = rs[target];
34816 if(typeof r != "function"){
34817 if(r.hasPanel(panelId)){
34818 return r.showPanel(panelId);
34826 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34827 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34830 restoreState : function(provider){
34832 provider = Roo.state.Manager;
34834 var sm = new Roo.LayoutStateManager();
34835 sm.init(this, provider);
34841 * Adds a xtype elements to the layout.
34845 xtype : 'ContentPanel',
34852 xtype : 'NestedLayoutPanel',
34858 items : [ ... list of content panels or nested layout panels.. ]
34862 * @param {Object} cfg Xtype definition of item to add.
34864 addxtype : function(cfg)
34866 // basically accepts a pannel...
34867 // can accept a layout region..!?!?
34868 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34871 // theory? children can only be panels??
34873 //if (!cfg.xtype.match(/Panel$/)) {
34878 if (typeof(cfg.region) == 'undefined') {
34879 Roo.log("Failed to add Panel, region was not set");
34883 var region = cfg.region;
34889 xitems = cfg.items;
34896 case 'Content': // ContentPanel (el, cfg)
34897 case 'Scroll': // ContentPanel (el, cfg)
34899 cfg.autoCreate = true;
34900 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34902 // var el = this.el.createChild();
34903 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34906 this.add(region, ret);
34910 case 'TreePanel': // our new panel!
34911 cfg.el = this.el.createChild();
34912 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34913 this.add(region, ret);
34918 // create a new Layout (which is a Border Layout...
34920 var clayout = cfg.layout;
34921 clayout.el = this.el.createChild();
34922 clayout.items = clayout.items || [];
34926 // replace this exitems with the clayout ones..
34927 xitems = clayout.items;
34929 // force background off if it's in center...
34930 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34931 cfg.background = false;
34933 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34936 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34937 //console.log('adding nested layout panel ' + cfg.toSource());
34938 this.add(region, ret);
34939 nb = {}; /// find first...
34944 // needs grid and region
34946 //var el = this.getRegion(region).el.createChild();
34948 *var el = this.el.createChild();
34949 // create the grid first...
34950 cfg.grid.container = el;
34951 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34954 if (region == 'center' && this.active ) {
34955 cfg.background = false;
34958 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34960 this.add(region, ret);
34962 if (cfg.background) {
34963 // render grid on panel activation (if panel background)
34964 ret.on('activate', function(gp) {
34965 if (!gp.grid.rendered) {
34966 // gp.grid.render(el);
34970 // cfg.grid.render(el);
34976 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34977 // it was the old xcomponent building that caused this before.
34978 // espeically if border is the top element in the tree.
34988 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34990 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34991 this.add(region, ret);
34995 throw "Can not add '" + cfg.xtype + "' to Border";
35001 this.beginUpdate();
35005 Roo.each(xitems, function(i) {
35006 region = nb && i.region ? i.region : false;
35008 var add = ret.addxtype(i);
35011 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35012 if (!i.background) {
35013 abn[region] = nb[region] ;
35020 // make the last non-background panel active..
35021 //if (nb) { Roo.log(abn); }
35024 for(var r in abn) {
35025 region = this.getRegion(r);
35027 // tried using nb[r], but it does not work..
35029 region.showPanel(abn[r]);
35040 factory : function(cfg)
35043 var validRegions = Roo.bootstrap.layout.Border.regions;
35045 var target = cfg.region;
35048 var r = Roo.bootstrap.layout;
35052 return new r.North(cfg);
35054 return new r.South(cfg);
35056 return new r.East(cfg);
35058 return new r.West(cfg);
35060 return new r.Center(cfg);
35062 throw 'Layout region "'+target+'" not supported.';
35069 * Ext JS Library 1.1.1
35070 * Copyright(c) 2006-2007, Ext JS, LLC.
35072 * Originally Released Under LGPL - original licence link has changed is not relivant.
35075 * <script type="text/javascript">
35079 * @class Roo.bootstrap.layout.Basic
35080 * @extends Roo.util.Observable
35081 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35082 * and does not have a titlebar, tabs or any other features. All it does is size and position
35083 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35084 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35085 * @cfg {string} region the region that it inhabits..
35086 * @cfg {bool} skipConfig skip config?
35090 Roo.bootstrap.layout.Basic = function(config){
35092 this.mgr = config.mgr;
35094 this.position = config.region;
35096 var skipConfig = config.skipConfig;
35100 * @scope Roo.BasicLayoutRegion
35104 * @event beforeremove
35105 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35106 * @param {Roo.LayoutRegion} this
35107 * @param {Roo.ContentPanel} panel The panel
35108 * @param {Object} e The cancel event object
35110 "beforeremove" : true,
35112 * @event invalidated
35113 * Fires when the layout for this region is changed.
35114 * @param {Roo.LayoutRegion} this
35116 "invalidated" : true,
35118 * @event visibilitychange
35119 * Fires when this region is shown or hidden
35120 * @param {Roo.LayoutRegion} this
35121 * @param {Boolean} visibility true or false
35123 "visibilitychange" : true,
35125 * @event paneladded
35126 * Fires when a panel is added.
35127 * @param {Roo.LayoutRegion} this
35128 * @param {Roo.ContentPanel} panel The panel
35130 "paneladded" : true,
35132 * @event panelremoved
35133 * Fires when a panel is removed.
35134 * @param {Roo.LayoutRegion} this
35135 * @param {Roo.ContentPanel} panel The panel
35137 "panelremoved" : true,
35139 * @event beforecollapse
35140 * Fires when this region before collapse.
35141 * @param {Roo.LayoutRegion} this
35143 "beforecollapse" : true,
35146 * Fires when this region is collapsed.
35147 * @param {Roo.LayoutRegion} this
35149 "collapsed" : true,
35152 * Fires when this region is expanded.
35153 * @param {Roo.LayoutRegion} this
35158 * Fires when this region is slid into view.
35159 * @param {Roo.LayoutRegion} this
35161 "slideshow" : true,
35164 * Fires when this region slides out of view.
35165 * @param {Roo.LayoutRegion} this
35167 "slidehide" : true,
35169 * @event panelactivated
35170 * Fires when a panel is activated.
35171 * @param {Roo.LayoutRegion} this
35172 * @param {Roo.ContentPanel} panel The activated panel
35174 "panelactivated" : true,
35177 * Fires when the user resizes this region.
35178 * @param {Roo.LayoutRegion} this
35179 * @param {Number} newSize The new size (width for east/west, height for north/south)
35183 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35184 this.panels = new Roo.util.MixedCollection();
35185 this.panels.getKey = this.getPanelId.createDelegate(this);
35187 this.activePanel = null;
35188 // ensure listeners are added...
35190 if (config.listeners || config.events) {
35191 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35192 listeners : config.listeners || {},
35193 events : config.events || {}
35197 if(skipConfig !== true){
35198 this.applyConfig(config);
35202 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35204 getPanelId : function(p){
35208 applyConfig : function(config){
35209 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35210 this.config = config;
35215 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35216 * the width, for horizontal (north, south) the height.
35217 * @param {Number} newSize The new width or height
35219 resizeTo : function(newSize){
35220 var el = this.el ? this.el :
35221 (this.activePanel ? this.activePanel.getEl() : null);
35223 switch(this.position){
35226 el.setWidth(newSize);
35227 this.fireEvent("resized", this, newSize);
35231 el.setHeight(newSize);
35232 this.fireEvent("resized", this, newSize);
35238 getBox : function(){
35239 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35242 getMargins : function(){
35243 return this.margins;
35246 updateBox : function(box){
35248 var el = this.activePanel.getEl();
35249 el.dom.style.left = box.x + "px";
35250 el.dom.style.top = box.y + "px";
35251 this.activePanel.setSize(box.width, box.height);
35255 * Returns the container element for this region.
35256 * @return {Roo.Element}
35258 getEl : function(){
35259 return this.activePanel;
35263 * Returns true if this region is currently visible.
35264 * @return {Boolean}
35266 isVisible : function(){
35267 return this.activePanel ? true : false;
35270 setActivePanel : function(panel){
35271 panel = this.getPanel(panel);
35272 if(this.activePanel && this.activePanel != panel){
35273 this.activePanel.setActiveState(false);
35274 this.activePanel.getEl().setLeftTop(-10000,-10000);
35276 this.activePanel = panel;
35277 panel.setActiveState(true);
35279 panel.setSize(this.box.width, this.box.height);
35281 this.fireEvent("panelactivated", this, panel);
35282 this.fireEvent("invalidated");
35286 * Show the specified panel.
35287 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35288 * @return {Roo.ContentPanel} The shown panel or null
35290 showPanel : function(panel){
35291 panel = this.getPanel(panel);
35293 this.setActivePanel(panel);
35299 * Get the active panel for this region.
35300 * @return {Roo.ContentPanel} The active panel or null
35302 getActivePanel : function(){
35303 return this.activePanel;
35307 * Add the passed ContentPanel(s)
35308 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35309 * @return {Roo.ContentPanel} The panel added (if only one was added)
35311 add : function(panel){
35312 if(arguments.length > 1){
35313 for(var i = 0, len = arguments.length; i < len; i++) {
35314 this.add(arguments[i]);
35318 if(this.hasPanel(panel)){
35319 this.showPanel(panel);
35322 var el = panel.getEl();
35323 if(el.dom.parentNode != this.mgr.el.dom){
35324 this.mgr.el.dom.appendChild(el.dom);
35326 if(panel.setRegion){
35327 panel.setRegion(this);
35329 this.panels.add(panel);
35330 el.setStyle("position", "absolute");
35331 if(!panel.background){
35332 this.setActivePanel(panel);
35333 if(this.config.initialSize && this.panels.getCount()==1){
35334 this.resizeTo(this.config.initialSize);
35337 this.fireEvent("paneladded", this, panel);
35342 * Returns true if the panel is in this region.
35343 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35344 * @return {Boolean}
35346 hasPanel : function(panel){
35347 if(typeof panel == "object"){ // must be panel obj
35348 panel = panel.getId();
35350 return this.getPanel(panel) ? true : false;
35354 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35355 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35356 * @param {Boolean} preservePanel Overrides the config preservePanel option
35357 * @return {Roo.ContentPanel} The panel that was removed
35359 remove : function(panel, preservePanel){
35360 panel = this.getPanel(panel);
35365 this.fireEvent("beforeremove", this, panel, e);
35366 if(e.cancel === true){
35369 var panelId = panel.getId();
35370 this.panels.removeKey(panelId);
35375 * Returns the panel specified or null if it's not in this region.
35376 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35377 * @return {Roo.ContentPanel}
35379 getPanel : function(id){
35380 if(typeof id == "object"){ // must be panel obj
35383 return this.panels.get(id);
35387 * Returns this regions position (north/south/east/west/center).
35390 getPosition: function(){
35391 return this.position;
35395 * Ext JS Library 1.1.1
35396 * Copyright(c) 2006-2007, Ext JS, LLC.
35398 * Originally Released Under LGPL - original licence link has changed is not relivant.
35401 * <script type="text/javascript">
35405 * @class Roo.bootstrap.layout.Region
35406 * @extends Roo.bootstrap.layout.Basic
35407 * This class represents a region in a layout manager.
35409 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35410 * @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})
35411 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35412 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35413 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35414 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35415 * @cfg {String} title The title for the region (overrides panel titles)
35416 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35417 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35418 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35419 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35420 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35421 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35422 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35423 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35424 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35425 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35427 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35428 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35429 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35430 * @cfg {Number} width For East/West panels
35431 * @cfg {Number} height For North/South panels
35432 * @cfg {Boolean} split To show the splitter
35433 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35435 * @cfg {string} cls Extra CSS classes to add to region
35437 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35438 * @cfg {string} region the region that it inhabits..
35441 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35442 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35444 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35445 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35446 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35448 Roo.bootstrap.layout.Region = function(config)
35450 this.applyConfig(config);
35452 var mgr = config.mgr;
35453 var pos = config.region;
35454 config.skipConfig = true;
35455 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35458 this.onRender(mgr.el);
35461 this.visible = true;
35462 this.collapsed = false;
35463 this.unrendered_panels = [];
35466 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35468 position: '', // set by wrapper (eg. north/south etc..)
35469 unrendered_panels : null, // unrendered panels.
35470 createBody : function(){
35471 /** This region's body element
35472 * @type Roo.Element */
35473 this.bodyEl = this.el.createChild({
35475 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35479 onRender: function(ctr, pos)
35481 var dh = Roo.DomHelper;
35482 /** This region's container element
35483 * @type Roo.Element */
35484 this.el = dh.append(ctr.dom, {
35486 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35488 /** This region's title element
35489 * @type Roo.Element */
35491 this.titleEl = dh.append(this.el.dom,
35494 unselectable: "on",
35495 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35497 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35498 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35501 this.titleEl.enableDisplayMode();
35502 /** This region's title text element
35503 * @type HTMLElement */
35504 this.titleTextEl = this.titleEl.dom.firstChild;
35505 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35507 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35508 this.closeBtn.enableDisplayMode();
35509 this.closeBtn.on("click", this.closeClicked, this);
35510 this.closeBtn.hide();
35512 this.createBody(this.config);
35513 if(this.config.hideWhenEmpty){
35515 this.on("paneladded", this.validateVisibility, this);
35516 this.on("panelremoved", this.validateVisibility, this);
35518 if(this.autoScroll){
35519 this.bodyEl.setStyle("overflow", "auto");
35521 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35523 //if(c.titlebar !== false){
35524 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35525 this.titleEl.hide();
35527 this.titleEl.show();
35528 if(this.config.title){
35529 this.titleTextEl.innerHTML = this.config.title;
35533 if(this.config.collapsed){
35534 this.collapse(true);
35536 if(this.config.hidden){
35540 if (this.unrendered_panels && this.unrendered_panels.length) {
35541 for (var i =0;i< this.unrendered_panels.length; i++) {
35542 this.add(this.unrendered_panels[i]);
35544 this.unrendered_panels = null;
35550 applyConfig : function(c)
35553 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35554 var dh = Roo.DomHelper;
35555 if(c.titlebar !== false){
35556 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35557 this.collapseBtn.on("click", this.collapse, this);
35558 this.collapseBtn.enableDisplayMode();
35560 if(c.showPin === true || this.showPin){
35561 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35562 this.stickBtn.enableDisplayMode();
35563 this.stickBtn.on("click", this.expand, this);
35564 this.stickBtn.hide();
35569 /** This region's collapsed element
35570 * @type Roo.Element */
35573 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35574 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35577 if(c.floatable !== false){
35578 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35579 this.collapsedEl.on("click", this.collapseClick, this);
35582 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35583 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35584 id: "message", unselectable: "on", style:{"float":"left"}});
35585 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35587 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35588 this.expandBtn.on("click", this.expand, this);
35592 if(this.collapseBtn){
35593 this.collapseBtn.setVisible(c.collapsible == true);
35596 this.cmargins = c.cmargins || this.cmargins ||
35597 (this.position == "west" || this.position == "east" ?
35598 {top: 0, left: 2, right:2, bottom: 0} :
35599 {top: 2, left: 0, right:0, bottom: 2});
35601 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35604 this.bottomTabs = c.tabPosition != "top";
35606 this.autoScroll = c.autoScroll || false;
35611 this.duration = c.duration || .30;
35612 this.slideDuration = c.slideDuration || .45;
35617 * Returns true if this region is currently visible.
35618 * @return {Boolean}
35620 isVisible : function(){
35621 return this.visible;
35625 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35626 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35628 //setCollapsedTitle : function(title){
35629 // title = title || " ";
35630 // if(this.collapsedTitleTextEl){
35631 // this.collapsedTitleTextEl.innerHTML = title;
35635 getBox : function(){
35637 // if(!this.collapsed){
35638 b = this.el.getBox(false, true);
35640 // b = this.collapsedEl.getBox(false, true);
35645 getMargins : function(){
35646 return this.margins;
35647 //return this.collapsed ? this.cmargins : this.margins;
35650 highlight : function(){
35651 this.el.addClass("x-layout-panel-dragover");
35654 unhighlight : function(){
35655 this.el.removeClass("x-layout-panel-dragover");
35658 updateBox : function(box)
35660 if (!this.bodyEl) {
35661 return; // not rendered yet..
35665 if(!this.collapsed){
35666 this.el.dom.style.left = box.x + "px";
35667 this.el.dom.style.top = box.y + "px";
35668 this.updateBody(box.width, box.height);
35670 this.collapsedEl.dom.style.left = box.x + "px";
35671 this.collapsedEl.dom.style.top = box.y + "px";
35672 this.collapsedEl.setSize(box.width, box.height);
35675 this.tabs.autoSizeTabs();
35679 updateBody : function(w, h)
35682 this.el.setWidth(w);
35683 w -= this.el.getBorderWidth("rl");
35684 if(this.config.adjustments){
35685 w += this.config.adjustments[0];
35688 if(h !== null && h > 0){
35689 this.el.setHeight(h);
35690 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35691 h -= this.el.getBorderWidth("tb");
35692 if(this.config.adjustments){
35693 h += this.config.adjustments[1];
35695 this.bodyEl.setHeight(h);
35697 h = this.tabs.syncHeight(h);
35700 if(this.panelSize){
35701 w = w !== null ? w : this.panelSize.width;
35702 h = h !== null ? h : this.panelSize.height;
35704 if(this.activePanel){
35705 var el = this.activePanel.getEl();
35706 w = w !== null ? w : el.getWidth();
35707 h = h !== null ? h : el.getHeight();
35708 this.panelSize = {width: w, height: h};
35709 this.activePanel.setSize(w, h);
35711 if(Roo.isIE && this.tabs){
35712 this.tabs.el.repaint();
35717 * Returns the container element for this region.
35718 * @return {Roo.Element}
35720 getEl : function(){
35725 * Hides this region.
35728 //if(!this.collapsed){
35729 this.el.dom.style.left = "-2000px";
35732 // this.collapsedEl.dom.style.left = "-2000px";
35733 // this.collapsedEl.hide();
35735 this.visible = false;
35736 this.fireEvent("visibilitychange", this, false);
35740 * Shows this region if it was previously hidden.
35743 //if(!this.collapsed){
35746 // this.collapsedEl.show();
35748 this.visible = true;
35749 this.fireEvent("visibilitychange", this, true);
35752 closeClicked : function(){
35753 if(this.activePanel){
35754 this.remove(this.activePanel);
35758 collapseClick : function(e){
35760 e.stopPropagation();
35763 e.stopPropagation();
35769 * Collapses this region.
35770 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35773 collapse : function(skipAnim, skipCheck = false){
35774 if(this.collapsed) {
35778 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35780 this.collapsed = true;
35782 this.split.el.hide();
35784 if(this.config.animate && skipAnim !== true){
35785 this.fireEvent("invalidated", this);
35786 this.animateCollapse();
35788 this.el.setLocation(-20000,-20000);
35790 this.collapsedEl.show();
35791 this.fireEvent("collapsed", this);
35792 this.fireEvent("invalidated", this);
35798 animateCollapse : function(){
35803 * Expands this region if it was previously collapsed.
35804 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35805 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35808 expand : function(e, skipAnim){
35810 e.stopPropagation();
35812 if(!this.collapsed || this.el.hasActiveFx()) {
35816 this.afterSlideIn();
35819 this.collapsed = false;
35820 if(this.config.animate && skipAnim !== true){
35821 this.animateExpand();
35825 this.split.el.show();
35827 this.collapsedEl.setLocation(-2000,-2000);
35828 this.collapsedEl.hide();
35829 this.fireEvent("invalidated", this);
35830 this.fireEvent("expanded", this);
35834 animateExpand : function(){
35838 initTabs : function()
35840 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35842 var ts = new Roo.bootstrap.panel.Tabs({
35843 el: this.bodyEl.dom,
35844 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35845 disableTooltips: this.config.disableTabTips,
35846 toolbar : this.config.toolbar
35849 if(this.config.hideTabs){
35850 ts.stripWrap.setDisplayed(false);
35853 ts.resizeTabs = this.config.resizeTabs === true;
35854 ts.minTabWidth = this.config.minTabWidth || 40;
35855 ts.maxTabWidth = this.config.maxTabWidth || 250;
35856 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35857 ts.monitorResize = false;
35858 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35859 ts.bodyEl.addClass('roo-layout-tabs-body');
35860 this.panels.each(this.initPanelAsTab, this);
35863 initPanelAsTab : function(panel){
35864 var ti = this.tabs.addTab(
35868 this.config.closeOnTab && panel.isClosable(),
35871 if(panel.tabTip !== undefined){
35872 ti.setTooltip(panel.tabTip);
35874 ti.on("activate", function(){
35875 this.setActivePanel(panel);
35878 if(this.config.closeOnTab){
35879 ti.on("beforeclose", function(t, e){
35881 this.remove(panel);
35885 panel.tabItem = ti;
35890 updatePanelTitle : function(panel, title)
35892 if(this.activePanel == panel){
35893 this.updateTitle(title);
35896 var ti = this.tabs.getTab(panel.getEl().id);
35898 if(panel.tabTip !== undefined){
35899 ti.setTooltip(panel.tabTip);
35904 updateTitle : function(title){
35905 if(this.titleTextEl && !this.config.title){
35906 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35910 setActivePanel : function(panel)
35912 panel = this.getPanel(panel);
35913 if(this.activePanel && this.activePanel != panel){
35914 if(this.activePanel.setActiveState(false) === false){
35918 this.activePanel = panel;
35919 panel.setActiveState(true);
35920 if(this.panelSize){
35921 panel.setSize(this.panelSize.width, this.panelSize.height);
35924 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35926 this.updateTitle(panel.getTitle());
35928 this.fireEvent("invalidated", this);
35930 this.fireEvent("panelactivated", this, panel);
35934 * Shows the specified panel.
35935 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35936 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35938 showPanel : function(panel)
35940 panel = this.getPanel(panel);
35943 var tab = this.tabs.getTab(panel.getEl().id);
35944 if(tab.isHidden()){
35945 this.tabs.unhideTab(tab.id);
35949 this.setActivePanel(panel);
35956 * Get the active panel for this region.
35957 * @return {Roo.ContentPanel} The active panel or null
35959 getActivePanel : function(){
35960 return this.activePanel;
35963 validateVisibility : function(){
35964 if(this.panels.getCount() < 1){
35965 this.updateTitle(" ");
35966 this.closeBtn.hide();
35969 if(!this.isVisible()){
35976 * Adds the passed ContentPanel(s) to this region.
35977 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35978 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35980 add : function(panel)
35982 if(arguments.length > 1){
35983 for(var i = 0, len = arguments.length; i < len; i++) {
35984 this.add(arguments[i]);
35989 // if we have not been rendered yet, then we can not really do much of this..
35990 if (!this.bodyEl) {
35991 this.unrendered_panels.push(panel);
35998 if(this.hasPanel(panel)){
35999 this.showPanel(panel);
36002 panel.setRegion(this);
36003 this.panels.add(panel);
36004 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36005 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36006 // and hide them... ???
36007 this.bodyEl.dom.appendChild(panel.getEl().dom);
36008 if(panel.background !== true){
36009 this.setActivePanel(panel);
36011 this.fireEvent("paneladded", this, panel);
36018 this.initPanelAsTab(panel);
36022 if(panel.background !== true){
36023 this.tabs.activate(panel.getEl().id);
36025 this.fireEvent("paneladded", this, panel);
36030 * Hides the tab for the specified panel.
36031 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36033 hidePanel : function(panel){
36034 if(this.tabs && (panel = this.getPanel(panel))){
36035 this.tabs.hideTab(panel.getEl().id);
36040 * Unhides the tab for a previously hidden panel.
36041 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36043 unhidePanel : function(panel){
36044 if(this.tabs && (panel = this.getPanel(panel))){
36045 this.tabs.unhideTab(panel.getEl().id);
36049 clearPanels : function(){
36050 while(this.panels.getCount() > 0){
36051 this.remove(this.panels.first());
36056 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36057 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36058 * @param {Boolean} preservePanel Overrides the config preservePanel option
36059 * @return {Roo.ContentPanel} The panel that was removed
36061 remove : function(panel, preservePanel)
36063 panel = this.getPanel(panel);
36068 this.fireEvent("beforeremove", this, panel, e);
36069 if(e.cancel === true){
36072 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36073 var panelId = panel.getId();
36074 this.panels.removeKey(panelId);
36076 document.body.appendChild(panel.getEl().dom);
36079 this.tabs.removeTab(panel.getEl().id);
36080 }else if (!preservePanel){
36081 this.bodyEl.dom.removeChild(panel.getEl().dom);
36083 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36084 var p = this.panels.first();
36085 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36086 tempEl.appendChild(p.getEl().dom);
36087 this.bodyEl.update("");
36088 this.bodyEl.dom.appendChild(p.getEl().dom);
36090 this.updateTitle(p.getTitle());
36092 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36093 this.setActivePanel(p);
36095 panel.setRegion(null);
36096 if(this.activePanel == panel){
36097 this.activePanel = null;
36099 if(this.config.autoDestroy !== false && preservePanel !== true){
36100 try{panel.destroy();}catch(e){}
36102 this.fireEvent("panelremoved", this, panel);
36107 * Returns the TabPanel component used by this region
36108 * @return {Roo.TabPanel}
36110 getTabs : function(){
36114 createTool : function(parentEl, className){
36115 var btn = Roo.DomHelper.append(parentEl, {
36117 cls: "x-layout-tools-button",
36120 cls: "roo-layout-tools-button-inner " + className,
36124 btn.addClassOnOver("roo-layout-tools-button-over");
36129 * Ext JS Library 1.1.1
36130 * Copyright(c) 2006-2007, Ext JS, LLC.
36132 * Originally Released Under LGPL - original licence link has changed is not relivant.
36135 * <script type="text/javascript">
36141 * @class Roo.SplitLayoutRegion
36142 * @extends Roo.LayoutRegion
36143 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36145 Roo.bootstrap.layout.Split = function(config){
36146 this.cursor = config.cursor;
36147 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36150 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36152 splitTip : "Drag to resize.",
36153 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36154 useSplitTips : false,
36156 applyConfig : function(config){
36157 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36160 onRender : function(ctr,pos) {
36162 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36163 if(!this.config.split){
36168 var splitEl = Roo.DomHelper.append(ctr.dom, {
36170 id: this.el.id + "-split",
36171 cls: "roo-layout-split roo-layout-split-"+this.position,
36174 /** The SplitBar for this region
36175 * @type Roo.SplitBar */
36176 // does not exist yet...
36177 Roo.log([this.position, this.orientation]);
36179 this.split = new Roo.bootstrap.SplitBar({
36180 dragElement : splitEl,
36181 resizingElement: this.el,
36182 orientation : this.orientation
36185 this.split.on("moved", this.onSplitMove, this);
36186 this.split.useShim = this.config.useShim === true;
36187 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36188 if(this.useSplitTips){
36189 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36191 //if(config.collapsible){
36192 // this.split.el.on("dblclick", this.collapse, this);
36195 if(typeof this.config.minSize != "undefined"){
36196 this.split.minSize = this.config.minSize;
36198 if(typeof this.config.maxSize != "undefined"){
36199 this.split.maxSize = this.config.maxSize;
36201 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36202 this.hideSplitter();
36207 getHMaxSize : function(){
36208 var cmax = this.config.maxSize || 10000;
36209 var center = this.mgr.getRegion("center");
36210 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36213 getVMaxSize : function(){
36214 var cmax = this.config.maxSize || 10000;
36215 var center = this.mgr.getRegion("center");
36216 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36219 onSplitMove : function(split, newSize){
36220 this.fireEvent("resized", this, newSize);
36224 * Returns the {@link Roo.SplitBar} for this region.
36225 * @return {Roo.SplitBar}
36227 getSplitBar : function(){
36232 this.hideSplitter();
36233 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36236 hideSplitter : function(){
36238 this.split.el.setLocation(-2000,-2000);
36239 this.split.el.hide();
36245 this.split.el.show();
36247 Roo.bootstrap.layout.Split.superclass.show.call(this);
36250 beforeSlide: function(){
36251 if(Roo.isGecko){// firefox overflow auto bug workaround
36252 this.bodyEl.clip();
36254 this.tabs.bodyEl.clip();
36256 if(this.activePanel){
36257 this.activePanel.getEl().clip();
36259 if(this.activePanel.beforeSlide){
36260 this.activePanel.beforeSlide();
36266 afterSlide : function(){
36267 if(Roo.isGecko){// firefox overflow auto bug workaround
36268 this.bodyEl.unclip();
36270 this.tabs.bodyEl.unclip();
36272 if(this.activePanel){
36273 this.activePanel.getEl().unclip();
36274 if(this.activePanel.afterSlide){
36275 this.activePanel.afterSlide();
36281 initAutoHide : function(){
36282 if(this.autoHide !== false){
36283 if(!this.autoHideHd){
36284 var st = new Roo.util.DelayedTask(this.slideIn, this);
36285 this.autoHideHd = {
36286 "mouseout": function(e){
36287 if(!e.within(this.el, true)){
36291 "mouseover" : function(e){
36297 this.el.on(this.autoHideHd);
36301 clearAutoHide : function(){
36302 if(this.autoHide !== false){
36303 this.el.un("mouseout", this.autoHideHd.mouseout);
36304 this.el.un("mouseover", this.autoHideHd.mouseover);
36308 clearMonitor : function(){
36309 Roo.get(document).un("click", this.slideInIf, this);
36312 // these names are backwards but not changed for compat
36313 slideOut : function(){
36314 if(this.isSlid || this.el.hasActiveFx()){
36317 this.isSlid = true;
36318 if(this.collapseBtn){
36319 this.collapseBtn.hide();
36321 this.closeBtnState = this.closeBtn.getStyle('display');
36322 this.closeBtn.hide();
36324 this.stickBtn.show();
36327 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36328 this.beforeSlide();
36329 this.el.setStyle("z-index", 10001);
36330 this.el.slideIn(this.getSlideAnchor(), {
36331 callback: function(){
36333 this.initAutoHide();
36334 Roo.get(document).on("click", this.slideInIf, this);
36335 this.fireEvent("slideshow", this);
36342 afterSlideIn : function(){
36343 this.clearAutoHide();
36344 this.isSlid = false;
36345 this.clearMonitor();
36346 this.el.setStyle("z-index", "");
36347 if(this.collapseBtn){
36348 this.collapseBtn.show();
36350 this.closeBtn.setStyle('display', this.closeBtnState);
36352 this.stickBtn.hide();
36354 this.fireEvent("slidehide", this);
36357 slideIn : function(cb){
36358 if(!this.isSlid || this.el.hasActiveFx()){
36362 this.isSlid = false;
36363 this.beforeSlide();
36364 this.el.slideOut(this.getSlideAnchor(), {
36365 callback: function(){
36366 this.el.setLeftTop(-10000, -10000);
36368 this.afterSlideIn();
36376 slideInIf : function(e){
36377 if(!e.within(this.el)){
36382 animateCollapse : function(){
36383 this.beforeSlide();
36384 this.el.setStyle("z-index", 20000);
36385 var anchor = this.getSlideAnchor();
36386 this.el.slideOut(anchor, {
36387 callback : function(){
36388 this.el.setStyle("z-index", "");
36389 this.collapsedEl.slideIn(anchor, {duration:.3});
36391 this.el.setLocation(-10000,-10000);
36393 this.fireEvent("collapsed", this);
36400 animateExpand : function(){
36401 this.beforeSlide();
36402 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36403 this.el.setStyle("z-index", 20000);
36404 this.collapsedEl.hide({
36407 this.el.slideIn(this.getSlideAnchor(), {
36408 callback : function(){
36409 this.el.setStyle("z-index", "");
36412 this.split.el.show();
36414 this.fireEvent("invalidated", this);
36415 this.fireEvent("expanded", this);
36443 getAnchor : function(){
36444 return this.anchors[this.position];
36447 getCollapseAnchor : function(){
36448 return this.canchors[this.position];
36451 getSlideAnchor : function(){
36452 return this.sanchors[this.position];
36455 getAlignAdj : function(){
36456 var cm = this.cmargins;
36457 switch(this.position){
36473 getExpandAdj : function(){
36474 var c = this.collapsedEl, cm = this.cmargins;
36475 switch(this.position){
36477 return [-(cm.right+c.getWidth()+cm.left), 0];
36480 return [cm.right+c.getWidth()+cm.left, 0];
36483 return [0, -(cm.top+cm.bottom+c.getHeight())];
36486 return [0, cm.top+cm.bottom+c.getHeight()];
36492 * Ext JS Library 1.1.1
36493 * Copyright(c) 2006-2007, Ext JS, LLC.
36495 * Originally Released Under LGPL - original licence link has changed is not relivant.
36498 * <script type="text/javascript">
36501 * These classes are private internal classes
36503 Roo.bootstrap.layout.Center = function(config){
36504 config.region = "center";
36505 Roo.bootstrap.layout.Region.call(this, config);
36506 this.visible = true;
36507 this.minWidth = config.minWidth || 20;
36508 this.minHeight = config.minHeight || 20;
36511 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36513 // center panel can't be hidden
36517 // center panel can't be hidden
36520 getMinWidth: function(){
36521 return this.minWidth;
36524 getMinHeight: function(){
36525 return this.minHeight;
36538 Roo.bootstrap.layout.North = function(config)
36540 config.region = 'north';
36541 config.cursor = 'n-resize';
36543 Roo.bootstrap.layout.Split.call(this, config);
36547 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36548 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36549 this.split.el.addClass("roo-layout-split-v");
36551 var size = config.initialSize || config.height;
36552 if(typeof size != "undefined"){
36553 this.el.setHeight(size);
36556 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36558 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36562 getBox : function(){
36563 if(this.collapsed){
36564 return this.collapsedEl.getBox();
36566 var box = this.el.getBox();
36568 box.height += this.split.el.getHeight();
36573 updateBox : function(box){
36574 if(this.split && !this.collapsed){
36575 box.height -= this.split.el.getHeight();
36576 this.split.el.setLeft(box.x);
36577 this.split.el.setTop(box.y+box.height);
36578 this.split.el.setWidth(box.width);
36580 if(this.collapsed){
36581 this.updateBody(box.width, null);
36583 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36591 Roo.bootstrap.layout.South = function(config){
36592 config.region = 'south';
36593 config.cursor = 's-resize';
36594 Roo.bootstrap.layout.Split.call(this, config);
36596 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36597 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36598 this.split.el.addClass("roo-layout-split-v");
36600 var size = config.initialSize || config.height;
36601 if(typeof size != "undefined"){
36602 this.el.setHeight(size);
36606 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36607 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36608 getBox : function(){
36609 if(this.collapsed){
36610 return this.collapsedEl.getBox();
36612 var box = this.el.getBox();
36614 var sh = this.split.el.getHeight();
36621 updateBox : function(box){
36622 if(this.split && !this.collapsed){
36623 var sh = this.split.el.getHeight();
36626 this.split.el.setLeft(box.x);
36627 this.split.el.setTop(box.y-sh);
36628 this.split.el.setWidth(box.width);
36630 if(this.collapsed){
36631 this.updateBody(box.width, null);
36633 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36637 Roo.bootstrap.layout.East = function(config){
36638 config.region = "east";
36639 config.cursor = "e-resize";
36640 Roo.bootstrap.layout.Split.call(this, config);
36642 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36643 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36644 this.split.el.addClass("roo-layout-split-h");
36646 var size = config.initialSize || config.width;
36647 if(typeof size != "undefined"){
36648 this.el.setWidth(size);
36651 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36652 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36653 getBox : function(){
36654 if(this.collapsed){
36655 return this.collapsedEl.getBox();
36657 var box = this.el.getBox();
36659 var sw = this.split.el.getWidth();
36666 updateBox : function(box){
36667 if(this.split && !this.collapsed){
36668 var sw = this.split.el.getWidth();
36670 this.split.el.setLeft(box.x);
36671 this.split.el.setTop(box.y);
36672 this.split.el.setHeight(box.height);
36675 if(this.collapsed){
36676 this.updateBody(null, box.height);
36678 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36682 Roo.bootstrap.layout.West = function(config){
36683 config.region = "west";
36684 config.cursor = "w-resize";
36686 Roo.bootstrap.layout.Split.call(this, config);
36688 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36689 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36690 this.split.el.addClass("roo-layout-split-h");
36694 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36695 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36697 onRender: function(ctr, pos)
36699 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36700 var size = this.config.initialSize || this.config.width;
36701 if(typeof size != "undefined"){
36702 this.el.setWidth(size);
36706 getBox : function(){
36707 if(this.collapsed){
36708 return this.collapsedEl.getBox();
36710 var box = this.el.getBox();
36712 box.width += this.split.el.getWidth();
36717 updateBox : function(box){
36718 if(this.split && !this.collapsed){
36719 var sw = this.split.el.getWidth();
36721 this.split.el.setLeft(box.x+box.width);
36722 this.split.el.setTop(box.y);
36723 this.split.el.setHeight(box.height);
36725 if(this.collapsed){
36726 this.updateBody(null, box.height);
36728 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36731 Roo.namespace("Roo.bootstrap.panel");/*
36733 * Ext JS Library 1.1.1
36734 * Copyright(c) 2006-2007, Ext JS, LLC.
36736 * Originally Released Under LGPL - original licence link has changed is not relivant.
36739 * <script type="text/javascript">
36742 * @class Roo.ContentPanel
36743 * @extends Roo.util.Observable
36744 * A basic ContentPanel element.
36745 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36746 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36747 * @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
36748 * @cfg {Boolean} closable True if the panel can be closed/removed
36749 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36750 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36751 * @cfg {Toolbar} toolbar A toolbar for this panel
36752 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36753 * @cfg {String} title The title for this panel
36754 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36755 * @cfg {String} url Calls {@link #setUrl} with this value
36756 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36757 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36758 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36759 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36760 * @cfg {Boolean} badges render the badges
36763 * Create a new ContentPanel.
36764 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36765 * @param {String/Object} config A string to set only the title or a config object
36766 * @param {String} content (optional) Set the HTML content for this panel
36767 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36769 Roo.bootstrap.panel.Content = function( config){
36771 this.tpl = config.tpl || false;
36773 var el = config.el;
36774 var content = config.content;
36776 if(config.autoCreate){ // xtype is available if this is called from factory
36779 this.el = Roo.get(el);
36780 if(!this.el && config && config.autoCreate){
36781 if(typeof config.autoCreate == "object"){
36782 if(!config.autoCreate.id){
36783 config.autoCreate.id = config.id||el;
36785 this.el = Roo.DomHelper.append(document.body,
36786 config.autoCreate, true);
36788 var elcfg = { tag: "div",
36789 cls: "roo-layout-inactive-content",
36793 elcfg.html = config.html;
36797 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36800 this.closable = false;
36801 this.loaded = false;
36802 this.active = false;
36805 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36807 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36809 this.wrapEl = this.el; //this.el.wrap();
36811 if (config.toolbar.items) {
36812 ti = config.toolbar.items ;
36813 delete config.toolbar.items ;
36817 this.toolbar.render(this.wrapEl, 'before');
36818 for(var i =0;i < ti.length;i++) {
36819 // Roo.log(['add child', items[i]]);
36820 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36822 this.toolbar.items = nitems;
36823 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36824 delete config.toolbar;
36828 // xtype created footer. - not sure if will work as we normally have to render first..
36829 if (this.footer && !this.footer.el && this.footer.xtype) {
36830 if (!this.wrapEl) {
36831 this.wrapEl = this.el.wrap();
36834 this.footer.container = this.wrapEl.createChild();
36836 this.footer = Roo.factory(this.footer, Roo);
36841 if(typeof config == "string"){
36842 this.title = config;
36844 Roo.apply(this, config);
36848 this.resizeEl = Roo.get(this.resizeEl, true);
36850 this.resizeEl = this.el;
36852 // handle view.xtype
36860 * Fires when this panel is activated.
36861 * @param {Roo.ContentPanel} this
36865 * @event deactivate
36866 * Fires when this panel is activated.
36867 * @param {Roo.ContentPanel} this
36869 "deactivate" : true,
36873 * Fires when this panel is resized if fitToFrame is true.
36874 * @param {Roo.ContentPanel} this
36875 * @param {Number} width The width after any component adjustments
36876 * @param {Number} height The height after any component adjustments
36882 * Fires when this tab is created
36883 * @param {Roo.ContentPanel} this
36894 if(this.autoScroll){
36895 this.resizeEl.setStyle("overflow", "auto");
36897 // fix randome scrolling
36898 //this.el.on('scroll', function() {
36899 // Roo.log('fix random scolling');
36900 // this.scrollTo('top',0);
36903 content = content || this.content;
36905 this.setContent(content);
36907 if(config && config.url){
36908 this.setUrl(this.url, this.params, this.loadOnce);
36913 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36915 if (this.view && typeof(this.view.xtype) != 'undefined') {
36916 this.view.el = this.el.appendChild(document.createElement("div"));
36917 this.view = Roo.factory(this.view);
36918 this.view.render && this.view.render(false, '');
36922 this.fireEvent('render', this);
36925 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36929 setRegion : function(region){
36930 this.region = region;
36931 this.setActiveClass(region && !this.background);
36935 setActiveClass: function(state)
36938 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36939 this.el.setStyle('position','relative');
36941 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36942 this.el.setStyle('position', 'absolute');
36947 * Returns the toolbar for this Panel if one was configured.
36948 * @return {Roo.Toolbar}
36950 getToolbar : function(){
36951 return this.toolbar;
36954 setActiveState : function(active)
36956 this.active = active;
36957 this.setActiveClass(active);
36959 if(this.fireEvent("deactivate", this) === false){
36964 this.fireEvent("activate", this);
36968 * Updates this panel's element
36969 * @param {String} content The new content
36970 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36972 setContent : function(content, loadScripts){
36973 this.el.update(content, loadScripts);
36976 ignoreResize : function(w, h){
36977 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36980 this.lastSize = {width: w, height: h};
36985 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36986 * @return {Roo.UpdateManager} The UpdateManager
36988 getUpdateManager : function(){
36989 return this.el.getUpdateManager();
36992 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36993 * @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:
36996 url: "your-url.php",
36997 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36998 callback: yourFunction,
36999 scope: yourObject, //(optional scope)
37002 text: "Loading...",
37007 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37008 * 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.
37009 * @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}
37010 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37011 * @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.
37012 * @return {Roo.ContentPanel} this
37015 var um = this.el.getUpdateManager();
37016 um.update.apply(um, arguments);
37022 * 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.
37023 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37024 * @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)
37025 * @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)
37026 * @return {Roo.UpdateManager} The UpdateManager
37028 setUrl : function(url, params, loadOnce){
37029 if(this.refreshDelegate){
37030 this.removeListener("activate", this.refreshDelegate);
37032 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37033 this.on("activate", this.refreshDelegate);
37034 return this.el.getUpdateManager();
37037 _handleRefresh : function(url, params, loadOnce){
37038 if(!loadOnce || !this.loaded){
37039 var updater = this.el.getUpdateManager();
37040 updater.update(url, params, this._setLoaded.createDelegate(this));
37044 _setLoaded : function(){
37045 this.loaded = true;
37049 * Returns this panel's id
37052 getId : function(){
37057 * Returns this panel's element - used by regiosn to add.
37058 * @return {Roo.Element}
37060 getEl : function(){
37061 return this.wrapEl || this.el;
37066 adjustForComponents : function(width, height)
37068 //Roo.log('adjustForComponents ');
37069 if(this.resizeEl != this.el){
37070 width -= this.el.getFrameWidth('lr');
37071 height -= this.el.getFrameWidth('tb');
37074 var te = this.toolbar.getEl();
37075 te.setWidth(width);
37076 height -= te.getHeight();
37079 var te = this.footer.getEl();
37080 te.setWidth(width);
37081 height -= te.getHeight();
37085 if(this.adjustments){
37086 width += this.adjustments[0];
37087 height += this.adjustments[1];
37089 return {"width": width, "height": height};
37092 setSize : function(width, height){
37093 if(this.fitToFrame && !this.ignoreResize(width, height)){
37094 if(this.fitContainer && this.resizeEl != this.el){
37095 this.el.setSize(width, height);
37097 var size = this.adjustForComponents(width, height);
37098 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37099 this.fireEvent('resize', this, size.width, size.height);
37104 * Returns this panel's title
37107 getTitle : function(){
37109 if (typeof(this.title) != 'object') {
37114 for (var k in this.title) {
37115 if (!this.title.hasOwnProperty(k)) {
37119 if (k.indexOf('-') >= 0) {
37120 var s = k.split('-');
37121 for (var i = 0; i<s.length; i++) {
37122 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37125 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37132 * Set this panel's title
37133 * @param {String} title
37135 setTitle : function(title){
37136 this.title = title;
37138 this.region.updatePanelTitle(this, title);
37143 * Returns true is this panel was configured to be closable
37144 * @return {Boolean}
37146 isClosable : function(){
37147 return this.closable;
37150 beforeSlide : function(){
37152 this.resizeEl.clip();
37155 afterSlide : function(){
37157 this.resizeEl.unclip();
37161 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37162 * Will fail silently if the {@link #setUrl} method has not been called.
37163 * This does not activate the panel, just updates its content.
37165 refresh : function(){
37166 if(this.refreshDelegate){
37167 this.loaded = false;
37168 this.refreshDelegate();
37173 * Destroys this panel
37175 destroy : function(){
37176 this.el.removeAllListeners();
37177 var tempEl = document.createElement("span");
37178 tempEl.appendChild(this.el.dom);
37179 tempEl.innerHTML = "";
37185 * form - if the content panel contains a form - this is a reference to it.
37186 * @type {Roo.form.Form}
37190 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37191 * This contains a reference to it.
37197 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37207 * @param {Object} cfg Xtype definition of item to add.
37211 getChildContainer: function () {
37212 return this.getEl();
37217 var ret = new Roo.factory(cfg);
37222 if (cfg.xtype.match(/^Form$/)) {
37225 //if (this.footer) {
37226 // el = this.footer.container.insertSibling(false, 'before');
37228 el = this.el.createChild();
37231 this.form = new Roo.form.Form(cfg);
37234 if ( this.form.allItems.length) {
37235 this.form.render(el.dom);
37239 // should only have one of theses..
37240 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37241 // views.. should not be just added - used named prop 'view''
37243 cfg.el = this.el.appendChild(document.createElement("div"));
37246 var ret = new Roo.factory(cfg);
37248 ret.render && ret.render(false, ''); // render blank..
37258 * @class Roo.bootstrap.panel.Grid
37259 * @extends Roo.bootstrap.panel.Content
37261 * Create a new GridPanel.
37262 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37263 * @param {Object} config A the config object
37269 Roo.bootstrap.panel.Grid = function(config)
37273 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37274 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37276 config.el = this.wrapper;
37277 //this.el = this.wrapper;
37279 if (config.container) {
37280 // ctor'ed from a Border/panel.grid
37283 this.wrapper.setStyle("overflow", "hidden");
37284 this.wrapper.addClass('roo-grid-container');
37289 if(config.toolbar){
37290 var tool_el = this.wrapper.createChild();
37291 this.toolbar = Roo.factory(config.toolbar);
37293 if (config.toolbar.items) {
37294 ti = config.toolbar.items ;
37295 delete config.toolbar.items ;
37299 this.toolbar.render(tool_el);
37300 for(var i =0;i < ti.length;i++) {
37301 // Roo.log(['add child', items[i]]);
37302 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37304 this.toolbar.items = nitems;
37306 delete config.toolbar;
37309 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37310 config.grid.scrollBody = true;;
37311 config.grid.monitorWindowResize = false; // turn off autosizing
37312 config.grid.autoHeight = false;
37313 config.grid.autoWidth = false;
37315 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37317 if (config.background) {
37318 // render grid on panel activation (if panel background)
37319 this.on('activate', function(gp) {
37320 if (!gp.grid.rendered) {
37321 gp.grid.render(this.wrapper);
37322 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37327 this.grid.render(this.wrapper);
37328 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37331 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37332 // ??? needed ??? config.el = this.wrapper;
37337 // xtype created footer. - not sure if will work as we normally have to render first..
37338 if (this.footer && !this.footer.el && this.footer.xtype) {
37340 var ctr = this.grid.getView().getFooterPanel(true);
37341 this.footer.dataSource = this.grid.dataSource;
37342 this.footer = Roo.factory(this.footer, Roo);
37343 this.footer.render(ctr);
37353 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37354 getId : function(){
37355 return this.grid.id;
37359 * Returns the grid for this panel
37360 * @return {Roo.bootstrap.Table}
37362 getGrid : function(){
37366 setSize : function(width, height){
37367 if(!this.ignoreResize(width, height)){
37368 var grid = this.grid;
37369 var size = this.adjustForComponents(width, height);
37370 var gridel = grid.getGridEl();
37371 gridel.setSize(size.width, size.height);
37373 var thd = grid.getGridEl().select('thead',true).first();
37374 var tbd = grid.getGridEl().select('tbody', true).first();
37376 tbd.setSize(width, height - thd.getHeight());
37385 beforeSlide : function(){
37386 this.grid.getView().scroller.clip();
37389 afterSlide : function(){
37390 this.grid.getView().scroller.unclip();
37393 destroy : function(){
37394 this.grid.destroy();
37396 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37401 * @class Roo.bootstrap.panel.Nest
37402 * @extends Roo.bootstrap.panel.Content
37404 * Create a new Panel, that can contain a layout.Border.
37407 * @param {Roo.BorderLayout} layout The layout for this panel
37408 * @param {String/Object} config A string to set only the title or a config object
37410 Roo.bootstrap.panel.Nest = function(config)
37412 // construct with only one argument..
37413 /* FIXME - implement nicer consturctors
37414 if (layout.layout) {
37416 layout = config.layout;
37417 delete config.layout;
37419 if (layout.xtype && !layout.getEl) {
37420 // then layout needs constructing..
37421 layout = Roo.factory(layout, Roo);
37425 config.el = config.layout.getEl();
37427 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37429 config.layout.monitorWindowResize = false; // turn off autosizing
37430 this.layout = config.layout;
37431 this.layout.getEl().addClass("roo-layout-nested-layout");
37438 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37440 setSize : function(width, height){
37441 if(!this.ignoreResize(width, height)){
37442 var size = this.adjustForComponents(width, height);
37443 var el = this.layout.getEl();
37444 if (size.height < 1) {
37445 el.setWidth(size.width);
37447 el.setSize(size.width, size.height);
37449 var touch = el.dom.offsetWidth;
37450 this.layout.layout();
37451 // ie requires a double layout on the first pass
37452 if(Roo.isIE && !this.initialized){
37453 this.initialized = true;
37454 this.layout.layout();
37459 // activate all subpanels if not currently active..
37461 setActiveState : function(active){
37462 this.active = active;
37463 this.setActiveClass(active);
37466 this.fireEvent("deactivate", this);
37470 this.fireEvent("activate", this);
37471 // not sure if this should happen before or after..
37472 if (!this.layout) {
37473 return; // should not happen..
37476 for (var r in this.layout.regions) {
37477 reg = this.layout.getRegion(r);
37478 if (reg.getActivePanel()) {
37479 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37480 reg.setActivePanel(reg.getActivePanel());
37483 if (!reg.panels.length) {
37486 reg.showPanel(reg.getPanel(0));
37495 * Returns the nested BorderLayout for this panel
37496 * @return {Roo.BorderLayout}
37498 getLayout : function(){
37499 return this.layout;
37503 * Adds a xtype elements to the layout of the nested panel
37507 xtype : 'ContentPanel',
37514 xtype : 'NestedLayoutPanel',
37520 items : [ ... list of content panels or nested layout panels.. ]
37524 * @param {Object} cfg Xtype definition of item to add.
37526 addxtype : function(cfg) {
37527 return this.layout.addxtype(cfg);
37532 * Ext JS Library 1.1.1
37533 * Copyright(c) 2006-2007, Ext JS, LLC.
37535 * Originally Released Under LGPL - original licence link has changed is not relivant.
37538 * <script type="text/javascript">
37541 * @class Roo.TabPanel
37542 * @extends Roo.util.Observable
37543 * A lightweight tab container.
37547 // basic tabs 1, built from existing content
37548 var tabs = new Roo.TabPanel("tabs1");
37549 tabs.addTab("script", "View Script");
37550 tabs.addTab("markup", "View Markup");
37551 tabs.activate("script");
37553 // more advanced tabs, built from javascript
37554 var jtabs = new Roo.TabPanel("jtabs");
37555 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37557 // set up the UpdateManager
37558 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37559 var updater = tab2.getUpdateManager();
37560 updater.setDefaultUrl("ajax1.htm");
37561 tab2.on('activate', updater.refresh, updater, true);
37563 // Use setUrl for Ajax loading
37564 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37565 tab3.setUrl("ajax2.htm", null, true);
37568 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37571 jtabs.activate("jtabs-1");
37574 * Create a new TabPanel.
37575 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37576 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37578 Roo.bootstrap.panel.Tabs = function(config){
37580 * The container element for this TabPanel.
37581 * @type Roo.Element
37583 this.el = Roo.get(config.el);
37586 if(typeof config == "boolean"){
37587 this.tabPosition = config ? "bottom" : "top";
37589 Roo.apply(this, config);
37593 if(this.tabPosition == "bottom"){
37594 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37595 this.el.addClass("roo-tabs-bottom");
37597 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37598 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37599 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37601 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37603 if(this.tabPosition != "bottom"){
37604 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37605 * @type Roo.Element
37607 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37608 this.el.addClass("roo-tabs-top");
37612 this.bodyEl.setStyle("position", "relative");
37614 this.active = null;
37615 this.activateDelegate = this.activate.createDelegate(this);
37620 * Fires when the active tab changes
37621 * @param {Roo.TabPanel} this
37622 * @param {Roo.TabPanelItem} activePanel The new active tab
37626 * @event beforetabchange
37627 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37628 * @param {Roo.TabPanel} this
37629 * @param {Object} e Set cancel to true on this object to cancel the tab change
37630 * @param {Roo.TabPanelItem} tab The tab being changed to
37632 "beforetabchange" : true
37635 Roo.EventManager.onWindowResize(this.onResize, this);
37636 this.cpad = this.el.getPadding("lr");
37637 this.hiddenCount = 0;
37640 // toolbar on the tabbar support...
37641 if (this.toolbar) {
37642 alert("no toolbar support yet");
37643 this.toolbar = false;
37645 var tcfg = this.toolbar;
37646 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37647 this.toolbar = new Roo.Toolbar(tcfg);
37648 if (Roo.isSafari) {
37649 var tbl = tcfg.container.child('table', true);
37650 tbl.setAttribute('width', '100%');
37658 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37661 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37663 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37665 tabPosition : "top",
37667 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37669 currentTabWidth : 0,
37671 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37675 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37679 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37681 preferredTabWidth : 175,
37683 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37685 resizeTabs : false,
37687 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37689 monitorResize : true,
37691 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37696 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37697 * @param {String} id The id of the div to use <b>or create</b>
37698 * @param {String} text The text for the tab
37699 * @param {String} content (optional) Content to put in the TabPanelItem body
37700 * @param {Boolean} closable (optional) True to create a close icon on the tab
37701 * @return {Roo.TabPanelItem} The created TabPanelItem
37703 addTab : function(id, text, content, closable, tpl)
37705 var item = new Roo.bootstrap.panel.TabItem({
37709 closable : closable,
37712 this.addTabItem(item);
37714 item.setContent(content);
37720 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37721 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37722 * @return {Roo.TabPanelItem}
37724 getTab : function(id){
37725 return this.items[id];
37729 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37730 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37732 hideTab : function(id){
37733 var t = this.items[id];
37736 this.hiddenCount++;
37737 this.autoSizeTabs();
37742 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37743 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37745 unhideTab : function(id){
37746 var t = this.items[id];
37748 t.setHidden(false);
37749 this.hiddenCount--;
37750 this.autoSizeTabs();
37755 * Adds an existing {@link Roo.TabPanelItem}.
37756 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37758 addTabItem : function(item){
37759 this.items[item.id] = item;
37760 this.items.push(item);
37761 // if(this.resizeTabs){
37762 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37763 // this.autoSizeTabs();
37765 // item.autoSize();
37770 * Removes a {@link Roo.TabPanelItem}.
37771 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37773 removeTab : function(id){
37774 var items = this.items;
37775 var tab = items[id];
37776 if(!tab) { return; }
37777 var index = items.indexOf(tab);
37778 if(this.active == tab && items.length > 1){
37779 var newTab = this.getNextAvailable(index);
37784 this.stripEl.dom.removeChild(tab.pnode.dom);
37785 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37786 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37788 items.splice(index, 1);
37789 delete this.items[tab.id];
37790 tab.fireEvent("close", tab);
37791 tab.purgeListeners();
37792 this.autoSizeTabs();
37795 getNextAvailable : function(start){
37796 var items = this.items;
37798 // look for a next tab that will slide over to
37799 // replace the one being removed
37800 while(index < items.length){
37801 var item = items[++index];
37802 if(item && !item.isHidden()){
37806 // if one isn't found select the previous tab (on the left)
37809 var item = items[--index];
37810 if(item && !item.isHidden()){
37818 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37819 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37821 disableTab : function(id){
37822 var tab = this.items[id];
37823 if(tab && this.active != tab){
37829 * Enables a {@link Roo.TabPanelItem} that is disabled.
37830 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37832 enableTab : function(id){
37833 var tab = this.items[id];
37838 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37839 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37840 * @return {Roo.TabPanelItem} The TabPanelItem.
37842 activate : function(id){
37843 var tab = this.items[id];
37847 if(tab == this.active || tab.disabled){
37851 this.fireEvent("beforetabchange", this, e, tab);
37852 if(e.cancel !== true && !tab.disabled){
37854 this.active.hide();
37856 this.active = this.items[id];
37857 this.active.show();
37858 this.fireEvent("tabchange", this, this.active);
37864 * Gets the active {@link Roo.TabPanelItem}.
37865 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37867 getActiveTab : function(){
37868 return this.active;
37872 * Updates the tab body element to fit the height of the container element
37873 * for overflow scrolling
37874 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37876 syncHeight : function(targetHeight){
37877 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37878 var bm = this.bodyEl.getMargins();
37879 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37880 this.bodyEl.setHeight(newHeight);
37884 onResize : function(){
37885 if(this.monitorResize){
37886 this.autoSizeTabs();
37891 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37893 beginUpdate : function(){
37894 this.updating = true;
37898 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37900 endUpdate : function(){
37901 this.updating = false;
37902 this.autoSizeTabs();
37906 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37908 autoSizeTabs : function(){
37909 var count = this.items.length;
37910 var vcount = count - this.hiddenCount;
37911 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37914 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37915 var availWidth = Math.floor(w / vcount);
37916 var b = this.stripBody;
37917 if(b.getWidth() > w){
37918 var tabs = this.items;
37919 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37920 if(availWidth < this.minTabWidth){
37921 /*if(!this.sleft){ // incomplete scrolling code
37922 this.createScrollButtons();
37925 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37928 if(this.currentTabWidth < this.preferredTabWidth){
37929 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37935 * Returns the number of tabs in this TabPanel.
37938 getCount : function(){
37939 return this.items.length;
37943 * Resizes all the tabs to the passed width
37944 * @param {Number} The new width
37946 setTabWidth : function(width){
37947 this.currentTabWidth = width;
37948 for(var i = 0, len = this.items.length; i < len; i++) {
37949 if(!this.items[i].isHidden()) {
37950 this.items[i].setWidth(width);
37956 * Destroys this TabPanel
37957 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37959 destroy : function(removeEl){
37960 Roo.EventManager.removeResizeListener(this.onResize, this);
37961 for(var i = 0, len = this.items.length; i < len; i++){
37962 this.items[i].purgeListeners();
37964 if(removeEl === true){
37965 this.el.update("");
37970 createStrip : function(container)
37972 var strip = document.createElement("nav");
37973 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37974 container.appendChild(strip);
37978 createStripList : function(strip)
37980 // div wrapper for retard IE
37981 // returns the "tr" element.
37982 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37983 //'<div class="x-tabs-strip-wrap">'+
37984 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37985 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37986 return strip.firstChild; //.firstChild.firstChild.firstChild;
37988 createBody : function(container)
37990 var body = document.createElement("div");
37991 Roo.id(body, "tab-body");
37992 //Roo.fly(body).addClass("x-tabs-body");
37993 Roo.fly(body).addClass("tab-content");
37994 container.appendChild(body);
37997 createItemBody :function(bodyEl, id){
37998 var body = Roo.getDom(id);
38000 body = document.createElement("div");
38003 //Roo.fly(body).addClass("x-tabs-item-body");
38004 Roo.fly(body).addClass("tab-pane");
38005 bodyEl.insertBefore(body, bodyEl.firstChild);
38009 createStripElements : function(stripEl, text, closable, tpl)
38011 var td = document.createElement("li"); // was td..
38014 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38017 stripEl.appendChild(td);
38019 td.className = "x-tabs-closable";
38020 if(!this.closeTpl){
38021 this.closeTpl = new Roo.Template(
38022 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38023 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38024 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38027 var el = this.closeTpl.overwrite(td, {"text": text});
38028 var close = el.getElementsByTagName("div")[0];
38029 var inner = el.getElementsByTagName("em")[0];
38030 return {"el": el, "close": close, "inner": inner};
38033 // not sure what this is..
38034 // if(!this.tabTpl){
38035 //this.tabTpl = new Roo.Template(
38036 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38037 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38039 // this.tabTpl = new Roo.Template(
38040 // '<a href="#">' +
38041 // '<span unselectable="on"' +
38042 // (this.disableTooltips ? '' : ' title="{text}"') +
38043 // ' >{text}</span></a>'
38049 var template = tpl || this.tabTpl || false;
38053 template = new Roo.Template(
38055 '<span unselectable="on"' +
38056 (this.disableTooltips ? '' : ' title="{text}"') +
38057 ' >{text}</span></a>'
38061 switch (typeof(template)) {
38065 template = new Roo.Template(template);
38071 var el = template.overwrite(td, {"text": text});
38073 var inner = el.getElementsByTagName("span")[0];
38075 return {"el": el, "inner": inner};
38083 * @class Roo.TabPanelItem
38084 * @extends Roo.util.Observable
38085 * Represents an individual item (tab plus body) in a TabPanel.
38086 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38087 * @param {String} id The id of this TabPanelItem
38088 * @param {String} text The text for the tab of this TabPanelItem
38089 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38091 Roo.bootstrap.panel.TabItem = function(config){
38093 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38094 * @type Roo.TabPanel
38096 this.tabPanel = config.panel;
38098 * The id for this TabPanelItem
38101 this.id = config.id;
38103 this.disabled = false;
38105 this.text = config.text;
38107 this.loaded = false;
38108 this.closable = config.closable;
38111 * The body element for this TabPanelItem.
38112 * @type Roo.Element
38114 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38115 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38116 this.bodyEl.setStyle("display", "block");
38117 this.bodyEl.setStyle("zoom", "1");
38118 //this.hideAction();
38120 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38122 this.el = Roo.get(els.el);
38123 this.inner = Roo.get(els.inner, true);
38124 this.textEl = Roo.get(this.el.dom.firstChild, true);
38125 this.pnode = Roo.get(els.el.parentNode, true);
38126 // this.el.on("mousedown", this.onTabMouseDown, this);
38127 this.el.on("click", this.onTabClick, this);
38129 if(config.closable){
38130 var c = Roo.get(els.close, true);
38131 c.dom.title = this.closeText;
38132 c.addClassOnOver("close-over");
38133 c.on("click", this.closeClick, this);
38139 * Fires when this tab becomes the active tab.
38140 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38141 * @param {Roo.TabPanelItem} this
38145 * @event beforeclose
38146 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38147 * @param {Roo.TabPanelItem} this
38148 * @param {Object} e Set cancel to true on this object to cancel the close.
38150 "beforeclose": true,
38153 * Fires when this tab is closed.
38154 * @param {Roo.TabPanelItem} this
38158 * @event deactivate
38159 * Fires when this tab is no longer the active tab.
38160 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38161 * @param {Roo.TabPanelItem} this
38163 "deactivate" : true
38165 this.hidden = false;
38167 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38170 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38172 purgeListeners : function(){
38173 Roo.util.Observable.prototype.purgeListeners.call(this);
38174 this.el.removeAllListeners();
38177 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38180 this.pnode.addClass("active");
38183 this.tabPanel.stripWrap.repaint();
38185 this.fireEvent("activate", this.tabPanel, this);
38189 * Returns true if this tab is the active tab.
38190 * @return {Boolean}
38192 isActive : function(){
38193 return this.tabPanel.getActiveTab() == this;
38197 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38200 this.pnode.removeClass("active");
38202 this.fireEvent("deactivate", this.tabPanel, this);
38205 hideAction : function(){
38206 this.bodyEl.hide();
38207 this.bodyEl.setStyle("position", "absolute");
38208 this.bodyEl.setLeft("-20000px");
38209 this.bodyEl.setTop("-20000px");
38212 showAction : function(){
38213 this.bodyEl.setStyle("position", "relative");
38214 this.bodyEl.setTop("");
38215 this.bodyEl.setLeft("");
38216 this.bodyEl.show();
38220 * Set the tooltip for the tab.
38221 * @param {String} tooltip The tab's tooltip
38223 setTooltip : function(text){
38224 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38225 this.textEl.dom.qtip = text;
38226 this.textEl.dom.removeAttribute('title');
38228 this.textEl.dom.title = text;
38232 onTabClick : function(e){
38233 e.preventDefault();
38234 this.tabPanel.activate(this.id);
38237 onTabMouseDown : function(e){
38238 e.preventDefault();
38239 this.tabPanel.activate(this.id);
38242 getWidth : function(){
38243 return this.inner.getWidth();
38246 setWidth : function(width){
38247 var iwidth = width - this.pnode.getPadding("lr");
38248 this.inner.setWidth(iwidth);
38249 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38250 this.pnode.setWidth(width);
38254 * Show or hide the tab
38255 * @param {Boolean} hidden True to hide or false to show.
38257 setHidden : function(hidden){
38258 this.hidden = hidden;
38259 this.pnode.setStyle("display", hidden ? "none" : "");
38263 * Returns true if this tab is "hidden"
38264 * @return {Boolean}
38266 isHidden : function(){
38267 return this.hidden;
38271 * Returns the text for this tab
38274 getText : function(){
38278 autoSize : function(){
38279 //this.el.beginMeasure();
38280 this.textEl.setWidth(1);
38282 * #2804 [new] Tabs in Roojs
38283 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38285 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38286 //this.el.endMeasure();
38290 * Sets the text for the tab (Note: this also sets the tooltip text)
38291 * @param {String} text The tab's text and tooltip
38293 setText : function(text){
38295 this.textEl.update(text);
38296 this.setTooltip(text);
38297 //if(!this.tabPanel.resizeTabs){
38298 // this.autoSize();
38302 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38304 activate : function(){
38305 this.tabPanel.activate(this.id);
38309 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38311 disable : function(){
38312 if(this.tabPanel.active != this){
38313 this.disabled = true;
38314 this.pnode.addClass("disabled");
38319 * Enables this TabPanelItem if it was previously disabled.
38321 enable : function(){
38322 this.disabled = false;
38323 this.pnode.removeClass("disabled");
38327 * Sets the content for this TabPanelItem.
38328 * @param {String} content The content
38329 * @param {Boolean} loadScripts true to look for and load scripts
38331 setContent : function(content, loadScripts){
38332 this.bodyEl.update(content, loadScripts);
38336 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38337 * @return {Roo.UpdateManager} The UpdateManager
38339 getUpdateManager : function(){
38340 return this.bodyEl.getUpdateManager();
38344 * Set a URL to be used to load the content for this TabPanelItem.
38345 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38346 * @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)
38347 * @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)
38348 * @return {Roo.UpdateManager} The UpdateManager
38350 setUrl : function(url, params, loadOnce){
38351 if(this.refreshDelegate){
38352 this.un('activate', this.refreshDelegate);
38354 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38355 this.on("activate", this.refreshDelegate);
38356 return this.bodyEl.getUpdateManager();
38360 _handleRefresh : function(url, params, loadOnce){
38361 if(!loadOnce || !this.loaded){
38362 var updater = this.bodyEl.getUpdateManager();
38363 updater.update(url, params, this._setLoaded.createDelegate(this));
38368 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38369 * Will fail silently if the setUrl method has not been called.
38370 * This does not activate the panel, just updates its content.
38372 refresh : function(){
38373 if(this.refreshDelegate){
38374 this.loaded = false;
38375 this.refreshDelegate();
38380 _setLoaded : function(){
38381 this.loaded = true;
38385 closeClick : function(e){
38388 this.fireEvent("beforeclose", this, o);
38389 if(o.cancel !== true){
38390 this.tabPanel.removeTab(this.id);
38394 * The text displayed in the tooltip for the close icon.
38397 closeText : "Close this tab"
38400 * This script refer to:
38401 * Title: International Telephone Input
38402 * Author: Jack O'Connor
38403 * Code version: v12.1.12
38404 * Availability: https://github.com/jackocnr/intl-tel-input.git
38407 Roo.bootstrap.PhoneInputData = function() {
38410 "Afghanistan (افغانستان)",
38415 "Albania (Shqipëri)",
38420 "Algeria (الجزائر)",
38445 "Antigua and Barbuda",
38455 "Armenia (Հայաստան)",
38471 "Austria (Österreich)",
38476 "Azerbaijan (Azərbaycan)",
38486 "Bahrain (البحرين)",
38491 "Bangladesh (বাংলাদেশ)",
38501 "Belarus (Беларусь)",
38506 "Belgium (België)",
38536 "Bosnia and Herzegovina (Босна и Херцеговина)",
38551 "British Indian Ocean Territory",
38556 "British Virgin Islands",
38566 "Bulgaria (България)",
38576 "Burundi (Uburundi)",
38581 "Cambodia (កម្ពុជា)",
38586 "Cameroon (Cameroun)",
38595 ["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"]
38598 "Cape Verde (Kabu Verdi)",
38603 "Caribbean Netherlands",
38614 "Central African Republic (République centrafricaine)",
38634 "Christmas Island",
38640 "Cocos (Keeling) Islands",
38651 "Comoros (جزر القمر)",
38656 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38661 "Congo (Republic) (Congo-Brazzaville)",
38681 "Croatia (Hrvatska)",
38702 "Czech Republic (Česká republika)",
38707 "Denmark (Danmark)",
38722 "Dominican Republic (República Dominicana)",
38726 ["809", "829", "849"]
38744 "Equatorial Guinea (Guinea Ecuatorial)",
38764 "Falkland Islands (Islas Malvinas)",
38769 "Faroe Islands (Føroyar)",
38790 "French Guiana (Guyane française)",
38795 "French Polynesia (Polynésie française)",
38810 "Georgia (საქართველო)",
38815 "Germany (Deutschland)",
38835 "Greenland (Kalaallit Nunaat)",
38872 "Guinea-Bissau (Guiné Bissau)",
38897 "Hungary (Magyarország)",
38902 "Iceland (Ísland)",
38922 "Iraq (العراق)",
38938 "Israel (ישראל)",
38965 "Jordan (الأردن)",
38970 "Kazakhstan (Казахстан)",
38991 "Kuwait (الكويت)",
38996 "Kyrgyzstan (Кыргызстан)",
39006 "Latvia (Latvija)",
39011 "Lebanon (لبنان)",
39026 "Libya (ليبيا)",
39036 "Lithuania (Lietuva)",
39051 "Macedonia (FYROM) (Македонија)",
39056 "Madagascar (Madagasikara)",
39086 "Marshall Islands",
39096 "Mauritania (موريتانيا)",
39101 "Mauritius (Moris)",
39122 "Moldova (Republica Moldova)",
39132 "Mongolia (Монгол)",
39137 "Montenegro (Crna Gora)",
39147 "Morocco (المغرب)",
39153 "Mozambique (Moçambique)",
39158 "Myanmar (Burma) (မြန်မာ)",
39163 "Namibia (Namibië)",
39178 "Netherlands (Nederland)",
39183 "New Caledonia (Nouvelle-Calédonie)",
39218 "North Korea (조선 민주주의 인민 공화국)",
39223 "Northern Mariana Islands",
39239 "Pakistan (پاکستان)",
39249 "Palestine (فلسطين)",
39259 "Papua New Guinea",
39301 "Réunion (La Réunion)",
39307 "Romania (România)",
39323 "Saint Barthélemy",
39334 "Saint Kitts and Nevis",
39344 "Saint Martin (Saint-Martin (partie française))",
39350 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39355 "Saint Vincent and the Grenadines",
39370 "São Tomé and Príncipe (São Tomé e Príncipe)",
39375 "Saudi Arabia (المملكة العربية السعودية)",
39380 "Senegal (Sénégal)",
39410 "Slovakia (Slovensko)",
39415 "Slovenia (Slovenija)",
39425 "Somalia (Soomaaliya)",
39435 "South Korea (대한민국)",
39440 "South Sudan (جنوب السودان)",
39450 "Sri Lanka (ශ්රී ලංකාව)",
39455 "Sudan (السودان)",
39465 "Svalbard and Jan Mayen",
39476 "Sweden (Sverige)",
39481 "Switzerland (Schweiz)",
39486 "Syria (سوريا)",
39531 "Trinidad and Tobago",
39536 "Tunisia (تونس)",
39541 "Turkey (Türkiye)",
39551 "Turks and Caicos Islands",
39561 "U.S. Virgin Islands",
39571 "Ukraine (Україна)",
39576 "United Arab Emirates (الإمارات العربية المتحدة)",
39598 "Uzbekistan (Oʻzbekiston)",
39608 "Vatican City (Città del Vaticano)",
39619 "Vietnam (Việt Nam)",
39624 "Wallis and Futuna (Wallis-et-Futuna)",
39629 "Western Sahara (الصحراء الغربية)",
39635 "Yemen (اليمن)",
39659 * This script refer to:
39660 * Title: International Telephone Input
39661 * Author: Jack O'Connor
39662 * Code version: v12.1.12
39663 * Availability: https://github.com/jackocnr/intl-tel-input.git
39667 * @class Roo.bootstrap.PhoneInput
39668 * @extends Roo.bootstrap.TriggerField
39669 * An input with International dial-code selection
39671 * @cfg {String} defaultDialCode default '+852'
39672 * @cfg {Array} preferedCountries default []
39675 * Create a new PhoneInput.
39676 * @param {Object} config Configuration options
39679 Roo.bootstrap.PhoneInput = function(config) {
39680 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39683 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39685 listWidth: undefined,
39687 selectedClass: 'active',
39689 invalidClass : "has-warning",
39691 validClass: 'has-success',
39693 allowed: '0123456789',
39696 * @cfg {String} defaultDialCode The default dial code when initializing the input
39698 defaultDialCode: '+852',
39701 * @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
39703 preferedCountries: false,
39705 getAutoCreate : function()
39707 var data = Roo.bootstrap.PhoneInputData();
39708 var align = this.labelAlign || this.parentLabelAlign();
39711 this.allCountries = [];
39712 this.dialCodeMapping = [];
39714 for (var i = 0; i < data.length; i++) {
39716 this.allCountries[i] = {
39720 priority: c[3] || 0,
39721 areaCodes: c[4] || null
39723 this.dialCodeMapping[c[2]] = {
39726 priority: c[3] || 0,
39727 areaCodes: c[4] || null
39739 cls : 'form-control tel-input',
39740 autocomplete: 'new-password'
39743 var hiddenInput = {
39746 cls: 'hidden-tel-input'
39750 hiddenInput.name = this.name;
39753 if (this.disabled) {
39754 input.disabled = true;
39757 var flag_container = {
39774 cls: this.hasFeedback ? 'has-feedback' : '',
39780 cls: 'dial-code-holder',
39787 cls: 'roo-select2-container input-group',
39794 if (this.fieldLabel.length) {
39797 tooltip: 'This field is required'
39803 cls: 'control-label',
39809 html: this.fieldLabel
39812 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39818 if(this.indicatorpos == 'right') {
39819 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39826 if(align == 'left') {
39834 if(this.labelWidth > 12){
39835 label.style = "width: " + this.labelWidth + 'px';
39837 if(this.labelWidth < 13 && this.labelmd == 0){
39838 this.labelmd = this.labelWidth;
39840 if(this.labellg > 0){
39841 label.cls += ' col-lg-' + this.labellg;
39842 input.cls += ' col-lg-' + (12 - this.labellg);
39844 if(this.labelmd > 0){
39845 label.cls += ' col-md-' + this.labelmd;
39846 container.cls += ' col-md-' + (12 - this.labelmd);
39848 if(this.labelsm > 0){
39849 label.cls += ' col-sm-' + this.labelsm;
39850 container.cls += ' col-sm-' + (12 - this.labelsm);
39852 if(this.labelxs > 0){
39853 label.cls += ' col-xs-' + this.labelxs;
39854 container.cls += ' col-xs-' + (12 - this.labelxs);
39864 var settings = this;
39866 ['xs','sm','md','lg'].map(function(size){
39867 if (settings[size]) {
39868 cfg.cls += ' col-' + size + '-' + settings[size];
39872 this.store = new Roo.data.Store({
39873 proxy : new Roo.data.MemoryProxy({}),
39874 reader : new Roo.data.JsonReader({
39885 'name' : 'dialCode',
39889 'name' : 'priority',
39893 'name' : 'areaCodes',
39900 if(!this.preferedCountries) {
39901 this.preferedCountries = [
39908 var p = this.preferedCountries.reverse();
39911 for (var i = 0; i < p.length; i++) {
39912 for (var j = 0; j < this.allCountries.length; j++) {
39913 if(this.allCountries[j].iso2 == p[i]) {
39914 var t = this.allCountries[j];
39915 this.allCountries.splice(j,1);
39916 this.allCountries.unshift(t);
39922 this.store.proxy.data = {
39924 data: this.allCountries
39930 initEvents : function()
39933 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39935 this.indicator = this.indicatorEl();
39936 this.flag = this.flagEl();
39937 this.dialCodeHolder = this.dialCodeHolderEl();
39939 this.trigger = this.el.select('div.flag-box',true).first();
39940 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39945 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39946 _this.list.setWidth(lw);
39949 this.list.on('mouseover', this.onViewOver, this);
39950 this.list.on('mousemove', this.onViewMove, this);
39951 this.inputEl().on("keyup", this.onKeyUp, this);
39953 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39955 this.view = new Roo.View(this.list, this.tpl, {
39956 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39959 this.view.on('click', this.onViewClick, this);
39960 this.setValue(this.defaultDialCode);
39963 onTriggerClick : function(e)
39965 Roo.log('trigger click');
39970 if(this.isExpanded()){
39972 this.hasFocus = false;
39974 this.store.load({});
39975 this.hasFocus = true;
39980 isExpanded : function()
39982 return this.list.isVisible();
39985 collapse : function()
39987 if(!this.isExpanded()){
39991 Roo.get(document).un('mousedown', this.collapseIf, this);
39992 Roo.get(document).un('mousewheel', this.collapseIf, this);
39993 this.fireEvent('collapse', this);
39997 expand : function()
40001 if(this.isExpanded() || !this.hasFocus){
40005 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40006 this.list.setWidth(lw);
40009 this.restrictHeight();
40011 Roo.get(document).on('mousedown', this.collapseIf, this);
40012 Roo.get(document).on('mousewheel', this.collapseIf, this);
40014 this.fireEvent('expand', this);
40017 restrictHeight : function()
40019 this.list.alignTo(this.inputEl(), this.listAlign);
40020 this.list.alignTo(this.inputEl(), this.listAlign);
40023 onViewOver : function(e, t)
40025 if(this.inKeyMode){
40028 var item = this.view.findItemFromChild(t);
40031 var index = this.view.indexOf(item);
40032 this.select(index, false);
40037 onViewClick : function(view, doFocus, el, e)
40039 var index = this.view.getSelectedIndexes()[0];
40041 var r = this.store.getAt(index);
40044 this.onSelect(r, index);
40046 if(doFocus !== false && !this.blockFocus){
40047 this.inputEl().focus();
40051 onViewMove : function(e, t)
40053 this.inKeyMode = false;
40056 select : function(index, scrollIntoView)
40058 this.selectedIndex = index;
40059 this.view.select(index);
40060 if(scrollIntoView !== false){
40061 var el = this.view.getNode(index);
40063 this.list.scrollChildIntoView(el, false);
40068 createList : function()
40070 this.list = Roo.get(document.body).createChild({
40072 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40073 style: 'display:none'
40076 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40079 collapseIf : function(e)
40081 var in_combo = e.within(this.el);
40082 var in_list = e.within(this.list);
40083 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40085 if (in_combo || in_list || is_list) {
40091 onSelect : function(record, index)
40093 if(this.fireEvent('beforeselect', this, record, index) !== false){
40095 this.setFlagClass(record.data.iso2);
40096 this.setDialCode(record.data.dialCode);
40097 this.hasFocus = false;
40099 this.fireEvent('select', this, record, index);
40103 flagEl : function()
40105 var flag = this.el.select('div.flag',true).first();
40112 dialCodeHolderEl : function()
40114 var d = this.el.select('input.dial-code-holder',true).first();
40121 setDialCode : function(v)
40123 this.dialCodeHolder.dom.value = '+'+v;
40126 setFlagClass : function(n)
40128 this.flag.dom.className = 'flag '+n;
40131 getValue : function()
40133 var v = this.inputEl().getValue();
40134 if(this.dialCodeHolder) {
40135 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40140 setValue : function(v)
40142 var d = this.getDialCode(v);
40144 //invalid dial code
40145 if(v.length == 0 || !d || d.length == 0) {
40147 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40148 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40154 this.setFlagClass(this.dialCodeMapping[d].iso2);
40155 this.setDialCode(d);
40156 this.inputEl().dom.value = v.replace('+'+d,'');
40157 this.hiddenEl().dom.value = this.getValue();
40162 getDialCode : function(v)
40166 if (v.length == 0) {
40167 return this.dialCodeHolder.dom.value;
40171 if (v.charAt(0) != "+") {
40174 var numericChars = "";
40175 for (var i = 1; i < v.length; i++) {
40176 var c = v.charAt(i);
40179 if (this.dialCodeMapping[numericChars]) {
40180 dialCode = v.substr(1, i);
40182 if (numericChars.length == 4) {
40192 this.setValue(this.defaultDialCode);
40196 hiddenEl : function()
40198 return this.el.select('input.hidden-tel-input',true).first();
40201 onKeyUp : function(e){
40203 var k = e.getKey();
40204 var c = e.getCharCode();
40207 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40208 this.allowed.indexOf(String.fromCharCode(c)) === -1
40213 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40216 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40220 this.setValue(this.getValue());
40225 * @class Roo.bootstrap.MoneyField
40226 * @extends Roo.bootstrap.ComboBox
40227 * Bootstrap MoneyField class
40230 * Create a new MoneyField.
40231 * @param {Object} config Configuration options
40234 Roo.bootstrap.MoneyField = function(config) {
40236 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40240 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40243 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40245 allowDecimals : true,
40247 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40249 decimalSeparator : ".",
40251 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40253 decimalPrecision : 0,
40255 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40257 allowNegative : true,
40259 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40263 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40265 minValue : Number.NEGATIVE_INFINITY,
40267 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40269 maxValue : Number.MAX_VALUE,
40271 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40273 minText : "The minimum value for this field is {0}",
40275 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40277 maxText : "The maximum value for this field is {0}",
40279 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40280 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40282 nanText : "{0} is not a valid number",
40284 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40288 * @cfg {String} defaults currency of the MoneyField
40289 * value should be in lkey
40291 defaultCurrency : false,
40293 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40295 thousandsDelimiter : false,
40305 getAutoCreate : function()
40307 var align = this.labelAlign || this.parentLabelAlign();
40319 cls : 'form-control roo-money-amount-input',
40320 autocomplete: 'new-password'
40323 var hiddenInput = {
40327 cls: 'hidden-number-input'
40331 hiddenInput.name = this.name;
40334 if (this.disabled) {
40335 input.disabled = true;
40338 var clg = 12 - this.inputlg;
40339 var cmd = 12 - this.inputmd;
40340 var csm = 12 - this.inputsm;
40341 var cxs = 12 - this.inputxs;
40345 cls : 'row roo-money-field',
40349 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40353 cls: 'roo-select2-container input-group',
40357 cls : 'form-control roo-money-currency-input',
40358 autocomplete: 'new-password',
40360 name : this.currencyName
40364 cls : 'input-group-addon',
40378 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40382 cls: this.hasFeedback ? 'has-feedback' : '',
40393 if (this.fieldLabel.length) {
40396 tooltip: 'This field is required'
40402 cls: 'control-label',
40408 html: this.fieldLabel
40411 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40417 if(this.indicatorpos == 'right') {
40418 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40425 if(align == 'left') {
40433 if(this.labelWidth > 12){
40434 label.style = "width: " + this.labelWidth + 'px';
40436 if(this.labelWidth < 13 && this.labelmd == 0){
40437 this.labelmd = this.labelWidth;
40439 if(this.labellg > 0){
40440 label.cls += ' col-lg-' + this.labellg;
40441 input.cls += ' col-lg-' + (12 - this.labellg);
40443 if(this.labelmd > 0){
40444 label.cls += ' col-md-' + this.labelmd;
40445 container.cls += ' col-md-' + (12 - this.labelmd);
40447 if(this.labelsm > 0){
40448 label.cls += ' col-sm-' + this.labelsm;
40449 container.cls += ' col-sm-' + (12 - this.labelsm);
40451 if(this.labelxs > 0){
40452 label.cls += ' col-xs-' + this.labelxs;
40453 container.cls += ' col-xs-' + (12 - this.labelxs);
40464 var settings = this;
40466 ['xs','sm','md','lg'].map(function(size){
40467 if (settings[size]) {
40468 cfg.cls += ' col-' + size + '-' + settings[size];
40475 initEvents : function()
40477 this.indicator = this.indicatorEl();
40479 this.initCurrencyEvent();
40481 this.initNumberEvent();
40484 initCurrencyEvent : function()
40487 throw "can not find store for combo";
40490 this.store = Roo.factory(this.store, Roo.data);
40491 this.store.parent = this;
40495 this.triggerEl = this.el.select('.input-group-addon', true).first();
40497 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40502 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40503 _this.list.setWidth(lw);
40506 this.list.on('mouseover', this.onViewOver, this);
40507 this.list.on('mousemove', this.onViewMove, this);
40508 this.list.on('scroll', this.onViewScroll, this);
40511 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40514 this.view = new Roo.View(this.list, this.tpl, {
40515 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40518 this.view.on('click', this.onViewClick, this);
40520 this.store.on('beforeload', this.onBeforeLoad, this);
40521 this.store.on('load', this.onLoad, this);
40522 this.store.on('loadexception', this.onLoadException, this);
40524 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40525 "up" : function(e){
40526 this.inKeyMode = true;
40530 "down" : function(e){
40531 if(!this.isExpanded()){
40532 this.onTriggerClick();
40534 this.inKeyMode = true;
40539 "enter" : function(e){
40542 if(this.fireEvent("specialkey", this, e)){
40543 this.onViewClick(false);
40549 "esc" : function(e){
40553 "tab" : function(e){
40556 if(this.fireEvent("specialkey", this, e)){
40557 this.onViewClick(false);
40565 doRelay : function(foo, bar, hname){
40566 if(hname == 'down' || this.scope.isExpanded()){
40567 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40575 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40579 initNumberEvent : function(e)
40581 this.inputEl().on("keydown" , this.fireKey, this);
40582 this.inputEl().on("focus", this.onFocus, this);
40583 this.inputEl().on("blur", this.onBlur, this);
40585 this.inputEl().relayEvent('keyup', this);
40587 if(this.indicator){
40588 this.indicator.addClass('invisible');
40591 this.originalValue = this.getValue();
40593 if(this.validationEvent == 'keyup'){
40594 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40595 this.inputEl().on('keyup', this.filterValidation, this);
40597 else if(this.validationEvent !== false){
40598 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40601 if(this.selectOnFocus){
40602 this.on("focus", this.preFocus, this);
40605 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40606 this.inputEl().on("keypress", this.filterKeys, this);
40608 this.inputEl().relayEvent('keypress', this);
40611 var allowed = "0123456789";
40613 if(this.allowDecimals){
40614 allowed += this.decimalSeparator;
40617 if(this.allowNegative){
40621 if(this.thousandsDelimiter) {
40625 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40627 var keyPress = function(e){
40629 var k = e.getKey();
40631 var c = e.getCharCode();
40634 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40635 allowed.indexOf(String.fromCharCode(c)) === -1
40641 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40645 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40650 this.inputEl().on("keypress", keyPress, this);
40654 onTriggerClick : function(e)
40661 this.loadNext = false;
40663 if(this.isExpanded()){
40668 this.hasFocus = true;
40670 if(this.triggerAction == 'all') {
40671 this.doQuery(this.allQuery, true);
40675 this.doQuery(this.getRawValue());
40678 getCurrency : function()
40680 var v = this.currencyEl().getValue();
40685 restrictHeight : function()
40687 this.list.alignTo(this.currencyEl(), this.listAlign);
40688 this.list.alignTo(this.currencyEl(), this.listAlign);
40691 onViewClick : function(view, doFocus, el, e)
40693 var index = this.view.getSelectedIndexes()[0];
40695 var r = this.store.getAt(index);
40698 this.onSelect(r, index);
40702 onSelect : function(record, index){
40704 if(this.fireEvent('beforeselect', this, record, index) !== false){
40706 this.setFromCurrencyData(index > -1 ? record.data : false);
40710 this.fireEvent('select', this, record, index);
40714 setFromCurrencyData : function(o)
40718 this.lastCurrency = o;
40720 if (this.currencyField) {
40721 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40723 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40726 this.lastSelectionText = currency;
40728 //setting default currency
40729 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40730 this.setCurrency(this.defaultCurrency);
40734 this.setCurrency(currency);
40737 setFromData : function(o)
40741 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40743 this.setFromCurrencyData(c);
40748 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40750 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40753 this.setValue(value);
40757 setCurrency : function(v)
40759 this.currencyValue = v;
40762 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40767 setValue : function(v)
40769 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40775 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40777 this.inputEl().dom.value = (v == '') ? '' :
40778 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40780 if(!this.allowZero && v === '0') {
40781 this.hiddenEl().dom.value = '';
40782 this.inputEl().dom.value = '';
40789 getRawValue : function()
40791 var v = this.inputEl().getValue();
40796 getValue : function()
40798 return this.fixPrecision(this.parseValue(this.getRawValue()));
40801 parseValue : function(value)
40803 if(this.thousandsDelimiter) {
40805 r = new RegExp(",", "g");
40806 value = value.replace(r, "");
40809 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40810 return isNaN(value) ? '' : value;
40814 fixPrecision : function(value)
40816 if(this.thousandsDelimiter) {
40818 r = new RegExp(",", "g");
40819 value = value.replace(r, "");
40822 var nan = isNaN(value);
40824 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40825 return nan ? '' : value;
40827 return parseFloat(value).toFixed(this.decimalPrecision);
40830 decimalPrecisionFcn : function(v)
40832 return Math.floor(v);
40835 validateValue : function(value)
40837 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40841 var num = this.parseValue(value);
40844 this.markInvalid(String.format(this.nanText, value));
40848 if(num < this.minValue){
40849 this.markInvalid(String.format(this.minText, this.minValue));
40853 if(num > this.maxValue){
40854 this.markInvalid(String.format(this.maxText, this.maxValue));
40861 validate : function()
40863 if(this.disabled || this.allowBlank){
40868 var currency = this.getCurrency();
40870 if(this.validateValue(this.getRawValue()) && currency.length){
40875 this.markInvalid();
40879 getName: function()
40884 beforeBlur : function()
40890 var v = this.parseValue(this.getRawValue());
40897 onBlur : function()
40901 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40902 //this.el.removeClass(this.focusClass);
40905 this.hasFocus = false;
40907 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40911 var v = this.getValue();
40913 if(String(v) !== String(this.startValue)){
40914 this.fireEvent('change', this, v, this.startValue);
40917 this.fireEvent("blur", this);
40920 inputEl : function()
40922 return this.el.select('.roo-money-amount-input', true).first();
40925 currencyEl : function()
40927 return this.el.select('.roo-money-currency-input', true).first();
40930 hiddenEl : function()
40932 return this.el.select('input.hidden-number-input',true).first();