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.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2231 * Displays this menu at a specific xy position
2232 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2233 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2235 showAt : function(xy, parentMenu, /* private: */_e){
2236 this.parentMenu = parentMenu;
2241 this.fireEvent("beforeshow", this);
2242 // xy = this.el.adjustForConstraints(xy);
2246 this.hideMenuItems();
2247 this.hidden = false;
2248 this.triggerEl.addClass('open');
2250 xy = this.el.getAlignToXY(this.triggerEl, '?');
2252 // if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2253 // xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2256 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2261 this.fireEvent("show", this);
2267 this.doFocus.defer(50, this);
2271 doFocus : function(){
2273 this.focusEl.focus();
2278 * Hides this menu and optionally all parent menus
2279 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2281 hide : function(deep)
2284 this.hideMenuItems();
2285 if(this.el && this.isVisible()){
2286 this.fireEvent("beforehide", this);
2287 if(this.activeItem){
2288 this.activeItem.deactivate();
2289 this.activeItem = null;
2291 this.triggerEl.removeClass('open');;
2293 this.fireEvent("hide", this);
2295 if(deep === true && this.parentMenu){
2296 this.parentMenu.hide(true);
2300 onTriggerClick : function(e)
2302 Roo.log('trigger click');
2304 var target = e.getTarget();
2306 Roo.log(target.nodeName.toLowerCase());
2308 if(target.nodeName.toLowerCase() === 'i'){
2314 onTriggerPress : function(e)
2316 Roo.log('trigger press');
2317 //Roo.log(e.getTarget());
2318 // Roo.log(this.triggerEl.dom);
2320 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2321 var pel = Roo.get(e.getTarget());
2322 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2323 Roo.log('is treeview or dropdown?');
2327 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2331 if (this.isVisible()) {
2336 this.show(this.triggerEl, false, false);
2339 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2346 hideMenuItems : function()
2348 Roo.log("hide Menu Items");
2352 //$(backdrop).remove()
2353 this.el.select('.open',true).each(function(aa) {
2355 aa.removeClass('open');
2356 //var parent = getParent($(this))
2357 //var relatedTarget = { relatedTarget: this }
2359 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2360 //if (e.isDefaultPrevented()) return
2361 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2364 addxtypeChild : function (tree, cntr) {
2365 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2367 this.menuitems.add(comp);
2379 this.getEl().dom.innerHTML = '';
2380 this.menuitems.clear();
2394 * @class Roo.bootstrap.MenuItem
2395 * @extends Roo.bootstrap.Component
2396 * Bootstrap MenuItem class
2397 * @cfg {String} html the menu label
2398 * @cfg {String} href the link
2399 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2400 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2401 * @cfg {Boolean} active used on sidebars to highlight active itesm
2402 * @cfg {String} fa favicon to show on left of menu item.
2403 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2407 * Create a new MenuItem
2408 * @param {Object} config The config object
2412 Roo.bootstrap.MenuItem = function(config){
2413 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2418 * The raw click event for the entire grid.
2419 * @param {Roo.bootstrap.MenuItem} this
2420 * @param {Roo.EventObject} e
2426 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2430 preventDefault: false,
2431 isContainer : false,
2435 getAutoCreate : function(){
2437 if(this.isContainer){
2440 cls: 'dropdown-menu-item'
2454 if (this.fa !== false) {
2457 cls : 'fa fa-' + this.fa
2466 cls: 'dropdown-menu-item',
2469 if (this.parent().type == 'treeview') {
2470 cfg.cls = 'treeview-menu';
2473 cfg.cls += ' active';
2478 anc.href = this.href || cfg.cn[0].href ;
2479 ctag.html = this.html || cfg.cn[0].html ;
2483 initEvents: function()
2485 if (this.parent().type == 'treeview') {
2486 this.el.select('a').on('click', this.onClick, this);
2490 this.menu.parentType = this.xtype;
2491 this.menu.triggerEl = this.el;
2492 this.menu = this.addxtype(Roo.apply({}, this.menu));
2496 onClick : function(e)
2498 Roo.log('item on click ');
2500 if(this.preventDefault){
2503 //this.parent().hideMenuItems();
2505 this.fireEvent('click', this, e);
2524 * @class Roo.bootstrap.MenuSeparator
2525 * @extends Roo.bootstrap.Component
2526 * Bootstrap MenuSeparator class
2529 * Create a new MenuItem
2530 * @param {Object} config The config object
2534 Roo.bootstrap.MenuSeparator = function(config){
2535 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2538 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2540 getAutoCreate : function(){
2559 * @class Roo.bootstrap.Modal
2560 * @extends Roo.bootstrap.Component
2561 * Bootstrap Modal class
2562 * @cfg {String} title Title of dialog
2563 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2564 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2565 * @cfg {Boolean} specificTitle default false
2566 * @cfg {Array} buttons Array of buttons or standard button set..
2567 * @cfg {String} buttonPosition (left|right|center) default right
2568 * @cfg {Boolean} animate default true
2569 * @cfg {Boolean} allow_close default true
2570 * @cfg {Boolean} fitwindow default false
2571 * @cfg {String} size (sm|lg) default empty
2575 * Create a new Modal Dialog
2576 * @param {Object} config The config object
2579 Roo.bootstrap.Modal = function(config){
2580 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2585 * The raw btnclick event for the button
2586 * @param {Roo.EventObject} e
2591 * Fire when dialog resize
2592 * @param {Roo.bootstrap.Modal} this
2593 * @param {Roo.EventObject} e
2597 this.buttons = this.buttons || [];
2600 this.tmpl = Roo.factory(this.tmpl);
2605 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2607 title : 'test dialog',
2617 specificTitle: false,
2619 buttonPosition: 'right',
2638 onRender : function(ct, position)
2640 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2643 var cfg = Roo.apply({}, this.getAutoCreate());
2646 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2648 //if (!cfg.name.length) {
2652 cfg.cls += ' ' + this.cls;
2655 cfg.style = this.style;
2657 this.el = Roo.get(document.body).createChild(cfg, position);
2659 //var type = this.el.dom.type;
2662 if(this.tabIndex !== undefined){
2663 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2666 this.dialogEl = this.el.select('.modal-dialog',true).first();
2667 this.bodyEl = this.el.select('.modal-body',true).first();
2668 this.closeEl = this.el.select('.modal-header .close', true).first();
2669 this.headerEl = this.el.select('.modal-header',true).first();
2670 this.titleEl = this.el.select('.modal-title',true).first();
2671 this.footerEl = this.el.select('.modal-footer',true).first();
2673 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2675 //this.el.addClass("x-dlg-modal");
2677 if (this.buttons.length) {
2678 Roo.each(this.buttons, function(bb) {
2679 var b = Roo.apply({}, bb);
2680 b.xns = b.xns || Roo.bootstrap;
2681 b.xtype = b.xtype || 'Button';
2682 if (typeof(b.listeners) == 'undefined') {
2683 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2686 var btn = Roo.factory(b);
2688 btn.render(this.el.select('.modal-footer div').first());
2692 // render the children.
2695 if(typeof(this.items) != 'undefined'){
2696 var items = this.items;
2699 for(var i =0;i < items.length;i++) {
2700 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2704 this.items = nitems;
2706 // where are these used - they used to be body/close/footer
2710 //this.el.addClass([this.fieldClass, this.cls]);
2714 getAutoCreate : function(){
2719 html : this.html || ''
2724 cls : 'modal-title',
2728 if(this.specificTitle){
2734 if (this.allow_close) {
2746 if(this.size.length){
2747 size = 'modal-' + this.size;
2754 cls: "modal-dialog " + size,
2757 cls : "modal-content",
2760 cls : 'modal-header',
2765 cls : 'modal-footer',
2769 cls: 'btn-' + this.buttonPosition
2786 modal.cls += ' fade';
2792 getChildContainer : function() {
2797 getButtonContainer : function() {
2798 return this.el.select('.modal-footer div',true).first();
2801 initEvents : function()
2803 if (this.allow_close) {
2804 this.closeEl.on('click', this.hide, this);
2806 Roo.EventManager.onWindowResize(this.resize, this, true);
2813 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2814 if (this.fitwindow) {
2815 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2816 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2821 setSize : function(w,h)
2831 if (!this.rendered) {
2835 //this.el.setStyle('display', 'block');
2836 this.el.removeClass('hideing');
2837 this.el.addClass('show');
2839 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2842 this.el.addClass('in');
2845 this.el.addClass('in');
2849 // not sure how we can show data in here..
2851 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2854 Roo.get(document.body).addClass("x-body-masked");
2856 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2857 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2858 this.maskEl.addClass('show');
2862 this.fireEvent('show', this);
2864 // set zindex here - otherwise it appears to be ignored...
2865 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2868 this.items.forEach( function(e) {
2869 e.layout ? e.layout() : false;
2877 if(this.fireEvent("beforehide", this) !== false){
2878 this.maskEl.removeClass('show');
2879 Roo.get(document.body).removeClass("x-body-masked");
2880 this.el.removeClass('in');
2881 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2883 if(this.animate){ // why
2884 this.el.addClass('hideing');
2886 if (!this.el.hasClass('hideing')) {
2887 return; // it's been shown again...
2889 this.el.removeClass('show');
2890 this.el.removeClass('hideing');
2894 this.el.removeClass('show');
2896 this.fireEvent('hide', this);
2899 isVisible : function()
2902 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2906 addButton : function(str, cb)
2910 var b = Roo.apply({}, { html : str } );
2911 b.xns = b.xns || Roo.bootstrap;
2912 b.xtype = b.xtype || 'Button';
2913 if (typeof(b.listeners) == 'undefined') {
2914 b.listeners = { click : cb.createDelegate(this) };
2917 var btn = Roo.factory(b);
2919 btn.render(this.el.select('.modal-footer div').first());
2925 setDefaultButton : function(btn)
2927 //this.el.select('.modal-footer').()
2931 resizeTo: function(w,h)
2935 this.dialogEl.setWidth(w);
2936 if (this.diff === false) {
2937 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2940 this.bodyEl.setHeight(h-this.diff);
2942 this.fireEvent('resize', this);
2945 setContentSize : function(w, h)
2949 onButtonClick: function(btn,e)
2952 this.fireEvent('btnclick', btn.name, e);
2955 * Set the title of the Dialog
2956 * @param {String} str new Title
2958 setTitle: function(str) {
2959 this.titleEl.dom.innerHTML = str;
2962 * Set the body of the Dialog
2963 * @param {String} str new Title
2965 setBody: function(str) {
2966 this.bodyEl.dom.innerHTML = str;
2969 * Set the body of the Dialog using the template
2970 * @param {Obj} data - apply this data to the template and replace the body contents.
2972 applyBody: function(obj)
2975 Roo.log("Error - using apply Body without a template");
2978 this.tmpl.overwrite(this.bodyEl, obj);
2984 Roo.apply(Roo.bootstrap.Modal, {
2986 * Button config that displays a single OK button
2995 * Button config that displays Yes and No buttons
3011 * Button config that displays OK and Cancel buttons
3026 * Button config that displays Yes, No and Cancel buttons
3050 * messagebox - can be used as a replace
3054 * @class Roo.MessageBox
3055 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3059 Roo.Msg.alert('Status', 'Changes saved successfully.');
3061 // Prompt for user data:
3062 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3064 // process text value...
3068 // Show a dialog using config options:
3070 title:'Save Changes?',
3071 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3072 buttons: Roo.Msg.YESNOCANCEL,
3079 Roo.bootstrap.MessageBox = function(){
3080 var dlg, opt, mask, waitTimer;
3081 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3082 var buttons, activeTextEl, bwidth;
3086 var handleButton = function(button){
3088 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3092 var handleHide = function(){
3094 dlg.el.removeClass(opt.cls);
3097 // Roo.TaskMgr.stop(waitTimer);
3098 // waitTimer = null;
3103 var updateButtons = function(b){
3106 buttons["ok"].hide();
3107 buttons["cancel"].hide();
3108 buttons["yes"].hide();
3109 buttons["no"].hide();
3110 //dlg.footer.dom.style.display = 'none';
3113 dlg.footerEl.dom.style.display = '';
3114 for(var k in buttons){
3115 if(typeof buttons[k] != "function"){
3118 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3119 width += buttons[k].el.getWidth()+15;
3129 var handleEsc = function(d, k, e){
3130 if(opt && opt.closable !== false){
3140 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3141 * @return {Roo.BasicDialog} The BasicDialog element
3143 getDialog : function(){
3145 dlg = new Roo.bootstrap.Modal( {
3148 //constraintoviewport:false,
3150 //collapsible : false,
3155 //buttonAlign:"center",
3156 closeClick : function(){
3157 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3160 handleButton("cancel");
3165 dlg.on("hide", handleHide);
3167 //dlg.addKeyListener(27, handleEsc);
3169 this.buttons = buttons;
3170 var bt = this.buttonText;
3171 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3172 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3173 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3174 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3176 bodyEl = dlg.bodyEl.createChild({
3178 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3179 '<textarea class="roo-mb-textarea"></textarea>' +
3180 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3182 msgEl = bodyEl.dom.firstChild;
3183 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3184 textboxEl.enableDisplayMode();
3185 textboxEl.addKeyListener([10,13], function(){
3186 if(dlg.isVisible() && opt && opt.buttons){
3189 }else if(opt.buttons.yes){
3190 handleButton("yes");
3194 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3195 textareaEl.enableDisplayMode();
3196 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3197 progressEl.enableDisplayMode();
3199 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3200 var pf = progressEl.dom.firstChild;
3202 pp = Roo.get(pf.firstChild);
3203 pp.setHeight(pf.offsetHeight);
3211 * Updates the message box body text
3212 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3213 * the XHTML-compliant non-breaking space character '&#160;')
3214 * @return {Roo.MessageBox} This message box
3216 updateText : function(text)
3218 if(!dlg.isVisible() && !opt.width){
3219 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3220 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3222 msgEl.innerHTML = text || ' ';
3224 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3225 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3227 Math.min(opt.width || cw , this.maxWidth),
3228 Math.max(opt.minWidth || this.minWidth, bwidth)
3231 activeTextEl.setWidth(w);
3233 if(dlg.isVisible()){
3234 dlg.fixedcenter = false;
3236 // to big, make it scroll. = But as usual stupid IE does not support
3239 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3240 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3241 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3243 bodyEl.dom.style.height = '';
3244 bodyEl.dom.style.overflowY = '';
3247 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3249 bodyEl.dom.style.overflowX = '';
3252 dlg.setContentSize(w, bodyEl.getHeight());
3253 if(dlg.isVisible()){
3254 dlg.fixedcenter = true;
3260 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3261 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3262 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3263 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3264 * @return {Roo.MessageBox} This message box
3266 updateProgress : function(value, text){
3268 this.updateText(text);
3271 if (pp) { // weird bug on my firefox - for some reason this is not defined
3272 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3273 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3279 * Returns true if the message box is currently displayed
3280 * @return {Boolean} True if the message box is visible, else false
3282 isVisible : function(){
3283 return dlg && dlg.isVisible();
3287 * Hides the message box if it is displayed
3290 if(this.isVisible()){
3296 * Displays a new message box, or reinitializes an existing message box, based on the config options
3297 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3298 * The following config object properties are supported:
3300 Property Type Description
3301 ---------- --------------- ------------------------------------------------------------------------------------
3302 animEl String/Element An id or Element from which the message box should animate as it opens and
3303 closes (defaults to undefined)
3304 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3305 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3306 closable Boolean False to hide the top-right close button (defaults to true). Note that
3307 progress and wait dialogs will ignore this property and always hide the
3308 close button as they can only be closed programmatically.
3309 cls String A custom CSS class to apply to the message box element
3310 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3311 displayed (defaults to 75)
3312 fn Function A callback function to execute after closing the dialog. The arguments to the
3313 function will be btn (the name of the button that was clicked, if applicable,
3314 e.g. "ok"), and text (the value of the active text field, if applicable).
3315 Progress and wait dialogs will ignore this option since they do not respond to
3316 user actions and can only be closed programmatically, so any required function
3317 should be called by the same code after it closes the dialog.
3318 icon String A CSS class that provides a background image to be used as an icon for
3319 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3320 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3321 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3322 modal Boolean False to allow user interaction with the page while the message box is
3323 displayed (defaults to true)
3324 msg String A string that will replace the existing message box body text (defaults
3325 to the XHTML-compliant non-breaking space character ' ')
3326 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3327 progress Boolean True to display a progress bar (defaults to false)
3328 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3329 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3330 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3331 title String The title text
3332 value String The string value to set into the active textbox element if displayed
3333 wait Boolean True to display a progress bar (defaults to false)
3334 width Number The width of the dialog in pixels
3341 msg: 'Please enter your address:',
3343 buttons: Roo.MessageBox.OKCANCEL,
3346 animEl: 'addAddressBtn'
3349 * @param {Object} config Configuration options
3350 * @return {Roo.MessageBox} This message box
3352 show : function(options)
3355 // this causes nightmares if you show one dialog after another
3356 // especially on callbacks..
3358 if(this.isVisible()){
3361 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3362 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3363 Roo.log("New Dialog Message:" + options.msg )
3364 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3365 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3368 var d = this.getDialog();
3370 d.setTitle(opt.title || " ");
3371 d.closeEl.setDisplayed(opt.closable !== false);
3372 activeTextEl = textboxEl;
3373 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3378 textareaEl.setHeight(typeof opt.multiline == "number" ?
3379 opt.multiline : this.defaultTextHeight);
3380 activeTextEl = textareaEl;
3389 progressEl.setDisplayed(opt.progress === true);
3390 this.updateProgress(0);
3391 activeTextEl.dom.value = opt.value || "";
3393 dlg.setDefaultButton(activeTextEl);
3395 var bs = opt.buttons;
3399 }else if(bs && bs.yes){
3400 db = buttons["yes"];
3402 dlg.setDefaultButton(db);
3404 bwidth = updateButtons(opt.buttons);
3405 this.updateText(opt.msg);
3407 d.el.addClass(opt.cls);
3409 d.proxyDrag = opt.proxyDrag === true;
3410 d.modal = opt.modal !== false;
3411 d.mask = opt.modal !== false ? mask : false;
3413 // force it to the end of the z-index stack so it gets a cursor in FF
3414 document.body.appendChild(dlg.el.dom);
3415 d.animateTarget = null;
3416 d.show(options.animEl);
3422 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3423 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3424 * and closing the message box when the process is complete.
3425 * @param {String} title The title bar text
3426 * @param {String} msg The message box body text
3427 * @return {Roo.MessageBox} This message box
3429 progress : function(title, msg){
3436 minWidth: this.minProgressWidth,
3443 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3444 * If a callback function is passed it will be called after the user clicks the button, and the
3445 * id of the button that was clicked will be passed as the only parameter to the callback
3446 * (could also be the top-right close button).
3447 * @param {String} title The title bar text
3448 * @param {String} msg The message box body text
3449 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3450 * @param {Object} scope (optional) The scope of the callback function
3451 * @return {Roo.MessageBox} This message box
3453 alert : function(title, msg, fn, scope)
3468 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3469 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3470 * You are responsible for closing the message box when the process is complete.
3471 * @param {String} msg The message box body text
3472 * @param {String} title (optional) The title bar text
3473 * @return {Roo.MessageBox} This message box
3475 wait : function(msg, title){
3486 waitTimer = Roo.TaskMgr.start({
3488 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3496 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3497 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3498 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3499 * @param {String} title The title bar text
3500 * @param {String} msg The message box body text
3501 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3502 * @param {Object} scope (optional) The scope of the callback function
3503 * @return {Roo.MessageBox} This message box
3505 confirm : function(title, msg, fn, scope){
3509 buttons: this.YESNO,
3518 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3519 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3520 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3521 * (could also be the top-right close button) and the text that was entered will be passed as the two
3522 * parameters to the callback.
3523 * @param {String} title The title bar text
3524 * @param {String} msg The message box body text
3525 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3526 * @param {Object} scope (optional) The scope of the callback function
3527 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3528 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3529 * @return {Roo.MessageBox} This message box
3531 prompt : function(title, msg, fn, scope, multiline){
3535 buttons: this.OKCANCEL,
3540 multiline: multiline,
3547 * Button config that displays a single OK button
3552 * Button config that displays Yes and No buttons
3555 YESNO : {yes:true, no:true},
3557 * Button config that displays OK and Cancel buttons
3560 OKCANCEL : {ok:true, cancel:true},
3562 * Button config that displays Yes, No and Cancel buttons
3565 YESNOCANCEL : {yes:true, no:true, cancel:true},
3568 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3571 defaultTextHeight : 75,
3573 * The maximum width in pixels of the message box (defaults to 600)
3578 * The minimum width in pixels of the message box (defaults to 100)
3583 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3584 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3587 minProgressWidth : 250,
3589 * An object containing the default button text strings that can be overriden for localized language support.
3590 * Supported properties are: ok, cancel, yes and no.
3591 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3604 * Shorthand for {@link Roo.MessageBox}
3606 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3607 Roo.Msg = Roo.Msg || Roo.MessageBox;
3616 * @class Roo.bootstrap.Navbar
3617 * @extends Roo.bootstrap.Component
3618 * Bootstrap Navbar class
3621 * Create a new Navbar
3622 * @param {Object} config The config object
3626 Roo.bootstrap.Navbar = function(config){
3627 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3631 * @event beforetoggle
3632 * Fire before toggle the menu
3633 * @param {Roo.EventObject} e
3635 "beforetoggle" : true
3639 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3648 getAutoCreate : function(){
3651 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3655 initEvents :function ()
3657 //Roo.log(this.el.select('.navbar-toggle',true));
3658 this.el.select('.navbar-toggle',true).on('click', function() {
3659 if(this.fireEvent('beforetoggle', this) !== false){
3660 this.el.select('.navbar-collapse',true).toggleClass('in');
3670 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3672 var size = this.el.getSize();
3673 this.maskEl.setSize(size.width, size.height);
3674 this.maskEl.enableDisplayMode("block");
3683 getChildContainer : function()
3685 if (this.el.select('.collapse').getCount()) {
3686 return this.el.select('.collapse',true).first();
3719 * @class Roo.bootstrap.NavSimplebar
3720 * @extends Roo.bootstrap.Navbar
3721 * Bootstrap Sidebar class
3723 * @cfg {Boolean} inverse is inverted color
3725 * @cfg {String} type (nav | pills | tabs)
3726 * @cfg {Boolean} arrangement stacked | justified
3727 * @cfg {String} align (left | right) alignment
3729 * @cfg {Boolean} main (true|false) main nav bar? default false
3730 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3732 * @cfg {String} tag (header|footer|nav|div) default is nav
3738 * Create a new Sidebar
3739 * @param {Object} config The config object
3743 Roo.bootstrap.NavSimplebar = function(config){
3744 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3747 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3763 getAutoCreate : function(){
3767 tag : this.tag || 'div',
3780 this.type = this.type || 'nav';
3781 if (['tabs','pills'].indexOf(this.type)!==-1) {
3782 cfg.cn[0].cls += ' nav-' + this.type
3786 if (this.type!=='nav') {
3787 Roo.log('nav type must be nav/tabs/pills')
3789 cfg.cn[0].cls += ' navbar-nav'
3795 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3796 cfg.cn[0].cls += ' nav-' + this.arrangement;
3800 if (this.align === 'right') {
3801 cfg.cn[0].cls += ' navbar-right';
3805 cfg.cls += ' navbar-inverse';
3832 * @class Roo.bootstrap.NavHeaderbar
3833 * @extends Roo.bootstrap.NavSimplebar
3834 * Bootstrap Sidebar class
3836 * @cfg {String} brand what is brand
3837 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3838 * @cfg {String} brand_href href of the brand
3839 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3840 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3841 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3842 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3845 * Create a new Sidebar
3846 * @param {Object} config The config object
3850 Roo.bootstrap.NavHeaderbar = function(config){
3851 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3855 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3862 desktopCenter : false,
3865 getAutoCreate : function(){
3868 tag: this.nav || 'nav',
3875 if (this.desktopCenter) {
3876 cn.push({cls : 'container', cn : []});
3883 cls: 'navbar-header',
3888 cls: 'navbar-toggle',
3889 'data-toggle': 'collapse',
3894 html: 'Toggle navigation'
3916 cls: 'collapse navbar-collapse',
3920 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3922 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3923 cfg.cls += ' navbar-' + this.position;
3925 // tag can override this..
3927 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3930 if (this.brand !== '') {
3933 href: this.brand_href ? this.brand_href : '#',
3934 cls: 'navbar-brand',
3942 cfg.cls += ' main-nav';
3950 getHeaderChildContainer : function()
3952 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3953 return this.el.select('.navbar-header',true).first();
3956 return this.getChildContainer();
3960 initEvents : function()
3962 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3964 if (this.autohide) {
3969 Roo.get(document).on('scroll',function(e) {
3970 var ns = Roo.get(document).getScroll().top;
3971 var os = prevScroll;
3975 ft.removeClass('slideDown');
3976 ft.addClass('slideUp');
3979 ft.removeClass('slideUp');
3980 ft.addClass('slideDown');
4001 * @class Roo.bootstrap.NavSidebar
4002 * @extends Roo.bootstrap.Navbar
4003 * Bootstrap Sidebar class
4006 * Create a new Sidebar
4007 * @param {Object} config The config object
4011 Roo.bootstrap.NavSidebar = function(config){
4012 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4015 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4017 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4019 getAutoCreate : function(){
4024 cls: 'sidebar sidebar-nav'
4046 * @class Roo.bootstrap.NavGroup
4047 * @extends Roo.bootstrap.Component
4048 * Bootstrap NavGroup class
4049 * @cfg {String} align (left|right)
4050 * @cfg {Boolean} inverse
4051 * @cfg {String} type (nav|pills|tab) default nav
4052 * @cfg {String} navId - reference Id for navbar.
4056 * Create a new nav group
4057 * @param {Object} config The config object
4060 Roo.bootstrap.NavGroup = function(config){
4061 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4064 Roo.bootstrap.NavGroup.register(this);
4068 * Fires when the active item changes
4069 * @param {Roo.bootstrap.NavGroup} this
4070 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4071 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4078 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4089 getAutoCreate : function()
4091 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4098 if (['tabs','pills'].indexOf(this.type)!==-1) {
4099 cfg.cls += ' nav-' + this.type
4101 if (this.type!=='nav') {
4102 Roo.log('nav type must be nav/tabs/pills')
4104 cfg.cls += ' navbar-nav'
4107 if (this.parent() && this.parent().sidebar) {
4110 cls: 'dashboard-menu sidebar-menu'
4116 if (this.form === true) {
4122 if (this.align === 'right') {
4123 cfg.cls += ' navbar-right';
4125 cfg.cls += ' navbar-left';
4129 if (this.align === 'right') {
4130 cfg.cls += ' navbar-right';
4134 cfg.cls += ' navbar-inverse';
4142 * sets the active Navigation item
4143 * @param {Roo.bootstrap.NavItem} the new current navitem
4145 setActiveItem : function(item)
4148 Roo.each(this.navItems, function(v){
4153 v.setActive(false, true);
4160 item.setActive(true, true);
4161 this.fireEvent('changed', this, item, prev);
4166 * gets the active Navigation item
4167 * @return {Roo.bootstrap.NavItem} the current navitem
4169 getActive : function()
4173 Roo.each(this.navItems, function(v){
4184 indexOfNav : function()
4188 Roo.each(this.navItems, function(v,i){
4199 * adds a Navigation item
4200 * @param {Roo.bootstrap.NavItem} the navitem to add
4202 addItem : function(cfg)
4204 var cn = new Roo.bootstrap.NavItem(cfg);
4206 cn.parentId = this.id;
4207 cn.onRender(this.el, null);
4211 * register a Navigation item
4212 * @param {Roo.bootstrap.NavItem} the navitem to add
4214 register : function(item)
4216 this.navItems.push( item);
4217 item.navId = this.navId;
4222 * clear all the Navigation item
4225 clearAll : function()
4228 this.el.dom.innerHTML = '';
4231 getNavItem: function(tabId)
4234 Roo.each(this.navItems, function(e) {
4235 if (e.tabId == tabId) {
4245 setActiveNext : function()
4247 var i = this.indexOfNav(this.getActive());
4248 if (i > this.navItems.length) {
4251 this.setActiveItem(this.navItems[i+1]);
4253 setActivePrev : function()
4255 var i = this.indexOfNav(this.getActive());
4259 this.setActiveItem(this.navItems[i-1]);
4261 clearWasActive : function(except) {
4262 Roo.each(this.navItems, function(e) {
4263 if (e.tabId != except.tabId && e.was_active) {
4264 e.was_active = false;
4271 getWasActive : function ()
4274 Roo.each(this.navItems, function(e) {
4289 Roo.apply(Roo.bootstrap.NavGroup, {
4293 * register a Navigation Group
4294 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4296 register : function(navgrp)
4298 this.groups[navgrp.navId] = navgrp;
4302 * fetch a Navigation Group based on the navigation ID
4303 * @param {string} the navgroup to add
4304 * @returns {Roo.bootstrap.NavGroup} the navgroup
4306 get: function(navId) {
4307 if (typeof(this.groups[navId]) == 'undefined') {
4309 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4311 return this.groups[navId] ;
4326 * @class Roo.bootstrap.NavItem
4327 * @extends Roo.bootstrap.Component
4328 * Bootstrap Navbar.NavItem class
4329 * @cfg {String} href link to
4330 * @cfg {String} html content of button
4331 * @cfg {String} badge text inside badge
4332 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4333 * @cfg {String} glyphicon name of glyphicon
4334 * @cfg {String} icon name of font awesome icon
4335 * @cfg {Boolean} active Is item active
4336 * @cfg {Boolean} disabled Is item disabled
4338 * @cfg {Boolean} preventDefault (true | false) default false
4339 * @cfg {String} tabId the tab that this item activates.
4340 * @cfg {String} tagtype (a|span) render as a href or span?
4341 * @cfg {Boolean} animateRef (true|false) link to element default false
4344 * Create a new Navbar Item
4345 * @param {Object} config The config object
4347 Roo.bootstrap.NavItem = function(config){
4348 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4353 * The raw click event for the entire grid.
4354 * @param {Roo.EventObject} e
4359 * Fires when the active item active state changes
4360 * @param {Roo.bootstrap.NavItem} this
4361 * @param {boolean} state the new state
4367 * Fires when scroll to element
4368 * @param {Roo.bootstrap.NavItem} this
4369 * @param {Object} options
4370 * @param {Roo.EventObject} e
4378 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4386 preventDefault : false,
4393 getAutoCreate : function(){
4402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4404 if (this.disabled) {
4405 cfg.cls += ' disabled';
4408 if (this.href || this.html || this.glyphicon || this.icon) {
4412 href : this.href || "#",
4413 html: this.html || ''
4418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4421 if(this.glyphicon) {
4422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4427 cfg.cn[0].html += " <span class='caret'></span>";
4431 if (this.badge !== '') {
4433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4441 initEvents: function()
4443 if (typeof (this.menu) != 'undefined') {
4444 this.menu.parentType = this.xtype;
4445 this.menu.triggerEl = this.el;
4446 this.menu = this.addxtype(Roo.apply({}, this.menu));
4449 this.el.select('a',true).on('click', this.onClick, this);
4451 if(this.tagtype == 'span'){
4452 this.el.select('span',true).on('click', this.onClick, this);
4455 // at this point parent should be available..
4456 this.parent().register(this);
4459 onClick : function(e)
4461 if (e.getTarget('.dropdown-menu-item')) {
4462 // did you click on a menu itemm.... - then don't trigger onclick..
4467 this.preventDefault ||
4470 Roo.log("NavItem - prevent Default?");
4474 if (this.disabled) {
4478 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4479 if (tg && tg.transition) {
4480 Roo.log("waiting for the transitionend");
4486 //Roo.log("fire event clicked");
4487 if(this.fireEvent('click', this, e) === false){
4491 if(this.tagtype == 'span'){
4495 //Roo.log(this.href);
4496 var ael = this.el.select('a',true).first();
4499 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4500 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4501 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4502 return; // ignore... - it's a 'hash' to another page.
4504 Roo.log("NavItem - prevent Default?");
4506 this.scrollToElement(e);
4510 var p = this.parent();
4512 if (['tabs','pills'].indexOf(p.type)!==-1) {
4513 if (typeof(p.setActiveItem) !== 'undefined') {
4514 p.setActiveItem(this);
4518 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4519 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4520 // remove the collapsed menu expand...
4521 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4525 isActive: function () {
4528 setActive : function(state, fire, is_was_active)
4530 if (this.active && !state && this.navId) {
4531 this.was_active = true;
4532 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4534 nv.clearWasActive(this);
4538 this.active = state;
4541 this.el.removeClass('active');
4542 } else if (!this.el.hasClass('active')) {
4543 this.el.addClass('active');
4546 this.fireEvent('changed', this, state);
4549 // show a panel if it's registered and related..
4551 if (!this.navId || !this.tabId || !state || is_was_active) {
4555 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4559 var pan = tg.getPanelByName(this.tabId);
4563 // if we can not flip to new panel - go back to old nav highlight..
4564 if (false == tg.showPanel(pan)) {
4565 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4567 var onav = nv.getWasActive();
4569 onav.setActive(true, false, true);
4578 // this should not be here...
4579 setDisabled : function(state)
4581 this.disabled = state;
4583 this.el.removeClass('disabled');
4584 } else if (!this.el.hasClass('disabled')) {
4585 this.el.addClass('disabled');
4591 * Fetch the element to display the tooltip on.
4592 * @return {Roo.Element} defaults to this.el
4594 tooltipEl : function()
4596 return this.el.select('' + this.tagtype + '', true).first();
4599 scrollToElement : function(e)
4601 var c = document.body;
4604 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4606 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4607 c = document.documentElement;
4610 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4616 var o = target.calcOffsetsTo(c);
4623 this.fireEvent('scrollto', this, options, e);
4625 Roo.get(c).scrollTo('top', options.value, true);
4638 * <span> icon </span>
4639 * <span> text </span>
4640 * <span>badge </span>
4644 * @class Roo.bootstrap.NavSidebarItem
4645 * @extends Roo.bootstrap.NavItem
4646 * Bootstrap Navbar.NavSidebarItem class
4647 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4648 * {Boolean} open is the menu open
4649 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4650 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4651 * {String} buttonSize (sm|md|lg)the extra classes for the button
4652 * {Boolean} showArrow show arrow next to the text (default true)
4654 * Create a new Navbar Button
4655 * @param {Object} config The config object
4657 Roo.bootstrap.NavSidebarItem = function(config){
4658 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4663 * The raw click event for the entire grid.
4664 * @param {Roo.EventObject} e
4669 * Fires when the active item active state changes
4670 * @param {Roo.bootstrap.NavSidebarItem} this
4671 * @param {boolean} state the new state
4679 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4681 badgeWeight : 'default',
4687 buttonWeight : 'default',
4693 getAutoCreate : function(){
4698 href : this.href || '#',
4704 if(this.buttonView){
4707 href : this.href || '#',
4708 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4721 cfg.cls += ' active';
4724 if (this.disabled) {
4725 cfg.cls += ' disabled';
4728 cfg.cls += ' open x-open';
4731 if (this.glyphicon || this.icon) {
4732 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4733 a.cn.push({ tag : 'i', cls : c }) ;
4736 if(!this.buttonView){
4739 html : this.html || ''
4746 if (this.badge !== '') {
4747 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4753 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4756 a.cls += ' dropdown-toggle treeview' ;
4762 initEvents : function()
4764 if (typeof (this.menu) != 'undefined') {
4765 this.menu.parentType = this.xtype;
4766 this.menu.triggerEl = this.el;
4767 this.menu = this.addxtype(Roo.apply({}, this.menu));
4770 this.el.on('click', this.onClick, this);
4772 if(this.badge !== ''){
4773 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4778 onClick : function(e)
4785 if(this.preventDefault){
4789 this.fireEvent('click', this);
4792 disable : function()
4794 this.setDisabled(true);
4799 this.setDisabled(false);
4802 setDisabled : function(state)
4804 if(this.disabled == state){
4808 this.disabled = state;
4811 this.el.addClass('disabled');
4815 this.el.removeClass('disabled');
4820 setActive : function(state)
4822 if(this.active == state){
4826 this.active = state;
4829 this.el.addClass('active');
4833 this.el.removeClass('active');
4838 isActive: function ()
4843 setBadge : function(str)
4849 this.badgeEl.dom.innerHTML = str;
4866 * @class Roo.bootstrap.Row
4867 * @extends Roo.bootstrap.Component
4868 * Bootstrap Row class (contains columns...)
4872 * @param {Object} config The config object
4875 Roo.bootstrap.Row = function(config){
4876 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4879 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4881 getAutoCreate : function(){
4900 * @class Roo.bootstrap.Element
4901 * @extends Roo.bootstrap.Component
4902 * Bootstrap Element class
4903 * @cfg {String} html contents of the element
4904 * @cfg {String} tag tag of the element
4905 * @cfg {String} cls class of the element
4906 * @cfg {Boolean} preventDefault (true|false) default false
4907 * @cfg {Boolean} clickable (true|false) default false
4910 * Create a new Element
4911 * @param {Object} config The config object
4914 Roo.bootstrap.Element = function(config){
4915 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4921 * When a element is chick
4922 * @param {Roo.bootstrap.Element} this
4923 * @param {Roo.EventObject} e
4929 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4934 preventDefault: false,
4937 getAutoCreate : function(){
4941 // cls: this.cls, double assign in parent class Component.js :: onRender
4948 initEvents: function()
4950 Roo.bootstrap.Element.superclass.initEvents.call(this);
4953 this.el.on('click', this.onClick, this);
4958 onClick : function(e)
4960 if(this.preventDefault){
4964 this.fireEvent('click', this, e);
4967 getValue : function()
4969 return this.el.dom.innerHTML;
4972 setValue : function(value)
4974 this.el.dom.innerHTML = value;
4989 * @class Roo.bootstrap.Pagination
4990 * @extends Roo.bootstrap.Component
4991 * Bootstrap Pagination class
4992 * @cfg {String} size xs | sm | md | lg
4993 * @cfg {Boolean} inverse false | true
4996 * Create a new Pagination
4997 * @param {Object} config The config object
5000 Roo.bootstrap.Pagination = function(config){
5001 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5004 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5010 getAutoCreate : function(){
5016 cfg.cls += ' inverse';
5022 cfg.cls += " " + this.cls;
5040 * @class Roo.bootstrap.PaginationItem
5041 * @extends Roo.bootstrap.Component
5042 * Bootstrap PaginationItem class
5043 * @cfg {String} html text
5044 * @cfg {String} href the link
5045 * @cfg {Boolean} preventDefault (true | false) default true
5046 * @cfg {Boolean} active (true | false) default false
5047 * @cfg {Boolean} disabled default false
5051 * Create a new PaginationItem
5052 * @param {Object} config The config object
5056 Roo.bootstrap.PaginationItem = function(config){
5057 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5062 * The raw click event for the entire grid.
5063 * @param {Roo.EventObject} e
5069 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5073 preventDefault: true,
5078 getAutoCreate : function(){
5084 href : this.href ? this.href : '#',
5085 html : this.html ? this.html : ''
5095 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5099 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5105 initEvents: function() {
5107 this.el.on('click', this.onClick, this);
5110 onClick : function(e)
5112 Roo.log('PaginationItem on click ');
5113 if(this.preventDefault){
5121 this.fireEvent('click', this, e);
5137 * @class Roo.bootstrap.Slider
5138 * @extends Roo.bootstrap.Component
5139 * Bootstrap Slider class
5142 * Create a new Slider
5143 * @param {Object} config The config object
5146 Roo.bootstrap.Slider = function(config){
5147 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5150 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5152 getAutoCreate : function(){
5156 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5160 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5172 * Ext JS Library 1.1.1
5173 * Copyright(c) 2006-2007, Ext JS, LLC.
5175 * Originally Released Under LGPL - original licence link has changed is not relivant.
5178 * <script type="text/javascript">
5183 * @class Roo.grid.ColumnModel
5184 * @extends Roo.util.Observable
5185 * This is the default implementation of a ColumnModel used by the Grid. It defines
5186 * the columns in the grid.
5189 var colModel = new Roo.grid.ColumnModel([
5190 {header: "Ticker", width: 60, sortable: true, locked: true},
5191 {header: "Company Name", width: 150, sortable: true},
5192 {header: "Market Cap.", width: 100, sortable: true},
5193 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5194 {header: "Employees", width: 100, sortable: true, resizable: false}
5199 * The config options listed for this class are options which may appear in each
5200 * individual column definition.
5201 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5203 * @param {Object} config An Array of column config objects. See this class's
5204 * config objects for details.
5206 Roo.grid.ColumnModel = function(config){
5208 * The config passed into the constructor
5210 this.config = config;
5213 // if no id, create one
5214 // if the column does not have a dataIndex mapping,
5215 // map it to the order it is in the config
5216 for(var i = 0, len = config.length; i < len; i++){
5218 if(typeof c.dataIndex == "undefined"){
5221 if(typeof c.renderer == "string"){
5222 c.renderer = Roo.util.Format[c.renderer];
5224 if(typeof c.id == "undefined"){
5227 if(c.editor && c.editor.xtype){
5228 c.editor = Roo.factory(c.editor, Roo.grid);
5230 if(c.editor && c.editor.isFormField){
5231 c.editor = new Roo.grid.GridEditor(c.editor);
5233 this.lookup[c.id] = c;
5237 * The width of columns which have no width specified (defaults to 100)
5240 this.defaultWidth = 100;
5243 * Default sortable of columns which have no sortable specified (defaults to false)
5246 this.defaultSortable = false;
5250 * @event widthchange
5251 * Fires when the width of a column changes.
5252 * @param {ColumnModel} this
5253 * @param {Number} columnIndex The column index
5254 * @param {Number} newWidth The new width
5256 "widthchange": true,
5258 * @event headerchange
5259 * Fires when the text of a header changes.
5260 * @param {ColumnModel} this
5261 * @param {Number} columnIndex The column index
5262 * @param {Number} newText The new header text
5264 "headerchange": true,
5266 * @event hiddenchange
5267 * Fires when a column is hidden or "unhidden".
5268 * @param {ColumnModel} this
5269 * @param {Number} columnIndex The column index
5270 * @param {Boolean} hidden true if hidden, false otherwise
5272 "hiddenchange": true,
5274 * @event columnmoved
5275 * Fires when a column is moved.
5276 * @param {ColumnModel} this
5277 * @param {Number} oldIndex
5278 * @param {Number} newIndex
5280 "columnmoved" : true,
5282 * @event columlockchange
5283 * Fires when a column's locked state is changed
5284 * @param {ColumnModel} this
5285 * @param {Number} colIndex
5286 * @param {Boolean} locked true if locked
5288 "columnlockchange" : true
5290 Roo.grid.ColumnModel.superclass.constructor.call(this);
5292 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5294 * @cfg {String} header The header text to display in the Grid view.
5297 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5298 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5299 * specified, the column's index is used as an index into the Record's data Array.
5302 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5303 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5306 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5307 * Defaults to the value of the {@link #defaultSortable} property.
5308 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5311 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5314 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5317 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5320 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5323 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5324 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5325 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5326 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5329 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5332 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5335 * @cfg {String} cursor (Optional)
5338 * @cfg {String} tooltip (Optional)
5341 * @cfg {Number} xs (Optional)
5344 * @cfg {Number} sm (Optional)
5347 * @cfg {Number} md (Optional)
5350 * @cfg {Number} lg (Optional)
5353 * Returns the id of the column at the specified index.
5354 * @param {Number} index The column index
5355 * @return {String} the id
5357 getColumnId : function(index){
5358 return this.config[index].id;
5362 * Returns the column for a specified id.
5363 * @param {String} id The column id
5364 * @return {Object} the column
5366 getColumnById : function(id){
5367 return this.lookup[id];
5372 * Returns the column for a specified dataIndex.
5373 * @param {String} dataIndex The column dataIndex
5374 * @return {Object|Boolean} the column or false if not found
5376 getColumnByDataIndex: function(dataIndex){
5377 var index = this.findColumnIndex(dataIndex);
5378 return index > -1 ? this.config[index] : false;
5382 * Returns the index for a specified column id.
5383 * @param {String} id The column id
5384 * @return {Number} the index, or -1 if not found
5386 getIndexById : function(id){
5387 for(var i = 0, len = this.config.length; i < len; i++){
5388 if(this.config[i].id == id){
5396 * Returns the index for a specified column dataIndex.
5397 * @param {String} dataIndex The column dataIndex
5398 * @return {Number} the index, or -1 if not found
5401 findColumnIndex : function(dataIndex){
5402 for(var i = 0, len = this.config.length; i < len; i++){
5403 if(this.config[i].dataIndex == dataIndex){
5411 moveColumn : function(oldIndex, newIndex){
5412 var c = this.config[oldIndex];
5413 this.config.splice(oldIndex, 1);
5414 this.config.splice(newIndex, 0, c);
5415 this.dataMap = null;
5416 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5419 isLocked : function(colIndex){
5420 return this.config[colIndex].locked === true;
5423 setLocked : function(colIndex, value, suppressEvent){
5424 if(this.isLocked(colIndex) == value){
5427 this.config[colIndex].locked = value;
5429 this.fireEvent("columnlockchange", this, colIndex, value);
5433 getTotalLockedWidth : function(){
5435 for(var i = 0; i < this.config.length; i++){
5436 if(this.isLocked(i) && !this.isHidden(i)){
5437 this.totalWidth += this.getColumnWidth(i);
5443 getLockedCount : function(){
5444 for(var i = 0, len = this.config.length; i < len; i++){
5445 if(!this.isLocked(i)){
5450 return this.config.length;
5454 * Returns the number of columns.
5457 getColumnCount : function(visibleOnly){
5458 if(visibleOnly === true){
5460 for(var i = 0, len = this.config.length; i < len; i++){
5461 if(!this.isHidden(i)){
5467 return this.config.length;
5471 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5472 * @param {Function} fn
5473 * @param {Object} scope (optional)
5474 * @return {Array} result
5476 getColumnsBy : function(fn, scope){
5478 for(var i = 0, len = this.config.length; i < len; i++){
5479 var c = this.config[i];
5480 if(fn.call(scope||this, c, i) === true){
5488 * Returns true if the specified column is sortable.
5489 * @param {Number} col The column index
5492 isSortable : function(col){
5493 if(typeof this.config[col].sortable == "undefined"){
5494 return this.defaultSortable;
5496 return this.config[col].sortable;
5500 * Returns the rendering (formatting) function defined for the column.
5501 * @param {Number} col The column index.
5502 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5504 getRenderer : function(col){
5505 if(!this.config[col].renderer){
5506 return Roo.grid.ColumnModel.defaultRenderer;
5508 return this.config[col].renderer;
5512 * Sets the rendering (formatting) function for a column.
5513 * @param {Number} col The column index
5514 * @param {Function} fn The function to use to process the cell's raw data
5515 * to return HTML markup for the grid view. The render function is called with
5516 * the following parameters:<ul>
5517 * <li>Data value.</li>
5518 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5519 * <li>css A CSS style string to apply to the table cell.</li>
5520 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5521 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5522 * <li>Row index</li>
5523 * <li>Column index</li>
5524 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5526 setRenderer : function(col, fn){
5527 this.config[col].renderer = fn;
5531 * Returns the width for the specified column.
5532 * @param {Number} col The column index
5535 getColumnWidth : function(col){
5536 return this.config[col].width * 1 || this.defaultWidth;
5540 * Sets the width for a column.
5541 * @param {Number} col The column index
5542 * @param {Number} width The new width
5544 setColumnWidth : function(col, width, suppressEvent){
5545 this.config[col].width = width;
5546 this.totalWidth = null;
5548 this.fireEvent("widthchange", this, col, width);
5553 * Returns the total width of all columns.
5554 * @param {Boolean} includeHidden True to include hidden column widths
5557 getTotalWidth : function(includeHidden){
5558 if(!this.totalWidth){
5559 this.totalWidth = 0;
5560 for(var i = 0, len = this.config.length; i < len; i++){
5561 if(includeHidden || !this.isHidden(i)){
5562 this.totalWidth += this.getColumnWidth(i);
5566 return this.totalWidth;
5570 * Returns the header for the specified column.
5571 * @param {Number} col The column index
5574 getColumnHeader : function(col){
5575 return this.config[col].header;
5579 * Sets the header for a column.
5580 * @param {Number} col The column index
5581 * @param {String} header The new header
5583 setColumnHeader : function(col, header){
5584 this.config[col].header = header;
5585 this.fireEvent("headerchange", this, col, header);
5589 * Returns the tooltip for the specified column.
5590 * @param {Number} col The column index
5593 getColumnTooltip : function(col){
5594 return this.config[col].tooltip;
5597 * Sets the tooltip for a column.
5598 * @param {Number} col The column index
5599 * @param {String} tooltip The new tooltip
5601 setColumnTooltip : function(col, tooltip){
5602 this.config[col].tooltip = tooltip;
5606 * Returns the dataIndex for the specified column.
5607 * @param {Number} col The column index
5610 getDataIndex : function(col){
5611 return this.config[col].dataIndex;
5615 * Sets the dataIndex for a column.
5616 * @param {Number} col The column index
5617 * @param {Number} dataIndex The new dataIndex
5619 setDataIndex : function(col, dataIndex){
5620 this.config[col].dataIndex = dataIndex;
5626 * Returns true if the cell is editable.
5627 * @param {Number} colIndex The column index
5628 * @param {Number} rowIndex The row index - this is nto actually used..?
5631 isCellEditable : function(colIndex, rowIndex){
5632 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5636 * Returns the editor defined for the cell/column.
5637 * return false or null to disable editing.
5638 * @param {Number} colIndex The column index
5639 * @param {Number} rowIndex The row index
5642 getCellEditor : function(colIndex, rowIndex){
5643 return this.config[colIndex].editor;
5647 * Sets if a column is editable.
5648 * @param {Number} col The column index
5649 * @param {Boolean} editable True if the column is editable
5651 setEditable : function(col, editable){
5652 this.config[col].editable = editable;
5657 * Returns true if the column is hidden.
5658 * @param {Number} colIndex The column index
5661 isHidden : function(colIndex){
5662 return this.config[colIndex].hidden;
5667 * Returns true if the column width cannot be changed
5669 isFixed : function(colIndex){
5670 return this.config[colIndex].fixed;
5674 * Returns true if the column can be resized
5677 isResizable : function(colIndex){
5678 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5681 * Sets if a column is hidden.
5682 * @param {Number} colIndex The column index
5683 * @param {Boolean} hidden True if the column is hidden
5685 setHidden : function(colIndex, hidden){
5686 this.config[colIndex].hidden = hidden;
5687 this.totalWidth = null;
5688 this.fireEvent("hiddenchange", this, colIndex, hidden);
5692 * Sets the editor for a column.
5693 * @param {Number} col The column index
5694 * @param {Object} editor The editor object
5696 setEditor : function(col, editor){
5697 this.config[col].editor = editor;
5701 Roo.grid.ColumnModel.defaultRenderer = function(value)
5703 if(typeof value == "object") {
5706 if(typeof value == "string" && value.length < 1){
5710 return String.format("{0}", value);
5713 // Alias for backwards compatibility
5714 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5717 * Ext JS Library 1.1.1
5718 * Copyright(c) 2006-2007, Ext JS, LLC.
5720 * Originally Released Under LGPL - original licence link has changed is not relivant.
5723 * <script type="text/javascript">
5727 * @class Roo.LoadMask
5728 * A simple utility class for generically masking elements while loading data. If the element being masked has
5729 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5730 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5731 * element's UpdateManager load indicator and will be destroyed after the initial load.
5733 * Create a new LoadMask
5734 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5735 * @param {Object} config The config object
5737 Roo.LoadMask = function(el, config){
5738 this.el = Roo.get(el);
5739 Roo.apply(this, config);
5741 this.store.on('beforeload', this.onBeforeLoad, this);
5742 this.store.on('load', this.onLoad, this);
5743 this.store.on('loadexception', this.onLoadException, this);
5744 this.removeMask = false;
5746 var um = this.el.getUpdateManager();
5747 um.showLoadIndicator = false; // disable the default indicator
5748 um.on('beforeupdate', this.onBeforeLoad, this);
5749 um.on('update', this.onLoad, this);
5750 um.on('failure', this.onLoad, this);
5751 this.removeMask = true;
5755 Roo.LoadMask.prototype = {
5757 * @cfg {Boolean} removeMask
5758 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5759 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5763 * The text to display in a centered loading message box (defaults to 'Loading...')
5767 * @cfg {String} msgCls
5768 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5770 msgCls : 'x-mask-loading',
5773 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5779 * Disables the mask to prevent it from being displayed
5781 disable : function(){
5782 this.disabled = true;
5786 * Enables the mask so that it can be displayed
5788 enable : function(){
5789 this.disabled = false;
5792 onLoadException : function()
5796 if (typeof(arguments[3]) != 'undefined') {
5797 Roo.MessageBox.alert("Error loading",arguments[3]);
5801 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5802 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5809 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5814 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5818 onBeforeLoad : function(){
5820 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5825 destroy : function(){
5827 this.store.un('beforeload', this.onBeforeLoad, this);
5828 this.store.un('load', this.onLoad, this);
5829 this.store.un('loadexception', this.onLoadException, this);
5831 var um = this.el.getUpdateManager();
5832 um.un('beforeupdate', this.onBeforeLoad, this);
5833 um.un('update', this.onLoad, this);
5834 um.un('failure', this.onLoad, this);
5845 * @class Roo.bootstrap.Table
5846 * @extends Roo.bootstrap.Component
5847 * Bootstrap Table class
5848 * @cfg {String} cls table class
5849 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5850 * @cfg {String} bgcolor Specifies the background color for a table
5851 * @cfg {Number} border Specifies whether the table cells should have borders or not
5852 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5853 * @cfg {Number} cellspacing Specifies the space between cells
5854 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5855 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5856 * @cfg {String} sortable Specifies that the table should be sortable
5857 * @cfg {String} summary Specifies a summary of the content of a table
5858 * @cfg {Number} width Specifies the width of a table
5859 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5861 * @cfg {boolean} striped Should the rows be alternative striped
5862 * @cfg {boolean} bordered Add borders to the table
5863 * @cfg {boolean} hover Add hover highlighting
5864 * @cfg {boolean} condensed Format condensed
5865 * @cfg {boolean} responsive Format condensed
5866 * @cfg {Boolean} loadMask (true|false) default false
5867 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5868 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5869 * @cfg {Boolean} rowSelection (true|false) default false
5870 * @cfg {Boolean} cellSelection (true|false) default false
5871 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5872 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5873 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5877 * Create a new Table
5878 * @param {Object} config The config object
5881 Roo.bootstrap.Table = function(config){
5882 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5887 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5888 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5889 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5890 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5892 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5894 this.sm.grid = this;
5895 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5896 this.sm = this.selModel;
5897 this.sm.xmodule = this.xmodule || false;
5900 if (this.cm && typeof(this.cm.config) == 'undefined') {
5901 this.colModel = new Roo.grid.ColumnModel(this.cm);
5902 this.cm = this.colModel;
5903 this.cm.xmodule = this.xmodule || false;
5906 this.store= Roo.factory(this.store, Roo.data);
5907 this.ds = this.store;
5908 this.ds.xmodule = this.xmodule || false;
5911 if (this.footer && this.store) {
5912 this.footer.dataSource = this.ds;
5913 this.footer = Roo.factory(this.footer);
5920 * Fires when a cell is clicked
5921 * @param {Roo.bootstrap.Table} this
5922 * @param {Roo.Element} el
5923 * @param {Number} rowIndex
5924 * @param {Number} columnIndex
5925 * @param {Roo.EventObject} e
5929 * @event celldblclick
5930 * Fires when a cell is double clicked
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Number} columnIndex
5935 * @param {Roo.EventObject} e
5937 "celldblclick" : true,
5940 * Fires when a row is clicked
5941 * @param {Roo.bootstrap.Table} this
5942 * @param {Roo.Element} el
5943 * @param {Number} rowIndex
5944 * @param {Roo.EventObject} e
5948 * @event rowdblclick
5949 * Fires when a row is double clicked
5950 * @param {Roo.bootstrap.Table} this
5951 * @param {Roo.Element} el
5952 * @param {Number} rowIndex
5953 * @param {Roo.EventObject} e
5955 "rowdblclick" : true,
5958 * Fires when a mouseover occur
5959 * @param {Roo.bootstrap.Table} this
5960 * @param {Roo.Element} el
5961 * @param {Number} rowIndex
5962 * @param {Number} columnIndex
5963 * @param {Roo.EventObject} e
5968 * Fires when a mouseout occur
5969 * @param {Roo.bootstrap.Table} this
5970 * @param {Roo.Element} el
5971 * @param {Number} rowIndex
5972 * @param {Number} columnIndex
5973 * @param {Roo.EventObject} e
5978 * Fires when a row is rendered, so you can change add a style to it.
5979 * @param {Roo.bootstrap.Table} this
5980 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5984 * @event rowsrendered
5985 * Fires when all the rows have been rendered
5986 * @param {Roo.bootstrap.Table} this
5988 'rowsrendered' : true,
5990 * @event contextmenu
5991 * The raw contextmenu event for the entire grid.
5992 * @param {Roo.EventObject} e
5994 "contextmenu" : true,
5996 * @event rowcontextmenu
5997 * Fires when a row is right clicked
5998 * @param {Roo.bootstrap.Table} this
5999 * @param {Number} rowIndex
6000 * @param {Roo.EventObject} e
6002 "rowcontextmenu" : true,
6004 * @event cellcontextmenu
6005 * Fires when a cell is right clicked
6006 * @param {Roo.bootstrap.Table} this
6007 * @param {Number} rowIndex
6008 * @param {Number} cellIndex
6009 * @param {Roo.EventObject} e
6011 "cellcontextmenu" : true,
6013 * @event headercontextmenu
6014 * Fires when a header is right clicked
6015 * @param {Roo.bootstrap.Table} this
6016 * @param {Number} columnIndex
6017 * @param {Roo.EventObject} e
6019 "headercontextmenu" : true
6023 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6049 rowSelection : false,
6050 cellSelection : false,
6053 // Roo.Element - the tbody
6055 // Roo.Element - thead element
6058 container: false, // used by gridpanel...
6064 getAutoCreate : function()
6066 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6073 if (this.scrollBody) {
6074 cfg.cls += ' table-body-fixed';
6077 cfg.cls += ' table-striped';
6081 cfg.cls += ' table-hover';
6083 if (this.bordered) {
6084 cfg.cls += ' table-bordered';
6086 if (this.condensed) {
6087 cfg.cls += ' table-condensed';
6089 if (this.responsive) {
6090 cfg.cls += ' table-responsive';
6094 cfg.cls+= ' ' +this.cls;
6097 // this lot should be simplifed...
6100 cfg.align=this.align;
6103 cfg.bgcolor=this.bgcolor;
6106 cfg.border=this.border;
6108 if (this.cellpadding) {
6109 cfg.cellpadding=this.cellpadding;
6111 if (this.cellspacing) {
6112 cfg.cellspacing=this.cellspacing;
6115 cfg.frame=this.frame;
6118 cfg.rules=this.rules;
6120 if (this.sortable) {
6121 cfg.sortable=this.sortable;
6124 cfg.summary=this.summary;
6127 cfg.width=this.width;
6130 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6133 if(this.store || this.cm){
6134 if(this.headerShow){
6135 cfg.cn.push(this.renderHeader());
6138 cfg.cn.push(this.renderBody());
6140 if(this.footerShow){
6141 cfg.cn.push(this.renderFooter());
6143 // where does this come from?
6144 //cfg.cls+= ' TableGrid';
6147 return { cn : [ cfg ] };
6150 initEvents : function()
6152 if(!this.store || !this.cm){
6155 if (this.selModel) {
6156 this.selModel.initEvents();
6160 //Roo.log('initEvents with ds!!!!');
6162 this.mainBody = this.el.select('tbody', true).first();
6163 this.mainHead = this.el.select('thead', true).first();
6170 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6171 e.on('click', _this.sort, _this);
6174 this.mainBody.on("click", this.onClick, this);
6175 this.mainBody.on("dblclick", this.onDblClick, this);
6177 // why is this done????? = it breaks dialogs??
6178 //this.parent().el.setStyle('position', 'relative');
6182 this.footer.parentId = this.id;
6183 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6186 this.el.select('tfoot tr td').first().addClass('hide');
6190 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6192 this.store.on('load', this.onLoad, this);
6193 this.store.on('beforeload', this.onBeforeLoad, this);
6194 this.store.on('update', this.onUpdate, this);
6195 this.store.on('add', this.onAdd, this);
6196 this.store.on("clear", this.clear, this);
6198 this.el.on("contextmenu", this.onContextMenu, this);
6200 this.mainBody.on('scroll', this.onBodyScroll, this);
6202 this.cm.on("headerchange", this.onHeaderChange, this);
6204 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6208 onContextMenu : function(e, t)
6210 this.processEvent("contextmenu", e);
6213 processEvent : function(name, e)
6215 if (name != 'touchstart' ) {
6216 this.fireEvent(name, e);
6219 var t = e.getTarget();
6221 var cell = Roo.get(t);
6227 if(cell.findParent('tfoot', false, true)){
6231 if(cell.findParent('thead', false, true)){
6233 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6234 cell = Roo.get(t).findParent('th', false, true);
6236 Roo.log("failed to find th in thead?");
6237 Roo.log(e.getTarget());
6242 var cellIndex = cell.dom.cellIndex;
6244 var ename = name == 'touchstart' ? 'click' : name;
6245 this.fireEvent("header" + ename, this, cellIndex, e);
6250 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6251 cell = Roo.get(t).findParent('td', false, true);
6253 Roo.log("failed to find th in tbody?");
6254 Roo.log(e.getTarget());
6259 var row = cell.findParent('tr', false, true);
6260 var cellIndex = cell.dom.cellIndex;
6261 var rowIndex = row.dom.rowIndex - 1;
6265 this.fireEvent("row" + name, this, rowIndex, e);
6269 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6275 onMouseover : function(e, el)
6277 var cell = Roo.get(el);
6283 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6284 cell = cell.findParent('td', false, true);
6287 var row = cell.findParent('tr', false, true);
6288 var cellIndex = cell.dom.cellIndex;
6289 var rowIndex = row.dom.rowIndex - 1; // start from 0
6291 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6295 onMouseout : function(e, el)
6297 var cell = Roo.get(el);
6303 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6304 cell = cell.findParent('td', false, true);
6307 var row = cell.findParent('tr', false, true);
6308 var cellIndex = cell.dom.cellIndex;
6309 var rowIndex = row.dom.rowIndex - 1; // start from 0
6311 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6315 onClick : function(e, el)
6317 var cell = Roo.get(el);
6319 if(!cell || (!this.cellSelection && !this.rowSelection)){
6323 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6324 cell = cell.findParent('td', false, true);
6327 if(!cell || typeof(cell) == 'undefined'){
6331 var row = cell.findParent('tr', false, true);
6333 if(!row || typeof(row) == 'undefined'){
6337 var cellIndex = cell.dom.cellIndex;
6338 var rowIndex = this.getRowIndex(row);
6340 // why??? - should these not be based on SelectionModel?
6341 if(this.cellSelection){
6342 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6345 if(this.rowSelection){
6346 this.fireEvent('rowclick', this, row, rowIndex, e);
6352 onDblClick : function(e,el)
6354 var cell = Roo.get(el);
6356 if(!cell || (!this.cellSelection && !this.rowSelection)){
6360 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6361 cell = cell.findParent('td', false, true);
6364 if(!cell || typeof(cell) == 'undefined'){
6368 var row = cell.findParent('tr', false, true);
6370 if(!row || typeof(row) == 'undefined'){
6374 var cellIndex = cell.dom.cellIndex;
6375 var rowIndex = this.getRowIndex(row);
6377 if(this.cellSelection){
6378 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6381 if(this.rowSelection){
6382 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6386 sort : function(e,el)
6388 var col = Roo.get(el);
6390 if(!col.hasClass('sortable')){
6394 var sort = col.attr('sort');
6397 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6401 this.store.sortInfo = {field : sort, direction : dir};
6404 Roo.log("calling footer first");
6405 this.footer.onClick('first');
6408 this.store.load({ params : { start : 0 } });
6412 renderHeader : function()
6420 this.totalWidth = 0;
6422 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6424 var config = cm.config[i];
6428 cls : 'x-hcol-' + i,
6430 html: cm.getColumnHeader(i)
6435 if(typeof(config.sortable) != 'undefined' && config.sortable){
6437 c.html = '<i class="glyphicon"></i>' + c.html;
6440 if(typeof(config.lgHeader) != 'undefined'){
6441 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6444 if(typeof(config.mdHeader) != 'undefined'){
6445 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6448 if(typeof(config.smHeader) != 'undefined'){
6449 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6452 if(typeof(config.xsHeader) != 'undefined'){
6453 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6460 if(typeof(config.tooltip) != 'undefined'){
6461 c.tooltip = config.tooltip;
6464 if(typeof(config.colspan) != 'undefined'){
6465 c.colspan = config.colspan;
6468 if(typeof(config.hidden) != 'undefined' && config.hidden){
6469 c.style += ' display:none;';
6472 if(typeof(config.dataIndex) != 'undefined'){
6473 c.sort = config.dataIndex;
6478 if(typeof(config.align) != 'undefined' && config.align.length){
6479 c.style += ' text-align:' + config.align + ';';
6482 if(typeof(config.width) != 'undefined'){
6483 c.style += ' width:' + config.width + 'px;';
6484 this.totalWidth += config.width;
6486 this.totalWidth += 100; // assume minimum of 100 per column?
6489 if(typeof(config.cls) != 'undefined'){
6490 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6493 ['xs','sm','md','lg'].map(function(size){
6495 if(typeof(config[size]) == 'undefined'){
6499 if (!config[size]) { // 0 = hidden
6500 c.cls += ' hidden-' + size;
6504 c.cls += ' col-' + size + '-' + config[size];
6514 renderBody : function()
6524 colspan : this.cm.getColumnCount()
6534 renderFooter : function()
6544 colspan : this.cm.getColumnCount()
6558 // Roo.log('ds onload');
6563 var ds = this.store;
6565 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6566 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6567 if (_this.store.sortInfo) {
6569 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6570 e.select('i', true).addClass(['glyphicon-arrow-up']);
6573 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6574 e.select('i', true).addClass(['glyphicon-arrow-down']);
6579 var tbody = this.mainBody;
6581 if(ds.getCount() > 0){
6582 ds.data.each(function(d,rowIndex){
6583 var row = this.renderRow(cm, ds, rowIndex);
6585 tbody.createChild(row);
6589 if(row.cellObjects.length){
6590 Roo.each(row.cellObjects, function(r){
6591 _this.renderCellObject(r);
6598 Roo.each(this.el.select('tbody td', true).elements, function(e){
6599 e.on('mouseover', _this.onMouseover, _this);
6602 Roo.each(this.el.select('tbody td', true).elements, function(e){
6603 e.on('mouseout', _this.onMouseout, _this);
6605 this.fireEvent('rowsrendered', this);
6606 //if(this.loadMask){
6607 // this.maskEl.hide();
6614 onUpdate : function(ds,record)
6616 this.refreshRow(record);
6620 onRemove : function(ds, record, index, isUpdate){
6621 if(isUpdate !== true){
6622 this.fireEvent("beforerowremoved", this, index, record);
6624 var bt = this.mainBody.dom;
6626 var rows = this.el.select('tbody > tr', true).elements;
6628 if(typeof(rows[index]) != 'undefined'){
6629 bt.removeChild(rows[index].dom);
6632 // if(bt.rows[index]){
6633 // bt.removeChild(bt.rows[index]);
6636 if(isUpdate !== true){
6637 //this.stripeRows(index);
6638 //this.syncRowHeights(index, index);
6640 this.fireEvent("rowremoved", this, index, record);
6644 onAdd : function(ds, records, rowIndex)
6646 //Roo.log('on Add called');
6647 // - note this does not handle multiple adding very well..
6648 var bt = this.mainBody.dom;
6649 for (var i =0 ; i < records.length;i++) {
6650 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6651 //Roo.log(records[i]);
6652 //Roo.log(this.store.getAt(rowIndex+i));
6653 this.insertRow(this.store, rowIndex + i, false);
6660 refreshRow : function(record){
6661 var ds = this.store, index;
6662 if(typeof record == 'number'){
6664 record = ds.getAt(index);
6666 index = ds.indexOf(record);
6668 this.insertRow(ds, index, true);
6670 this.onRemove(ds, record, index+1, true);
6672 //this.syncRowHeights(index, index);
6674 this.fireEvent("rowupdated", this, index, record);
6677 insertRow : function(dm, rowIndex, isUpdate){
6680 this.fireEvent("beforerowsinserted", this, rowIndex);
6682 //var s = this.getScrollState();
6683 var row = this.renderRow(this.cm, this.store, rowIndex);
6684 // insert before rowIndex..
6685 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6689 if(row.cellObjects.length){
6690 Roo.each(row.cellObjects, function(r){
6691 _this.renderCellObject(r);
6696 this.fireEvent("rowsinserted", this, rowIndex);
6697 //this.syncRowHeights(firstRow, lastRow);
6698 //this.stripeRows(firstRow);
6705 getRowDom : function(rowIndex)
6707 var rows = this.el.select('tbody > tr', true).elements;
6709 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6712 // returns the object tree for a tr..
6715 renderRow : function(cm, ds, rowIndex)
6717 var d = ds.getAt(rowIndex);
6721 cls : 'x-row-' + rowIndex,
6725 var cellObjects = [];
6727 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6728 var config = cm.config[i];
6730 var renderer = cm.getRenderer(i);
6734 if(typeof(renderer) !== 'undefined'){
6735 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6737 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6738 // and are rendered into the cells after the row is rendered - using the id for the element.
6740 if(typeof(value) === 'object'){
6750 rowIndex : rowIndex,
6755 this.fireEvent('rowclass', this, rowcfg);
6759 cls : rowcfg.rowClass + ' x-col-' + i,
6761 html: (typeof(value) === 'object') ? '' : value
6768 if(typeof(config.colspan) != 'undefined'){
6769 td.colspan = config.colspan;
6772 if(typeof(config.hidden) != 'undefined' && config.hidden){
6773 td.style += ' display:none;';
6776 if(typeof(config.align) != 'undefined' && config.align.length){
6777 td.style += ' text-align:' + config.align + ';';
6780 if(typeof(config.width) != 'undefined'){
6781 td.style += ' width:' + config.width + 'px;';
6784 if(typeof(config.cursor) != 'undefined'){
6785 td.style += ' cursor:' + config.cursor + ';';
6788 if(typeof(config.cls) != 'undefined'){
6789 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6792 ['xs','sm','md','lg'].map(function(size){
6794 if(typeof(config[size]) == 'undefined'){
6798 if (!config[size]) { // 0 = hidden
6799 td.cls += ' hidden-' + size;
6803 td.cls += ' col-' + size + '-' + config[size];
6811 row.cellObjects = cellObjects;
6819 onBeforeLoad : function()
6821 //Roo.log('ds onBeforeLoad');
6825 //if(this.loadMask){
6826 // this.maskEl.show();
6834 this.el.select('tbody', true).first().dom.innerHTML = '';
6837 * Show or hide a row.
6838 * @param {Number} rowIndex to show or hide
6839 * @param {Boolean} state hide
6841 setRowVisibility : function(rowIndex, state)
6843 var bt = this.mainBody.dom;
6845 var rows = this.el.select('tbody > tr', true).elements;
6847 if(typeof(rows[rowIndex]) == 'undefined'){
6850 rows[rowIndex].dom.style.display = state ? '' : 'none';
6854 getSelectionModel : function(){
6856 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6858 return this.selModel;
6861 * Render the Roo.bootstrap object from renderder
6863 renderCellObject : function(r)
6867 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6869 var t = r.cfg.render(r.container);
6872 Roo.each(r.cfg.cn, function(c){
6874 container: t.getChildContainer(),
6877 _this.renderCellObject(child);
6882 getRowIndex : function(row)
6886 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6897 * Returns the grid's underlying element = used by panel.Grid
6898 * @return {Element} The element
6900 getGridEl : function(){
6904 * Forces a resize - used by panel.Grid
6905 * @return {Element} The element
6907 autoSize : function()
6909 //var ctr = Roo.get(this.container.dom.parentElement);
6910 var ctr = Roo.get(this.el.dom);
6912 var thd = this.getGridEl().select('thead',true).first();
6913 var tbd = this.getGridEl().select('tbody', true).first();
6914 var tfd = this.getGridEl().select('tfoot', true).first();
6916 var cw = ctr.getWidth();
6920 tbd.setSize(ctr.getWidth(),
6921 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6923 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6926 cw = Math.max(cw, this.totalWidth);
6927 this.getGridEl().select('tr',true).setWidth(cw);
6928 // resize 'expandable coloumn?
6930 return; // we doe not have a view in this design..
6933 onBodyScroll: function()
6935 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6937 this.mainHead.setStyle({
6938 'position' : 'relative',
6939 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6945 var scrollHeight = this.mainBody.dom.scrollHeight;
6947 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6949 var height = this.mainBody.getHeight();
6951 if(scrollHeight - height == scrollTop) {
6953 var total = this.ds.getTotalCount();
6955 if(this.footer.cursor + this.footer.pageSize < total){
6957 this.footer.ds.load({
6959 start : this.footer.cursor + this.footer.pageSize,
6960 limit : this.footer.pageSize
6970 onHeaderChange : function()
6972 var header = this.renderHeader();
6973 var table = this.el.select('table', true).first();
6975 this.mainHead.remove();
6976 this.mainHead = table.createChild(header, this.mainBody, false);
6979 onHiddenChange : function(colModel, colIndex, hidden)
6981 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6982 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6984 this.CSS.updateRule(thSelector, "display", "");
6985 this.CSS.updateRule(tdSelector, "display", "");
6988 this.CSS.updateRule(thSelector, "display", "none");
6989 this.CSS.updateRule(tdSelector, "display", "none");
6992 this.onHeaderChange();
7009 * @class Roo.bootstrap.TableCell
7010 * @extends Roo.bootstrap.Component
7011 * Bootstrap TableCell class
7012 * @cfg {String} html cell contain text
7013 * @cfg {String} cls cell class
7014 * @cfg {String} tag cell tag (td|th) default td
7015 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7016 * @cfg {String} align Aligns the content in a cell
7017 * @cfg {String} axis Categorizes cells
7018 * @cfg {String} bgcolor Specifies the background color of a cell
7019 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7020 * @cfg {Number} colspan Specifies the number of columns a cell should span
7021 * @cfg {String} headers Specifies one or more header cells a cell is related to
7022 * @cfg {Number} height Sets the height of a cell
7023 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7024 * @cfg {Number} rowspan Sets the number of rows a cell should span
7025 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7026 * @cfg {String} valign Vertical aligns the content in a cell
7027 * @cfg {Number} width Specifies the width of a cell
7030 * Create a new TableCell
7031 * @param {Object} config The config object
7034 Roo.bootstrap.TableCell = function(config){
7035 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7038 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7058 getAutoCreate : function(){
7059 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7079 cfg.align=this.align
7085 cfg.bgcolor=this.bgcolor
7088 cfg.charoff=this.charoff
7091 cfg.colspan=this.colspan
7094 cfg.headers=this.headers
7097 cfg.height=this.height
7100 cfg.nowrap=this.nowrap
7103 cfg.rowspan=this.rowspan
7106 cfg.scope=this.scope
7109 cfg.valign=this.valign
7112 cfg.width=this.width
7131 * @class Roo.bootstrap.TableRow
7132 * @extends Roo.bootstrap.Component
7133 * Bootstrap TableRow class
7134 * @cfg {String} cls row class
7135 * @cfg {String} align Aligns the content in a table row
7136 * @cfg {String} bgcolor Specifies a background color for a table row
7137 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7138 * @cfg {String} valign Vertical aligns the content in a table row
7141 * Create a new TableRow
7142 * @param {Object} config The config object
7145 Roo.bootstrap.TableRow = function(config){
7146 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7149 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7157 getAutoCreate : function(){
7158 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7168 cfg.align = this.align;
7171 cfg.bgcolor = this.bgcolor;
7174 cfg.charoff = this.charoff;
7177 cfg.valign = this.valign;
7195 * @class Roo.bootstrap.TableBody
7196 * @extends Roo.bootstrap.Component
7197 * Bootstrap TableBody class
7198 * @cfg {String} cls element class
7199 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7200 * @cfg {String} align Aligns the content inside the element
7201 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7202 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7205 * Create a new TableBody
7206 * @param {Object} config The config object
7209 Roo.bootstrap.TableBody = function(config){
7210 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7213 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7221 getAutoCreate : function(){
7222 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7236 cfg.align = this.align;
7239 cfg.charoff = this.charoff;
7242 cfg.valign = this.valign;
7249 // initEvents : function()
7256 // this.store = Roo.factory(this.store, Roo.data);
7257 // this.store.on('load', this.onLoad, this);
7259 // this.store.load();
7263 // onLoad: function ()
7265 // this.fireEvent('load', this);
7275 * Ext JS Library 1.1.1
7276 * Copyright(c) 2006-2007, Ext JS, LLC.
7278 * Originally Released Under LGPL - original licence link has changed is not relivant.
7281 * <script type="text/javascript">
7284 // as we use this in bootstrap.
7285 Roo.namespace('Roo.form');
7287 * @class Roo.form.Action
7288 * Internal Class used to handle form actions
7290 * @param {Roo.form.BasicForm} el The form element or its id
7291 * @param {Object} config Configuration options
7296 // define the action interface
7297 Roo.form.Action = function(form, options){
7299 this.options = options || {};
7302 * Client Validation Failed
7305 Roo.form.Action.CLIENT_INVALID = 'client';
7307 * Server Validation Failed
7310 Roo.form.Action.SERVER_INVALID = 'server';
7312 * Connect to Server Failed
7315 Roo.form.Action.CONNECT_FAILURE = 'connect';
7317 * Reading Data from Server Failed
7320 Roo.form.Action.LOAD_FAILURE = 'load';
7322 Roo.form.Action.prototype = {
7324 failureType : undefined,
7325 response : undefined,
7329 run : function(options){
7334 success : function(response){
7339 handleResponse : function(response){
7343 // default connection failure
7344 failure : function(response){
7346 this.response = response;
7347 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7348 this.form.afterAction(this, false);
7351 processResponse : function(response){
7352 this.response = response;
7353 if(!response.responseText){
7356 this.result = this.handleResponse(response);
7360 // utility functions used internally
7361 getUrl : function(appendParams){
7362 var url = this.options.url || this.form.url || this.form.el.dom.action;
7364 var p = this.getParams();
7366 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7372 getMethod : function(){
7373 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7376 getParams : function(){
7377 var bp = this.form.baseParams;
7378 var p = this.options.params;
7380 if(typeof p == "object"){
7381 p = Roo.urlEncode(Roo.applyIf(p, bp));
7382 }else if(typeof p == 'string' && bp){
7383 p += '&' + Roo.urlEncode(bp);
7386 p = Roo.urlEncode(bp);
7391 createCallback : function(){
7393 success: this.success,
7394 failure: this.failure,
7396 timeout: (this.form.timeout*1000),
7397 upload: this.form.fileUpload ? this.success : undefined
7402 Roo.form.Action.Submit = function(form, options){
7403 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7406 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7409 haveProgress : false,
7410 uploadComplete : false,
7412 // uploadProgress indicator.
7413 uploadProgress : function()
7415 if (!this.form.progressUrl) {
7419 if (!this.haveProgress) {
7420 Roo.MessageBox.progress("Uploading", "Uploading");
7422 if (this.uploadComplete) {
7423 Roo.MessageBox.hide();
7427 this.haveProgress = true;
7429 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7431 var c = new Roo.data.Connection();
7433 url : this.form.progressUrl,
7438 success : function(req){
7439 //console.log(data);
7443 rdata = Roo.decode(req.responseText)
7445 Roo.log("Invalid data from server..");
7449 if (!rdata || !rdata.success) {
7451 Roo.MessageBox.alert(Roo.encode(rdata));
7454 var data = rdata.data;
7456 if (this.uploadComplete) {
7457 Roo.MessageBox.hide();
7462 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7463 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7466 this.uploadProgress.defer(2000,this);
7469 failure: function(data) {
7470 Roo.log('progress url failed ');
7481 // run get Values on the form, so it syncs any secondary forms.
7482 this.form.getValues();
7484 var o = this.options;
7485 var method = this.getMethod();
7486 var isPost = method == 'POST';
7487 if(o.clientValidation === false || this.form.isValid()){
7489 if (this.form.progressUrl) {
7490 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7491 (new Date() * 1) + '' + Math.random());
7496 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7497 form:this.form.el.dom,
7498 url:this.getUrl(!isPost),
7500 params:isPost ? this.getParams() : null,
7501 isUpload: this.form.fileUpload
7504 this.uploadProgress();
7506 }else if (o.clientValidation !== false){ // client validation failed
7507 this.failureType = Roo.form.Action.CLIENT_INVALID;
7508 this.form.afterAction(this, false);
7512 success : function(response)
7514 this.uploadComplete= true;
7515 if (this.haveProgress) {
7516 Roo.MessageBox.hide();
7520 var result = this.processResponse(response);
7521 if(result === true || result.success){
7522 this.form.afterAction(this, true);
7526 this.form.markInvalid(result.errors);
7527 this.failureType = Roo.form.Action.SERVER_INVALID;
7529 this.form.afterAction(this, false);
7531 failure : function(response)
7533 this.uploadComplete= true;
7534 if (this.haveProgress) {
7535 Roo.MessageBox.hide();
7538 this.response = response;
7539 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7540 this.form.afterAction(this, false);
7543 handleResponse : function(response){
7544 if(this.form.errorReader){
7545 var rs = this.form.errorReader.read(response);
7548 for(var i = 0, len = rs.records.length; i < len; i++) {
7549 var r = rs.records[i];
7553 if(errors.length < 1){
7557 success : rs.success,
7563 ret = Roo.decode(response.responseText);
7567 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7577 Roo.form.Action.Load = function(form, options){
7578 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7579 this.reader = this.form.reader;
7582 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7587 Roo.Ajax.request(Roo.apply(
7588 this.createCallback(), {
7589 method:this.getMethod(),
7590 url:this.getUrl(false),
7591 params:this.getParams()
7595 success : function(response){
7597 var result = this.processResponse(response);
7598 if(result === true || !result.success || !result.data){
7599 this.failureType = Roo.form.Action.LOAD_FAILURE;
7600 this.form.afterAction(this, false);
7603 this.form.clearInvalid();
7604 this.form.setValues(result.data);
7605 this.form.afterAction(this, true);
7608 handleResponse : function(response){
7609 if(this.form.reader){
7610 var rs = this.form.reader.read(response);
7611 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7613 success : rs.success,
7617 return Roo.decode(response.responseText);
7621 Roo.form.Action.ACTION_TYPES = {
7622 'load' : Roo.form.Action.Load,
7623 'submit' : Roo.form.Action.Submit
7632 * @class Roo.bootstrap.Form
7633 * @extends Roo.bootstrap.Component
7634 * Bootstrap Form class
7635 * @cfg {String} method GET | POST (default POST)
7636 * @cfg {String} labelAlign top | left (default top)
7637 * @cfg {String} align left | right - for navbars
7638 * @cfg {Boolean} loadMask load mask when submit (default true)
7643 * @param {Object} config The config object
7647 Roo.bootstrap.Form = function(config){
7649 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7651 Roo.bootstrap.Form.popover.apply();
7655 * @event clientvalidation
7656 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7657 * @param {Form} this
7658 * @param {Boolean} valid true if the form has passed client-side validation
7660 clientvalidation: true,
7662 * @event beforeaction
7663 * Fires before any action is performed. Return false to cancel the action.
7664 * @param {Form} this
7665 * @param {Action} action The action to be performed
7669 * @event actionfailed
7670 * Fires when an action fails.
7671 * @param {Form} this
7672 * @param {Action} action The action that failed
7674 actionfailed : true,
7676 * @event actioncomplete
7677 * Fires when an action is completed.
7678 * @param {Form} this
7679 * @param {Action} action The action that completed
7681 actioncomplete : true
7685 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7688 * @cfg {String} method
7689 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7694 * The URL to use for form actions if one isn't supplied in the action options.
7697 * @cfg {Boolean} fileUpload
7698 * Set to true if this form is a file upload.
7702 * @cfg {Object} baseParams
7703 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7707 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7711 * @cfg {Sting} align (left|right) for navbar forms
7716 activeAction : null,
7719 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7720 * element by passing it or its id or mask the form itself by passing in true.
7723 waitMsgTarget : false,
7728 * @cfg {Boolean} errorMask (true|false) default false
7733 * @cfg {Number} maskOffset Default 100
7738 * @cfg {Boolean} maskBody
7742 getAutoCreate : function(){
7746 method : this.method || 'POST',
7747 id : this.id || Roo.id(),
7750 if (this.parent().xtype.match(/^Nav/)) {
7751 cfg.cls = 'navbar-form navbar-' + this.align;
7755 if (this.labelAlign == 'left' ) {
7756 cfg.cls += ' form-horizontal';
7762 initEvents : function()
7764 this.el.on('submit', this.onSubmit, this);
7765 // this was added as random key presses on the form where triggering form submit.
7766 this.el.on('keypress', function(e) {
7767 if (e.getCharCode() != 13) {
7770 // we might need to allow it for textareas.. and some other items.
7771 // check e.getTarget().
7773 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7777 Roo.log("keypress blocked");
7785 onSubmit : function(e){
7790 * Returns true if client-side validation on the form is successful.
7793 isValid : function(){
7794 var items = this.getItems();
7798 items.each(function(f){
7805 if(!target && f.el.isVisible(true)){
7811 if(this.errorMask && !valid){
7812 Roo.bootstrap.Form.popover.mask(this, target);
7819 * Returns true if any fields in this form have changed since their original load.
7822 isDirty : function(){
7824 var items = this.getItems();
7825 items.each(function(f){
7835 * Performs a predefined action (submit or load) or custom actions you define on this form.
7836 * @param {String} actionName The name of the action type
7837 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7838 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7839 * accept other config options):
7841 Property Type Description
7842 ---------------- --------------- ----------------------------------------------------------------------------------
7843 url String The url for the action (defaults to the form's url)
7844 method String The form method to use (defaults to the form's method, or POST if not defined)
7845 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7846 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7847 validate the form on the client (defaults to false)
7849 * @return {BasicForm} this
7851 doAction : function(action, options){
7852 if(typeof action == 'string'){
7853 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7855 if(this.fireEvent('beforeaction', this, action) !== false){
7856 this.beforeAction(action);
7857 action.run.defer(100, action);
7863 beforeAction : function(action){
7864 var o = action.options;
7869 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7871 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7874 // not really supported yet.. ??
7876 //if(this.waitMsgTarget === true){
7877 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7878 //}else if(this.waitMsgTarget){
7879 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7880 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7882 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7888 afterAction : function(action, success){
7889 this.activeAction = null;
7890 var o = action.options;
7895 Roo.get(document.body).unmask();
7901 //if(this.waitMsgTarget === true){
7902 // this.el.unmask();
7903 //}else if(this.waitMsgTarget){
7904 // this.waitMsgTarget.unmask();
7906 // Roo.MessageBox.updateProgress(1);
7907 // Roo.MessageBox.hide();
7914 Roo.callback(o.success, o.scope, [this, action]);
7915 this.fireEvent('actioncomplete', this, action);
7919 // failure condition..
7920 // we have a scenario where updates need confirming.
7921 // eg. if a locking scenario exists..
7922 // we look for { errors : { needs_confirm : true }} in the response.
7924 (typeof(action.result) != 'undefined') &&
7925 (typeof(action.result.errors) != 'undefined') &&
7926 (typeof(action.result.errors.needs_confirm) != 'undefined')
7929 Roo.log("not supported yet");
7932 Roo.MessageBox.confirm(
7933 "Change requires confirmation",
7934 action.result.errorMsg,
7939 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7949 Roo.callback(o.failure, o.scope, [this, action]);
7950 // show an error message if no failed handler is set..
7951 if (!this.hasListener('actionfailed')) {
7952 Roo.log("need to add dialog support");
7954 Roo.MessageBox.alert("Error",
7955 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7956 action.result.errorMsg :
7957 "Saving Failed, please check your entries or try again"
7962 this.fireEvent('actionfailed', this, action);
7967 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7968 * @param {String} id The value to search for
7971 findField : function(id){
7972 var items = this.getItems();
7973 var field = items.get(id);
7975 items.each(function(f){
7976 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7983 return field || null;
7986 * Mark fields in this form invalid in bulk.
7987 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7988 * @return {BasicForm} this
7990 markInvalid : function(errors){
7991 if(errors instanceof Array){
7992 for(var i = 0, len = errors.length; i < len; i++){
7993 var fieldError = errors[i];
7994 var f = this.findField(fieldError.id);
7996 f.markInvalid(fieldError.msg);
8002 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8003 field.markInvalid(errors[id]);
8007 //Roo.each(this.childForms || [], function (f) {
8008 // f.markInvalid(errors);
8015 * Set values for fields in this form in bulk.
8016 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8017 * @return {BasicForm} this
8019 setValues : function(values){
8020 if(values instanceof Array){ // array of objects
8021 for(var i = 0, len = values.length; i < len; i++){
8023 var f = this.findField(v.id);
8025 f.setValue(v.value);
8026 if(this.trackResetOnLoad){
8027 f.originalValue = f.getValue();
8031 }else{ // object hash
8034 if(typeof values[id] != 'function' && (field = this.findField(id))){
8036 if (field.setFromData &&
8038 field.displayField &&
8039 // combos' with local stores can
8040 // be queried via setValue()
8041 // to set their value..
8042 (field.store && !field.store.isLocal)
8046 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8047 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8048 field.setFromData(sd);
8050 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8052 field.setFromData(values);
8055 field.setValue(values[id]);
8059 if(this.trackResetOnLoad){
8060 field.originalValue = field.getValue();
8066 //Roo.each(this.childForms || [], function (f) {
8067 // f.setValues(values);
8074 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8075 * they are returned as an array.
8076 * @param {Boolean} asString
8079 getValues : function(asString){
8080 //if (this.childForms) {
8081 // copy values from the child forms
8082 // Roo.each(this.childForms, function (f) {
8083 // this.setValues(f.getValues());
8089 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8090 if(asString === true){
8093 return Roo.urlDecode(fs);
8097 * Returns the fields in this form as an object with key/value pairs.
8098 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8101 getFieldValues : function(with_hidden)
8103 var items = this.getItems();
8105 items.each(function(f){
8111 var v = f.getValue();
8113 if (f.inputType =='radio') {
8114 if (typeof(ret[f.getName()]) == 'undefined') {
8115 ret[f.getName()] = ''; // empty..
8118 if (!f.el.dom.checked) {
8126 if(f.xtype == 'MoneyField'){
8127 ret[f.currencyName] = f.getCurrency();
8130 // not sure if this supported any more..
8131 if ((typeof(v) == 'object') && f.getRawValue) {
8132 v = f.getRawValue() ; // dates..
8134 // combo boxes where name != hiddenName...
8135 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8136 ret[f.name] = f.getRawValue();
8138 ret[f.getName()] = v;
8145 * Clears all invalid messages in this form.
8146 * @return {BasicForm} this
8148 clearInvalid : function(){
8149 var items = this.getItems();
8151 items.each(function(f){
8160 * @return {BasicForm} this
8163 var items = this.getItems();
8164 items.each(function(f){
8168 Roo.each(this.childForms || [], function (f) {
8176 getItems : function()
8178 var r=new Roo.util.MixedCollection(false, function(o){
8179 return o.id || (o.id = Roo.id());
8181 var iter = function(el) {
8188 Roo.each(el.items,function(e) {
8197 hideFields : function(items)
8199 Roo.each(items, function(i){
8201 var f = this.findField(i);
8207 if(f.xtype == 'DateField'){
8208 f.setVisible(false);
8217 showFields : function(items)
8219 Roo.each(items, function(i){
8221 var f = this.findField(i);
8227 if(f.xtype == 'DateField'){
8239 Roo.apply(Roo.bootstrap.Form, {
8266 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8267 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8268 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8269 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8272 this.maskEl.top.enableDisplayMode("block");
8273 this.maskEl.left.enableDisplayMode("block");
8274 this.maskEl.bottom.enableDisplayMode("block");
8275 this.maskEl.right.enableDisplayMode("block");
8277 this.toolTip = new Roo.bootstrap.Tooltip({
8278 cls : 'roo-form-error-popover',
8280 'left' : ['r-l', [-2,0], 'right'],
8281 'right' : ['l-r', [2,0], 'left'],
8282 'bottom' : ['tl-bl', [0,2], 'top'],
8283 'top' : [ 'bl-tl', [0,-2], 'bottom']
8287 this.toolTip.render(Roo.get(document.body));
8289 this.toolTip.el.enableDisplayMode("block");
8291 Roo.get(document.body).on('click', function(){
8295 Roo.get(document.body).on('touchstart', function(){
8299 this.isApplied = true
8302 mask : function(form, target)
8306 this.target = target;
8308 if(!this.form.errorMask || !target.el){
8312 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8314 Roo.log(scrollable);
8316 var ot = this.target.el.calcOffsetsTo(scrollable);
8318 var scrollTo = ot[1] - this.form.maskOffset;
8320 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8322 scrollable.scrollTo('top', scrollTo);
8324 var box = this.target.el.getBox();
8326 var zIndex = Roo.bootstrap.Modal.zIndex++;
8329 this.maskEl.top.setStyle('position', 'absolute');
8330 this.maskEl.top.setStyle('z-index', zIndex);
8331 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8332 this.maskEl.top.setLeft(0);
8333 this.maskEl.top.setTop(0);
8334 this.maskEl.top.show();
8336 this.maskEl.left.setStyle('position', 'absolute');
8337 this.maskEl.left.setStyle('z-index', zIndex);
8338 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8339 this.maskEl.left.setLeft(0);
8340 this.maskEl.left.setTop(box.y - this.padding);
8341 this.maskEl.left.show();
8343 this.maskEl.bottom.setStyle('position', 'absolute');
8344 this.maskEl.bottom.setStyle('z-index', zIndex);
8345 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8346 this.maskEl.bottom.setLeft(0);
8347 this.maskEl.bottom.setTop(box.bottom + this.padding);
8348 this.maskEl.bottom.show();
8350 this.maskEl.right.setStyle('position', 'absolute');
8351 this.maskEl.right.setStyle('z-index', zIndex);
8352 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8353 this.maskEl.right.setLeft(box.right + this.padding);
8354 this.maskEl.right.setTop(box.y - this.padding);
8355 this.maskEl.right.show();
8357 this.toolTip.bindEl = this.target.el;
8359 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8361 var tip = this.target.blankText;
8363 if(this.target.getValue() !== '' ) {
8365 if (this.target.invalidText.length) {
8366 tip = this.target.invalidText;
8367 } else if (this.target.regexText.length){
8368 tip = this.target.regexText;
8372 this.toolTip.show(tip);
8374 this.intervalID = window.setInterval(function() {
8375 Roo.bootstrap.Form.popover.unmask();
8378 window.onwheel = function(){ return false;};
8380 (function(){ this.isMasked = true; }).defer(500, this);
8386 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8390 this.maskEl.top.setStyle('position', 'absolute');
8391 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8392 this.maskEl.top.hide();
8394 this.maskEl.left.setStyle('position', 'absolute');
8395 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8396 this.maskEl.left.hide();
8398 this.maskEl.bottom.setStyle('position', 'absolute');
8399 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8400 this.maskEl.bottom.hide();
8402 this.maskEl.right.setStyle('position', 'absolute');
8403 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8404 this.maskEl.right.hide();
8406 this.toolTip.hide();
8408 this.toolTip.el.hide();
8410 window.onwheel = function(){ return true;};
8412 if(this.intervalID){
8413 window.clearInterval(this.intervalID);
8414 this.intervalID = false;
8417 this.isMasked = false;
8427 * Ext JS Library 1.1.1
8428 * Copyright(c) 2006-2007, Ext JS, LLC.
8430 * Originally Released Under LGPL - original licence link has changed is not relivant.
8433 * <script type="text/javascript">
8436 * @class Roo.form.VTypes
8437 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8440 Roo.form.VTypes = function(){
8441 // closure these in so they are only created once.
8442 var alpha = /^[a-zA-Z_]+$/;
8443 var alphanum = /^[a-zA-Z0-9_]+$/;
8444 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8445 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8447 // All these messages and functions are configurable
8450 * The function used to validate email addresses
8451 * @param {String} value The email address
8453 'email' : function(v){
8454 return email.test(v);
8457 * The error text to display when the email validation function returns false
8460 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8462 * The keystroke filter mask to be applied on email input
8465 'emailMask' : /[a-z0-9_\.\-@]/i,
8468 * The function used to validate URLs
8469 * @param {String} value The URL
8471 'url' : function(v){
8475 * The error text to display when the url validation function returns false
8478 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8481 * The function used to validate alpha values
8482 * @param {String} value The value
8484 'alpha' : function(v){
8485 return alpha.test(v);
8488 * The error text to display when the alpha validation function returns false
8491 'alphaText' : 'This field should only contain letters and _',
8493 * The keystroke filter mask to be applied on alpha input
8496 'alphaMask' : /[a-z_]/i,
8499 * The function used to validate alphanumeric values
8500 * @param {String} value The value
8502 'alphanum' : function(v){
8503 return alphanum.test(v);
8506 * The error text to display when the alphanumeric validation function returns false
8509 'alphanumText' : 'This field should only contain letters, numbers and _',
8511 * The keystroke filter mask to be applied on alphanumeric input
8514 'alphanumMask' : /[a-z0-9_]/i
8524 * @class Roo.bootstrap.Input
8525 * @extends Roo.bootstrap.Component
8526 * Bootstrap Input class
8527 * @cfg {Boolean} disabled is it disabled
8528 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8529 * @cfg {String} name name of the input
8530 * @cfg {string} fieldLabel - the label associated
8531 * @cfg {string} placeholder - placeholder to put in text.
8532 * @cfg {string} before - input group add on before
8533 * @cfg {string} after - input group add on after
8534 * @cfg {string} size - (lg|sm) or leave empty..
8535 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8536 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8537 * @cfg {Number} md colspan out of 12 for computer-sized screens
8538 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8539 * @cfg {string} value default value of the input
8540 * @cfg {Number} labelWidth set the width of label
8541 * @cfg {Number} labellg set the width of label (1-12)
8542 * @cfg {Number} labelmd set the width of label (1-12)
8543 * @cfg {Number} labelsm set the width of label (1-12)
8544 * @cfg {Number} labelxs set the width of label (1-12)
8545 * @cfg {String} labelAlign (top|left)
8546 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8547 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8548 * @cfg {String} indicatorpos (left|right) default left
8549 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8550 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8552 * @cfg {String} align (left|center|right) Default left
8553 * @cfg {Boolean} forceFeedback (true|false) Default false
8556 * Create a new Input
8557 * @param {Object} config The config object
8560 Roo.bootstrap.Input = function(config){
8562 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8567 * Fires when this field receives input focus.
8568 * @param {Roo.form.Field} this
8573 * Fires when this field loses input focus.
8574 * @param {Roo.form.Field} this
8579 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8580 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8581 * @param {Roo.form.Field} this
8582 * @param {Roo.EventObject} e The event object
8587 * Fires just before the field blurs if the field value has changed.
8588 * @param {Roo.form.Field} this
8589 * @param {Mixed} newValue The new value
8590 * @param {Mixed} oldValue The original value
8595 * Fires after the field has been marked as invalid.
8596 * @param {Roo.form.Field} this
8597 * @param {String} msg The validation message
8602 * Fires after the field has been validated with no errors.
8603 * @param {Roo.form.Field} this
8608 * Fires after the key up
8609 * @param {Roo.form.Field} this
8610 * @param {Roo.EventObject} e The event Object
8616 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8618 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8619 automatic validation (defaults to "keyup").
8621 validationEvent : "keyup",
8623 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8625 validateOnBlur : true,
8627 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8629 validationDelay : 250,
8631 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8633 focusClass : "x-form-focus", // not needed???
8637 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8639 invalidClass : "has-warning",
8642 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8644 validClass : "has-success",
8647 * @cfg {Boolean} hasFeedback (true|false) default true
8652 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8654 invalidFeedbackClass : "glyphicon-warning-sign",
8657 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8659 validFeedbackClass : "glyphicon-ok",
8662 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8664 selectOnFocus : false,
8667 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8671 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8676 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8678 disableKeyFilter : false,
8681 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8685 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8689 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8691 blankText : "Please complete this mandatory field",
8694 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8698 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8700 maxLength : Number.MAX_VALUE,
8702 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8704 minLengthText : "The minimum length for this field is {0}",
8706 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8708 maxLengthText : "The maximum length for this field is {0}",
8712 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8713 * If available, this function will be called only after the basic validators all return true, and will be passed the
8714 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8718 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8719 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8720 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8724 * @cfg {String} regexText -- Depricated - use Invalid Text
8729 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8735 autocomplete: false,
8754 formatedValue : false,
8755 forceFeedback : false,
8757 indicatorpos : 'left',
8767 parentLabelAlign : function()
8770 while (parent.parent()) {
8771 parent = parent.parent();
8772 if (typeof(parent.labelAlign) !='undefined') {
8773 return parent.labelAlign;
8780 getAutoCreate : function()
8782 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8788 if(this.inputType != 'hidden'){
8789 cfg.cls = 'form-group' //input-group
8795 type : this.inputType,
8797 cls : 'form-control',
8798 placeholder : this.placeholder || '',
8799 autocomplete : this.autocomplete || 'new-password'
8802 if(this.capture.length){
8803 input.capture = this.capture;
8806 if(this.accept.length){
8807 input.accept = this.accept + "/*";
8811 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8814 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8815 input.maxLength = this.maxLength;
8818 if (this.disabled) {
8819 input.disabled=true;
8822 if (this.readOnly) {
8823 input.readonly=true;
8827 input.name = this.name;
8831 input.cls += ' input-' + this.size;
8835 ['xs','sm','md','lg'].map(function(size){
8836 if (settings[size]) {
8837 cfg.cls += ' col-' + size + '-' + settings[size];
8841 var inputblock = input;
8845 cls: 'glyphicon form-control-feedback'
8848 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8851 cls : 'has-feedback',
8859 if (this.before || this.after) {
8862 cls : 'input-group',
8866 if (this.before && typeof(this.before) == 'string') {
8868 inputblock.cn.push({
8870 cls : 'roo-input-before input-group-addon',
8874 if (this.before && typeof(this.before) == 'object') {
8875 this.before = Roo.factory(this.before);
8877 inputblock.cn.push({
8879 cls : 'roo-input-before input-group-' +
8880 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8884 inputblock.cn.push(input);
8886 if (this.after && typeof(this.after) == 'string') {
8887 inputblock.cn.push({
8889 cls : 'roo-input-after input-group-addon',
8893 if (this.after && typeof(this.after) == 'object') {
8894 this.after = Roo.factory(this.after);
8896 inputblock.cn.push({
8898 cls : 'roo-input-after input-group-' +
8899 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8903 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8904 inputblock.cls += ' has-feedback';
8905 inputblock.cn.push(feedback);
8909 if (align ==='left' && this.fieldLabel.length) {
8911 cfg.cls += ' roo-form-group-label-left';
8916 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8917 tooltip : 'This field is required'
8922 cls : 'control-label',
8923 html : this.fieldLabel
8934 var labelCfg = cfg.cn[1];
8935 var contentCfg = cfg.cn[2];
8937 if(this.indicatorpos == 'right'){
8942 cls : 'control-label',
8946 html : this.fieldLabel
8950 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8951 tooltip : 'This field is required'
8964 labelCfg = cfg.cn[0];
8965 contentCfg = cfg.cn[1];
8969 if(this.labelWidth > 12){
8970 labelCfg.style = "width: " + this.labelWidth + 'px';
8973 if(this.labelWidth < 13 && this.labelmd == 0){
8974 this.labelmd = this.labelWidth;
8977 if(this.labellg > 0){
8978 labelCfg.cls += ' col-lg-' + this.labellg;
8979 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8982 if(this.labelmd > 0){
8983 labelCfg.cls += ' col-md-' + this.labelmd;
8984 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8987 if(this.labelsm > 0){
8988 labelCfg.cls += ' col-sm-' + this.labelsm;
8989 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8992 if(this.labelxs > 0){
8993 labelCfg.cls += ' col-xs-' + this.labelxs;
8994 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8998 } else if ( this.fieldLabel.length) {
9003 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9004 tooltip : 'This field is required'
9008 //cls : 'input-group-addon',
9009 html : this.fieldLabel
9017 if(this.indicatorpos == 'right'){
9022 //cls : 'input-group-addon',
9023 html : this.fieldLabel
9028 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9029 tooltip : 'This field is required'
9049 if (this.parentType === 'Navbar' && this.parent().bar) {
9050 cfg.cls += ' navbar-form';
9053 if (this.parentType === 'NavGroup') {
9054 cfg.cls += ' navbar-form';
9062 * return the real input element.
9064 inputEl: function ()
9066 return this.el.select('input.form-control',true).first();
9069 tooltipEl : function()
9071 return this.inputEl();
9074 indicatorEl : function()
9076 var indicator = this.el.select('i.roo-required-indicator',true).first();
9086 setDisabled : function(v)
9088 var i = this.inputEl().dom;
9090 i.removeAttribute('disabled');
9094 i.setAttribute('disabled','true');
9096 initEvents : function()
9099 this.inputEl().on("keydown" , this.fireKey, this);
9100 this.inputEl().on("focus", this.onFocus, this);
9101 this.inputEl().on("blur", this.onBlur, this);
9103 this.inputEl().relayEvent('keyup', this);
9105 this.indicator = this.indicatorEl();
9108 this.indicator.addClass('invisible');
9111 // reference to original value for reset
9112 this.originalValue = this.getValue();
9113 //Roo.form.TextField.superclass.initEvents.call(this);
9114 if(this.validationEvent == 'keyup'){
9115 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9116 this.inputEl().on('keyup', this.filterValidation, this);
9118 else if(this.validationEvent !== false){
9119 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9122 if(this.selectOnFocus){
9123 this.on("focus", this.preFocus, this);
9126 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9127 this.inputEl().on("keypress", this.filterKeys, this);
9129 this.inputEl().relayEvent('keypress', this);
9132 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9133 this.el.on("click", this.autoSize, this);
9136 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9137 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9140 if (typeof(this.before) == 'object') {
9141 this.before.render(this.el.select('.roo-input-before',true).first());
9143 if (typeof(this.after) == 'object') {
9144 this.after.render(this.el.select('.roo-input-after',true).first());
9147 this.inputEl().on('change', this.onChange, this);
9150 filterValidation : function(e){
9151 if(!e.isNavKeyPress()){
9152 this.validationTask.delay(this.validationDelay);
9156 * Validates the field value
9157 * @return {Boolean} True if the value is valid, else false
9159 validate : function(){
9160 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9161 if(this.disabled || this.validateValue(this.getRawValue())){
9172 * Validates a value according to the field's validation rules and marks the field as invalid
9173 * if the validation fails
9174 * @param {Mixed} value The value to validate
9175 * @return {Boolean} True if the value is valid, else false
9177 validateValue : function(value)
9179 if(this.getVisibilityEl().hasClass('hidden')){
9183 if(value.length < 1) { // if it's blank
9184 if(this.allowBlank){
9190 if(value.length < this.minLength){
9193 if(value.length > this.maxLength){
9197 var vt = Roo.form.VTypes;
9198 if(!vt[this.vtype](value, this)){
9202 if(typeof this.validator == "function"){
9203 var msg = this.validator(value);
9207 if (typeof(msg) == 'string') {
9208 this.invalidText = msg;
9212 if(this.regex && !this.regex.test(value)){
9220 fireKey : function(e){
9221 //Roo.log('field ' + e.getKey());
9222 if(e.isNavKeyPress()){
9223 this.fireEvent("specialkey", this, e);
9226 focus : function (selectText){
9228 this.inputEl().focus();
9229 if(selectText === true){
9230 this.inputEl().dom.select();
9236 onFocus : function(){
9237 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9238 // this.el.addClass(this.focusClass);
9241 this.hasFocus = true;
9242 this.startValue = this.getValue();
9243 this.fireEvent("focus", this);
9247 beforeBlur : Roo.emptyFn,
9251 onBlur : function(){
9253 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9254 //this.el.removeClass(this.focusClass);
9256 this.hasFocus = false;
9257 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9260 var v = this.getValue();
9261 if(String(v) !== String(this.startValue)){
9262 this.fireEvent('change', this, v, this.startValue);
9264 this.fireEvent("blur", this);
9267 onChange : function(e)
9269 var v = this.getValue();
9270 if(String(v) !== String(this.startValue)){
9271 this.fireEvent('change', this, v, this.startValue);
9277 * Resets the current field value to the originally loaded value and clears any validation messages
9280 this.setValue(this.originalValue);
9284 * Returns the name of the field
9285 * @return {Mixed} name The name field
9287 getName: function(){
9291 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9292 * @return {Mixed} value The field value
9294 getValue : function(){
9296 var v = this.inputEl().getValue();
9301 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9302 * @return {Mixed} value The field value
9304 getRawValue : function(){
9305 var v = this.inputEl().getValue();
9311 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9312 * @param {Mixed} value The value to set
9314 setRawValue : function(v){
9315 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9318 selectText : function(start, end){
9319 var v = this.getRawValue();
9321 start = start === undefined ? 0 : start;
9322 end = end === undefined ? v.length : end;
9323 var d = this.inputEl().dom;
9324 if(d.setSelectionRange){
9325 d.setSelectionRange(start, end);
9326 }else if(d.createTextRange){
9327 var range = d.createTextRange();
9328 range.moveStart("character", start);
9329 range.moveEnd("character", v.length-end);
9336 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9337 * @param {Mixed} value The value to set
9339 setValue : function(v){
9342 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9348 processValue : function(value){
9349 if(this.stripCharsRe){
9350 var newValue = value.replace(this.stripCharsRe, '');
9351 if(newValue !== value){
9352 this.setRawValue(newValue);
9359 preFocus : function(){
9361 if(this.selectOnFocus){
9362 this.inputEl().dom.select();
9365 filterKeys : function(e){
9367 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9370 var c = e.getCharCode(), cc = String.fromCharCode(c);
9371 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9374 if(!this.maskRe.test(cc)){
9379 * Clear any invalid styles/messages for this field
9381 clearInvalid : function(){
9383 if(!this.el || this.preventMark){ // not rendered
9388 this.el.removeClass(this.invalidClass);
9390 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9392 var feedback = this.el.select('.form-control-feedback', true).first();
9395 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9400 this.fireEvent('valid', this);
9404 * Mark this field as valid
9406 markValid : function()
9408 if(!this.el || this.preventMark){ // not rendered...
9412 this.el.removeClass([this.invalidClass, this.validClass]);
9414 var feedback = this.el.select('.form-control-feedback', true).first();
9417 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9421 this.indicator.removeClass('visible');
9422 this.indicator.addClass('invisible');
9429 if(this.allowBlank && !this.getRawValue().length){
9433 this.el.addClass(this.validClass);
9435 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9437 var feedback = this.el.select('.form-control-feedback', true).first();
9440 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9441 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9446 this.fireEvent('valid', this);
9450 * Mark this field as invalid
9451 * @param {String} msg The validation message
9453 markInvalid : function(msg)
9455 if(!this.el || this.preventMark){ // not rendered
9459 this.el.removeClass([this.invalidClass, this.validClass]);
9461 var feedback = this.el.select('.form-control-feedback', true).first();
9464 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9471 if(this.allowBlank && !this.getRawValue().length){
9476 this.indicator.removeClass('invisible');
9477 this.indicator.addClass('visible');
9480 this.el.addClass(this.invalidClass);
9482 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9484 var feedback = this.el.select('.form-control-feedback', true).first();
9487 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9489 if(this.getValue().length || this.forceFeedback){
9490 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9497 this.fireEvent('invalid', this, msg);
9500 SafariOnKeyDown : function(event)
9502 // this is a workaround for a password hang bug on chrome/ webkit.
9503 if (this.inputEl().dom.type != 'password') {
9507 var isSelectAll = false;
9509 if(this.inputEl().dom.selectionEnd > 0){
9510 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9512 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9513 event.preventDefault();
9518 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9520 event.preventDefault();
9521 // this is very hacky as keydown always get's upper case.
9523 var cc = String.fromCharCode(event.getCharCode());
9524 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9528 adjustWidth : function(tag, w){
9529 tag = tag.toLowerCase();
9530 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9531 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9535 if(tag == 'textarea'){
9538 }else if(Roo.isOpera){
9542 if(tag == 'textarea'){
9550 setFieldLabel : function(v)
9557 var ar = this.el.select('label > span',true);
9559 if (ar.elements.length) {
9560 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9561 this.fieldLabel = v;
9565 var br = this.el.select('label',true);
9567 if(br.elements.length) {
9568 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9569 this.fieldLabel = v;
9573 Roo.log('Cannot Found any of label > span || label in input');
9577 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9578 this.fieldLabel = v;
9593 * @class Roo.bootstrap.TextArea
9594 * @extends Roo.bootstrap.Input
9595 * Bootstrap TextArea class
9596 * @cfg {Number} cols Specifies the visible width of a text area
9597 * @cfg {Number} rows Specifies the visible number of lines in a text area
9598 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9599 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9600 * @cfg {string} html text
9603 * Create a new TextArea
9604 * @param {Object} config The config object
9607 Roo.bootstrap.TextArea = function(config){
9608 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9612 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9622 getAutoCreate : function(){
9624 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9630 if(this.inputType != 'hidden'){
9631 cfg.cls = 'form-group' //input-group
9639 value : this.value || '',
9640 html: this.html || '',
9641 cls : 'form-control',
9642 placeholder : this.placeholder || ''
9646 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9647 input.maxLength = this.maxLength;
9651 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9655 input.cols = this.cols;
9658 if (this.readOnly) {
9659 input.readonly = true;
9663 input.name = this.name;
9667 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9671 ['xs','sm','md','lg'].map(function(size){
9672 if (settings[size]) {
9673 cfg.cls += ' col-' + size + '-' + settings[size];
9677 var inputblock = input;
9679 if(this.hasFeedback && !this.allowBlank){
9683 cls: 'glyphicon form-control-feedback'
9687 cls : 'has-feedback',
9696 if (this.before || this.after) {
9699 cls : 'input-group',
9703 inputblock.cn.push({
9705 cls : 'input-group-addon',
9710 inputblock.cn.push(input);
9712 if(this.hasFeedback && !this.allowBlank){
9713 inputblock.cls += ' has-feedback';
9714 inputblock.cn.push(feedback);
9718 inputblock.cn.push({
9720 cls : 'input-group-addon',
9727 if (align ==='left' && this.fieldLabel.length) {
9732 cls : 'control-label',
9733 html : this.fieldLabel
9744 if(this.labelWidth > 12){
9745 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9748 if(this.labelWidth < 13 && this.labelmd == 0){
9749 this.labelmd = this.labelWidth;
9752 if(this.labellg > 0){
9753 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9754 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9757 if(this.labelmd > 0){
9758 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9759 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9762 if(this.labelsm > 0){
9763 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9764 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9767 if(this.labelxs > 0){
9768 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9769 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9772 } else if ( this.fieldLabel.length) {
9777 //cls : 'input-group-addon',
9778 html : this.fieldLabel
9796 if (this.disabled) {
9797 input.disabled=true;
9804 * return the real textarea element.
9806 inputEl: function ()
9808 return this.el.select('textarea.form-control',true).first();
9812 * Clear any invalid styles/messages for this field
9814 clearInvalid : function()
9817 if(!this.el || this.preventMark){ // not rendered
9821 var label = this.el.select('label', true).first();
9822 var icon = this.el.select('i.fa-star', true).first();
9828 this.el.removeClass(this.invalidClass);
9830 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9832 var feedback = this.el.select('.form-control-feedback', true).first();
9835 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9840 this.fireEvent('valid', this);
9844 * Mark this field as valid
9846 markValid : function()
9848 if(!this.el || this.preventMark){ // not rendered
9852 this.el.removeClass([this.invalidClass, this.validClass]);
9854 var feedback = this.el.select('.form-control-feedback', true).first();
9857 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9860 if(this.disabled || this.allowBlank){
9864 var label = this.el.select('label', true).first();
9865 var icon = this.el.select('i.fa-star', true).first();
9871 this.el.addClass(this.validClass);
9873 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9875 var feedback = this.el.select('.form-control-feedback', true).first();
9878 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9879 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9884 this.fireEvent('valid', this);
9888 * Mark this field as invalid
9889 * @param {String} msg The validation message
9891 markInvalid : function(msg)
9893 if(!this.el || this.preventMark){ // not rendered
9897 this.el.removeClass([this.invalidClass, this.validClass]);
9899 var feedback = this.el.select('.form-control-feedback', true).first();
9902 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9905 if(this.disabled || this.allowBlank){
9909 var label = this.el.select('label', true).first();
9910 var icon = this.el.select('i.fa-star', true).first();
9912 if(!this.getValue().length && label && !icon){
9913 this.el.createChild({
9915 cls : 'text-danger fa fa-lg fa-star',
9916 tooltip : 'This field is required',
9917 style : 'margin-right:5px;'
9921 this.el.addClass(this.invalidClass);
9923 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9925 var feedback = this.el.select('.form-control-feedback', true).first();
9928 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9930 if(this.getValue().length || this.forceFeedback){
9931 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9938 this.fireEvent('invalid', this, msg);
9946 * trigger field - base class for combo..
9951 * @class Roo.bootstrap.TriggerField
9952 * @extends Roo.bootstrap.Input
9953 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9954 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9955 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9956 * for which you can provide a custom implementation. For example:
9958 var trigger = new Roo.bootstrap.TriggerField();
9959 trigger.onTriggerClick = myTriggerFn;
9960 trigger.applyTo('my-field');
9963 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9964 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9965 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9966 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9967 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9970 * Create a new TriggerField.
9971 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9972 * to the base TextField)
9974 Roo.bootstrap.TriggerField = function(config){
9975 this.mimicing = false;
9976 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9979 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9981 * @cfg {String} triggerClass A CSS class to apply to the trigger
9984 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9989 * @cfg {Boolean} removable (true|false) special filter default false
9993 /** @cfg {Boolean} grow @hide */
9994 /** @cfg {Number} growMin @hide */
9995 /** @cfg {Number} growMax @hide */
10001 autoSize: Roo.emptyFn,
10005 deferHeight : true,
10008 actionMode : 'wrap',
10013 getAutoCreate : function(){
10015 var align = this.labelAlign || this.parentLabelAlign();
10020 cls: 'form-group' //input-group
10027 type : this.inputType,
10028 cls : 'form-control',
10029 autocomplete: 'new-password',
10030 placeholder : this.placeholder || ''
10034 input.name = this.name;
10037 input.cls += ' input-' + this.size;
10040 if (this.disabled) {
10041 input.disabled=true;
10044 var inputblock = input;
10046 if(this.hasFeedback && !this.allowBlank){
10050 cls: 'glyphicon form-control-feedback'
10053 if(this.removable && !this.editable && !this.tickable){
10055 cls : 'has-feedback',
10061 cls : 'roo-combo-removable-btn close'
10068 cls : 'has-feedback',
10077 if(this.removable && !this.editable && !this.tickable){
10079 cls : 'roo-removable',
10085 cls : 'roo-combo-removable-btn close'
10092 if (this.before || this.after) {
10095 cls : 'input-group',
10099 inputblock.cn.push({
10101 cls : 'input-group-addon',
10106 inputblock.cn.push(input);
10108 if(this.hasFeedback && !this.allowBlank){
10109 inputblock.cls += ' has-feedback';
10110 inputblock.cn.push(feedback);
10114 inputblock.cn.push({
10116 cls : 'input-group-addon',
10129 cls: 'form-hidden-field'
10143 cls: 'form-hidden-field'
10147 cls: 'roo-select2-choices',
10151 cls: 'roo-select2-search-field',
10164 cls: 'roo-select2-container input-group',
10169 // cls: 'typeahead typeahead-long dropdown-menu',
10170 // style: 'display:none'
10175 if(!this.multiple && this.showToggleBtn){
10181 if (this.caret != false) {
10184 cls: 'fa fa-' + this.caret
10191 cls : 'input-group-addon btn dropdown-toggle',
10196 cls: 'combobox-clear',
10210 combobox.cls += ' roo-select2-container-multi';
10213 if (align ==='left' && this.fieldLabel.length) {
10215 cfg.cls += ' roo-form-group-label-left';
10220 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10221 tooltip : 'This field is required'
10226 cls : 'control-label',
10227 html : this.fieldLabel
10239 var labelCfg = cfg.cn[1];
10240 var contentCfg = cfg.cn[2];
10242 if(this.indicatorpos == 'right'){
10247 cls : 'control-label',
10251 html : this.fieldLabel
10255 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10256 tooltip : 'This field is required'
10269 labelCfg = cfg.cn[0];
10270 contentCfg = cfg.cn[1];
10273 if(this.labelWidth > 12){
10274 labelCfg.style = "width: " + this.labelWidth + 'px';
10277 if(this.labelWidth < 13 && this.labelmd == 0){
10278 this.labelmd = this.labelWidth;
10281 if(this.labellg > 0){
10282 labelCfg.cls += ' col-lg-' + this.labellg;
10283 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10286 if(this.labelmd > 0){
10287 labelCfg.cls += ' col-md-' + this.labelmd;
10288 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10291 if(this.labelsm > 0){
10292 labelCfg.cls += ' col-sm-' + this.labelsm;
10293 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10296 if(this.labelxs > 0){
10297 labelCfg.cls += ' col-xs-' + this.labelxs;
10298 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10301 } else if ( this.fieldLabel.length) {
10302 // Roo.log(" label");
10306 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10307 tooltip : 'This field is required'
10311 //cls : 'input-group-addon',
10312 html : this.fieldLabel
10320 if(this.indicatorpos == 'right'){
10328 html : this.fieldLabel
10332 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10333 tooltip : 'This field is required'
10346 // Roo.log(" no label && no align");
10353 ['xs','sm','md','lg'].map(function(size){
10354 if (settings[size]) {
10355 cfg.cls += ' col-' + size + '-' + settings[size];
10366 onResize : function(w, h){
10367 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10368 // if(typeof w == 'number'){
10369 // var x = w - this.trigger.getWidth();
10370 // this.inputEl().setWidth(this.adjustWidth('input', x));
10371 // this.trigger.setStyle('left', x+'px');
10376 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10379 getResizeEl : function(){
10380 return this.inputEl();
10384 getPositionEl : function(){
10385 return this.inputEl();
10389 alignErrorIcon : function(){
10390 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10394 initEvents : function(){
10398 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10399 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10400 if(!this.multiple && this.showToggleBtn){
10401 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10402 if(this.hideTrigger){
10403 this.trigger.setDisplayed(false);
10405 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10409 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10412 if(this.removable && !this.editable && !this.tickable){
10413 var close = this.closeTriggerEl();
10416 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10417 close.on('click', this.removeBtnClick, this, close);
10421 //this.trigger.addClassOnOver('x-form-trigger-over');
10422 //this.trigger.addClassOnClick('x-form-trigger-click');
10425 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10429 closeTriggerEl : function()
10431 var close = this.el.select('.roo-combo-removable-btn', true).first();
10432 return close ? close : false;
10435 removeBtnClick : function(e, h, el)
10437 e.preventDefault();
10439 if(this.fireEvent("remove", this) !== false){
10441 this.fireEvent("afterremove", this)
10445 createList : function()
10447 this.list = Roo.get(document.body).createChild({
10449 cls: 'typeahead typeahead-long dropdown-menu',
10450 style: 'display:none'
10453 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10458 initTrigger : function(){
10463 onDestroy : function(){
10465 this.trigger.removeAllListeners();
10466 // this.trigger.remove();
10469 // this.wrap.remove();
10471 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10475 onFocus : function(){
10476 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10478 if(!this.mimicing){
10479 this.wrap.addClass('x-trigger-wrap-focus');
10480 this.mimicing = true;
10481 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10482 if(this.monitorTab){
10483 this.el.on("keydown", this.checkTab, this);
10490 checkTab : function(e){
10491 if(e.getKey() == e.TAB){
10492 this.triggerBlur();
10497 onBlur : function(){
10502 mimicBlur : function(e, t){
10504 if(!this.wrap.contains(t) && this.validateBlur()){
10505 this.triggerBlur();
10511 triggerBlur : function(){
10512 this.mimicing = false;
10513 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10514 if(this.monitorTab){
10515 this.el.un("keydown", this.checkTab, this);
10517 //this.wrap.removeClass('x-trigger-wrap-focus');
10518 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10522 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10523 validateBlur : function(e, t){
10528 onDisable : function(){
10529 this.inputEl().dom.disabled = true;
10530 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10532 // this.wrap.addClass('x-item-disabled');
10537 onEnable : function(){
10538 this.inputEl().dom.disabled = false;
10539 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10541 // this.el.removeClass('x-item-disabled');
10546 onShow : function(){
10547 var ae = this.getActionEl();
10550 ae.dom.style.display = '';
10551 ae.dom.style.visibility = 'visible';
10557 onHide : function(){
10558 var ae = this.getActionEl();
10559 ae.dom.style.display = 'none';
10563 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10564 * by an implementing function.
10566 * @param {EventObject} e
10568 onTriggerClick : Roo.emptyFn
10572 * Ext JS Library 1.1.1
10573 * Copyright(c) 2006-2007, Ext JS, LLC.
10575 * Originally Released Under LGPL - original licence link has changed is not relivant.
10578 * <script type="text/javascript">
10583 * @class Roo.data.SortTypes
10585 * Defines the default sorting (casting?) comparison functions used when sorting data.
10587 Roo.data.SortTypes = {
10589 * Default sort that does nothing
10590 * @param {Mixed} s The value being converted
10591 * @return {Mixed} The comparison value
10593 none : function(s){
10598 * The regular expression used to strip tags
10602 stripTagsRE : /<\/?[^>]+>/gi,
10605 * Strips all HTML tags to sort on text only
10606 * @param {Mixed} s The value being converted
10607 * @return {String} The comparison value
10609 asText : function(s){
10610 return String(s).replace(this.stripTagsRE, "");
10614 * Strips all HTML tags to sort on text only - Case insensitive
10615 * @param {Mixed} s The value being converted
10616 * @return {String} The comparison value
10618 asUCText : function(s){
10619 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10623 * Case insensitive string
10624 * @param {Mixed} s The value being converted
10625 * @return {String} The comparison value
10627 asUCString : function(s) {
10628 return String(s).toUpperCase();
10633 * @param {Mixed} s The value being converted
10634 * @return {Number} The comparison value
10636 asDate : function(s) {
10640 if(s instanceof Date){
10641 return s.getTime();
10643 return Date.parse(String(s));
10648 * @param {Mixed} s The value being converted
10649 * @return {Float} The comparison value
10651 asFloat : function(s) {
10652 var val = parseFloat(String(s).replace(/,/g, ""));
10661 * @param {Mixed} s The value being converted
10662 * @return {Number} The comparison value
10664 asInt : function(s) {
10665 var val = parseInt(String(s).replace(/,/g, ""));
10673 * Ext JS Library 1.1.1
10674 * Copyright(c) 2006-2007, Ext JS, LLC.
10676 * Originally Released Under LGPL - original licence link has changed is not relivant.
10679 * <script type="text/javascript">
10683 * @class Roo.data.Record
10684 * Instances of this class encapsulate both record <em>definition</em> information, and record
10685 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10686 * to access Records cached in an {@link Roo.data.Store} object.<br>
10688 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10689 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10692 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10694 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10695 * {@link #create}. The parameters are the same.
10696 * @param {Array} data An associative Array of data values keyed by the field name.
10697 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10698 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10699 * not specified an integer id is generated.
10701 Roo.data.Record = function(data, id){
10702 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10707 * Generate a constructor for a specific record layout.
10708 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10709 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10710 * Each field definition object may contain the following properties: <ul>
10711 * <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,
10712 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10713 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10714 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10715 * is being used, then this is a string containing the javascript expression to reference the data relative to
10716 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10717 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10718 * this may be omitted.</p></li>
10719 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10720 * <ul><li>auto (Default, implies no conversion)</li>
10725 * <li>date</li></ul></p></li>
10726 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10727 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10728 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10729 * by the Reader into an object that will be stored in the Record. It is passed the
10730 * following parameters:<ul>
10731 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10733 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10735 * <br>usage:<br><pre><code>
10736 var TopicRecord = Roo.data.Record.create(
10737 {name: 'title', mapping: 'topic_title'},
10738 {name: 'author', mapping: 'username'},
10739 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10740 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10741 {name: 'lastPoster', mapping: 'user2'},
10742 {name: 'excerpt', mapping: 'post_text'}
10745 var myNewRecord = new TopicRecord({
10746 title: 'Do my job please',
10749 lastPost: new Date(),
10750 lastPoster: 'Animal',
10751 excerpt: 'No way dude!'
10753 myStore.add(myNewRecord);
10758 Roo.data.Record.create = function(o){
10759 var f = function(){
10760 f.superclass.constructor.apply(this, arguments);
10762 Roo.extend(f, Roo.data.Record);
10763 var p = f.prototype;
10764 p.fields = new Roo.util.MixedCollection(false, function(field){
10767 for(var i = 0, len = o.length; i < len; i++){
10768 p.fields.add(new Roo.data.Field(o[i]));
10770 f.getField = function(name){
10771 return p.fields.get(name);
10776 Roo.data.Record.AUTO_ID = 1000;
10777 Roo.data.Record.EDIT = 'edit';
10778 Roo.data.Record.REJECT = 'reject';
10779 Roo.data.Record.COMMIT = 'commit';
10781 Roo.data.Record.prototype = {
10783 * Readonly flag - true if this record has been modified.
10792 join : function(store){
10793 this.store = store;
10797 * Set the named field to the specified value.
10798 * @param {String} name The name of the field to set.
10799 * @param {Object} value The value to set the field to.
10801 set : function(name, value){
10802 if(this.data[name] == value){
10806 if(!this.modified){
10807 this.modified = {};
10809 if(typeof this.modified[name] == 'undefined'){
10810 this.modified[name] = this.data[name];
10812 this.data[name] = value;
10813 if(!this.editing && this.store){
10814 this.store.afterEdit(this);
10819 * Get the value of the named field.
10820 * @param {String} name The name of the field to get the value of.
10821 * @return {Object} The value of the field.
10823 get : function(name){
10824 return this.data[name];
10828 beginEdit : function(){
10829 this.editing = true;
10830 this.modified = {};
10834 cancelEdit : function(){
10835 this.editing = false;
10836 delete this.modified;
10840 endEdit : function(){
10841 this.editing = false;
10842 if(this.dirty && this.store){
10843 this.store.afterEdit(this);
10848 * Usually called by the {@link Roo.data.Store} which owns the Record.
10849 * Rejects all changes made to the Record since either creation, or the last commit operation.
10850 * Modified fields are reverted to their original values.
10852 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10853 * of reject operations.
10855 reject : function(){
10856 var m = this.modified;
10858 if(typeof m[n] != "function"){
10859 this.data[n] = m[n];
10862 this.dirty = false;
10863 delete this.modified;
10864 this.editing = false;
10866 this.store.afterReject(this);
10871 * Usually called by the {@link Roo.data.Store} which owns the Record.
10872 * Commits all changes made to the Record since either creation, or the last commit operation.
10874 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10875 * of commit operations.
10877 commit : function(){
10878 this.dirty = false;
10879 delete this.modified;
10880 this.editing = false;
10882 this.store.afterCommit(this);
10887 hasError : function(){
10888 return this.error != null;
10892 clearError : function(){
10897 * Creates a copy of this record.
10898 * @param {String} id (optional) A new record id if you don't want to use this record's id
10901 copy : function(newId) {
10902 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10906 * Ext JS Library 1.1.1
10907 * Copyright(c) 2006-2007, Ext JS, LLC.
10909 * Originally Released Under LGPL - original licence link has changed is not relivant.
10912 * <script type="text/javascript">
10918 * @class Roo.data.Store
10919 * @extends Roo.util.Observable
10920 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10921 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10923 * 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
10924 * has no knowledge of the format of the data returned by the Proxy.<br>
10926 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10927 * instances from the data object. These records are cached and made available through accessor functions.
10929 * Creates a new Store.
10930 * @param {Object} config A config object containing the objects needed for the Store to access data,
10931 * and read the data into Records.
10933 Roo.data.Store = function(config){
10934 this.data = new Roo.util.MixedCollection(false);
10935 this.data.getKey = function(o){
10938 this.baseParams = {};
10940 this.paramNames = {
10945 "multisort" : "_multisort"
10948 if(config && config.data){
10949 this.inlineData = config.data;
10950 delete config.data;
10953 Roo.apply(this, config);
10955 if(this.reader){ // reader passed
10956 this.reader = Roo.factory(this.reader, Roo.data);
10957 this.reader.xmodule = this.xmodule || false;
10958 if(!this.recordType){
10959 this.recordType = this.reader.recordType;
10961 if(this.reader.onMetaChange){
10962 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10966 if(this.recordType){
10967 this.fields = this.recordType.prototype.fields;
10969 this.modified = [];
10973 * @event datachanged
10974 * Fires when the data cache has changed, and a widget which is using this Store
10975 * as a Record cache should refresh its view.
10976 * @param {Store} this
10978 datachanged : true,
10980 * @event metachange
10981 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10982 * @param {Store} this
10983 * @param {Object} meta The JSON metadata
10988 * Fires when Records have been added to the Store
10989 * @param {Store} this
10990 * @param {Roo.data.Record[]} records The array of Records added
10991 * @param {Number} index The index at which the record(s) were added
10996 * Fires when a Record has been removed from the Store
10997 * @param {Store} this
10998 * @param {Roo.data.Record} record The Record that was removed
10999 * @param {Number} index The index at which the record was removed
11004 * Fires when a Record has been updated
11005 * @param {Store} this
11006 * @param {Roo.data.Record} record The Record that was updated
11007 * @param {String} operation The update operation being performed. Value may be one of:
11009 Roo.data.Record.EDIT
11010 Roo.data.Record.REJECT
11011 Roo.data.Record.COMMIT
11017 * Fires when the data cache has been cleared.
11018 * @param {Store} this
11022 * @event beforeload
11023 * Fires before a request is made for a new data object. If the beforeload handler returns false
11024 * the load action will be canceled.
11025 * @param {Store} this
11026 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11030 * @event beforeloadadd
11031 * Fires after a new set of Records has been loaded.
11032 * @param {Store} this
11033 * @param {Roo.data.Record[]} records The Records that were loaded
11034 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11036 beforeloadadd : true,
11039 * Fires after a new set of Records has been loaded, before they are added to the store.
11040 * @param {Store} this
11041 * @param {Roo.data.Record[]} records The Records that were loaded
11042 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11043 * @params {Object} return from reader
11047 * @event loadexception
11048 * Fires if an exception occurs in the Proxy during loading.
11049 * Called with the signature of the Proxy's "loadexception" event.
11050 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11053 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11054 * @param {Object} load options
11055 * @param {Object} jsonData from your request (normally this contains the Exception)
11057 loadexception : true
11061 this.proxy = Roo.factory(this.proxy, Roo.data);
11062 this.proxy.xmodule = this.xmodule || false;
11063 this.relayEvents(this.proxy, ["loadexception"]);
11065 this.sortToggle = {};
11066 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11068 Roo.data.Store.superclass.constructor.call(this);
11070 if(this.inlineData){
11071 this.loadData(this.inlineData);
11072 delete this.inlineData;
11076 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11078 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11079 * without a remote query - used by combo/forms at present.
11083 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11086 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11089 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11090 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11093 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11094 * on any HTTP request
11097 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11100 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11104 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11105 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11107 remoteSort : false,
11110 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11111 * loaded or when a record is removed. (defaults to false).
11113 pruneModifiedRecords : false,
11116 lastOptions : null,
11119 * Add Records to the Store and fires the add event.
11120 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11122 add : function(records){
11123 records = [].concat(records);
11124 for(var i = 0, len = records.length; i < len; i++){
11125 records[i].join(this);
11127 var index = this.data.length;
11128 this.data.addAll(records);
11129 this.fireEvent("add", this, records, index);
11133 * Remove a Record from the Store and fires the remove event.
11134 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11136 remove : function(record){
11137 var index = this.data.indexOf(record);
11138 this.data.removeAt(index);
11140 if(this.pruneModifiedRecords){
11141 this.modified.remove(record);
11143 this.fireEvent("remove", this, record, index);
11147 * Remove all Records from the Store and fires the clear event.
11149 removeAll : function(){
11151 if(this.pruneModifiedRecords){
11152 this.modified = [];
11154 this.fireEvent("clear", this);
11158 * Inserts Records to the Store at the given index and fires the add event.
11159 * @param {Number} index The start index at which to insert the passed Records.
11160 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11162 insert : function(index, records){
11163 records = [].concat(records);
11164 for(var i = 0, len = records.length; i < len; i++){
11165 this.data.insert(index, records[i]);
11166 records[i].join(this);
11168 this.fireEvent("add", this, records, index);
11172 * Get the index within the cache of the passed Record.
11173 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11174 * @return {Number} The index of the passed Record. Returns -1 if not found.
11176 indexOf : function(record){
11177 return this.data.indexOf(record);
11181 * Get the index within the cache of the Record with the passed id.
11182 * @param {String} id The id of the Record to find.
11183 * @return {Number} The index of the Record. Returns -1 if not found.
11185 indexOfId : function(id){
11186 return this.data.indexOfKey(id);
11190 * Get the Record with the specified id.
11191 * @param {String} id The id of the Record to find.
11192 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11194 getById : function(id){
11195 return this.data.key(id);
11199 * Get the Record at the specified index.
11200 * @param {Number} index The index of the Record to find.
11201 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11203 getAt : function(index){
11204 return this.data.itemAt(index);
11208 * Returns a range of Records between specified indices.
11209 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11210 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11211 * @return {Roo.data.Record[]} An array of Records
11213 getRange : function(start, end){
11214 return this.data.getRange(start, end);
11218 storeOptions : function(o){
11219 o = Roo.apply({}, o);
11222 this.lastOptions = o;
11226 * Loads the Record cache from the configured Proxy using the configured Reader.
11228 * If using remote paging, then the first load call must specify the <em>start</em>
11229 * and <em>limit</em> properties in the options.params property to establish the initial
11230 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11232 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11233 * and this call will return before the new data has been loaded. Perform any post-processing
11234 * in a callback function, or in a "load" event handler.</strong>
11236 * @param {Object} options An object containing properties which control loading options:<ul>
11237 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11238 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11239 * passed the following arguments:<ul>
11240 * <li>r : Roo.data.Record[]</li>
11241 * <li>options: Options object from the load call</li>
11242 * <li>success: Boolean success indicator</li></ul></li>
11243 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11244 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11247 load : function(options){
11248 options = options || {};
11249 if(this.fireEvent("beforeload", this, options) !== false){
11250 this.storeOptions(options);
11251 var p = Roo.apply(options.params || {}, this.baseParams);
11252 // if meta was not loaded from remote source.. try requesting it.
11253 if (!this.reader.metaFromRemote) {
11254 p._requestMeta = 1;
11256 if(this.sortInfo && this.remoteSort){
11257 var pn = this.paramNames;
11258 p[pn["sort"]] = this.sortInfo.field;
11259 p[pn["dir"]] = this.sortInfo.direction;
11261 if (this.multiSort) {
11262 var pn = this.paramNames;
11263 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11266 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11271 * Reloads the Record cache from the configured Proxy using the configured Reader and
11272 * the options from the last load operation performed.
11273 * @param {Object} options (optional) An object containing properties which may override the options
11274 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11275 * the most recently used options are reused).
11277 reload : function(options){
11278 this.load(Roo.applyIf(options||{}, this.lastOptions));
11282 // Called as a callback by the Reader during a load operation.
11283 loadRecords : function(o, options, success){
11284 if(!o || success === false){
11285 if(success !== false){
11286 this.fireEvent("load", this, [], options, o);
11288 if(options.callback){
11289 options.callback.call(options.scope || this, [], options, false);
11293 // if data returned failure - throw an exception.
11294 if (o.success === false) {
11295 // show a message if no listener is registered.
11296 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11297 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11299 // loadmask wil be hooked into this..
11300 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11303 var r = o.records, t = o.totalRecords || r.length;
11305 this.fireEvent("beforeloadadd", this, r, options, o);
11307 if(!options || options.add !== true){
11308 if(this.pruneModifiedRecords){
11309 this.modified = [];
11311 for(var i = 0, len = r.length; i < len; i++){
11315 this.data = this.snapshot;
11316 delete this.snapshot;
11319 this.data.addAll(r);
11320 this.totalLength = t;
11322 this.fireEvent("datachanged", this);
11324 this.totalLength = Math.max(t, this.data.length+r.length);
11328 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11330 var e = new Roo.data.Record({});
11332 e.set(this.parent.displayField, this.parent.emptyTitle);
11333 e.set(this.parent.valueField, '');
11338 this.fireEvent("load", this, r, options, o);
11339 if(options.callback){
11340 options.callback.call(options.scope || this, r, options, true);
11346 * Loads data from a passed data block. A Reader which understands the format of the data
11347 * must have been configured in the constructor.
11348 * @param {Object} data The data block from which to read the Records. The format of the data expected
11349 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11350 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11352 loadData : function(o, append){
11353 var r = this.reader.readRecords(o);
11354 this.loadRecords(r, {add: append}, true);
11358 * Gets the number of cached records.
11360 * <em>If using paging, this may not be the total size of the dataset. If the data object
11361 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11362 * the data set size</em>
11364 getCount : function(){
11365 return this.data.length || 0;
11369 * Gets the total number of records in the dataset as returned by the server.
11371 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11372 * the dataset size</em>
11374 getTotalCount : function(){
11375 return this.totalLength || 0;
11379 * Returns the sort state of the Store as an object with two properties:
11381 field {String} The name of the field by which the Records are sorted
11382 direction {String} The sort order, "ASC" or "DESC"
11385 getSortState : function(){
11386 return this.sortInfo;
11390 applySort : function(){
11391 if(this.sortInfo && !this.remoteSort){
11392 var s = this.sortInfo, f = s.field;
11393 var st = this.fields.get(f).sortType;
11394 var fn = function(r1, r2){
11395 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11396 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11398 this.data.sort(s.direction, fn);
11399 if(this.snapshot && this.snapshot != this.data){
11400 this.snapshot.sort(s.direction, fn);
11406 * Sets the default sort column and order to be used by the next load operation.
11407 * @param {String} fieldName The name of the field to sort by.
11408 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11410 setDefaultSort : function(field, dir){
11411 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11415 * Sort the Records.
11416 * If remote sorting is used, the sort is performed on the server, and the cache is
11417 * reloaded. If local sorting is used, the cache is sorted internally.
11418 * @param {String} fieldName The name of the field to sort by.
11419 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11421 sort : function(fieldName, dir){
11422 var f = this.fields.get(fieldName);
11424 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11426 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11427 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11432 this.sortToggle[f.name] = dir;
11433 this.sortInfo = {field: f.name, direction: dir};
11434 if(!this.remoteSort){
11436 this.fireEvent("datachanged", this);
11438 this.load(this.lastOptions);
11443 * Calls the specified function for each of the Records in the cache.
11444 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11445 * Returning <em>false</em> aborts and exits the iteration.
11446 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11448 each : function(fn, scope){
11449 this.data.each(fn, scope);
11453 * Gets all records modified since the last commit. Modified records are persisted across load operations
11454 * (e.g., during paging).
11455 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11457 getModifiedRecords : function(){
11458 return this.modified;
11462 createFilterFn : function(property, value, anyMatch){
11463 if(!value.exec){ // not a regex
11464 value = String(value);
11465 if(value.length == 0){
11468 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11470 return function(r){
11471 return value.test(r.data[property]);
11476 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11477 * @param {String} property A field on your records
11478 * @param {Number} start The record index to start at (defaults to 0)
11479 * @param {Number} end The last record index to include (defaults to length - 1)
11480 * @return {Number} The sum
11482 sum : function(property, start, end){
11483 var rs = this.data.items, v = 0;
11484 start = start || 0;
11485 end = (end || end === 0) ? end : rs.length-1;
11487 for(var i = start; i <= end; i++){
11488 v += (rs[i].data[property] || 0);
11494 * Filter the records by a specified property.
11495 * @param {String} field A field on your records
11496 * @param {String/RegExp} value Either a string that the field
11497 * should start with or a RegExp to test against the field
11498 * @param {Boolean} anyMatch True to match any part not just the beginning
11500 filter : function(property, value, anyMatch){
11501 var fn = this.createFilterFn(property, value, anyMatch);
11502 return fn ? this.filterBy(fn) : this.clearFilter();
11506 * Filter by a function. The specified function will be called with each
11507 * record in this data source. If the function returns true the record is included,
11508 * otherwise it is filtered.
11509 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11510 * @param {Object} scope (optional) The scope of the function (defaults to this)
11512 filterBy : function(fn, scope){
11513 this.snapshot = this.snapshot || this.data;
11514 this.data = this.queryBy(fn, scope||this);
11515 this.fireEvent("datachanged", this);
11519 * Query the records by a specified property.
11520 * @param {String} field A field on your records
11521 * @param {String/RegExp} value Either a string that the field
11522 * should start with or a RegExp to test against the field
11523 * @param {Boolean} anyMatch True to match any part not just the beginning
11524 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11526 query : function(property, value, anyMatch){
11527 var fn = this.createFilterFn(property, value, anyMatch);
11528 return fn ? this.queryBy(fn) : this.data.clone();
11532 * Query by a function. The specified function will be called with each
11533 * record in this data source. If the function returns true the record is included
11535 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11536 * @param {Object} scope (optional) The scope of the function (defaults to this)
11537 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11539 queryBy : function(fn, scope){
11540 var data = this.snapshot || this.data;
11541 return data.filterBy(fn, scope||this);
11545 * Collects unique values for a particular dataIndex from this store.
11546 * @param {String} dataIndex The property to collect
11547 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11548 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11549 * @return {Array} An array of the unique values
11551 collect : function(dataIndex, allowNull, bypassFilter){
11552 var d = (bypassFilter === true && this.snapshot) ?
11553 this.snapshot.items : this.data.items;
11554 var v, sv, r = [], l = {};
11555 for(var i = 0, len = d.length; i < len; i++){
11556 v = d[i].data[dataIndex];
11558 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11567 * Revert to a view of the Record cache with no filtering applied.
11568 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11570 clearFilter : function(suppressEvent){
11571 if(this.snapshot && this.snapshot != this.data){
11572 this.data = this.snapshot;
11573 delete this.snapshot;
11574 if(suppressEvent !== true){
11575 this.fireEvent("datachanged", this);
11581 afterEdit : function(record){
11582 if(this.modified.indexOf(record) == -1){
11583 this.modified.push(record);
11585 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11589 afterReject : function(record){
11590 this.modified.remove(record);
11591 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11595 afterCommit : function(record){
11596 this.modified.remove(record);
11597 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11601 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11602 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11604 commitChanges : function(){
11605 var m = this.modified.slice(0);
11606 this.modified = [];
11607 for(var i = 0, len = m.length; i < len; i++){
11613 * Cancel outstanding changes on all changed records.
11615 rejectChanges : function(){
11616 var m = this.modified.slice(0);
11617 this.modified = [];
11618 for(var i = 0, len = m.length; i < len; i++){
11623 onMetaChange : function(meta, rtype, o){
11624 this.recordType = rtype;
11625 this.fields = rtype.prototype.fields;
11626 delete this.snapshot;
11627 this.sortInfo = meta.sortInfo || this.sortInfo;
11628 this.modified = [];
11629 this.fireEvent('metachange', this, this.reader.meta);
11632 moveIndex : function(data, type)
11634 var index = this.indexOf(data);
11636 var newIndex = index + type;
11640 this.insert(newIndex, data);
11645 * Ext JS Library 1.1.1
11646 * Copyright(c) 2006-2007, Ext JS, LLC.
11648 * Originally Released Under LGPL - original licence link has changed is not relivant.
11651 * <script type="text/javascript">
11655 * @class Roo.data.SimpleStore
11656 * @extends Roo.data.Store
11657 * Small helper class to make creating Stores from Array data easier.
11658 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11659 * @cfg {Array} fields An array of field definition objects, or field name strings.
11660 * @cfg {Array} data The multi-dimensional array of data
11662 * @param {Object} config
11664 Roo.data.SimpleStore = function(config){
11665 Roo.data.SimpleStore.superclass.constructor.call(this, {
11667 reader: new Roo.data.ArrayReader({
11670 Roo.data.Record.create(config.fields)
11672 proxy : new Roo.data.MemoryProxy(config.data)
11676 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11678 * Ext JS Library 1.1.1
11679 * Copyright(c) 2006-2007, Ext JS, LLC.
11681 * Originally Released Under LGPL - original licence link has changed is not relivant.
11684 * <script type="text/javascript">
11689 * @extends Roo.data.Store
11690 * @class Roo.data.JsonStore
11691 * Small helper class to make creating Stores for JSON data easier. <br/>
11693 var store = new Roo.data.JsonStore({
11694 url: 'get-images.php',
11696 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11699 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11700 * JsonReader and HttpProxy (unless inline data is provided).</b>
11701 * @cfg {Array} fields An array of field definition objects, or field name strings.
11703 * @param {Object} config
11705 Roo.data.JsonStore = function(c){
11706 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11707 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11708 reader: new Roo.data.JsonReader(c, c.fields)
11711 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11713 * Ext JS Library 1.1.1
11714 * Copyright(c) 2006-2007, Ext JS, LLC.
11716 * Originally Released Under LGPL - original licence link has changed is not relivant.
11719 * <script type="text/javascript">
11723 Roo.data.Field = function(config){
11724 if(typeof config == "string"){
11725 config = {name: config};
11727 Roo.apply(this, config);
11730 this.type = "auto";
11733 var st = Roo.data.SortTypes;
11734 // named sortTypes are supported, here we look them up
11735 if(typeof this.sortType == "string"){
11736 this.sortType = st[this.sortType];
11739 // set default sortType for strings and dates
11740 if(!this.sortType){
11743 this.sortType = st.asUCString;
11746 this.sortType = st.asDate;
11749 this.sortType = st.none;
11754 var stripRe = /[\$,%]/g;
11756 // prebuilt conversion function for this field, instead of
11757 // switching every time we're reading a value
11759 var cv, dateFormat = this.dateFormat;
11764 cv = function(v){ return v; };
11767 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11771 return v !== undefined && v !== null && v !== '' ?
11772 parseInt(String(v).replace(stripRe, ""), 10) : '';
11777 return v !== undefined && v !== null && v !== '' ?
11778 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11783 cv = function(v){ return v === true || v === "true" || v == 1; };
11790 if(v instanceof Date){
11794 if(dateFormat == "timestamp"){
11795 return new Date(v*1000);
11797 return Date.parseDate(v, dateFormat);
11799 var parsed = Date.parse(v);
11800 return parsed ? new Date(parsed) : null;
11809 Roo.data.Field.prototype = {
11817 * Ext JS Library 1.1.1
11818 * Copyright(c) 2006-2007, Ext JS, LLC.
11820 * Originally Released Under LGPL - original licence link has changed is not relivant.
11823 * <script type="text/javascript">
11826 // Base class for reading structured data from a data source. This class is intended to be
11827 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11830 * @class Roo.data.DataReader
11831 * Base class for reading structured data from a data source. This class is intended to be
11832 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11835 Roo.data.DataReader = function(meta, recordType){
11839 this.recordType = recordType instanceof Array ?
11840 Roo.data.Record.create(recordType) : recordType;
11843 Roo.data.DataReader.prototype = {
11845 * Create an empty record
11846 * @param {Object} data (optional) - overlay some values
11847 * @return {Roo.data.Record} record created.
11849 newRow : function(d) {
11851 this.recordType.prototype.fields.each(function(c) {
11853 case 'int' : da[c.name] = 0; break;
11854 case 'date' : da[c.name] = new Date(); break;
11855 case 'float' : da[c.name] = 0.0; break;
11856 case 'boolean' : da[c.name] = false; break;
11857 default : da[c.name] = ""; break;
11861 return new this.recordType(Roo.apply(da, d));
11866 * Ext JS Library 1.1.1
11867 * Copyright(c) 2006-2007, Ext JS, LLC.
11869 * Originally Released Under LGPL - original licence link has changed is not relivant.
11872 * <script type="text/javascript">
11876 * @class Roo.data.DataProxy
11877 * @extends Roo.data.Observable
11878 * This class is an abstract base class for implementations which provide retrieval of
11879 * unformatted data objects.<br>
11881 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11882 * (of the appropriate type which knows how to parse the data object) to provide a block of
11883 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11885 * Custom implementations must implement the load method as described in
11886 * {@link Roo.data.HttpProxy#load}.
11888 Roo.data.DataProxy = function(){
11891 * @event beforeload
11892 * Fires before a network request is made to retrieve a data object.
11893 * @param {Object} This DataProxy object.
11894 * @param {Object} params The params parameter to the load function.
11899 * Fires before the load method's callback is called.
11900 * @param {Object} This DataProxy object.
11901 * @param {Object} o The data object.
11902 * @param {Object} arg The callback argument object passed to the load function.
11906 * @event loadexception
11907 * Fires if an Exception occurs during data retrieval.
11908 * @param {Object} This DataProxy object.
11909 * @param {Object} o The data object.
11910 * @param {Object} arg The callback argument object passed to the load function.
11911 * @param {Object} e The Exception.
11913 loadexception : true
11915 Roo.data.DataProxy.superclass.constructor.call(this);
11918 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11921 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11925 * Ext JS Library 1.1.1
11926 * Copyright(c) 2006-2007, Ext JS, LLC.
11928 * Originally Released Under LGPL - original licence link has changed is not relivant.
11931 * <script type="text/javascript">
11934 * @class Roo.data.MemoryProxy
11935 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11936 * to the Reader when its load method is called.
11938 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11940 Roo.data.MemoryProxy = function(data){
11944 Roo.data.MemoryProxy.superclass.constructor.call(this);
11948 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11951 * Load data from the requested source (in this case an in-memory
11952 * data object passed to the constructor), read the data object into
11953 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11954 * process that block using the passed callback.
11955 * @param {Object} params This parameter is not used by the MemoryProxy class.
11956 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11957 * object into a block of Roo.data.Records.
11958 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11959 * The function must be passed <ul>
11960 * <li>The Record block object</li>
11961 * <li>The "arg" argument from the load function</li>
11962 * <li>A boolean success indicator</li>
11964 * @param {Object} scope The scope in which to call the callback
11965 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11967 load : function(params, reader, callback, scope, arg){
11968 params = params || {};
11971 result = reader.readRecords(this.data);
11973 this.fireEvent("loadexception", this, arg, null, e);
11974 callback.call(scope, null, arg, false);
11977 callback.call(scope, result, arg, true);
11981 update : function(params, records){
11986 * Ext JS Library 1.1.1
11987 * Copyright(c) 2006-2007, Ext JS, LLC.
11989 * Originally Released Under LGPL - original licence link has changed is not relivant.
11992 * <script type="text/javascript">
11995 * @class Roo.data.HttpProxy
11996 * @extends Roo.data.DataProxy
11997 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11998 * configured to reference a certain URL.<br><br>
12000 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12001 * from which the running page was served.<br><br>
12003 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12005 * Be aware that to enable the browser to parse an XML document, the server must set
12006 * the Content-Type header in the HTTP response to "text/xml".
12008 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12009 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12010 * will be used to make the request.
12012 Roo.data.HttpProxy = function(conn){
12013 Roo.data.HttpProxy.superclass.constructor.call(this);
12014 // is conn a conn config or a real conn?
12016 this.useAjax = !conn || !conn.events;
12020 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12021 // thse are take from connection...
12024 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12027 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12028 * extra parameters to each request made by this object. (defaults to undefined)
12031 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12032 * to each request made by this object. (defaults to undefined)
12035 * @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)
12038 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12041 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12047 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12051 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12052 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12053 * a finer-grained basis than the DataProxy events.
12055 getConnection : function(){
12056 return this.useAjax ? Roo.Ajax : this.conn;
12060 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12061 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12062 * process that block using the passed callback.
12063 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12064 * for the request to the remote server.
12065 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12066 * object into a block of Roo.data.Records.
12067 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12068 * The function must be passed <ul>
12069 * <li>The Record block object</li>
12070 * <li>The "arg" argument from the load function</li>
12071 * <li>A boolean success indicator</li>
12073 * @param {Object} scope The scope in which to call the callback
12074 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12076 load : function(params, reader, callback, scope, arg){
12077 if(this.fireEvent("beforeload", this, params) !== false){
12079 params : params || {},
12081 callback : callback,
12086 callback : this.loadResponse,
12090 Roo.applyIf(o, this.conn);
12091 if(this.activeRequest){
12092 Roo.Ajax.abort(this.activeRequest);
12094 this.activeRequest = Roo.Ajax.request(o);
12096 this.conn.request(o);
12099 callback.call(scope||this, null, arg, false);
12104 loadResponse : function(o, success, response){
12105 delete this.activeRequest;
12107 this.fireEvent("loadexception", this, o, response);
12108 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12113 result = o.reader.read(response);
12115 this.fireEvent("loadexception", this, o, response, e);
12116 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12120 this.fireEvent("load", this, o, o.request.arg);
12121 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12125 update : function(dataSet){
12130 updateResponse : function(dataSet){
12135 * Ext JS Library 1.1.1
12136 * Copyright(c) 2006-2007, Ext JS, LLC.
12138 * Originally Released Under LGPL - original licence link has changed is not relivant.
12141 * <script type="text/javascript">
12145 * @class Roo.data.ScriptTagProxy
12146 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12147 * other than the originating domain of the running page.<br><br>
12149 * <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
12150 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12152 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12153 * source code that is used as the source inside a <script> tag.<br><br>
12155 * In order for the browser to process the returned data, the server must wrap the data object
12156 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12157 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12158 * depending on whether the callback name was passed:
12161 boolean scriptTag = false;
12162 String cb = request.getParameter("callback");
12165 response.setContentType("text/javascript");
12167 response.setContentType("application/x-json");
12169 Writer out = response.getWriter();
12171 out.write(cb + "(");
12173 out.print(dataBlock.toJsonString());
12180 * @param {Object} config A configuration object.
12182 Roo.data.ScriptTagProxy = function(config){
12183 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12184 Roo.apply(this, config);
12185 this.head = document.getElementsByTagName("head")[0];
12188 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12190 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12192 * @cfg {String} url The URL from which to request the data object.
12195 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12199 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12200 * the server the name of the callback function set up by the load call to process the returned data object.
12201 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12202 * javascript output which calls this named function passing the data object as its only parameter.
12204 callbackParam : "callback",
12206 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12207 * name to the request.
12212 * Load data from the configured URL, read the data object into
12213 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12214 * process that block using the passed callback.
12215 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12216 * for the request to the remote server.
12217 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12218 * object into a block of Roo.data.Records.
12219 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12220 * The function must be passed <ul>
12221 * <li>The Record block object</li>
12222 * <li>The "arg" argument from the load function</li>
12223 * <li>A boolean success indicator</li>
12225 * @param {Object} scope The scope in which to call the callback
12226 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12228 load : function(params, reader, callback, scope, arg){
12229 if(this.fireEvent("beforeload", this, params) !== false){
12231 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12233 var url = this.url;
12234 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12236 url += "&_dc=" + (new Date().getTime());
12238 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12241 cb : "stcCallback"+transId,
12242 scriptId : "stcScript"+transId,
12246 callback : callback,
12252 window[trans.cb] = function(o){
12253 conn.handleResponse(o, trans);
12256 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12258 if(this.autoAbort !== false){
12262 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12264 var script = document.createElement("script");
12265 script.setAttribute("src", url);
12266 script.setAttribute("type", "text/javascript");
12267 script.setAttribute("id", trans.scriptId);
12268 this.head.appendChild(script);
12270 this.trans = trans;
12272 callback.call(scope||this, null, arg, false);
12277 isLoading : function(){
12278 return this.trans ? true : false;
12282 * Abort the current server request.
12284 abort : function(){
12285 if(this.isLoading()){
12286 this.destroyTrans(this.trans);
12291 destroyTrans : function(trans, isLoaded){
12292 this.head.removeChild(document.getElementById(trans.scriptId));
12293 clearTimeout(trans.timeoutId);
12295 window[trans.cb] = undefined;
12297 delete window[trans.cb];
12300 // if hasn't been loaded, wait for load to remove it to prevent script error
12301 window[trans.cb] = function(){
12302 window[trans.cb] = undefined;
12304 delete window[trans.cb];
12311 handleResponse : function(o, trans){
12312 this.trans = false;
12313 this.destroyTrans(trans, true);
12316 result = trans.reader.readRecords(o);
12318 this.fireEvent("loadexception", this, o, trans.arg, e);
12319 trans.callback.call(trans.scope||window, null, trans.arg, false);
12322 this.fireEvent("load", this, o, trans.arg);
12323 trans.callback.call(trans.scope||window, result, trans.arg, true);
12327 handleFailure : function(trans){
12328 this.trans = false;
12329 this.destroyTrans(trans, false);
12330 this.fireEvent("loadexception", this, null, trans.arg);
12331 trans.callback.call(trans.scope||window, null, trans.arg, false);
12335 * Ext JS Library 1.1.1
12336 * Copyright(c) 2006-2007, Ext JS, LLC.
12338 * Originally Released Under LGPL - original licence link has changed is not relivant.
12341 * <script type="text/javascript">
12345 * @class Roo.data.JsonReader
12346 * @extends Roo.data.DataReader
12347 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12348 * based on mappings in a provided Roo.data.Record constructor.
12350 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12351 * in the reply previously.
12356 var RecordDef = Roo.data.Record.create([
12357 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12358 {name: 'occupation'} // This field will use "occupation" as the mapping.
12360 var myReader = new Roo.data.JsonReader({
12361 totalProperty: "results", // The property which contains the total dataset size (optional)
12362 root: "rows", // The property which contains an Array of row objects
12363 id: "id" // The property within each row object that provides an ID for the record (optional)
12367 * This would consume a JSON file like this:
12369 { 'results': 2, 'rows': [
12370 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12371 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12374 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12375 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12376 * paged from the remote server.
12377 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12378 * @cfg {String} root name of the property which contains the Array of row objects.
12379 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12380 * @cfg {Array} fields Array of field definition objects
12382 * Create a new JsonReader
12383 * @param {Object} meta Metadata configuration options
12384 * @param {Object} recordType Either an Array of field definition objects,
12385 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12387 Roo.data.JsonReader = function(meta, recordType){
12390 // set some defaults:
12391 Roo.applyIf(meta, {
12392 totalProperty: 'total',
12393 successProperty : 'success',
12398 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12400 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12403 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12404 * Used by Store query builder to append _requestMeta to params.
12407 metaFromRemote : false,
12409 * This method is only used by a DataProxy which has retrieved data from a remote server.
12410 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12411 * @return {Object} data A data block which is used by an Roo.data.Store object as
12412 * a cache of Roo.data.Records.
12414 read : function(response){
12415 var json = response.responseText;
12417 var o = /* eval:var:o */ eval("("+json+")");
12419 throw {message: "JsonReader.read: Json object not found"};
12425 this.metaFromRemote = true;
12426 this.meta = o.metaData;
12427 this.recordType = Roo.data.Record.create(o.metaData.fields);
12428 this.onMetaChange(this.meta, this.recordType, o);
12430 return this.readRecords(o);
12433 // private function a store will implement
12434 onMetaChange : function(meta, recordType, o){
12441 simpleAccess: function(obj, subsc) {
12448 getJsonAccessor: function(){
12450 return function(expr) {
12452 return(re.test(expr))
12453 ? new Function("obj", "return obj." + expr)
12458 return Roo.emptyFn;
12463 * Create a data block containing Roo.data.Records from an XML document.
12464 * @param {Object} o An object which contains an Array of row objects in the property specified
12465 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12466 * which contains the total size of the dataset.
12467 * @return {Object} data A data block which is used by an Roo.data.Store object as
12468 * a cache of Roo.data.Records.
12470 readRecords : function(o){
12472 * After any data loads, the raw JSON data is available for further custom processing.
12476 var s = this.meta, Record = this.recordType,
12477 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12479 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12481 if(s.totalProperty) {
12482 this.getTotal = this.getJsonAccessor(s.totalProperty);
12484 if(s.successProperty) {
12485 this.getSuccess = this.getJsonAccessor(s.successProperty);
12487 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12489 var g = this.getJsonAccessor(s.id);
12490 this.getId = function(rec) {
12492 return (r === undefined || r === "") ? null : r;
12495 this.getId = function(){return null;};
12498 for(var jj = 0; jj < fl; jj++){
12500 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12501 this.ef[jj] = this.getJsonAccessor(map);
12505 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12506 if(s.totalProperty){
12507 var vt = parseInt(this.getTotal(o), 10);
12512 if(s.successProperty){
12513 var vs = this.getSuccess(o);
12514 if(vs === false || vs === 'false'){
12519 for(var i = 0; i < c; i++){
12522 var id = this.getId(n);
12523 for(var j = 0; j < fl; j++){
12525 var v = this.ef[j](n);
12527 Roo.log('missing convert for ' + f.name);
12531 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12533 var record = new Record(values, id);
12535 records[i] = record;
12541 totalRecords : totalRecords
12546 * Ext JS Library 1.1.1
12547 * Copyright(c) 2006-2007, Ext JS, LLC.
12549 * Originally Released Under LGPL - original licence link has changed is not relivant.
12552 * <script type="text/javascript">
12556 * @class Roo.data.ArrayReader
12557 * @extends Roo.data.DataReader
12558 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12559 * Each element of that Array represents a row of data fields. The
12560 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12561 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12565 var RecordDef = Roo.data.Record.create([
12566 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12567 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12569 var myReader = new Roo.data.ArrayReader({
12570 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12574 * This would consume an Array like this:
12576 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12578 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12580 * Create a new JsonReader
12581 * @param {Object} meta Metadata configuration options.
12582 * @param {Object} recordType Either an Array of field definition objects
12583 * as specified to {@link Roo.data.Record#create},
12584 * or an {@link Roo.data.Record} object
12585 * created using {@link Roo.data.Record#create}.
12587 Roo.data.ArrayReader = function(meta, recordType){
12588 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12591 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12593 * Create a data block containing Roo.data.Records from an XML document.
12594 * @param {Object} o An Array of row objects which represents the dataset.
12595 * @return {Object} data A data block which is used by an Roo.data.Store object as
12596 * a cache of Roo.data.Records.
12598 readRecords : function(o){
12599 var sid = this.meta ? this.meta.id : null;
12600 var recordType = this.recordType, fields = recordType.prototype.fields;
12603 for(var i = 0; i < root.length; i++){
12606 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12607 for(var j = 0, jlen = fields.length; j < jlen; j++){
12608 var f = fields.items[j];
12609 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12610 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12612 values[f.name] = v;
12614 var record = new recordType(values, id);
12616 records[records.length] = record;
12620 totalRecords : records.length
12629 * @class Roo.bootstrap.ComboBox
12630 * @extends Roo.bootstrap.TriggerField
12631 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12632 * @cfg {Boolean} append (true|false) default false
12633 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12634 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12635 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12636 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12637 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12638 * @cfg {Boolean} animate default true
12639 * @cfg {Boolean} emptyResultText only for touch device
12640 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12641 * @cfg {String} emptyTitle default ''
12643 * Create a new ComboBox.
12644 * @param {Object} config Configuration options
12646 Roo.bootstrap.ComboBox = function(config){
12647 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12651 * Fires when the dropdown list is expanded
12652 * @param {Roo.bootstrap.ComboBox} combo This combo box
12657 * Fires when the dropdown list is collapsed
12658 * @param {Roo.bootstrap.ComboBox} combo This combo box
12662 * @event beforeselect
12663 * Fires before a list item is selected. Return false to cancel the selection.
12664 * @param {Roo.bootstrap.ComboBox} combo This combo box
12665 * @param {Roo.data.Record} record The data record returned from the underlying store
12666 * @param {Number} index The index of the selected item in the dropdown list
12668 'beforeselect' : true,
12671 * Fires when a list item is selected
12672 * @param {Roo.bootstrap.ComboBox} combo This combo box
12673 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12674 * @param {Number} index The index of the selected item in the dropdown list
12678 * @event beforequery
12679 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12680 * The event object passed has these properties:
12681 * @param {Roo.bootstrap.ComboBox} combo This combo box
12682 * @param {String} query The query
12683 * @param {Boolean} forceAll true to force "all" query
12684 * @param {Boolean} cancel true to cancel the query
12685 * @param {Object} e The query event object
12687 'beforequery': true,
12690 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12691 * @param {Roo.bootstrap.ComboBox} combo This combo box
12696 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12697 * @param {Roo.bootstrap.ComboBox} combo This combo box
12698 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12703 * Fires when the remove value from the combobox array
12704 * @param {Roo.bootstrap.ComboBox} combo This combo box
12708 * @event afterremove
12709 * Fires when the remove value from the combobox array
12710 * @param {Roo.bootstrap.ComboBox} combo This combo box
12712 'afterremove' : true,
12714 * @event specialfilter
12715 * Fires when specialfilter
12716 * @param {Roo.bootstrap.ComboBox} combo This combo box
12718 'specialfilter' : true,
12721 * Fires when tick the element
12722 * @param {Roo.bootstrap.ComboBox} combo This combo box
12726 * @event touchviewdisplay
12727 * Fires when touch view require special display (default is using displayField)
12728 * @param {Roo.bootstrap.ComboBox} combo This combo box
12729 * @param {Object} cfg set html .
12731 'touchviewdisplay' : true
12736 this.tickItems = [];
12738 this.selectedIndex = -1;
12739 if(this.mode == 'local'){
12740 if(config.queryDelay === undefined){
12741 this.queryDelay = 10;
12743 if(config.minChars === undefined){
12749 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12752 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12753 * rendering into an Roo.Editor, defaults to false)
12756 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12757 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12760 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12763 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12764 * the dropdown list (defaults to undefined, with no header element)
12768 * @cfg {String/Roo.Template} tpl The template to use to render the output
12772 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12774 listWidth: undefined,
12776 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12777 * mode = 'remote' or 'text' if mode = 'local')
12779 displayField: undefined,
12782 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12783 * mode = 'remote' or 'value' if mode = 'local').
12784 * Note: use of a valueField requires the user make a selection
12785 * in order for a value to be mapped.
12787 valueField: undefined,
12789 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12794 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12795 * field's data value (defaults to the underlying DOM element's name)
12797 hiddenName: undefined,
12799 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12803 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12805 selectedClass: 'active',
12808 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12812 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12813 * anchor positions (defaults to 'tl-bl')
12815 listAlign: 'tl-bl?',
12817 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12821 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12822 * query specified by the allQuery config option (defaults to 'query')
12824 triggerAction: 'query',
12826 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12827 * (defaults to 4, does not apply if editable = false)
12831 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12832 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12836 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12837 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12841 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12842 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12846 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12847 * when editable = true (defaults to false)
12849 selectOnFocus:false,
12851 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12853 queryParam: 'query',
12855 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12856 * when mode = 'remote' (defaults to 'Loading...')
12858 loadingText: 'Loading...',
12860 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12864 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12868 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12869 * traditional select (defaults to true)
12873 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12877 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12881 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12882 * listWidth has a higher value)
12886 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12887 * allow the user to set arbitrary text into the field (defaults to false)
12889 forceSelection:false,
12891 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12892 * if typeAhead = true (defaults to 250)
12894 typeAheadDelay : 250,
12896 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12897 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12899 valueNotFoundText : undefined,
12901 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12903 blockFocus : false,
12906 * @cfg {Boolean} disableClear Disable showing of clear button.
12908 disableClear : false,
12910 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12912 alwaysQuery : false,
12915 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12920 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12922 invalidClass : "has-warning",
12925 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12927 validClass : "has-success",
12930 * @cfg {Boolean} specialFilter (true|false) special filter default false
12932 specialFilter : false,
12935 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12937 mobileTouchView : true,
12940 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12942 useNativeIOS : false,
12944 ios_options : false,
12956 btnPosition : 'right',
12957 triggerList : true,
12958 showToggleBtn : true,
12960 emptyResultText: 'Empty',
12961 triggerText : 'Select',
12964 // element that contains real text value.. (when hidden is used..)
12966 getAutoCreate : function()
12971 * Render classic select for iso
12974 if(Roo.isIOS && this.useNativeIOS){
12975 cfg = this.getAutoCreateNativeIOS();
12983 if(Roo.isTouch && this.mobileTouchView){
12984 cfg = this.getAutoCreateTouchView();
12991 if(!this.tickable){
12992 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12997 * ComboBox with tickable selections
13000 var align = this.labelAlign || this.parentLabelAlign();
13003 cls : 'form-group roo-combobox-tickable' //input-group
13006 var btn_text_select = '';
13007 var btn_text_done = '';
13008 var btn_text_cancel = '';
13010 if (this.btn_text_show) {
13011 btn_text_select = 'Select';
13012 btn_text_done = 'Done';
13013 btn_text_cancel = 'Cancel';
13018 cls : 'tickable-buttons',
13023 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13024 //html : this.triggerText
13025 html: btn_text_select
13031 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13033 html: btn_text_done
13039 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13041 html: btn_text_cancel
13047 buttons.cn.unshift({
13049 cls: 'roo-select2-search-field-input'
13055 Roo.each(buttons.cn, function(c){
13057 c.cls += ' btn-' + _this.size;
13060 if (_this.disabled) {
13071 cls: 'form-hidden-field'
13075 cls: 'roo-select2-choices',
13079 cls: 'roo-select2-search-field',
13090 cls: 'roo-select2-container input-group roo-select2-container-multi',
13095 // cls: 'typeahead typeahead-long dropdown-menu',
13096 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13101 if(this.hasFeedback && !this.allowBlank){
13105 cls: 'glyphicon form-control-feedback'
13108 combobox.cn.push(feedback);
13112 if (align ==='left' && this.fieldLabel.length) {
13114 cfg.cls += ' roo-form-group-label-left';
13119 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13120 tooltip : 'This field is required'
13125 cls : 'control-label',
13126 html : this.fieldLabel
13138 var labelCfg = cfg.cn[1];
13139 var contentCfg = cfg.cn[2];
13142 if(this.indicatorpos == 'right'){
13148 cls : 'control-label',
13152 html : this.fieldLabel
13156 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13157 tooltip : 'This field is required'
13172 labelCfg = cfg.cn[0];
13173 contentCfg = cfg.cn[1];
13177 if(this.labelWidth > 12){
13178 labelCfg.style = "width: " + this.labelWidth + 'px';
13181 if(this.labelWidth < 13 && this.labelmd == 0){
13182 this.labelmd = this.labelWidth;
13185 if(this.labellg > 0){
13186 labelCfg.cls += ' col-lg-' + this.labellg;
13187 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13190 if(this.labelmd > 0){
13191 labelCfg.cls += ' col-md-' + this.labelmd;
13192 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13195 if(this.labelsm > 0){
13196 labelCfg.cls += ' col-sm-' + this.labelsm;
13197 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13200 if(this.labelxs > 0){
13201 labelCfg.cls += ' col-xs-' + this.labelxs;
13202 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13206 } else if ( this.fieldLabel.length) {
13207 // Roo.log(" label");
13211 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13212 tooltip : 'This field is required'
13216 //cls : 'input-group-addon',
13217 html : this.fieldLabel
13222 if(this.indicatorpos == 'right'){
13226 //cls : 'input-group-addon',
13227 html : this.fieldLabel
13231 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13232 tooltip : 'This field is required'
13241 // Roo.log(" no label && no align");
13248 ['xs','sm','md','lg'].map(function(size){
13249 if (settings[size]) {
13250 cfg.cls += ' col-' + size + '-' + settings[size];
13258 _initEventsCalled : false,
13261 initEvents: function()
13263 if (this._initEventsCalled) { // as we call render... prevent looping...
13266 this._initEventsCalled = true;
13269 throw "can not find store for combo";
13272 this.indicator = this.indicatorEl();
13274 this.store = Roo.factory(this.store, Roo.data);
13275 this.store.parent = this;
13277 // if we are building from html. then this element is so complex, that we can not really
13278 // use the rendered HTML.
13279 // so we have to trash and replace the previous code.
13280 if (Roo.XComponent.build_from_html) {
13281 // remove this element....
13282 var e = this.el.dom, k=0;
13283 while (e ) { e = e.previousSibling; ++k;}
13288 this.rendered = false;
13290 this.render(this.parent().getChildContainer(true), k);
13293 if(Roo.isIOS && this.useNativeIOS){
13294 this.initIOSView();
13302 if(Roo.isTouch && this.mobileTouchView){
13303 this.initTouchView();
13308 this.initTickableEvents();
13312 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13314 if(this.hiddenName){
13316 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13318 this.hiddenField.dom.value =
13319 this.hiddenValue !== undefined ? this.hiddenValue :
13320 this.value !== undefined ? this.value : '';
13322 // prevent input submission
13323 this.el.dom.removeAttribute('name');
13324 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13329 // this.el.dom.setAttribute('autocomplete', 'off');
13332 var cls = 'x-combo-list';
13334 //this.list = new Roo.Layer({
13335 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13341 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13342 _this.list.setWidth(lw);
13345 this.list.on('mouseover', this.onViewOver, this);
13346 this.list.on('mousemove', this.onViewMove, this);
13347 this.list.on('scroll', this.onViewScroll, this);
13350 this.list.swallowEvent('mousewheel');
13351 this.assetHeight = 0;
13354 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13355 this.assetHeight += this.header.getHeight();
13358 this.innerList = this.list.createChild({cls:cls+'-inner'});
13359 this.innerList.on('mouseover', this.onViewOver, this);
13360 this.innerList.on('mousemove', this.onViewMove, this);
13361 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13363 if(this.allowBlank && !this.pageSize && !this.disableClear){
13364 this.footer = this.list.createChild({cls:cls+'-ft'});
13365 this.pageTb = new Roo.Toolbar(this.footer);
13369 this.footer = this.list.createChild({cls:cls+'-ft'});
13370 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13371 {pageSize: this.pageSize});
13375 if (this.pageTb && this.allowBlank && !this.disableClear) {
13377 this.pageTb.add(new Roo.Toolbar.Fill(), {
13378 cls: 'x-btn-icon x-btn-clear',
13380 handler: function()
13383 _this.clearValue();
13384 _this.onSelect(false, -1);
13389 this.assetHeight += this.footer.getHeight();
13394 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13397 this.view = new Roo.View(this.list, this.tpl, {
13398 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13400 //this.view.wrapEl.setDisplayed(false);
13401 this.view.on('click', this.onViewClick, this);
13404 this.store.on('beforeload', this.onBeforeLoad, this);
13405 this.store.on('load', this.onLoad, this);
13406 this.store.on('loadexception', this.onLoadException, this);
13408 if(this.resizable){
13409 this.resizer = new Roo.Resizable(this.list, {
13410 pinned:true, handles:'se'
13412 this.resizer.on('resize', function(r, w, h){
13413 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13414 this.listWidth = w;
13415 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13416 this.restrictHeight();
13418 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13421 if(!this.editable){
13422 this.editable = true;
13423 this.setEditable(false);
13428 if (typeof(this.events.add.listeners) != 'undefined') {
13430 this.addicon = this.wrap.createChild(
13431 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13433 this.addicon.on('click', function(e) {
13434 this.fireEvent('add', this);
13437 if (typeof(this.events.edit.listeners) != 'undefined') {
13439 this.editicon = this.wrap.createChild(
13440 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13441 if (this.addicon) {
13442 this.editicon.setStyle('margin-left', '40px');
13444 this.editicon.on('click', function(e) {
13446 // we fire even if inothing is selected..
13447 this.fireEvent('edit', this, this.lastData );
13453 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13454 "up" : function(e){
13455 this.inKeyMode = true;
13459 "down" : function(e){
13460 if(!this.isExpanded()){
13461 this.onTriggerClick();
13463 this.inKeyMode = true;
13468 "enter" : function(e){
13469 // this.onViewClick();
13473 if(this.fireEvent("specialkey", this, e)){
13474 this.onViewClick(false);
13480 "esc" : function(e){
13484 "tab" : function(e){
13487 if(this.fireEvent("specialkey", this, e)){
13488 this.onViewClick(false);
13496 doRelay : function(foo, bar, hname){
13497 if(hname == 'down' || this.scope.isExpanded()){
13498 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13507 this.queryDelay = Math.max(this.queryDelay || 10,
13508 this.mode == 'local' ? 10 : 250);
13511 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13513 if(this.typeAhead){
13514 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13516 if(this.editable !== false){
13517 this.inputEl().on("keyup", this.onKeyUp, this);
13519 if(this.forceSelection){
13520 this.inputEl().on('blur', this.doForce, this);
13524 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13525 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13529 initTickableEvents: function()
13533 if(this.hiddenName){
13535 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13537 this.hiddenField.dom.value =
13538 this.hiddenValue !== undefined ? this.hiddenValue :
13539 this.value !== undefined ? this.value : '';
13541 // prevent input submission
13542 this.el.dom.removeAttribute('name');
13543 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13548 // this.list = this.el.select('ul.dropdown-menu',true).first();
13550 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13551 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13552 if(this.triggerList){
13553 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13556 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13557 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13559 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13560 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13562 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13563 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13565 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13566 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13567 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13570 this.cancelBtn.hide();
13575 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13576 _this.list.setWidth(lw);
13579 this.list.on('mouseover', this.onViewOver, this);
13580 this.list.on('mousemove', this.onViewMove, this);
13582 this.list.on('scroll', this.onViewScroll, this);
13585 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>';
13588 this.view = new Roo.View(this.list, this.tpl, {
13589 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13592 //this.view.wrapEl.setDisplayed(false);
13593 this.view.on('click', this.onViewClick, this);
13597 this.store.on('beforeload', this.onBeforeLoad, this);
13598 this.store.on('load', this.onLoad, this);
13599 this.store.on('loadexception', this.onLoadException, this);
13602 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13603 "up" : function(e){
13604 this.inKeyMode = true;
13608 "down" : function(e){
13609 this.inKeyMode = true;
13613 "enter" : function(e){
13614 if(this.fireEvent("specialkey", this, e)){
13615 this.onViewClick(false);
13621 "esc" : function(e){
13622 this.onTickableFooterButtonClick(e, false, false);
13625 "tab" : function(e){
13626 this.fireEvent("specialkey", this, e);
13628 this.onTickableFooterButtonClick(e, false, false);
13635 doRelay : function(e, fn, key){
13636 if(this.scope.isExpanded()){
13637 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13646 this.queryDelay = Math.max(this.queryDelay || 10,
13647 this.mode == 'local' ? 10 : 250);
13650 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13652 if(this.typeAhead){
13653 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13656 if(this.editable !== false){
13657 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13660 this.indicator = this.indicatorEl();
13662 if(this.indicator){
13663 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13664 this.indicator.hide();
13669 onDestroy : function(){
13671 this.view.setStore(null);
13672 this.view.el.removeAllListeners();
13673 this.view.el.remove();
13674 this.view.purgeListeners();
13677 this.list.dom.innerHTML = '';
13681 this.store.un('beforeload', this.onBeforeLoad, this);
13682 this.store.un('load', this.onLoad, this);
13683 this.store.un('loadexception', this.onLoadException, this);
13685 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13689 fireKey : function(e){
13690 if(e.isNavKeyPress() && !this.list.isVisible()){
13691 this.fireEvent("specialkey", this, e);
13696 onResize: function(w, h){
13697 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13699 // if(typeof w != 'number'){
13700 // // we do not handle it!?!?
13703 // var tw = this.trigger.getWidth();
13704 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13705 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13707 // this.inputEl().setWidth( this.adjustWidth('input', x));
13709 // //this.trigger.setStyle('left', x+'px');
13711 // if(this.list && this.listWidth === undefined){
13712 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13713 // this.list.setWidth(lw);
13714 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13722 * Allow or prevent the user from directly editing the field text. If false is passed,
13723 * the user will only be able to select from the items defined in the dropdown list. This method
13724 * is the runtime equivalent of setting the 'editable' config option at config time.
13725 * @param {Boolean} value True to allow the user to directly edit the field text
13727 setEditable : function(value){
13728 if(value == this.editable){
13731 this.editable = value;
13733 this.inputEl().dom.setAttribute('readOnly', true);
13734 this.inputEl().on('mousedown', this.onTriggerClick, this);
13735 this.inputEl().addClass('x-combo-noedit');
13737 this.inputEl().dom.setAttribute('readOnly', false);
13738 this.inputEl().un('mousedown', this.onTriggerClick, this);
13739 this.inputEl().removeClass('x-combo-noedit');
13745 onBeforeLoad : function(combo,opts){
13746 if(!this.hasFocus){
13750 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13752 this.restrictHeight();
13753 this.selectedIndex = -1;
13757 onLoad : function(){
13759 this.hasQuery = false;
13761 if(!this.hasFocus){
13765 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13766 this.loading.hide();
13769 if(this.store.getCount() > 0){
13772 this.restrictHeight();
13773 if(this.lastQuery == this.allQuery){
13774 if(this.editable && !this.tickable){
13775 this.inputEl().dom.select();
13779 !this.selectByValue(this.value, true) &&
13782 !this.store.lastOptions ||
13783 typeof(this.store.lastOptions.add) == 'undefined' ||
13784 this.store.lastOptions.add != true
13787 this.select(0, true);
13790 if(this.autoFocus){
13793 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13794 this.taTask.delay(this.typeAheadDelay);
13798 this.onEmptyResults();
13804 onLoadException : function()
13806 this.hasQuery = false;
13808 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13809 this.loading.hide();
13812 if(this.tickable && this.editable){
13817 // only causes errors at present
13818 //Roo.log(this.store.reader.jsonData);
13819 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13821 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13827 onTypeAhead : function(){
13828 if(this.store.getCount() > 0){
13829 var r = this.store.getAt(0);
13830 var newValue = r.data[this.displayField];
13831 var len = newValue.length;
13832 var selStart = this.getRawValue().length;
13834 if(selStart != len){
13835 this.setRawValue(newValue);
13836 this.selectText(selStart, newValue.length);
13842 onSelect : function(record, index){
13844 if(this.fireEvent('beforeselect', this, record, index) !== false){
13846 this.setFromData(index > -1 ? record.data : false);
13849 this.fireEvent('select', this, record, index);
13854 * Returns the currently selected field value or empty string if no value is set.
13855 * @return {String} value The selected value
13857 getValue : function()
13859 if(Roo.isIOS && this.useNativeIOS){
13860 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13864 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13867 if(this.valueField){
13868 return typeof this.value != 'undefined' ? this.value : '';
13870 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13874 getRawValue : function()
13876 if(Roo.isIOS && this.useNativeIOS){
13877 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13880 var v = this.inputEl().getValue();
13886 * Clears any text/value currently set in the field
13888 clearValue : function(){
13890 if(this.hiddenField){
13891 this.hiddenField.dom.value = '';
13894 this.setRawValue('');
13895 this.lastSelectionText = '';
13896 this.lastData = false;
13898 var close = this.closeTriggerEl();
13909 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13910 * will be displayed in the field. If the value does not match the data value of an existing item,
13911 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13912 * Otherwise the field will be blank (although the value will still be set).
13913 * @param {String} value The value to match
13915 setValue : function(v)
13917 if(Roo.isIOS && this.useNativeIOS){
13918 this.setIOSValue(v);
13928 if(this.valueField){
13929 var r = this.findRecord(this.valueField, v);
13931 text = r.data[this.displayField];
13932 }else if(this.valueNotFoundText !== undefined){
13933 text = this.valueNotFoundText;
13936 this.lastSelectionText = text;
13937 if(this.hiddenField){
13938 this.hiddenField.dom.value = v;
13940 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13943 var close = this.closeTriggerEl();
13946 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13952 * @property {Object} the last set data for the element
13957 * Sets the value of the field based on a object which is related to the record format for the store.
13958 * @param {Object} value the value to set as. or false on reset?
13960 setFromData : function(o){
13967 var dv = ''; // display value
13968 var vv = ''; // value value..
13970 if (this.displayField) {
13971 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13973 // this is an error condition!!!
13974 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13977 if(this.valueField){
13978 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13981 var close = this.closeTriggerEl();
13984 if(dv.length || vv * 1 > 0){
13986 this.blockFocus=true;
13992 if(this.hiddenField){
13993 this.hiddenField.dom.value = vv;
13995 this.lastSelectionText = dv;
13996 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14000 // no hidden field.. - we store the value in 'value', but still display
14001 // display field!!!!
14002 this.lastSelectionText = dv;
14003 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14010 reset : function(){
14011 // overridden so that last data is reset..
14018 this.setValue(this.originalValue);
14019 //this.clearInvalid();
14020 this.lastData = false;
14022 this.view.clearSelections();
14028 findRecord : function(prop, value){
14030 if(this.store.getCount() > 0){
14031 this.store.each(function(r){
14032 if(r.data[prop] == value){
14042 getName: function()
14044 // returns hidden if it's set..
14045 if (!this.rendered) {return ''};
14046 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14050 onViewMove : function(e, t){
14051 this.inKeyMode = false;
14055 onViewOver : function(e, t){
14056 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14059 var item = this.view.findItemFromChild(t);
14062 var index = this.view.indexOf(item);
14063 this.select(index, false);
14068 onViewClick : function(view, doFocus, el, e)
14070 var index = this.view.getSelectedIndexes()[0];
14072 var r = this.store.getAt(index);
14076 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14083 Roo.each(this.tickItems, function(v,k){
14085 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14087 _this.tickItems.splice(k, 1);
14089 if(typeof(e) == 'undefined' && view == false){
14090 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14102 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14103 this.tickItems.push(r.data);
14106 if(typeof(e) == 'undefined' && view == false){
14107 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14114 this.onSelect(r, index);
14116 if(doFocus !== false && !this.blockFocus){
14117 this.inputEl().focus();
14122 restrictHeight : function(){
14123 //this.innerList.dom.style.height = '';
14124 //var inner = this.innerList.dom;
14125 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14126 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14127 //this.list.beginUpdate();
14128 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14129 this.list.alignTo(this.inputEl(), this.listAlign);
14130 this.list.alignTo(this.inputEl(), this.listAlign);
14131 //this.list.endUpdate();
14135 onEmptyResults : function(){
14137 if(this.tickable && this.editable){
14138 this.hasFocus = false;
14139 this.restrictHeight();
14147 * Returns true if the dropdown list is expanded, else false.
14149 isExpanded : function(){
14150 return this.list.isVisible();
14154 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14155 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14156 * @param {String} value The data value of the item to select
14157 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14158 * selected item if it is not currently in view (defaults to true)
14159 * @return {Boolean} True if the value matched an item in the list, else false
14161 selectByValue : function(v, scrollIntoView){
14162 if(v !== undefined && v !== null){
14163 var r = this.findRecord(this.valueField || this.displayField, v);
14165 this.select(this.store.indexOf(r), scrollIntoView);
14173 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14174 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14175 * @param {Number} index The zero-based index of the list item to select
14176 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14177 * selected item if it is not currently in view (defaults to true)
14179 select : function(index, scrollIntoView){
14180 this.selectedIndex = index;
14181 this.view.select(index);
14182 if(scrollIntoView !== false){
14183 var el = this.view.getNode(index);
14185 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14188 this.list.scrollChildIntoView(el, false);
14194 selectNext : function(){
14195 var ct = this.store.getCount();
14197 if(this.selectedIndex == -1){
14199 }else if(this.selectedIndex < ct-1){
14200 this.select(this.selectedIndex+1);
14206 selectPrev : function(){
14207 var ct = this.store.getCount();
14209 if(this.selectedIndex == -1){
14211 }else if(this.selectedIndex != 0){
14212 this.select(this.selectedIndex-1);
14218 onKeyUp : function(e){
14219 if(this.editable !== false && !e.isSpecialKey()){
14220 this.lastKey = e.getKey();
14221 this.dqTask.delay(this.queryDelay);
14226 validateBlur : function(){
14227 return !this.list || !this.list.isVisible();
14231 initQuery : function(){
14233 var v = this.getRawValue();
14235 if(this.tickable && this.editable){
14236 v = this.tickableInputEl().getValue();
14243 doForce : function(){
14244 if(this.inputEl().dom.value.length > 0){
14245 this.inputEl().dom.value =
14246 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14252 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14253 * query allowing the query action to be canceled if needed.
14254 * @param {String} query The SQL query to execute
14255 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14256 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14257 * saved in the current store (defaults to false)
14259 doQuery : function(q, forceAll){
14261 if(q === undefined || q === null){
14266 forceAll: forceAll,
14270 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14275 forceAll = qe.forceAll;
14276 if(forceAll === true || (q.length >= this.minChars)){
14278 this.hasQuery = true;
14280 if(this.lastQuery != q || this.alwaysQuery){
14281 this.lastQuery = q;
14282 if(this.mode == 'local'){
14283 this.selectedIndex = -1;
14285 this.store.clearFilter();
14288 if(this.specialFilter){
14289 this.fireEvent('specialfilter', this);
14294 this.store.filter(this.displayField, q);
14297 this.store.fireEvent("datachanged", this.store);
14304 this.store.baseParams[this.queryParam] = q;
14306 var options = {params : this.getParams(q)};
14309 options.add = true;
14310 options.params.start = this.page * this.pageSize;
14313 this.store.load(options);
14316 * this code will make the page width larger, at the beginning, the list not align correctly,
14317 * we should expand the list on onLoad
14318 * so command out it
14323 this.selectedIndex = -1;
14328 this.loadNext = false;
14332 getParams : function(q){
14334 //p[this.queryParam] = q;
14338 p.limit = this.pageSize;
14344 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14346 collapse : function(){
14347 if(!this.isExpanded()){
14353 this.hasFocus = false;
14357 this.cancelBtn.hide();
14358 this.trigger.show();
14361 this.tickableInputEl().dom.value = '';
14362 this.tickableInputEl().blur();
14367 Roo.get(document).un('mousedown', this.collapseIf, this);
14368 Roo.get(document).un('mousewheel', this.collapseIf, this);
14369 if (!this.editable) {
14370 Roo.get(document).un('keydown', this.listKeyPress, this);
14372 this.fireEvent('collapse', this);
14378 collapseIf : function(e){
14379 var in_combo = e.within(this.el);
14380 var in_list = e.within(this.list);
14381 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14383 if (in_combo || in_list || is_list) {
14384 //e.stopPropagation();
14389 this.onTickableFooterButtonClick(e, false, false);
14397 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14399 expand : function(){
14401 if(this.isExpanded() || !this.hasFocus){
14405 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14406 this.list.setWidth(lw);
14412 this.restrictHeight();
14416 this.tickItems = Roo.apply([], this.item);
14419 this.cancelBtn.show();
14420 this.trigger.hide();
14423 this.tickableInputEl().focus();
14428 Roo.get(document).on('mousedown', this.collapseIf, this);
14429 Roo.get(document).on('mousewheel', this.collapseIf, this);
14430 if (!this.editable) {
14431 Roo.get(document).on('keydown', this.listKeyPress, this);
14434 this.fireEvent('expand', this);
14438 // Implements the default empty TriggerField.onTriggerClick function
14439 onTriggerClick : function(e)
14441 Roo.log('trigger click');
14443 if(this.disabled || !this.triggerList){
14448 this.loadNext = false;
14450 if(this.isExpanded()){
14452 if (!this.blockFocus) {
14453 this.inputEl().focus();
14457 this.hasFocus = true;
14458 if(this.triggerAction == 'all') {
14459 this.doQuery(this.allQuery, true);
14461 this.doQuery(this.getRawValue());
14463 if (!this.blockFocus) {
14464 this.inputEl().focus();
14469 onTickableTriggerClick : function(e)
14476 this.loadNext = false;
14477 this.hasFocus = true;
14479 if(this.triggerAction == 'all') {
14480 this.doQuery(this.allQuery, true);
14482 this.doQuery(this.getRawValue());
14486 onSearchFieldClick : function(e)
14488 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14489 this.onTickableFooterButtonClick(e, false, false);
14493 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14498 this.loadNext = false;
14499 this.hasFocus = true;
14501 if(this.triggerAction == 'all') {
14502 this.doQuery(this.allQuery, true);
14504 this.doQuery(this.getRawValue());
14508 listKeyPress : function(e)
14510 //Roo.log('listkeypress');
14511 // scroll to first matching element based on key pres..
14512 if (e.isSpecialKey()) {
14515 var k = String.fromCharCode(e.getKey()).toUpperCase();
14518 var csel = this.view.getSelectedNodes();
14519 var cselitem = false;
14521 var ix = this.view.indexOf(csel[0]);
14522 cselitem = this.store.getAt(ix);
14523 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14529 this.store.each(function(v) {
14531 // start at existing selection.
14532 if (cselitem.id == v.id) {
14538 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14539 match = this.store.indexOf(v);
14545 if (match === false) {
14546 return true; // no more action?
14549 this.view.select(match);
14550 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14551 sn.scrollIntoView(sn.dom.parentNode, false);
14554 onViewScroll : function(e, t){
14556 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){
14560 this.hasQuery = true;
14562 this.loading = this.list.select('.loading', true).first();
14564 if(this.loading === null){
14565 this.list.createChild({
14567 cls: 'loading roo-select2-more-results roo-select2-active',
14568 html: 'Loading more results...'
14571 this.loading = this.list.select('.loading', true).first();
14573 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14575 this.loading.hide();
14578 this.loading.show();
14583 this.loadNext = true;
14585 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14590 addItem : function(o)
14592 var dv = ''; // display value
14594 if (this.displayField) {
14595 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14597 // this is an error condition!!!
14598 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14605 var choice = this.choices.createChild({
14607 cls: 'roo-select2-search-choice',
14616 cls: 'roo-select2-search-choice-close fa fa-times',
14621 }, this.searchField);
14623 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14625 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14633 this.inputEl().dom.value = '';
14638 onRemoveItem : function(e, _self, o)
14640 e.preventDefault();
14642 this.lastItem = Roo.apply([], this.item);
14644 var index = this.item.indexOf(o.data) * 1;
14647 Roo.log('not this item?!');
14651 this.item.splice(index, 1);
14656 this.fireEvent('remove', this, e);
14662 syncValue : function()
14664 if(!this.item.length){
14671 Roo.each(this.item, function(i){
14672 if(_this.valueField){
14673 value.push(i[_this.valueField]);
14680 this.value = value.join(',');
14682 if(this.hiddenField){
14683 this.hiddenField.dom.value = this.value;
14686 this.store.fireEvent("datachanged", this.store);
14691 clearItem : function()
14693 if(!this.multiple){
14699 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14707 if(this.tickable && !Roo.isTouch){
14708 this.view.refresh();
14712 inputEl: function ()
14714 if(Roo.isIOS && this.useNativeIOS){
14715 return this.el.select('select.roo-ios-select', true).first();
14718 if(Roo.isTouch && this.mobileTouchView){
14719 return this.el.select('input.form-control',true).first();
14723 return this.searchField;
14726 return this.el.select('input.form-control',true).first();
14729 onTickableFooterButtonClick : function(e, btn, el)
14731 e.preventDefault();
14733 this.lastItem = Roo.apply([], this.item);
14735 if(btn && btn.name == 'cancel'){
14736 this.tickItems = Roo.apply([], this.item);
14745 Roo.each(this.tickItems, function(o){
14753 validate : function()
14755 if(this.getVisibilityEl().hasClass('hidden')){
14759 var v = this.getRawValue();
14762 v = this.getValue();
14765 if(this.disabled || this.allowBlank || v.length){
14770 this.markInvalid();
14774 tickableInputEl : function()
14776 if(!this.tickable || !this.editable){
14777 return this.inputEl();
14780 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14784 getAutoCreateTouchView : function()
14789 cls: 'form-group' //input-group
14795 type : this.inputType,
14796 cls : 'form-control x-combo-noedit',
14797 autocomplete: 'new-password',
14798 placeholder : this.placeholder || '',
14803 input.name = this.name;
14807 input.cls += ' input-' + this.size;
14810 if (this.disabled) {
14811 input.disabled = true;
14822 inputblock.cls += ' input-group';
14824 inputblock.cn.unshift({
14826 cls : 'input-group-addon',
14831 if(this.removable && !this.multiple){
14832 inputblock.cls += ' roo-removable';
14834 inputblock.cn.push({
14837 cls : 'roo-combo-removable-btn close'
14841 if(this.hasFeedback && !this.allowBlank){
14843 inputblock.cls += ' has-feedback';
14845 inputblock.cn.push({
14847 cls: 'glyphicon form-control-feedback'
14854 inputblock.cls += (this.before) ? '' : ' input-group';
14856 inputblock.cn.push({
14858 cls : 'input-group-addon',
14869 cls: 'form-hidden-field'
14883 cls: 'form-hidden-field'
14887 cls: 'roo-select2-choices',
14891 cls: 'roo-select2-search-field',
14904 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14910 if(!this.multiple && this.showToggleBtn){
14917 if (this.caret != false) {
14920 cls: 'fa fa-' + this.caret
14927 cls : 'input-group-addon btn dropdown-toggle',
14932 cls: 'combobox-clear',
14946 combobox.cls += ' roo-select2-container-multi';
14949 var align = this.labelAlign || this.parentLabelAlign();
14951 if (align ==='left' && this.fieldLabel.length) {
14956 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14957 tooltip : 'This field is required'
14961 cls : 'control-label',
14962 html : this.fieldLabel
14973 var labelCfg = cfg.cn[1];
14974 var contentCfg = cfg.cn[2];
14977 if(this.indicatorpos == 'right'){
14982 cls : 'control-label',
14986 html : this.fieldLabel
14990 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14991 tooltip : 'This field is required'
15004 labelCfg = cfg.cn[0];
15005 contentCfg = cfg.cn[1];
15010 if(this.labelWidth > 12){
15011 labelCfg.style = "width: " + this.labelWidth + 'px';
15014 if(this.labelWidth < 13 && this.labelmd == 0){
15015 this.labelmd = this.labelWidth;
15018 if(this.labellg > 0){
15019 labelCfg.cls += ' col-lg-' + this.labellg;
15020 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15023 if(this.labelmd > 0){
15024 labelCfg.cls += ' col-md-' + this.labelmd;
15025 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15028 if(this.labelsm > 0){
15029 labelCfg.cls += ' col-sm-' + this.labelsm;
15030 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15033 if(this.labelxs > 0){
15034 labelCfg.cls += ' col-xs-' + this.labelxs;
15035 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15039 } else if ( this.fieldLabel.length) {
15043 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15044 tooltip : 'This field is required'
15048 cls : 'control-label',
15049 html : this.fieldLabel
15060 if(this.indicatorpos == 'right'){
15064 cls : 'control-label',
15065 html : this.fieldLabel,
15069 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15070 tooltip : 'This field is required'
15087 var settings = this;
15089 ['xs','sm','md','lg'].map(function(size){
15090 if (settings[size]) {
15091 cfg.cls += ' col-' + size + '-' + settings[size];
15098 initTouchView : function()
15100 this.renderTouchView();
15102 this.touchViewEl.on('scroll', function(){
15103 this.el.dom.scrollTop = 0;
15106 this.originalValue = this.getValue();
15108 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15110 this.inputEl().on("click", this.showTouchView, this);
15111 if (this.triggerEl) {
15112 this.triggerEl.on("click", this.showTouchView, this);
15116 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15117 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15119 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15121 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15122 this.store.on('load', this.onTouchViewLoad, this);
15123 this.store.on('loadexception', this.onTouchViewLoadException, this);
15125 if(this.hiddenName){
15127 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15129 this.hiddenField.dom.value =
15130 this.hiddenValue !== undefined ? this.hiddenValue :
15131 this.value !== undefined ? this.value : '';
15133 this.el.dom.removeAttribute('name');
15134 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15138 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15139 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15142 if(this.removable && !this.multiple){
15143 var close = this.closeTriggerEl();
15145 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15146 close.on('click', this.removeBtnClick, this, close);
15150 * fix the bug in Safari iOS8
15152 this.inputEl().on("focus", function(e){
15153 document.activeElement.blur();
15161 renderTouchView : function()
15163 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15164 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15166 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15167 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15169 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15170 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15171 this.touchViewBodyEl.setStyle('overflow', 'auto');
15173 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15174 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15176 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15177 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15181 showTouchView : function()
15187 this.touchViewHeaderEl.hide();
15189 if(this.modalTitle.length){
15190 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15191 this.touchViewHeaderEl.show();
15194 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15195 this.touchViewEl.show();
15197 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15199 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15200 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15202 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15204 if(this.modalTitle.length){
15205 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15208 this.touchViewBodyEl.setHeight(bodyHeight);
15212 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15214 this.touchViewEl.addClass('in');
15217 this.doTouchViewQuery();
15221 hideTouchView : function()
15223 this.touchViewEl.removeClass('in');
15227 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15229 this.touchViewEl.setStyle('display', 'none');
15234 setTouchViewValue : function()
15241 Roo.each(this.tickItems, function(o){
15246 this.hideTouchView();
15249 doTouchViewQuery : function()
15258 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15262 if(!this.alwaysQuery || this.mode == 'local'){
15263 this.onTouchViewLoad();
15270 onTouchViewBeforeLoad : function(combo,opts)
15276 onTouchViewLoad : function()
15278 if(this.store.getCount() < 1){
15279 this.onTouchViewEmptyResults();
15283 this.clearTouchView();
15285 var rawValue = this.getRawValue();
15287 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15289 this.tickItems = [];
15291 this.store.data.each(function(d, rowIndex){
15292 var row = this.touchViewListGroup.createChild(template);
15294 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15295 row.addClass(d.data.cls);
15298 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15301 html : d.data[this.displayField]
15304 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15305 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15308 row.removeClass('selected');
15309 if(!this.multiple && this.valueField &&
15310 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15313 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15314 row.addClass('selected');
15317 if(this.multiple && this.valueField &&
15318 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15322 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15323 this.tickItems.push(d.data);
15326 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15330 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15332 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15334 if(this.modalTitle.length){
15335 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15338 var listHeight = this.touchViewListGroup.getHeight();
15342 if(firstChecked && listHeight > bodyHeight){
15343 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15348 onTouchViewLoadException : function()
15350 this.hideTouchView();
15353 onTouchViewEmptyResults : function()
15355 this.clearTouchView();
15357 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15359 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15363 clearTouchView : function()
15365 this.touchViewListGroup.dom.innerHTML = '';
15368 onTouchViewClick : function(e, el, o)
15370 e.preventDefault();
15373 var rowIndex = o.rowIndex;
15375 var r = this.store.getAt(rowIndex);
15377 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15379 if(!this.multiple){
15380 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15381 c.dom.removeAttribute('checked');
15384 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15386 this.setFromData(r.data);
15388 var close = this.closeTriggerEl();
15394 this.hideTouchView();
15396 this.fireEvent('select', this, r, rowIndex);
15401 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15402 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15403 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15407 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15408 this.addItem(r.data);
15409 this.tickItems.push(r.data);
15413 getAutoCreateNativeIOS : function()
15416 cls: 'form-group' //input-group,
15421 cls : 'roo-ios-select'
15425 combobox.name = this.name;
15428 if (this.disabled) {
15429 combobox.disabled = true;
15432 var settings = this;
15434 ['xs','sm','md','lg'].map(function(size){
15435 if (settings[size]) {
15436 cfg.cls += ' col-' + size + '-' + settings[size];
15446 initIOSView : function()
15448 this.store.on('load', this.onIOSViewLoad, this);
15453 onIOSViewLoad : function()
15455 if(this.store.getCount() < 1){
15459 this.clearIOSView();
15461 if(this.allowBlank) {
15463 var default_text = '-- SELECT --';
15465 if(this.placeholder.length){
15466 default_text = this.placeholder;
15469 if(this.emptyTitle.length){
15470 default_text += ' - ' + this.emptyTitle + ' -';
15473 var opt = this.inputEl().createChild({
15476 html : default_text
15480 o[this.valueField] = 0;
15481 o[this.displayField] = default_text;
15483 this.ios_options.push({
15490 this.store.data.each(function(d, rowIndex){
15494 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15495 html = d.data[this.displayField];
15500 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15501 value = d.data[this.valueField];
15510 if(this.value == d.data[this.valueField]){
15511 option['selected'] = true;
15514 var opt = this.inputEl().createChild(option);
15516 this.ios_options.push({
15523 this.inputEl().on('change', function(){
15524 this.fireEvent('select', this);
15529 clearIOSView: function()
15531 this.inputEl().dom.innerHTML = '';
15533 this.ios_options = [];
15536 setIOSValue: function(v)
15540 if(!this.ios_options){
15544 Roo.each(this.ios_options, function(opts){
15546 opts.el.dom.removeAttribute('selected');
15548 if(opts.data[this.valueField] != v){
15552 opts.el.dom.setAttribute('selected', true);
15558 * @cfg {Boolean} grow
15562 * @cfg {Number} growMin
15566 * @cfg {Number} growMax
15575 Roo.apply(Roo.bootstrap.ComboBox, {
15579 cls: 'modal-header',
15601 cls: 'list-group-item',
15605 cls: 'roo-combobox-list-group-item-value'
15609 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15623 listItemCheckbox : {
15625 cls: 'list-group-item',
15629 cls: 'roo-combobox-list-group-item-value'
15633 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15649 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15654 cls: 'modal-footer',
15662 cls: 'col-xs-6 text-left',
15665 cls: 'btn btn-danger roo-touch-view-cancel',
15671 cls: 'col-xs-6 text-right',
15674 cls: 'btn btn-success roo-touch-view-ok',
15685 Roo.apply(Roo.bootstrap.ComboBox, {
15687 touchViewTemplate : {
15689 cls: 'modal fade roo-combobox-touch-view',
15693 cls: 'modal-dialog',
15694 style : 'position:fixed', // we have to fix position....
15698 cls: 'modal-content',
15700 Roo.bootstrap.ComboBox.header,
15701 Roo.bootstrap.ComboBox.body,
15702 Roo.bootstrap.ComboBox.footer
15711 * Ext JS Library 1.1.1
15712 * Copyright(c) 2006-2007, Ext JS, LLC.
15714 * Originally Released Under LGPL - original licence link has changed is not relivant.
15717 * <script type="text/javascript">
15722 * @extends Roo.util.Observable
15723 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15724 * This class also supports single and multi selection modes. <br>
15725 * Create a data model bound view:
15727 var store = new Roo.data.Store(...);
15729 var view = new Roo.View({
15731 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15733 singleSelect: true,
15734 selectedClass: "ydataview-selected",
15738 // listen for node click?
15739 view.on("click", function(vw, index, node, e){
15740 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15744 dataModel.load("foobar.xml");
15746 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15748 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15749 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15751 * Note: old style constructor is still suported (container, template, config)
15754 * Create a new View
15755 * @param {Object} config The config object
15758 Roo.View = function(config, depreciated_tpl, depreciated_config){
15760 this.parent = false;
15762 if (typeof(depreciated_tpl) == 'undefined') {
15763 // new way.. - universal constructor.
15764 Roo.apply(this, config);
15765 this.el = Roo.get(this.el);
15768 this.el = Roo.get(config);
15769 this.tpl = depreciated_tpl;
15770 Roo.apply(this, depreciated_config);
15772 this.wrapEl = this.el.wrap().wrap();
15773 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15776 if(typeof(this.tpl) == "string"){
15777 this.tpl = new Roo.Template(this.tpl);
15779 // support xtype ctors..
15780 this.tpl = new Roo.factory(this.tpl, Roo);
15784 this.tpl.compile();
15789 * @event beforeclick
15790 * Fires before a click is processed. Returns false to cancel the default action.
15791 * @param {Roo.View} this
15792 * @param {Number} index The index of the target node
15793 * @param {HTMLElement} node The target node
15794 * @param {Roo.EventObject} e The raw event object
15796 "beforeclick" : true,
15799 * Fires when a template node is clicked.
15800 * @param {Roo.View} this
15801 * @param {Number} index The index of the target node
15802 * @param {HTMLElement} node The target node
15803 * @param {Roo.EventObject} e The raw event object
15808 * Fires when a template node is double clicked.
15809 * @param {Roo.View} this
15810 * @param {Number} index The index of the target node
15811 * @param {HTMLElement} node The target node
15812 * @param {Roo.EventObject} e The raw event object
15816 * @event contextmenu
15817 * Fires when a template node is right clicked.
15818 * @param {Roo.View} this
15819 * @param {Number} index The index of the target node
15820 * @param {HTMLElement} node The target node
15821 * @param {Roo.EventObject} e The raw event object
15823 "contextmenu" : true,
15825 * @event selectionchange
15826 * Fires when the selected nodes change.
15827 * @param {Roo.View} this
15828 * @param {Array} selections Array of the selected nodes
15830 "selectionchange" : true,
15833 * @event beforeselect
15834 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15835 * @param {Roo.View} this
15836 * @param {HTMLElement} node The node to be selected
15837 * @param {Array} selections Array of currently selected nodes
15839 "beforeselect" : true,
15841 * @event preparedata
15842 * Fires on every row to render, to allow you to change the data.
15843 * @param {Roo.View} this
15844 * @param {Object} data to be rendered (change this)
15846 "preparedata" : true
15854 "click": this.onClick,
15855 "dblclick": this.onDblClick,
15856 "contextmenu": this.onContextMenu,
15860 this.selections = [];
15862 this.cmp = new Roo.CompositeElementLite([]);
15864 this.store = Roo.factory(this.store, Roo.data);
15865 this.setStore(this.store, true);
15868 if ( this.footer && this.footer.xtype) {
15870 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15872 this.footer.dataSource = this.store;
15873 this.footer.container = fctr;
15874 this.footer = Roo.factory(this.footer, Roo);
15875 fctr.insertFirst(this.el);
15877 // this is a bit insane - as the paging toolbar seems to detach the el..
15878 // dom.parentNode.parentNode.parentNode
15879 // they get detached?
15883 Roo.View.superclass.constructor.call(this);
15888 Roo.extend(Roo.View, Roo.util.Observable, {
15891 * @cfg {Roo.data.Store} store Data store to load data from.
15896 * @cfg {String|Roo.Element} el The container element.
15901 * @cfg {String|Roo.Template} tpl The template used by this View
15905 * @cfg {String} dataName the named area of the template to use as the data area
15906 * Works with domtemplates roo-name="name"
15910 * @cfg {String} selectedClass The css class to add to selected nodes
15912 selectedClass : "x-view-selected",
15914 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15919 * @cfg {String} text to display on mask (default Loading)
15923 * @cfg {Boolean} multiSelect Allow multiple selection
15925 multiSelect : false,
15927 * @cfg {Boolean} singleSelect Allow single selection
15929 singleSelect: false,
15932 * @cfg {Boolean} toggleSelect - selecting
15934 toggleSelect : false,
15937 * @cfg {Boolean} tickable - selecting
15942 * Returns the element this view is bound to.
15943 * @return {Roo.Element}
15945 getEl : function(){
15946 return this.wrapEl;
15952 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15954 refresh : function(){
15955 //Roo.log('refresh');
15958 // if we are using something like 'domtemplate', then
15959 // the what gets used is:
15960 // t.applySubtemplate(NAME, data, wrapping data..)
15961 // the outer template then get' applied with
15962 // the store 'extra data'
15963 // and the body get's added to the
15964 // roo-name="data" node?
15965 // <span class='roo-tpl-{name}'></span> ?????
15969 this.clearSelections();
15970 this.el.update("");
15972 var records = this.store.getRange();
15973 if(records.length < 1) {
15975 // is this valid?? = should it render a template??
15977 this.el.update(this.emptyText);
15981 if (this.dataName) {
15982 this.el.update(t.apply(this.store.meta)); //????
15983 el = this.el.child('.roo-tpl-' + this.dataName);
15986 for(var i = 0, len = records.length; i < len; i++){
15987 var data = this.prepareData(records[i].data, i, records[i]);
15988 this.fireEvent("preparedata", this, data, i, records[i]);
15990 var d = Roo.apply({}, data);
15993 Roo.apply(d, {'roo-id' : Roo.id()});
15997 Roo.each(this.parent.item, function(item){
15998 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16001 Roo.apply(d, {'roo-data-checked' : 'checked'});
16005 html[html.length] = Roo.util.Format.trim(
16007 t.applySubtemplate(this.dataName, d, this.store.meta) :
16014 el.update(html.join(""));
16015 this.nodes = el.dom.childNodes;
16016 this.updateIndexes(0);
16021 * Function to override to reformat the data that is sent to
16022 * the template for each node.
16023 * DEPRICATED - use the preparedata event handler.
16024 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16025 * a JSON object for an UpdateManager bound view).
16027 prepareData : function(data, index, record)
16029 this.fireEvent("preparedata", this, data, index, record);
16033 onUpdate : function(ds, record){
16034 // Roo.log('on update');
16035 this.clearSelections();
16036 var index = this.store.indexOf(record);
16037 var n = this.nodes[index];
16038 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16039 n.parentNode.removeChild(n);
16040 this.updateIndexes(index, index);
16046 onAdd : function(ds, records, index)
16048 //Roo.log(['on Add', ds, records, index] );
16049 this.clearSelections();
16050 if(this.nodes.length == 0){
16054 var n = this.nodes[index];
16055 for(var i = 0, len = records.length; i < len; i++){
16056 var d = this.prepareData(records[i].data, i, records[i]);
16058 this.tpl.insertBefore(n, d);
16061 this.tpl.append(this.el, d);
16064 this.updateIndexes(index);
16067 onRemove : function(ds, record, index){
16068 // Roo.log('onRemove');
16069 this.clearSelections();
16070 var el = this.dataName ?
16071 this.el.child('.roo-tpl-' + this.dataName) :
16074 el.dom.removeChild(this.nodes[index]);
16075 this.updateIndexes(index);
16079 * Refresh an individual node.
16080 * @param {Number} index
16082 refreshNode : function(index){
16083 this.onUpdate(this.store, this.store.getAt(index));
16086 updateIndexes : function(startIndex, endIndex){
16087 var ns = this.nodes;
16088 startIndex = startIndex || 0;
16089 endIndex = endIndex || ns.length - 1;
16090 for(var i = startIndex; i <= endIndex; i++){
16091 ns[i].nodeIndex = i;
16096 * Changes the data store this view uses and refresh the view.
16097 * @param {Store} store
16099 setStore : function(store, initial){
16100 if(!initial && this.store){
16101 this.store.un("datachanged", this.refresh);
16102 this.store.un("add", this.onAdd);
16103 this.store.un("remove", this.onRemove);
16104 this.store.un("update", this.onUpdate);
16105 this.store.un("clear", this.refresh);
16106 this.store.un("beforeload", this.onBeforeLoad);
16107 this.store.un("load", this.onLoad);
16108 this.store.un("loadexception", this.onLoad);
16112 store.on("datachanged", this.refresh, this);
16113 store.on("add", this.onAdd, this);
16114 store.on("remove", this.onRemove, this);
16115 store.on("update", this.onUpdate, this);
16116 store.on("clear", this.refresh, this);
16117 store.on("beforeload", this.onBeforeLoad, this);
16118 store.on("load", this.onLoad, this);
16119 store.on("loadexception", this.onLoad, this);
16127 * onbeforeLoad - masks the loading area.
16130 onBeforeLoad : function(store,opts)
16132 //Roo.log('onBeforeLoad');
16134 this.el.update("");
16136 this.el.mask(this.mask ? this.mask : "Loading" );
16138 onLoad : function ()
16145 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16146 * @param {HTMLElement} node
16147 * @return {HTMLElement} The template node
16149 findItemFromChild : function(node){
16150 var el = this.dataName ?
16151 this.el.child('.roo-tpl-' + this.dataName,true) :
16154 if(!node || node.parentNode == el){
16157 var p = node.parentNode;
16158 while(p && p != el){
16159 if(p.parentNode == el){
16168 onClick : function(e){
16169 var item = this.findItemFromChild(e.getTarget());
16171 var index = this.indexOf(item);
16172 if(this.onItemClick(item, index, e) !== false){
16173 this.fireEvent("click", this, index, item, e);
16176 this.clearSelections();
16181 onContextMenu : function(e){
16182 var item = this.findItemFromChild(e.getTarget());
16184 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16189 onDblClick : function(e){
16190 var item = this.findItemFromChild(e.getTarget());
16192 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16196 onItemClick : function(item, index, e)
16198 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16201 if (this.toggleSelect) {
16202 var m = this.isSelected(item) ? 'unselect' : 'select';
16205 _t[m](item, true, false);
16208 if(this.multiSelect || this.singleSelect){
16209 if(this.multiSelect && e.shiftKey && this.lastSelection){
16210 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16212 this.select(item, this.multiSelect && e.ctrlKey);
16213 this.lastSelection = item;
16216 if(!this.tickable){
16217 e.preventDefault();
16225 * Get the number of selected nodes.
16228 getSelectionCount : function(){
16229 return this.selections.length;
16233 * Get the currently selected nodes.
16234 * @return {Array} An array of HTMLElements
16236 getSelectedNodes : function(){
16237 return this.selections;
16241 * Get the indexes of the selected nodes.
16244 getSelectedIndexes : function(){
16245 var indexes = [], s = this.selections;
16246 for(var i = 0, len = s.length; i < len; i++){
16247 indexes.push(s[i].nodeIndex);
16253 * Clear all selections
16254 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16256 clearSelections : function(suppressEvent){
16257 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16258 this.cmp.elements = this.selections;
16259 this.cmp.removeClass(this.selectedClass);
16260 this.selections = [];
16261 if(!suppressEvent){
16262 this.fireEvent("selectionchange", this, this.selections);
16268 * Returns true if the passed node is selected
16269 * @param {HTMLElement/Number} node The node or node index
16270 * @return {Boolean}
16272 isSelected : function(node){
16273 var s = this.selections;
16277 node = this.getNode(node);
16278 return s.indexOf(node) !== -1;
16283 * @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
16284 * @param {Boolean} keepExisting (optional) true to keep existing selections
16285 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16287 select : function(nodeInfo, keepExisting, suppressEvent){
16288 if(nodeInfo instanceof Array){
16290 this.clearSelections(true);
16292 for(var i = 0, len = nodeInfo.length; i < len; i++){
16293 this.select(nodeInfo[i], true, true);
16297 var node = this.getNode(nodeInfo);
16298 if(!node || this.isSelected(node)){
16299 return; // already selected.
16302 this.clearSelections(true);
16305 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16306 Roo.fly(node).addClass(this.selectedClass);
16307 this.selections.push(node);
16308 if(!suppressEvent){
16309 this.fireEvent("selectionchange", this, this.selections);
16317 * @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
16318 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16319 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16321 unselect : function(nodeInfo, keepExisting, suppressEvent)
16323 if(nodeInfo instanceof Array){
16324 Roo.each(this.selections, function(s) {
16325 this.unselect(s, nodeInfo);
16329 var node = this.getNode(nodeInfo);
16330 if(!node || !this.isSelected(node)){
16331 //Roo.log("not selected");
16332 return; // not selected.
16336 Roo.each(this.selections, function(s) {
16338 Roo.fly(node).removeClass(this.selectedClass);
16345 this.selections= ns;
16346 this.fireEvent("selectionchange", this, this.selections);
16350 * Gets a template node.
16351 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16352 * @return {HTMLElement} The node or null if it wasn't found
16354 getNode : function(nodeInfo){
16355 if(typeof nodeInfo == "string"){
16356 return document.getElementById(nodeInfo);
16357 }else if(typeof nodeInfo == "number"){
16358 return this.nodes[nodeInfo];
16364 * Gets a range template nodes.
16365 * @param {Number} startIndex
16366 * @param {Number} endIndex
16367 * @return {Array} An array of nodes
16369 getNodes : function(start, end){
16370 var ns = this.nodes;
16371 start = start || 0;
16372 end = typeof end == "undefined" ? ns.length - 1 : end;
16375 for(var i = start; i <= end; i++){
16379 for(var i = start; i >= end; i--){
16387 * Finds the index of the passed node
16388 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16389 * @return {Number} The index of the node or -1
16391 indexOf : function(node){
16392 node = this.getNode(node);
16393 if(typeof node.nodeIndex == "number"){
16394 return node.nodeIndex;
16396 var ns = this.nodes;
16397 for(var i = 0, len = ns.length; i < len; i++){
16408 * based on jquery fullcalendar
16412 Roo.bootstrap = Roo.bootstrap || {};
16414 * @class Roo.bootstrap.Calendar
16415 * @extends Roo.bootstrap.Component
16416 * Bootstrap Calendar class
16417 * @cfg {Boolean} loadMask (true|false) default false
16418 * @cfg {Object} header generate the user specific header of the calendar, default false
16421 * Create a new Container
16422 * @param {Object} config The config object
16427 Roo.bootstrap.Calendar = function(config){
16428 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16432 * Fires when a date is selected
16433 * @param {DatePicker} this
16434 * @param {Date} date The selected date
16438 * @event monthchange
16439 * Fires when the displayed month changes
16440 * @param {DatePicker} this
16441 * @param {Date} date The selected month
16443 'monthchange': true,
16445 * @event evententer
16446 * Fires when mouse over an event
16447 * @param {Calendar} this
16448 * @param {event} Event
16450 'evententer': true,
16452 * @event eventleave
16453 * Fires when the mouse leaves an
16454 * @param {Calendar} this
16457 'eventleave': true,
16459 * @event eventclick
16460 * Fires when the mouse click an
16461 * @param {Calendar} this
16470 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16473 * @cfg {Number} startDay
16474 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16482 getAutoCreate : function(){
16485 var fc_button = function(name, corner, style, content ) {
16486 return Roo.apply({},{
16488 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16490 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16493 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16504 style : 'width:100%',
16511 cls : 'fc-header-left',
16513 fc_button('prev', 'left', 'arrow', '‹' ),
16514 fc_button('next', 'right', 'arrow', '›' ),
16515 { tag: 'span', cls: 'fc-header-space' },
16516 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16524 cls : 'fc-header-center',
16528 cls: 'fc-header-title',
16531 html : 'month / year'
16539 cls : 'fc-header-right',
16541 /* fc_button('month', 'left', '', 'month' ),
16542 fc_button('week', '', '', 'week' ),
16543 fc_button('day', 'right', '', 'day' )
16555 header = this.header;
16558 var cal_heads = function() {
16560 // fixme - handle this.
16562 for (var i =0; i < Date.dayNames.length; i++) {
16563 var d = Date.dayNames[i];
16566 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16567 html : d.substring(0,3)
16571 ret[0].cls += ' fc-first';
16572 ret[6].cls += ' fc-last';
16575 var cal_cell = function(n) {
16578 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16583 cls: 'fc-day-number',
16587 cls: 'fc-day-content',
16591 style: 'position: relative;' // height: 17px;
16603 var cal_rows = function() {
16606 for (var r = 0; r < 6; r++) {
16613 for (var i =0; i < Date.dayNames.length; i++) {
16614 var d = Date.dayNames[i];
16615 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16618 row.cn[0].cls+=' fc-first';
16619 row.cn[0].cn[0].style = 'min-height:90px';
16620 row.cn[6].cls+=' fc-last';
16624 ret[0].cls += ' fc-first';
16625 ret[4].cls += ' fc-prev-last';
16626 ret[5].cls += ' fc-last';
16633 cls: 'fc-border-separate',
16634 style : 'width:100%',
16642 cls : 'fc-first fc-last',
16660 cls : 'fc-content',
16661 style : "position: relative;",
16664 cls : 'fc-view fc-view-month fc-grid',
16665 style : 'position: relative',
16666 unselectable : 'on',
16669 cls : 'fc-event-container',
16670 style : 'position:absolute;z-index:8;top:0;left:0;'
16688 initEvents : function()
16691 throw "can not find store for calendar";
16697 style: "text-align:center",
16701 style: "background-color:white;width:50%;margin:250 auto",
16705 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16716 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16718 var size = this.el.select('.fc-content', true).first().getSize();
16719 this.maskEl.setSize(size.width, size.height);
16720 this.maskEl.enableDisplayMode("block");
16721 if(!this.loadMask){
16722 this.maskEl.hide();
16725 this.store = Roo.factory(this.store, Roo.data);
16726 this.store.on('load', this.onLoad, this);
16727 this.store.on('beforeload', this.onBeforeLoad, this);
16731 this.cells = this.el.select('.fc-day',true);
16732 //Roo.log(this.cells);
16733 this.textNodes = this.el.query('.fc-day-number');
16734 this.cells.addClassOnOver('fc-state-hover');
16736 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16737 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16738 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16739 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16741 this.on('monthchange', this.onMonthChange, this);
16743 this.update(new Date().clearTime());
16746 resize : function() {
16747 var sz = this.el.getSize();
16749 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16750 this.el.select('.fc-day-content div',true).setHeight(34);
16755 showPrevMonth : function(e){
16756 this.update(this.activeDate.add("mo", -1));
16758 showToday : function(e){
16759 this.update(new Date().clearTime());
16762 showNextMonth : function(e){
16763 this.update(this.activeDate.add("mo", 1));
16767 showPrevYear : function(){
16768 this.update(this.activeDate.add("y", -1));
16772 showNextYear : function(){
16773 this.update(this.activeDate.add("y", 1));
16778 update : function(date)
16780 var vd = this.activeDate;
16781 this.activeDate = date;
16782 // if(vd && this.el){
16783 // var t = date.getTime();
16784 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16785 // Roo.log('using add remove');
16787 // this.fireEvent('monthchange', this, date);
16789 // this.cells.removeClass("fc-state-highlight");
16790 // this.cells.each(function(c){
16791 // if(c.dateValue == t){
16792 // c.addClass("fc-state-highlight");
16793 // setTimeout(function(){
16794 // try{c.dom.firstChild.focus();}catch(e){}
16804 var days = date.getDaysInMonth();
16806 var firstOfMonth = date.getFirstDateOfMonth();
16807 var startingPos = firstOfMonth.getDay()-this.startDay;
16809 if(startingPos < this.startDay){
16813 var pm = date.add(Date.MONTH, -1);
16814 var prevStart = pm.getDaysInMonth()-startingPos;
16816 this.cells = this.el.select('.fc-day',true);
16817 this.textNodes = this.el.query('.fc-day-number');
16818 this.cells.addClassOnOver('fc-state-hover');
16820 var cells = this.cells.elements;
16821 var textEls = this.textNodes;
16823 Roo.each(cells, function(cell){
16824 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16827 days += startingPos;
16829 // convert everything to numbers so it's fast
16830 var day = 86400000;
16831 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16834 //Roo.log(prevStart);
16836 var today = new Date().clearTime().getTime();
16837 var sel = date.clearTime().getTime();
16838 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16839 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16840 var ddMatch = this.disabledDatesRE;
16841 var ddText = this.disabledDatesText;
16842 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16843 var ddaysText = this.disabledDaysText;
16844 var format = this.format;
16846 var setCellClass = function(cal, cell){
16850 //Roo.log('set Cell Class');
16852 var t = d.getTime();
16856 cell.dateValue = t;
16858 cell.className += " fc-today";
16859 cell.className += " fc-state-highlight";
16860 cell.title = cal.todayText;
16863 // disable highlight in other month..
16864 //cell.className += " fc-state-highlight";
16869 cell.className = " fc-state-disabled";
16870 cell.title = cal.minText;
16874 cell.className = " fc-state-disabled";
16875 cell.title = cal.maxText;
16879 if(ddays.indexOf(d.getDay()) != -1){
16880 cell.title = ddaysText;
16881 cell.className = " fc-state-disabled";
16884 if(ddMatch && format){
16885 var fvalue = d.dateFormat(format);
16886 if(ddMatch.test(fvalue)){
16887 cell.title = ddText.replace("%0", fvalue);
16888 cell.className = " fc-state-disabled";
16892 if (!cell.initialClassName) {
16893 cell.initialClassName = cell.dom.className;
16896 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16901 for(; i < startingPos; i++) {
16902 textEls[i].innerHTML = (++prevStart);
16903 d.setDate(d.getDate()+1);
16905 cells[i].className = "fc-past fc-other-month";
16906 setCellClass(this, cells[i]);
16911 for(; i < days; i++){
16912 intDay = i - startingPos + 1;
16913 textEls[i].innerHTML = (intDay);
16914 d.setDate(d.getDate()+1);
16916 cells[i].className = ''; // "x-date-active";
16917 setCellClass(this, cells[i]);
16921 for(; i < 42; i++) {
16922 textEls[i].innerHTML = (++extraDays);
16923 d.setDate(d.getDate()+1);
16925 cells[i].className = "fc-future fc-other-month";
16926 setCellClass(this, cells[i]);
16929 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16931 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16933 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16934 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16936 if(totalRows != 6){
16937 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16938 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16941 this.fireEvent('monthchange', this, date);
16945 if(!this.internalRender){
16946 var main = this.el.dom.firstChild;
16947 var w = main.offsetWidth;
16948 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16949 Roo.fly(main).setWidth(w);
16950 this.internalRender = true;
16951 // opera does not respect the auto grow header center column
16952 // then, after it gets a width opera refuses to recalculate
16953 // without a second pass
16954 if(Roo.isOpera && !this.secondPass){
16955 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16956 this.secondPass = true;
16957 this.update.defer(10, this, [date]);
16964 findCell : function(dt) {
16965 dt = dt.clearTime().getTime();
16967 this.cells.each(function(c){
16968 //Roo.log("check " +c.dateValue + '?=' + dt);
16969 if(c.dateValue == dt){
16979 findCells : function(ev) {
16980 var s = ev.start.clone().clearTime().getTime();
16982 var e= ev.end.clone().clearTime().getTime();
16985 this.cells.each(function(c){
16986 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16988 if(c.dateValue > e){
16991 if(c.dateValue < s){
17000 // findBestRow: function(cells)
17004 // for (var i =0 ; i < cells.length;i++) {
17005 // ret = Math.max(cells[i].rows || 0,ret);
17012 addItem : function(ev)
17014 // look for vertical location slot in
17015 var cells = this.findCells(ev);
17017 // ev.row = this.findBestRow(cells);
17019 // work out the location.
17023 for(var i =0; i < cells.length; i++) {
17025 cells[i].row = cells[0].row;
17028 cells[i].row = cells[i].row + 1;
17038 if (crow.start.getY() == cells[i].getY()) {
17040 crow.end = cells[i];
17057 cells[0].events.push(ev);
17059 this.calevents.push(ev);
17062 clearEvents: function() {
17064 if(!this.calevents){
17068 Roo.each(this.cells.elements, function(c){
17074 Roo.each(this.calevents, function(e) {
17075 Roo.each(e.els, function(el) {
17076 el.un('mouseenter' ,this.onEventEnter, this);
17077 el.un('mouseleave' ,this.onEventLeave, this);
17082 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17088 renderEvents: function()
17092 this.cells.each(function(c) {
17101 if(c.row != c.events.length){
17102 r = 4 - (4 - (c.row - c.events.length));
17105 c.events = ev.slice(0, r);
17106 c.more = ev.slice(r);
17108 if(c.more.length && c.more.length == 1){
17109 c.events.push(c.more.pop());
17112 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17116 this.cells.each(function(c) {
17118 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17121 for (var e = 0; e < c.events.length; e++){
17122 var ev = c.events[e];
17123 var rows = ev.rows;
17125 for(var i = 0; i < rows.length; i++) {
17127 // how many rows should it span..
17130 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17131 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17133 unselectable : "on",
17136 cls: 'fc-event-inner',
17140 // cls: 'fc-event-time',
17141 // html : cells.length > 1 ? '' : ev.time
17145 cls: 'fc-event-title',
17146 html : String.format('{0}', ev.title)
17153 cls: 'ui-resizable-handle ui-resizable-e',
17154 html : '  '
17161 cfg.cls += ' fc-event-start';
17163 if ((i+1) == rows.length) {
17164 cfg.cls += ' fc-event-end';
17167 var ctr = _this.el.select('.fc-event-container',true).first();
17168 var cg = ctr.createChild(cfg);
17170 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17171 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17173 var r = (c.more.length) ? 1 : 0;
17174 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17175 cg.setWidth(ebox.right - sbox.x -2);
17177 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17178 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17179 cg.on('click', _this.onEventClick, _this, ev);
17190 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17191 style : 'position: absolute',
17192 unselectable : "on",
17195 cls: 'fc-event-inner',
17199 cls: 'fc-event-title',
17207 cls: 'ui-resizable-handle ui-resizable-e',
17208 html : '  '
17214 var ctr = _this.el.select('.fc-event-container',true).first();
17215 var cg = ctr.createChild(cfg);
17217 var sbox = c.select('.fc-day-content',true).first().getBox();
17218 var ebox = c.select('.fc-day-content',true).first().getBox();
17220 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17221 cg.setWidth(ebox.right - sbox.x -2);
17223 cg.on('click', _this.onMoreEventClick, _this, c.more);
17233 onEventEnter: function (e, el,event,d) {
17234 this.fireEvent('evententer', this, el, event);
17237 onEventLeave: function (e, el,event,d) {
17238 this.fireEvent('eventleave', this, el, event);
17241 onEventClick: function (e, el,event,d) {
17242 this.fireEvent('eventclick', this, el, event);
17245 onMonthChange: function () {
17249 onMoreEventClick: function(e, el, more)
17253 this.calpopover.placement = 'right';
17254 this.calpopover.setTitle('More');
17256 this.calpopover.setContent('');
17258 var ctr = this.calpopover.el.select('.popover-content', true).first();
17260 Roo.each(more, function(m){
17262 cls : 'fc-event-hori fc-event-draggable',
17265 var cg = ctr.createChild(cfg);
17267 cg.on('click', _this.onEventClick, _this, m);
17270 this.calpopover.show(el);
17275 onLoad: function ()
17277 this.calevents = [];
17280 if(this.store.getCount() > 0){
17281 this.store.data.each(function(d){
17284 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17285 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17286 time : d.data.start_time,
17287 title : d.data.title,
17288 description : d.data.description,
17289 venue : d.data.venue
17294 this.renderEvents();
17296 if(this.calevents.length && this.loadMask){
17297 this.maskEl.hide();
17301 onBeforeLoad: function()
17303 this.clearEvents();
17305 this.maskEl.show();
17319 * @class Roo.bootstrap.Popover
17320 * @extends Roo.bootstrap.Component
17321 * Bootstrap Popover class
17322 * @cfg {String} html contents of the popover (or false to use children..)
17323 * @cfg {String} title of popover (or false to hide)
17324 * @cfg {String} placement how it is placed
17325 * @cfg {String} trigger click || hover (or false to trigger manually)
17326 * @cfg {String} over what (parent or false to trigger manually.)
17327 * @cfg {Number} delay - delay before showing
17330 * Create a new Popover
17331 * @param {Object} config The config object
17334 Roo.bootstrap.Popover = function(config){
17335 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17341 * After the popover show
17343 * @param {Roo.bootstrap.Popover} this
17348 * After the popover hide
17350 * @param {Roo.bootstrap.Popover} this
17356 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17358 title: 'Fill in a title',
17361 placement : 'right',
17362 trigger : 'hover', // hover
17368 can_build_overlaid : false,
17370 getChildContainer : function()
17372 return this.el.select('.popover-content',true).first();
17375 getAutoCreate : function(){
17378 cls : 'popover roo-dynamic',
17379 style: 'display:block',
17385 cls : 'popover-inner',
17389 cls: 'popover-title',
17393 cls : 'popover-content',
17404 setTitle: function(str)
17407 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17409 setContent: function(str)
17412 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17414 // as it get's added to the bottom of the page.
17415 onRender : function(ct, position)
17417 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17419 var cfg = Roo.apply({}, this.getAutoCreate());
17423 cfg.cls += ' ' + this.cls;
17426 cfg.style = this.style;
17428 //Roo.log("adding to ");
17429 this.el = Roo.get(document.body).createChild(cfg, position);
17430 // Roo.log(this.el);
17435 initEvents : function()
17437 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17438 this.el.enableDisplayMode('block');
17440 if (this.over === false) {
17443 if (this.triggers === false) {
17446 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17447 var triggers = this.trigger ? this.trigger.split(' ') : [];
17448 Roo.each(triggers, function(trigger) {
17450 if (trigger == 'click') {
17451 on_el.on('click', this.toggle, this);
17452 } else if (trigger != 'manual') {
17453 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17454 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17456 on_el.on(eventIn ,this.enter, this);
17457 on_el.on(eventOut, this.leave, this);
17468 toggle : function () {
17469 this.hoverState == 'in' ? this.leave() : this.enter();
17472 enter : function () {
17474 clearTimeout(this.timeout);
17476 this.hoverState = 'in';
17478 if (!this.delay || !this.delay.show) {
17483 this.timeout = setTimeout(function () {
17484 if (_t.hoverState == 'in') {
17487 }, this.delay.show)
17490 leave : function() {
17491 clearTimeout(this.timeout);
17493 this.hoverState = 'out';
17495 if (!this.delay || !this.delay.hide) {
17500 this.timeout = setTimeout(function () {
17501 if (_t.hoverState == 'out') {
17504 }, this.delay.hide)
17507 show : function (on_el)
17510 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17514 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17515 if (this.html !== false) {
17516 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17518 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17519 if (!this.title.length) {
17520 this.el.select('.popover-title',true).hide();
17523 var placement = typeof this.placement == 'function' ?
17524 this.placement.call(this, this.el, on_el) :
17527 var autoToken = /\s?auto?\s?/i;
17528 var autoPlace = autoToken.test(placement);
17530 placement = placement.replace(autoToken, '') || 'top';
17534 //this.el.setXY([0,0]);
17536 this.el.dom.style.display='block';
17537 this.el.addClass(placement);
17539 //this.el.appendTo(on_el);
17541 var p = this.getPosition();
17542 var box = this.el.getBox();
17547 var align = Roo.bootstrap.Popover.alignment[placement];
17550 this.el.alignTo(on_el, align[0],align[1]);
17551 //var arrow = this.el.select('.arrow',true).first();
17552 //arrow.set(align[2],
17554 this.el.addClass('in');
17557 if (this.el.hasClass('fade')) {
17561 this.hoverState = 'in';
17563 this.fireEvent('show', this);
17568 this.el.setXY([0,0]);
17569 this.el.removeClass('in');
17571 this.hoverState = null;
17573 this.fireEvent('hide', this);
17578 Roo.bootstrap.Popover.alignment = {
17579 'left' : ['r-l', [-10,0], 'right'],
17580 'right' : ['l-r', [10,0], 'left'],
17581 'bottom' : ['t-b', [0,10], 'top'],
17582 'top' : [ 'b-t', [0,-10], 'bottom']
17593 * @class Roo.bootstrap.Progress
17594 * @extends Roo.bootstrap.Component
17595 * Bootstrap Progress class
17596 * @cfg {Boolean} striped striped of the progress bar
17597 * @cfg {Boolean} active animated of the progress bar
17601 * Create a new Progress
17602 * @param {Object} config The config object
17605 Roo.bootstrap.Progress = function(config){
17606 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17609 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17614 getAutoCreate : function(){
17622 cfg.cls += ' progress-striped';
17626 cfg.cls += ' active';
17645 * @class Roo.bootstrap.ProgressBar
17646 * @extends Roo.bootstrap.Component
17647 * Bootstrap ProgressBar class
17648 * @cfg {Number} aria_valuenow aria-value now
17649 * @cfg {Number} aria_valuemin aria-value min
17650 * @cfg {Number} aria_valuemax aria-value max
17651 * @cfg {String} label label for the progress bar
17652 * @cfg {String} panel (success | info | warning | danger )
17653 * @cfg {String} role role of the progress bar
17654 * @cfg {String} sr_only text
17658 * Create a new ProgressBar
17659 * @param {Object} config The config object
17662 Roo.bootstrap.ProgressBar = function(config){
17663 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17666 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17670 aria_valuemax : 100,
17676 getAutoCreate : function()
17681 cls: 'progress-bar',
17682 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17694 cfg.role = this.role;
17697 if(this.aria_valuenow){
17698 cfg['aria-valuenow'] = this.aria_valuenow;
17701 if(this.aria_valuemin){
17702 cfg['aria-valuemin'] = this.aria_valuemin;
17705 if(this.aria_valuemax){
17706 cfg['aria-valuemax'] = this.aria_valuemax;
17709 if(this.label && !this.sr_only){
17710 cfg.html = this.label;
17714 cfg.cls += ' progress-bar-' + this.panel;
17720 update : function(aria_valuenow)
17722 this.aria_valuenow = aria_valuenow;
17724 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17739 * @class Roo.bootstrap.TabGroup
17740 * @extends Roo.bootstrap.Column
17741 * Bootstrap Column class
17742 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17743 * @cfg {Boolean} carousel true to make the group behave like a carousel
17744 * @cfg {Boolean} bullets show bullets for the panels
17745 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17746 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17747 * @cfg {Boolean} showarrow (true|false) show arrow default true
17750 * Create a new TabGroup
17751 * @param {Object} config The config object
17754 Roo.bootstrap.TabGroup = function(config){
17755 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17757 this.navId = Roo.id();
17760 Roo.bootstrap.TabGroup.register(this);
17764 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17767 transition : false,
17772 slideOnTouch : false,
17775 getAutoCreate : function()
17777 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17779 cfg.cls += ' tab-content';
17781 if (this.carousel) {
17782 cfg.cls += ' carousel slide';
17785 cls : 'carousel-inner',
17789 if(this.bullets && !Roo.isTouch){
17792 cls : 'carousel-bullets',
17796 if(this.bullets_cls){
17797 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17804 cfg.cn[0].cn.push(bullets);
17807 if(this.showarrow){
17808 cfg.cn[0].cn.push({
17810 class : 'carousel-arrow',
17814 class : 'carousel-prev',
17818 class : 'fa fa-chevron-left'
17824 class : 'carousel-next',
17828 class : 'fa fa-chevron-right'
17841 initEvents: function()
17843 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17844 // this.el.on("touchstart", this.onTouchStart, this);
17847 if(this.autoslide){
17850 this.slideFn = window.setInterval(function() {
17851 _this.showPanelNext();
17855 if(this.showarrow){
17856 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17857 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17863 // onTouchStart : function(e, el, o)
17865 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17869 // this.showPanelNext();
17873 getChildContainer : function()
17875 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17879 * register a Navigation item
17880 * @param {Roo.bootstrap.NavItem} the navitem to add
17882 register : function(item)
17884 this.tabs.push( item);
17885 item.navId = this.navId; // not really needed..
17890 getActivePanel : function()
17893 Roo.each(this.tabs, function(t) {
17903 getPanelByName : function(n)
17906 Roo.each(this.tabs, function(t) {
17907 if (t.tabId == n) {
17915 indexOfPanel : function(p)
17918 Roo.each(this.tabs, function(t,i) {
17919 if (t.tabId == p.tabId) {
17928 * show a specific panel
17929 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17930 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17932 showPanel : function (pan)
17934 if(this.transition || typeof(pan) == 'undefined'){
17935 Roo.log("waiting for the transitionend");
17939 if (typeof(pan) == 'number') {
17940 pan = this.tabs[pan];
17943 if (typeof(pan) == 'string') {
17944 pan = this.getPanelByName(pan);
17947 var cur = this.getActivePanel();
17950 Roo.log('pan or acitve pan is undefined');
17954 if (pan.tabId == this.getActivePanel().tabId) {
17958 if (false === cur.fireEvent('beforedeactivate')) {
17962 if(this.bullets > 0 && !Roo.isTouch){
17963 this.setActiveBullet(this.indexOfPanel(pan));
17966 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17968 this.transition = true;
17969 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17970 var lr = dir == 'next' ? 'left' : 'right';
17971 pan.el.addClass(dir); // or prev
17972 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17973 cur.el.addClass(lr); // or right
17974 pan.el.addClass(lr);
17977 cur.el.on('transitionend', function() {
17978 Roo.log("trans end?");
17980 pan.el.removeClass([lr,dir]);
17981 pan.setActive(true);
17983 cur.el.removeClass([lr]);
17984 cur.setActive(false);
17986 _this.transition = false;
17988 }, this, { single: true } );
17993 cur.setActive(false);
17994 pan.setActive(true);
17999 showPanelNext : function()
18001 var i = this.indexOfPanel(this.getActivePanel());
18003 if (i >= this.tabs.length - 1 && !this.autoslide) {
18007 if (i >= this.tabs.length - 1 && this.autoslide) {
18011 this.showPanel(this.tabs[i+1]);
18014 showPanelPrev : function()
18016 var i = this.indexOfPanel(this.getActivePanel());
18018 if (i < 1 && !this.autoslide) {
18022 if (i < 1 && this.autoslide) {
18023 i = this.tabs.length;
18026 this.showPanel(this.tabs[i-1]);
18030 addBullet: function()
18032 if(!this.bullets || Roo.isTouch){
18035 var ctr = this.el.select('.carousel-bullets',true).first();
18036 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18037 var bullet = ctr.createChild({
18038 cls : 'bullet bullet-' + i
18039 },ctr.dom.lastChild);
18044 bullet.on('click', (function(e, el, o, ii, t){
18046 e.preventDefault();
18048 this.showPanel(ii);
18050 if(this.autoslide && this.slideFn){
18051 clearInterval(this.slideFn);
18052 this.slideFn = window.setInterval(function() {
18053 _this.showPanelNext();
18057 }).createDelegate(this, [i, bullet], true));
18062 setActiveBullet : function(i)
18068 Roo.each(this.el.select('.bullet', true).elements, function(el){
18069 el.removeClass('selected');
18072 var bullet = this.el.select('.bullet-' + i, true).first();
18078 bullet.addClass('selected');
18089 Roo.apply(Roo.bootstrap.TabGroup, {
18093 * register a Navigation Group
18094 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18096 register : function(navgrp)
18098 this.groups[navgrp.navId] = navgrp;
18102 * fetch a Navigation Group based on the navigation ID
18103 * if one does not exist , it will get created.
18104 * @param {string} the navgroup to add
18105 * @returns {Roo.bootstrap.NavGroup} the navgroup
18107 get: function(navId) {
18108 if (typeof(this.groups[navId]) == 'undefined') {
18109 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18111 return this.groups[navId] ;
18126 * @class Roo.bootstrap.TabPanel
18127 * @extends Roo.bootstrap.Component
18128 * Bootstrap TabPanel class
18129 * @cfg {Boolean} active panel active
18130 * @cfg {String} html panel content
18131 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18132 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18133 * @cfg {String} href click to link..
18137 * Create a new TabPanel
18138 * @param {Object} config The config object
18141 Roo.bootstrap.TabPanel = function(config){
18142 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18146 * Fires when the active status changes
18147 * @param {Roo.bootstrap.TabPanel} this
18148 * @param {Boolean} state the new state
18153 * @event beforedeactivate
18154 * Fires before a tab is de-activated - can be used to do validation on a form.
18155 * @param {Roo.bootstrap.TabPanel} this
18156 * @return {Boolean} false if there is an error
18159 'beforedeactivate': true
18162 this.tabId = this.tabId || Roo.id();
18166 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18174 getAutoCreate : function(){
18177 // item is needed for carousel - not sure if it has any effect otherwise
18178 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18179 html: this.html || ''
18183 cfg.cls += ' active';
18187 cfg.tabId = this.tabId;
18194 initEvents: function()
18196 var p = this.parent();
18198 this.navId = this.navId || p.navId;
18200 if (typeof(this.navId) != 'undefined') {
18201 // not really needed.. but just in case.. parent should be a NavGroup.
18202 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18206 var i = tg.tabs.length - 1;
18208 if(this.active && tg.bullets > 0 && i < tg.bullets){
18209 tg.setActiveBullet(i);
18213 this.el.on('click', this.onClick, this);
18216 this.el.on("touchstart", this.onTouchStart, this);
18217 this.el.on("touchmove", this.onTouchMove, this);
18218 this.el.on("touchend", this.onTouchEnd, this);
18223 onRender : function(ct, position)
18225 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18228 setActive : function(state)
18230 Roo.log("panel - set active " + this.tabId + "=" + state);
18232 this.active = state;
18234 this.el.removeClass('active');
18236 } else if (!this.el.hasClass('active')) {
18237 this.el.addClass('active');
18240 this.fireEvent('changed', this, state);
18243 onClick : function(e)
18245 e.preventDefault();
18247 if(!this.href.length){
18251 window.location.href = this.href;
18260 onTouchStart : function(e)
18262 this.swiping = false;
18264 this.startX = e.browserEvent.touches[0].clientX;
18265 this.startY = e.browserEvent.touches[0].clientY;
18268 onTouchMove : function(e)
18270 this.swiping = true;
18272 this.endX = e.browserEvent.touches[0].clientX;
18273 this.endY = e.browserEvent.touches[0].clientY;
18276 onTouchEnd : function(e)
18283 var tabGroup = this.parent();
18285 if(this.endX > this.startX){ // swiping right
18286 tabGroup.showPanelPrev();
18290 if(this.startX > this.endX){ // swiping left
18291 tabGroup.showPanelNext();
18310 * @class Roo.bootstrap.DateField
18311 * @extends Roo.bootstrap.Input
18312 * Bootstrap DateField class
18313 * @cfg {Number} weekStart default 0
18314 * @cfg {String} viewMode default empty, (months|years)
18315 * @cfg {String} minViewMode default empty, (months|years)
18316 * @cfg {Number} startDate default -Infinity
18317 * @cfg {Number} endDate default Infinity
18318 * @cfg {Boolean} todayHighlight default false
18319 * @cfg {Boolean} todayBtn default false
18320 * @cfg {Boolean} calendarWeeks default false
18321 * @cfg {Object} daysOfWeekDisabled default empty
18322 * @cfg {Boolean} singleMode default false (true | false)
18324 * @cfg {Boolean} keyboardNavigation default true
18325 * @cfg {String} language default en
18328 * Create a new DateField
18329 * @param {Object} config The config object
18332 Roo.bootstrap.DateField = function(config){
18333 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18337 * Fires when this field show.
18338 * @param {Roo.bootstrap.DateField} this
18339 * @param {Mixed} date The date value
18344 * Fires when this field hide.
18345 * @param {Roo.bootstrap.DateField} this
18346 * @param {Mixed} date The date value
18351 * Fires when select a date.
18352 * @param {Roo.bootstrap.DateField} this
18353 * @param {Mixed} date The date value
18357 * @event beforeselect
18358 * Fires when before select a date.
18359 * @param {Roo.bootstrap.DateField} this
18360 * @param {Mixed} date The date value
18362 beforeselect : true
18366 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18369 * @cfg {String} format
18370 * The default date format string which can be overriden for localization support. The format must be
18371 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18375 * @cfg {String} altFormats
18376 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18377 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18379 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18387 todayHighlight : false,
18393 keyboardNavigation: true,
18395 calendarWeeks: false,
18397 startDate: -Infinity,
18401 daysOfWeekDisabled: [],
18405 singleMode : false,
18407 UTCDate: function()
18409 return new Date(Date.UTC.apply(Date, arguments));
18412 UTCToday: function()
18414 var today = new Date();
18415 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18418 getDate: function() {
18419 var d = this.getUTCDate();
18420 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18423 getUTCDate: function() {
18427 setDate: function(d) {
18428 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18431 setUTCDate: function(d) {
18433 this.setValue(this.formatDate(this.date));
18436 onRender: function(ct, position)
18439 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18441 this.language = this.language || 'en';
18442 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18443 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18445 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18446 this.format = this.format || 'm/d/y';
18447 this.isInline = false;
18448 this.isInput = true;
18449 this.component = this.el.select('.add-on', true).first() || false;
18450 this.component = (this.component && this.component.length === 0) ? false : this.component;
18451 this.hasInput = this.component && this.inputEl().length;
18453 if (typeof(this.minViewMode === 'string')) {
18454 switch (this.minViewMode) {
18456 this.minViewMode = 1;
18459 this.minViewMode = 2;
18462 this.minViewMode = 0;
18467 if (typeof(this.viewMode === 'string')) {
18468 switch (this.viewMode) {
18481 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18483 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18485 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18487 this.picker().on('mousedown', this.onMousedown, this);
18488 this.picker().on('click', this.onClick, this);
18490 this.picker().addClass('datepicker-dropdown');
18492 this.startViewMode = this.viewMode;
18494 if(this.singleMode){
18495 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18496 v.setVisibilityMode(Roo.Element.DISPLAY);
18500 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18501 v.setStyle('width', '189px');
18505 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18506 if(!this.calendarWeeks){
18511 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18512 v.attr('colspan', function(i, val){
18513 return parseInt(val) + 1;
18518 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18520 this.setStartDate(this.startDate);
18521 this.setEndDate(this.endDate);
18523 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18530 if(this.isInline) {
18535 picker : function()
18537 return this.pickerEl;
18538 // return this.el.select('.datepicker', true).first();
18541 fillDow: function()
18543 var dowCnt = this.weekStart;
18552 if(this.calendarWeeks){
18560 while (dowCnt < this.weekStart + 7) {
18564 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18568 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18571 fillMonths: function()
18574 var months = this.picker().select('>.datepicker-months td', true).first();
18576 months.dom.innerHTML = '';
18582 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18585 months.createChild(month);
18592 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;
18594 if (this.date < this.startDate) {
18595 this.viewDate = new Date(this.startDate);
18596 } else if (this.date > this.endDate) {
18597 this.viewDate = new Date(this.endDate);
18599 this.viewDate = new Date(this.date);
18607 var d = new Date(this.viewDate),
18608 year = d.getUTCFullYear(),
18609 month = d.getUTCMonth(),
18610 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18611 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18612 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18613 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18614 currentDate = this.date && this.date.valueOf(),
18615 today = this.UTCToday();
18617 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18619 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18621 // this.picker.select('>tfoot th.today').
18622 // .text(dates[this.language].today)
18623 // .toggle(this.todayBtn !== false);
18625 this.updateNavArrows();
18628 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18630 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18632 prevMonth.setUTCDate(day);
18634 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18636 var nextMonth = new Date(prevMonth);
18638 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18640 nextMonth = nextMonth.valueOf();
18642 var fillMonths = false;
18644 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18646 while(prevMonth.valueOf() < nextMonth) {
18649 if (prevMonth.getUTCDay() === this.weekStart) {
18651 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18659 if(this.calendarWeeks){
18660 // ISO 8601: First week contains first thursday.
18661 // ISO also states week starts on Monday, but we can be more abstract here.
18663 // Start of current week: based on weekstart/current date
18664 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18665 // Thursday of this week
18666 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18667 // First Thursday of year, year from thursday
18668 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18669 // Calendar week: ms between thursdays, div ms per day, div 7 days
18670 calWeek = (th - yth) / 864e5 / 7 + 1;
18672 fillMonths.cn.push({
18680 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18682 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18685 if (this.todayHighlight &&
18686 prevMonth.getUTCFullYear() == today.getFullYear() &&
18687 prevMonth.getUTCMonth() == today.getMonth() &&
18688 prevMonth.getUTCDate() == today.getDate()) {
18689 clsName += ' today';
18692 if (currentDate && prevMonth.valueOf() === currentDate) {
18693 clsName += ' active';
18696 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18697 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18698 clsName += ' disabled';
18701 fillMonths.cn.push({
18703 cls: 'day ' + clsName,
18704 html: prevMonth.getDate()
18707 prevMonth.setDate(prevMonth.getDate()+1);
18710 var currentYear = this.date && this.date.getUTCFullYear();
18711 var currentMonth = this.date && this.date.getUTCMonth();
18713 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18715 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18716 v.removeClass('active');
18718 if(currentYear === year && k === currentMonth){
18719 v.addClass('active');
18722 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18723 v.addClass('disabled');
18729 year = parseInt(year/10, 10) * 10;
18731 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18733 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18736 for (var i = -1; i < 11; i++) {
18737 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18739 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18747 showMode: function(dir)
18750 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18753 Roo.each(this.picker().select('>div',true).elements, function(v){
18754 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18757 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18762 if(this.isInline) {
18766 this.picker().removeClass(['bottom', 'top']);
18768 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18770 * place to the top of element!
18774 this.picker().addClass('top');
18775 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18780 this.picker().addClass('bottom');
18782 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18785 parseDate : function(value)
18787 if(!value || value instanceof Date){
18790 var v = Date.parseDate(value, this.format);
18791 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18792 v = Date.parseDate(value, 'Y-m-d');
18794 if(!v && this.altFormats){
18795 if(!this.altFormatsArray){
18796 this.altFormatsArray = this.altFormats.split("|");
18798 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18799 v = Date.parseDate(value, this.altFormatsArray[i]);
18805 formatDate : function(date, fmt)
18807 return (!date || !(date instanceof Date)) ?
18808 date : date.dateFormat(fmt || this.format);
18811 onFocus : function()
18813 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18817 onBlur : function()
18819 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18821 var d = this.inputEl().getValue();
18830 this.picker().show();
18834 this.fireEvent('show', this, this.date);
18839 if(this.isInline) {
18842 this.picker().hide();
18843 this.viewMode = this.startViewMode;
18846 this.fireEvent('hide', this, this.date);
18850 onMousedown: function(e)
18852 e.stopPropagation();
18853 e.preventDefault();
18858 Roo.bootstrap.DateField.superclass.keyup.call(this);
18862 setValue: function(v)
18864 if(this.fireEvent('beforeselect', this, v) !== false){
18865 var d = new Date(this.parseDate(v) ).clearTime();
18867 if(isNaN(d.getTime())){
18868 this.date = this.viewDate = '';
18869 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18873 v = this.formatDate(d);
18875 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18877 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18881 this.fireEvent('select', this, this.date);
18885 getValue: function()
18887 return this.formatDate(this.date);
18890 fireKey: function(e)
18892 if (!this.picker().isVisible()){
18893 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18899 var dateChanged = false,
18901 newDate, newViewDate;
18906 e.preventDefault();
18910 if (!this.keyboardNavigation) {
18913 dir = e.keyCode == 37 ? -1 : 1;
18916 newDate = this.moveYear(this.date, dir);
18917 newViewDate = this.moveYear(this.viewDate, dir);
18918 } else if (e.shiftKey){
18919 newDate = this.moveMonth(this.date, dir);
18920 newViewDate = this.moveMonth(this.viewDate, dir);
18922 newDate = new Date(this.date);
18923 newDate.setUTCDate(this.date.getUTCDate() + dir);
18924 newViewDate = new Date(this.viewDate);
18925 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18927 if (this.dateWithinRange(newDate)){
18928 this.date = newDate;
18929 this.viewDate = newViewDate;
18930 this.setValue(this.formatDate(this.date));
18932 e.preventDefault();
18933 dateChanged = true;
18938 if (!this.keyboardNavigation) {
18941 dir = e.keyCode == 38 ? -1 : 1;
18943 newDate = this.moveYear(this.date, dir);
18944 newViewDate = this.moveYear(this.viewDate, dir);
18945 } else if (e.shiftKey){
18946 newDate = this.moveMonth(this.date, dir);
18947 newViewDate = this.moveMonth(this.viewDate, dir);
18949 newDate = new Date(this.date);
18950 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18951 newViewDate = new Date(this.viewDate);
18952 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18954 if (this.dateWithinRange(newDate)){
18955 this.date = newDate;
18956 this.viewDate = newViewDate;
18957 this.setValue(this.formatDate(this.date));
18959 e.preventDefault();
18960 dateChanged = true;
18964 this.setValue(this.formatDate(this.date));
18966 e.preventDefault();
18969 this.setValue(this.formatDate(this.date));
18983 onClick: function(e)
18985 e.stopPropagation();
18986 e.preventDefault();
18988 var target = e.getTarget();
18990 if(target.nodeName.toLowerCase() === 'i'){
18991 target = Roo.get(target).dom.parentNode;
18994 var nodeName = target.nodeName;
18995 var className = target.className;
18996 var html = target.innerHTML;
18997 //Roo.log(nodeName);
18999 switch(nodeName.toLowerCase()) {
19001 switch(className) {
19007 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19008 switch(this.viewMode){
19010 this.viewDate = this.moveMonth(this.viewDate, dir);
19014 this.viewDate = this.moveYear(this.viewDate, dir);
19020 var date = new Date();
19021 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19023 this.setValue(this.formatDate(this.date));
19030 if (className.indexOf('disabled') < 0) {
19031 this.viewDate.setUTCDate(1);
19032 if (className.indexOf('month') > -1) {
19033 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19035 var year = parseInt(html, 10) || 0;
19036 this.viewDate.setUTCFullYear(year);
19040 if(this.singleMode){
19041 this.setValue(this.formatDate(this.viewDate));
19052 //Roo.log(className);
19053 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19054 var day = parseInt(html, 10) || 1;
19055 var year = this.viewDate.getUTCFullYear(),
19056 month = this.viewDate.getUTCMonth();
19058 if (className.indexOf('old') > -1) {
19065 } else if (className.indexOf('new') > -1) {
19073 //Roo.log([year,month,day]);
19074 this.date = this.UTCDate(year, month, day,0,0,0,0);
19075 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19077 //Roo.log(this.formatDate(this.date));
19078 this.setValue(this.formatDate(this.date));
19085 setStartDate: function(startDate)
19087 this.startDate = startDate || -Infinity;
19088 if (this.startDate !== -Infinity) {
19089 this.startDate = this.parseDate(this.startDate);
19092 this.updateNavArrows();
19095 setEndDate: function(endDate)
19097 this.endDate = endDate || Infinity;
19098 if (this.endDate !== Infinity) {
19099 this.endDate = this.parseDate(this.endDate);
19102 this.updateNavArrows();
19105 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19107 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19108 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19109 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19111 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19112 return parseInt(d, 10);
19115 this.updateNavArrows();
19118 updateNavArrows: function()
19120 if(this.singleMode){
19124 var d = new Date(this.viewDate),
19125 year = d.getUTCFullYear(),
19126 month = d.getUTCMonth();
19128 Roo.each(this.picker().select('.prev', true).elements, function(v){
19130 switch (this.viewMode) {
19133 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19139 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19146 Roo.each(this.picker().select('.next', true).elements, function(v){
19148 switch (this.viewMode) {
19151 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19157 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19165 moveMonth: function(date, dir)
19170 var new_date = new Date(date.valueOf()),
19171 day = new_date.getUTCDate(),
19172 month = new_date.getUTCMonth(),
19173 mag = Math.abs(dir),
19175 dir = dir > 0 ? 1 : -1;
19178 // If going back one month, make sure month is not current month
19179 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19181 return new_date.getUTCMonth() == month;
19183 // If going forward one month, make sure month is as expected
19184 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19186 return new_date.getUTCMonth() != new_month;
19188 new_month = month + dir;
19189 new_date.setUTCMonth(new_month);
19190 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19191 if (new_month < 0 || new_month > 11) {
19192 new_month = (new_month + 12) % 12;
19195 // For magnitudes >1, move one month at a time...
19196 for (var i=0; i<mag; i++) {
19197 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19198 new_date = this.moveMonth(new_date, dir);
19200 // ...then reset the day, keeping it in the new month
19201 new_month = new_date.getUTCMonth();
19202 new_date.setUTCDate(day);
19204 return new_month != new_date.getUTCMonth();
19207 // Common date-resetting loop -- if date is beyond end of month, make it
19210 new_date.setUTCDate(--day);
19211 new_date.setUTCMonth(new_month);
19216 moveYear: function(date, dir)
19218 return this.moveMonth(date, dir*12);
19221 dateWithinRange: function(date)
19223 return date >= this.startDate && date <= this.endDate;
19229 this.picker().remove();
19232 validateValue : function(value)
19234 if(this.getVisibilityEl().hasClass('hidden')){
19238 if(value.length < 1) {
19239 if(this.allowBlank){
19245 if(value.length < this.minLength){
19248 if(value.length > this.maxLength){
19252 var vt = Roo.form.VTypes;
19253 if(!vt[this.vtype](value, this)){
19257 if(typeof this.validator == "function"){
19258 var msg = this.validator(value);
19264 if(this.regex && !this.regex.test(value)){
19268 if(typeof(this.parseDate(value)) == 'undefined'){
19272 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19276 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19284 setVisible : function(visible)
19290 this.getEl().removeClass('hidden');
19296 this.getEl().addClass('hidden');
19301 Roo.apply(Roo.bootstrap.DateField, {
19312 html: '<i class="fa fa-arrow-left"/>'
19322 html: '<i class="fa fa-arrow-right"/>'
19364 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19365 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19366 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19367 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19368 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19381 navFnc: 'FullYear',
19386 navFnc: 'FullYear',
19391 Roo.apply(Roo.bootstrap.DateField, {
19395 cls: 'datepicker dropdown-menu roo-dynamic',
19399 cls: 'datepicker-days',
19403 cls: 'table-condensed',
19405 Roo.bootstrap.DateField.head,
19409 Roo.bootstrap.DateField.footer
19416 cls: 'datepicker-months',
19420 cls: 'table-condensed',
19422 Roo.bootstrap.DateField.head,
19423 Roo.bootstrap.DateField.content,
19424 Roo.bootstrap.DateField.footer
19431 cls: 'datepicker-years',
19435 cls: 'table-condensed',
19437 Roo.bootstrap.DateField.head,
19438 Roo.bootstrap.DateField.content,
19439 Roo.bootstrap.DateField.footer
19458 * @class Roo.bootstrap.TimeField
19459 * @extends Roo.bootstrap.Input
19460 * Bootstrap DateField class
19464 * Create a new TimeField
19465 * @param {Object} config The config object
19468 Roo.bootstrap.TimeField = function(config){
19469 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19473 * Fires when this field show.
19474 * @param {Roo.bootstrap.DateField} thisthis
19475 * @param {Mixed} date The date value
19480 * Fires when this field hide.
19481 * @param {Roo.bootstrap.DateField} this
19482 * @param {Mixed} date The date value
19487 * Fires when select a date.
19488 * @param {Roo.bootstrap.DateField} this
19489 * @param {Mixed} date The date value
19495 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19498 * @cfg {String} format
19499 * The default time format string which can be overriden for localization support. The format must be
19500 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19504 onRender: function(ct, position)
19507 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19509 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19511 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19513 this.pop = this.picker().select('>.datepicker-time',true).first();
19514 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19516 this.picker().on('mousedown', this.onMousedown, this);
19517 this.picker().on('click', this.onClick, this);
19519 this.picker().addClass('datepicker-dropdown');
19524 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19525 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19526 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19527 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19528 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19529 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19533 fireKey: function(e){
19534 if (!this.picker().isVisible()){
19535 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19541 e.preventDefault();
19549 this.onTogglePeriod();
19552 this.onIncrementMinutes();
19555 this.onDecrementMinutes();
19564 onClick: function(e) {
19565 e.stopPropagation();
19566 e.preventDefault();
19569 picker : function()
19571 return this.el.select('.datepicker', true).first();
19574 fillTime: function()
19576 var time = this.pop.select('tbody', true).first();
19578 time.dom.innerHTML = '';
19593 cls: 'hours-up glyphicon glyphicon-chevron-up'
19613 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19634 cls: 'timepicker-hour',
19649 cls: 'timepicker-minute',
19664 cls: 'btn btn-primary period',
19686 cls: 'hours-down glyphicon glyphicon-chevron-down'
19706 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19724 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19731 var hours = this.time.getHours();
19732 var minutes = this.time.getMinutes();
19745 hours = hours - 12;
19749 hours = '0' + hours;
19753 minutes = '0' + minutes;
19756 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19757 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19758 this.pop.select('button', true).first().dom.innerHTML = period;
19764 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19766 var cls = ['bottom'];
19768 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19775 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19780 this.picker().addClass(cls.join('-'));
19784 Roo.each(cls, function(c){
19786 _this.picker().setTop(_this.inputEl().getHeight());
19790 _this.picker().setTop(0 - _this.picker().getHeight());
19795 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19799 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19806 onFocus : function()
19808 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19812 onBlur : function()
19814 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19820 this.picker().show();
19825 this.fireEvent('show', this, this.date);
19830 this.picker().hide();
19833 this.fireEvent('hide', this, this.date);
19836 setTime : function()
19839 this.setValue(this.time.format(this.format));
19841 this.fireEvent('select', this, this.date);
19846 onMousedown: function(e){
19847 e.stopPropagation();
19848 e.preventDefault();
19851 onIncrementHours: function()
19853 Roo.log('onIncrementHours');
19854 this.time = this.time.add(Date.HOUR, 1);
19859 onDecrementHours: function()
19861 Roo.log('onDecrementHours');
19862 this.time = this.time.add(Date.HOUR, -1);
19866 onIncrementMinutes: function()
19868 Roo.log('onIncrementMinutes');
19869 this.time = this.time.add(Date.MINUTE, 1);
19873 onDecrementMinutes: function()
19875 Roo.log('onDecrementMinutes');
19876 this.time = this.time.add(Date.MINUTE, -1);
19880 onTogglePeriod: function()
19882 Roo.log('onTogglePeriod');
19883 this.time = this.time.add(Date.HOUR, 12);
19890 Roo.apply(Roo.bootstrap.TimeField, {
19920 cls: 'btn btn-info ok',
19932 Roo.apply(Roo.bootstrap.TimeField, {
19936 cls: 'datepicker dropdown-menu',
19940 cls: 'datepicker-time',
19944 cls: 'table-condensed',
19946 Roo.bootstrap.TimeField.content,
19947 Roo.bootstrap.TimeField.footer
19966 * @class Roo.bootstrap.MonthField
19967 * @extends Roo.bootstrap.Input
19968 * Bootstrap MonthField class
19970 * @cfg {String} language default en
19973 * Create a new MonthField
19974 * @param {Object} config The config object
19977 Roo.bootstrap.MonthField = function(config){
19978 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19983 * Fires when this field show.
19984 * @param {Roo.bootstrap.MonthField} this
19985 * @param {Mixed} date The date value
19990 * Fires when this field hide.
19991 * @param {Roo.bootstrap.MonthField} this
19992 * @param {Mixed} date The date value
19997 * Fires when select a date.
19998 * @param {Roo.bootstrap.MonthField} this
19999 * @param {String} oldvalue The old value
20000 * @param {String} newvalue The new value
20006 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20008 onRender: function(ct, position)
20011 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20013 this.language = this.language || 'en';
20014 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20015 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20017 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20018 this.isInline = false;
20019 this.isInput = true;
20020 this.component = this.el.select('.add-on', true).first() || false;
20021 this.component = (this.component && this.component.length === 0) ? false : this.component;
20022 this.hasInput = this.component && this.inputEL().length;
20024 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20026 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20028 this.picker().on('mousedown', this.onMousedown, this);
20029 this.picker().on('click', this.onClick, this);
20031 this.picker().addClass('datepicker-dropdown');
20033 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20034 v.setStyle('width', '189px');
20041 if(this.isInline) {
20047 setValue: function(v, suppressEvent)
20049 var o = this.getValue();
20051 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20055 if(suppressEvent !== true){
20056 this.fireEvent('select', this, o, v);
20061 getValue: function()
20066 onClick: function(e)
20068 e.stopPropagation();
20069 e.preventDefault();
20071 var target = e.getTarget();
20073 if(target.nodeName.toLowerCase() === 'i'){
20074 target = Roo.get(target).dom.parentNode;
20077 var nodeName = target.nodeName;
20078 var className = target.className;
20079 var html = target.innerHTML;
20081 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20085 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20087 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20093 picker : function()
20095 return this.pickerEl;
20098 fillMonths: function()
20101 var months = this.picker().select('>.datepicker-months td', true).first();
20103 months.dom.innerHTML = '';
20109 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20112 months.createChild(month);
20121 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20122 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20125 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20126 e.removeClass('active');
20128 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20129 e.addClass('active');
20136 if(this.isInline) {
20140 this.picker().removeClass(['bottom', 'top']);
20142 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20144 * place to the top of element!
20148 this.picker().addClass('top');
20149 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20154 this.picker().addClass('bottom');
20156 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20159 onFocus : function()
20161 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20165 onBlur : function()
20167 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20169 var d = this.inputEl().getValue();
20178 this.picker().show();
20179 this.picker().select('>.datepicker-months', true).first().show();
20183 this.fireEvent('show', this, this.date);
20188 if(this.isInline) {
20191 this.picker().hide();
20192 this.fireEvent('hide', this, this.date);
20196 onMousedown: function(e)
20198 e.stopPropagation();
20199 e.preventDefault();
20204 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20208 fireKey: function(e)
20210 if (!this.picker().isVisible()){
20211 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20222 e.preventDefault();
20226 dir = e.keyCode == 37 ? -1 : 1;
20228 this.vIndex = this.vIndex + dir;
20230 if(this.vIndex < 0){
20234 if(this.vIndex > 11){
20238 if(isNaN(this.vIndex)){
20242 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20248 dir = e.keyCode == 38 ? -1 : 1;
20250 this.vIndex = this.vIndex + dir * 4;
20252 if(this.vIndex < 0){
20256 if(this.vIndex > 11){
20260 if(isNaN(this.vIndex)){
20264 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20269 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20270 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20274 e.preventDefault();
20277 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20278 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20294 this.picker().remove();
20299 Roo.apply(Roo.bootstrap.MonthField, {
20318 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20319 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20324 Roo.apply(Roo.bootstrap.MonthField, {
20328 cls: 'datepicker dropdown-menu roo-dynamic',
20332 cls: 'datepicker-months',
20336 cls: 'table-condensed',
20338 Roo.bootstrap.DateField.content
20358 * @class Roo.bootstrap.CheckBox
20359 * @extends Roo.bootstrap.Input
20360 * Bootstrap CheckBox class
20362 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20363 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20364 * @cfg {String} boxLabel The text that appears beside the checkbox
20365 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20366 * @cfg {Boolean} checked initnal the element
20367 * @cfg {Boolean} inline inline the element (default false)
20368 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20369 * @cfg {String} tooltip label tooltip
20372 * Create a new CheckBox
20373 * @param {Object} config The config object
20376 Roo.bootstrap.CheckBox = function(config){
20377 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20382 * Fires when the element is checked or unchecked.
20383 * @param {Roo.bootstrap.CheckBox} this This input
20384 * @param {Boolean} checked The new checked value
20389 * Fires when the element is click.
20390 * @param {Roo.bootstrap.CheckBox} this This input
20397 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20399 inputType: 'checkbox',
20408 getAutoCreate : function()
20410 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20416 cfg.cls = 'form-group ' + this.inputType; //input-group
20419 cfg.cls += ' ' + this.inputType + '-inline';
20425 type : this.inputType,
20426 value : this.inputValue,
20427 cls : 'roo-' + this.inputType, //'form-box',
20428 placeholder : this.placeholder || ''
20432 if(this.inputType != 'radio'){
20436 cls : 'roo-hidden-value',
20437 value : this.checked ? this.inputValue : this.valueOff
20442 if (this.weight) { // Validity check?
20443 cfg.cls += " " + this.inputType + "-" + this.weight;
20446 if (this.disabled) {
20447 input.disabled=true;
20451 input.checked = this.checked;
20456 input.name = this.name;
20458 if(this.inputType != 'radio'){
20459 hidden.name = this.name;
20460 input.name = '_hidden_' + this.name;
20465 input.cls += ' input-' + this.size;
20470 ['xs','sm','md','lg'].map(function(size){
20471 if (settings[size]) {
20472 cfg.cls += ' col-' + size + '-' + settings[size];
20476 var inputblock = input;
20478 if (this.before || this.after) {
20481 cls : 'input-group',
20486 inputblock.cn.push({
20488 cls : 'input-group-addon',
20493 inputblock.cn.push(input);
20495 if(this.inputType != 'radio'){
20496 inputblock.cn.push(hidden);
20500 inputblock.cn.push({
20502 cls : 'input-group-addon',
20509 if (align ==='left' && this.fieldLabel.length) {
20510 // Roo.log("left and has label");
20515 cls : 'control-label',
20516 html : this.fieldLabel
20526 if(this.labelWidth > 12){
20527 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20530 if(this.labelWidth < 13 && this.labelmd == 0){
20531 this.labelmd = this.labelWidth;
20534 if(this.labellg > 0){
20535 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20536 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20539 if(this.labelmd > 0){
20540 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20541 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20544 if(this.labelsm > 0){
20545 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20546 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20549 if(this.labelxs > 0){
20550 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20551 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20554 } else if ( this.fieldLabel.length) {
20555 // Roo.log(" label");
20559 tag: this.boxLabel ? 'span' : 'label',
20561 cls: 'control-label box-input-label',
20562 //cls : 'input-group-addon',
20563 html : this.fieldLabel
20572 // Roo.log(" no label && no align");
20573 cfg.cn = [ inputblock ] ;
20579 var boxLabelCfg = {
20581 //'for': id, // box label is handled by onclick - so no for...
20583 html: this.boxLabel
20587 boxLabelCfg.tooltip = this.tooltip;
20590 cfg.cn.push(boxLabelCfg);
20593 if(this.inputType != 'radio'){
20594 cfg.cn.push(hidden);
20602 * return the real input element.
20604 inputEl: function ()
20606 return this.el.select('input.roo-' + this.inputType,true).first();
20608 hiddenEl: function ()
20610 return this.el.select('input.roo-hidden-value',true).first();
20613 labelEl: function()
20615 return this.el.select('label.control-label',true).first();
20617 /* depricated... */
20621 return this.labelEl();
20624 boxLabelEl: function()
20626 return this.el.select('label.box-label',true).first();
20629 initEvents : function()
20631 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20633 this.inputEl().on('click', this.onClick, this);
20635 if (this.boxLabel) {
20636 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20639 this.startValue = this.getValue();
20642 Roo.bootstrap.CheckBox.register(this);
20646 onClick : function(e)
20648 if(this.fireEvent('click', this, e) !== false){
20649 this.setChecked(!this.checked);
20654 setChecked : function(state,suppressEvent)
20656 this.startValue = this.getValue();
20658 if(this.inputType == 'radio'){
20660 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20661 e.dom.checked = false;
20664 this.inputEl().dom.checked = true;
20666 this.inputEl().dom.value = this.inputValue;
20668 if(suppressEvent !== true){
20669 this.fireEvent('check', this, true);
20677 this.checked = state;
20679 this.inputEl().dom.checked = state;
20682 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20684 if(suppressEvent !== true){
20685 this.fireEvent('check', this, state);
20691 getValue : function()
20693 if(this.inputType == 'radio'){
20694 return this.getGroupValue();
20697 return this.hiddenEl().dom.value;
20701 getGroupValue : function()
20703 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20707 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20710 setValue : function(v,suppressEvent)
20712 if(this.inputType == 'radio'){
20713 this.setGroupValue(v, suppressEvent);
20717 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20722 setGroupValue : function(v, suppressEvent)
20724 this.startValue = this.getValue();
20726 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20727 e.dom.checked = false;
20729 if(e.dom.value == v){
20730 e.dom.checked = true;
20734 if(suppressEvent !== true){
20735 this.fireEvent('check', this, true);
20743 validate : function()
20745 if(this.getVisibilityEl().hasClass('hidden')){
20751 (this.inputType == 'radio' && this.validateRadio()) ||
20752 (this.inputType == 'checkbox' && this.validateCheckbox())
20758 this.markInvalid();
20762 validateRadio : function()
20764 if(this.getVisibilityEl().hasClass('hidden')){
20768 if(this.allowBlank){
20774 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20775 if(!e.dom.checked){
20787 validateCheckbox : function()
20790 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20791 //return (this.getValue() == this.inputValue) ? true : false;
20794 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20802 for(var i in group){
20803 if(group[i].el.isVisible(true)){
20811 for(var i in group){
20816 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20823 * Mark this field as valid
20825 markValid : function()
20829 this.fireEvent('valid', this);
20831 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20834 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20841 if(this.inputType == 'radio'){
20842 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20843 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20844 e.findParent('.form-group', false, true).addClass(_this.validClass);
20851 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20852 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20856 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20862 for(var i in group){
20863 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20864 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20869 * Mark this field as invalid
20870 * @param {String} msg The validation message
20872 markInvalid : function(msg)
20874 if(this.allowBlank){
20880 this.fireEvent('invalid', this, msg);
20882 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20885 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20889 label.markInvalid();
20892 if(this.inputType == 'radio'){
20893 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20894 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20895 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20902 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20903 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20907 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20913 for(var i in group){
20914 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20915 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20920 clearInvalid : function()
20922 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20924 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20926 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20928 if (label && label.iconEl) {
20929 label.iconEl.removeClass(label.validClass);
20930 label.iconEl.removeClass(label.invalidClass);
20934 disable : function()
20936 if(this.inputType != 'radio'){
20937 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20944 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20945 _this.getActionEl().addClass(this.disabledClass);
20946 e.dom.disabled = true;
20950 this.disabled = true;
20951 this.fireEvent("disable", this);
20955 enable : function()
20957 if(this.inputType != 'radio'){
20958 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20965 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20966 _this.getActionEl().removeClass(this.disabledClass);
20967 e.dom.disabled = false;
20971 this.disabled = false;
20972 this.fireEvent("enable", this);
20976 setBoxLabel : function(v)
20981 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20987 Roo.apply(Roo.bootstrap.CheckBox, {
20992 * register a CheckBox Group
20993 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20995 register : function(checkbox)
20997 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20998 this.groups[checkbox.groupId] = {};
21001 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21005 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21009 * fetch a CheckBox Group based on the group ID
21010 * @param {string} the group ID
21011 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21013 get: function(groupId) {
21014 if (typeof(this.groups[groupId]) == 'undefined') {
21018 return this.groups[groupId] ;
21031 * @class Roo.bootstrap.Radio
21032 * @extends Roo.bootstrap.Component
21033 * Bootstrap Radio class
21034 * @cfg {String} boxLabel - the label associated
21035 * @cfg {String} value - the value of radio
21038 * Create a new Radio
21039 * @param {Object} config The config object
21041 Roo.bootstrap.Radio = function(config){
21042 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21046 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21052 getAutoCreate : function()
21056 cls : 'form-group radio',
21061 html : this.boxLabel
21069 initEvents : function()
21071 this.parent().register(this);
21073 this.el.on('click', this.onClick, this);
21077 onClick : function(e)
21079 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21080 this.setChecked(true);
21084 setChecked : function(state, suppressEvent)
21086 this.parent().setValue(this.value, suppressEvent);
21090 setBoxLabel : function(v)
21095 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21110 * @class Roo.bootstrap.SecurePass
21111 * @extends Roo.bootstrap.Input
21112 * Bootstrap SecurePass class
21116 * Create a new SecurePass
21117 * @param {Object} config The config object
21120 Roo.bootstrap.SecurePass = function (config) {
21121 // these go here, so the translation tool can replace them..
21123 PwdEmpty: "Please type a password, and then retype it to confirm.",
21124 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21125 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21126 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21127 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21128 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21129 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21130 TooWeak: "Your password is Too Weak."
21132 this.meterLabel = "Password strength:";
21133 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21134 this.meterClass = [
21135 "roo-password-meter-tooweak",
21136 "roo-password-meter-weak",
21137 "roo-password-meter-medium",
21138 "roo-password-meter-strong",
21139 "roo-password-meter-grey"
21144 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21147 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21149 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21151 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21152 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21153 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21154 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21155 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21156 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21157 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21167 * @cfg {String/Object} Label for the strength meter (defaults to
21168 * 'Password strength:')
21173 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21174 * ['Weak', 'Medium', 'Strong'])
21177 pwdStrengths: false,
21190 initEvents: function ()
21192 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21194 if (this.el.is('input[type=password]') && Roo.isSafari) {
21195 this.el.on('keydown', this.SafariOnKeyDown, this);
21198 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21201 onRender: function (ct, position)
21203 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21204 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21205 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21207 this.trigger.createChild({
21212 cls: 'roo-password-meter-grey col-xs-12',
21215 //width: this.meterWidth + 'px'
21219 cls: 'roo-password-meter-text'
21225 if (this.hideTrigger) {
21226 this.trigger.setDisplayed(false);
21228 this.setSize(this.width || '', this.height || '');
21231 onDestroy: function ()
21233 if (this.trigger) {
21234 this.trigger.removeAllListeners();
21235 this.trigger.remove();
21238 this.wrap.remove();
21240 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21243 checkStrength: function ()
21245 var pwd = this.inputEl().getValue();
21246 if (pwd == this._lastPwd) {
21251 if (this.ClientSideStrongPassword(pwd)) {
21253 } else if (this.ClientSideMediumPassword(pwd)) {
21255 } else if (this.ClientSideWeakPassword(pwd)) {
21261 Roo.log('strength1: ' + strength);
21263 //var pm = this.trigger.child('div/div/div').dom;
21264 var pm = this.trigger.child('div/div');
21265 pm.removeClass(this.meterClass);
21266 pm.addClass(this.meterClass[strength]);
21269 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21271 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21273 this._lastPwd = pwd;
21277 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21279 this._lastPwd = '';
21281 var pm = this.trigger.child('div/div');
21282 pm.removeClass(this.meterClass);
21283 pm.addClass('roo-password-meter-grey');
21286 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21289 this.inputEl().dom.type='password';
21292 validateValue: function (value)
21295 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21298 if (value.length == 0) {
21299 if (this.allowBlank) {
21300 this.clearInvalid();
21304 this.markInvalid(this.errors.PwdEmpty);
21305 this.errorMsg = this.errors.PwdEmpty;
21313 if ('[\x21-\x7e]*'.match(value)) {
21314 this.markInvalid(this.errors.PwdBadChar);
21315 this.errorMsg = this.errors.PwdBadChar;
21318 if (value.length < 6) {
21319 this.markInvalid(this.errors.PwdShort);
21320 this.errorMsg = this.errors.PwdShort;
21323 if (value.length > 16) {
21324 this.markInvalid(this.errors.PwdLong);
21325 this.errorMsg = this.errors.PwdLong;
21329 if (this.ClientSideStrongPassword(value)) {
21331 } else if (this.ClientSideMediumPassword(value)) {
21333 } else if (this.ClientSideWeakPassword(value)) {
21340 if (strength < 2) {
21341 //this.markInvalid(this.errors.TooWeak);
21342 this.errorMsg = this.errors.TooWeak;
21347 console.log('strength2: ' + strength);
21349 //var pm = this.trigger.child('div/div/div').dom;
21351 var pm = this.trigger.child('div/div');
21352 pm.removeClass(this.meterClass);
21353 pm.addClass(this.meterClass[strength]);
21355 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21357 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21359 this.errorMsg = '';
21363 CharacterSetChecks: function (type)
21366 this.fResult = false;
21369 isctype: function (character, type)
21372 case this.kCapitalLetter:
21373 if (character >= 'A' && character <= 'Z') {
21378 case this.kSmallLetter:
21379 if (character >= 'a' && character <= 'z') {
21385 if (character >= '0' && character <= '9') {
21390 case this.kPunctuation:
21391 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21402 IsLongEnough: function (pwd, size)
21404 return !(pwd == null || isNaN(size) || pwd.length < size);
21407 SpansEnoughCharacterSets: function (word, nb)
21409 if (!this.IsLongEnough(word, nb))
21414 var characterSetChecks = new Array(
21415 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21416 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21419 for (var index = 0; index < word.length; ++index) {
21420 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21421 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21422 characterSetChecks[nCharSet].fResult = true;
21429 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21430 if (characterSetChecks[nCharSet].fResult) {
21435 if (nCharSets < nb) {
21441 ClientSideStrongPassword: function (pwd)
21443 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21446 ClientSideMediumPassword: function (pwd)
21448 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21451 ClientSideWeakPassword: function (pwd)
21453 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21456 })//<script type="text/javascript">
21459 * Based Ext JS Library 1.1.1
21460 * Copyright(c) 2006-2007, Ext JS, LLC.
21466 * @class Roo.HtmlEditorCore
21467 * @extends Roo.Component
21468 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21470 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21473 Roo.HtmlEditorCore = function(config){
21476 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21481 * @event initialize
21482 * Fires when the editor is fully initialized (including the iframe)
21483 * @param {Roo.HtmlEditorCore} this
21488 * Fires when the editor is first receives the focus. Any insertion must wait
21489 * until after this event.
21490 * @param {Roo.HtmlEditorCore} this
21494 * @event beforesync
21495 * Fires before the textarea is updated with content from the editor iframe. Return false
21496 * to cancel the sync.
21497 * @param {Roo.HtmlEditorCore} this
21498 * @param {String} html
21502 * @event beforepush
21503 * Fires before the iframe editor is updated with content from the textarea. Return false
21504 * to cancel the push.
21505 * @param {Roo.HtmlEditorCore} this
21506 * @param {String} html
21511 * Fires when the textarea is updated with content from the editor iframe.
21512 * @param {Roo.HtmlEditorCore} this
21513 * @param {String} html
21518 * Fires when the iframe editor is updated with content from the textarea.
21519 * @param {Roo.HtmlEditorCore} this
21520 * @param {String} html
21525 * @event editorevent
21526 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21527 * @param {Roo.HtmlEditorCore} this
21533 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21535 // defaults : white / black...
21536 this.applyBlacklists();
21543 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21547 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21553 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21558 * @cfg {Number} height (in pixels)
21562 * @cfg {Number} width (in pixels)
21567 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21570 stylesheets: false,
21575 // private properties
21576 validationEvent : false,
21578 initialized : false,
21580 sourceEditMode : false,
21581 onFocus : Roo.emptyFn,
21583 hideMode:'offsets',
21587 // blacklist + whitelisted elements..
21594 * Protected method that will not generally be called directly. It
21595 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21596 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21598 getDocMarkup : function(){
21602 // inherit styels from page...??
21603 if (this.stylesheets === false) {
21605 Roo.get(document.head).select('style').each(function(node) {
21606 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21609 Roo.get(document.head).select('link').each(function(node) {
21610 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21613 } else if (!this.stylesheets.length) {
21615 st = '<style type="text/css">' +
21616 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21619 st = '<style type="text/css">' +
21624 st += '<style type="text/css">' +
21625 'IMG { cursor: pointer } ' +
21628 var cls = 'roo-htmleditor-body';
21630 if(this.bodyCls.length){
21631 cls += ' ' + this.bodyCls;
21634 return '<html><head>' + st +
21635 //<style type="text/css">' +
21636 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21638 ' </head><body class="' + cls + '"></body></html>';
21642 onRender : function(ct, position)
21645 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21646 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21649 this.el.dom.style.border = '0 none';
21650 this.el.dom.setAttribute('tabIndex', -1);
21651 this.el.addClass('x-hidden hide');
21655 if(Roo.isIE){ // fix IE 1px bogus margin
21656 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21660 this.frameId = Roo.id();
21664 var iframe = this.owner.wrap.createChild({
21666 cls: 'form-control', // bootstrap..
21668 name: this.frameId,
21669 frameBorder : 'no',
21670 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21675 this.iframe = iframe.dom;
21677 this.assignDocWin();
21679 this.doc.designMode = 'on';
21682 this.doc.write(this.getDocMarkup());
21686 var task = { // must defer to wait for browser to be ready
21688 //console.log("run task?" + this.doc.readyState);
21689 this.assignDocWin();
21690 if(this.doc.body || this.doc.readyState == 'complete'){
21692 this.doc.designMode="on";
21696 Roo.TaskMgr.stop(task);
21697 this.initEditor.defer(10, this);
21704 Roo.TaskMgr.start(task);
21709 onResize : function(w, h)
21711 Roo.log('resize: ' +w + ',' + h );
21712 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21716 if(typeof w == 'number'){
21718 this.iframe.style.width = w + 'px';
21720 if(typeof h == 'number'){
21722 this.iframe.style.height = h + 'px';
21724 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21731 * Toggles the editor between standard and source edit mode.
21732 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21734 toggleSourceEdit : function(sourceEditMode){
21736 this.sourceEditMode = sourceEditMode === true;
21738 if(this.sourceEditMode){
21740 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21743 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21744 //this.iframe.className = '';
21747 //this.setSize(this.owner.wrap.getSize());
21748 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21755 * Protected method that will not generally be called directly. If you need/want
21756 * custom HTML cleanup, this is the method you should override.
21757 * @param {String} html The HTML to be cleaned
21758 * return {String} The cleaned HTML
21760 cleanHtml : function(html){
21761 html = String(html);
21762 if(html.length > 5){
21763 if(Roo.isSafari){ // strip safari nonsense
21764 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21767 if(html == ' '){
21774 * HTML Editor -> Textarea
21775 * Protected method that will not generally be called directly. Syncs the contents
21776 * of the editor iframe with the textarea.
21778 syncValue : function(){
21779 if(this.initialized){
21780 var bd = (this.doc.body || this.doc.documentElement);
21781 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21782 var html = bd.innerHTML;
21784 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21785 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21787 html = '<div style="'+m[0]+'">' + html + '</div>';
21790 html = this.cleanHtml(html);
21791 // fix up the special chars.. normaly like back quotes in word...
21792 // however we do not want to do this with chinese..
21793 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21794 var cc = b.charCodeAt();
21796 (cc >= 0x4E00 && cc < 0xA000 ) ||
21797 (cc >= 0x3400 && cc < 0x4E00 ) ||
21798 (cc >= 0xf900 && cc < 0xfb00 )
21804 if(this.owner.fireEvent('beforesync', this, html) !== false){
21805 this.el.dom.value = html;
21806 this.owner.fireEvent('sync', this, html);
21812 * Protected method that will not generally be called directly. Pushes the value of the textarea
21813 * into the iframe editor.
21815 pushValue : function(){
21816 if(this.initialized){
21817 var v = this.el.dom.value.trim();
21819 // if(v.length < 1){
21823 if(this.owner.fireEvent('beforepush', this, v) !== false){
21824 var d = (this.doc.body || this.doc.documentElement);
21826 this.cleanUpPaste();
21827 this.el.dom.value = d.innerHTML;
21828 this.owner.fireEvent('push', this, v);
21834 deferFocus : function(){
21835 this.focus.defer(10, this);
21839 focus : function(){
21840 if(this.win && !this.sourceEditMode){
21847 assignDocWin: function()
21849 var iframe = this.iframe;
21852 this.doc = iframe.contentWindow.document;
21853 this.win = iframe.contentWindow;
21855 // if (!Roo.get(this.frameId)) {
21858 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21859 // this.win = Roo.get(this.frameId).dom.contentWindow;
21861 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21865 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21866 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21871 initEditor : function(){
21872 //console.log("INIT EDITOR");
21873 this.assignDocWin();
21877 this.doc.designMode="on";
21879 this.doc.write(this.getDocMarkup());
21882 var dbody = (this.doc.body || this.doc.documentElement);
21883 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21884 // this copies styles from the containing element into thsi one..
21885 // not sure why we need all of this..
21886 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21888 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21889 //ss['background-attachment'] = 'fixed'; // w3c
21890 dbody.bgProperties = 'fixed'; // ie
21891 //Roo.DomHelper.applyStyles(dbody, ss);
21892 Roo.EventManager.on(this.doc, {
21893 //'mousedown': this.onEditorEvent,
21894 'mouseup': this.onEditorEvent,
21895 'dblclick': this.onEditorEvent,
21896 'click': this.onEditorEvent,
21897 'keyup': this.onEditorEvent,
21902 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21904 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21905 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21907 this.initialized = true;
21909 this.owner.fireEvent('initialize', this);
21914 onDestroy : function(){
21920 //for (var i =0; i < this.toolbars.length;i++) {
21921 // // fixme - ask toolbars for heights?
21922 // this.toolbars[i].onDestroy();
21925 //this.wrap.dom.innerHTML = '';
21926 //this.wrap.remove();
21931 onFirstFocus : function(){
21933 this.assignDocWin();
21936 this.activated = true;
21939 if(Roo.isGecko){ // prevent silly gecko errors
21941 var s = this.win.getSelection();
21942 if(!s.focusNode || s.focusNode.nodeType != 3){
21943 var r = s.getRangeAt(0);
21944 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21949 this.execCmd('useCSS', true);
21950 this.execCmd('styleWithCSS', false);
21953 this.owner.fireEvent('activate', this);
21957 adjustFont: function(btn){
21958 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21959 //if(Roo.isSafari){ // safari
21962 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21963 if(Roo.isSafari){ // safari
21964 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21965 v = (v < 10) ? 10 : v;
21966 v = (v > 48) ? 48 : v;
21967 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21972 v = Math.max(1, v+adjust);
21974 this.execCmd('FontSize', v );
21977 onEditorEvent : function(e)
21979 this.owner.fireEvent('editorevent', this, e);
21980 // this.updateToolbar();
21981 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21984 insertTag : function(tg)
21986 // could be a bit smarter... -> wrap the current selected tRoo..
21987 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21989 range = this.createRange(this.getSelection());
21990 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21991 wrappingNode.appendChild(range.extractContents());
21992 range.insertNode(wrappingNode);
21999 this.execCmd("formatblock", tg);
22003 insertText : function(txt)
22007 var range = this.createRange();
22008 range.deleteContents();
22009 //alert(Sender.getAttribute('label'));
22011 range.insertNode(this.doc.createTextNode(txt));
22017 * Executes a Midas editor command on the editor document and performs necessary focus and
22018 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22019 * @param {String} cmd The Midas command
22020 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22022 relayCmd : function(cmd, value){
22024 this.execCmd(cmd, value);
22025 this.owner.fireEvent('editorevent', this);
22026 //this.updateToolbar();
22027 this.owner.deferFocus();
22031 * Executes a Midas editor command directly on the editor document.
22032 * For visual commands, you should use {@link #relayCmd} instead.
22033 * <b>This should only be called after the editor is initialized.</b>
22034 * @param {String} cmd The Midas command
22035 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22037 execCmd : function(cmd, value){
22038 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22045 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22047 * @param {String} text | dom node..
22049 insertAtCursor : function(text)
22052 if(!this.activated){
22058 var r = this.doc.selection.createRange();
22069 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22073 // from jquery ui (MIT licenced)
22075 var win = this.win;
22077 if (win.getSelection && win.getSelection().getRangeAt) {
22078 range = win.getSelection().getRangeAt(0);
22079 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22080 range.insertNode(node);
22081 } else if (win.document.selection && win.document.selection.createRange) {
22082 // no firefox support
22083 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22084 win.document.selection.createRange().pasteHTML(txt);
22086 // no firefox support
22087 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22088 this.execCmd('InsertHTML', txt);
22097 mozKeyPress : function(e){
22099 var c = e.getCharCode(), cmd;
22102 c = String.fromCharCode(c).toLowerCase();
22116 this.cleanUpPaste.defer(100, this);
22124 e.preventDefault();
22132 fixKeys : function(){ // load time branching for fastest keydown performance
22134 return function(e){
22135 var k = e.getKey(), r;
22138 r = this.doc.selection.createRange();
22141 r.pasteHTML('    ');
22148 r = this.doc.selection.createRange();
22150 var target = r.parentElement();
22151 if(!target || target.tagName.toLowerCase() != 'li'){
22153 r.pasteHTML('<br />');
22159 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22160 this.cleanUpPaste.defer(100, this);
22166 }else if(Roo.isOpera){
22167 return function(e){
22168 var k = e.getKey();
22172 this.execCmd('InsertHTML','    ');
22175 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22176 this.cleanUpPaste.defer(100, this);
22181 }else if(Roo.isSafari){
22182 return function(e){
22183 var k = e.getKey();
22187 this.execCmd('InsertText','\t');
22191 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22192 this.cleanUpPaste.defer(100, this);
22200 getAllAncestors: function()
22202 var p = this.getSelectedNode();
22205 a.push(p); // push blank onto stack..
22206 p = this.getParentElement();
22210 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22214 a.push(this.doc.body);
22218 lastSelNode : false,
22221 getSelection : function()
22223 this.assignDocWin();
22224 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22227 getSelectedNode: function()
22229 // this may only work on Gecko!!!
22231 // should we cache this!!!!
22236 var range = this.createRange(this.getSelection()).cloneRange();
22239 var parent = range.parentElement();
22241 var testRange = range.duplicate();
22242 testRange.moveToElementText(parent);
22243 if (testRange.inRange(range)) {
22246 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22249 parent = parent.parentElement;
22254 // is ancestor a text element.
22255 var ac = range.commonAncestorContainer;
22256 if (ac.nodeType == 3) {
22257 ac = ac.parentNode;
22260 var ar = ac.childNodes;
22263 var other_nodes = [];
22264 var has_other_nodes = false;
22265 for (var i=0;i<ar.length;i++) {
22266 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22269 // fullly contained node.
22271 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22276 // probably selected..
22277 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22278 other_nodes.push(ar[i]);
22282 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22287 has_other_nodes = true;
22289 if (!nodes.length && other_nodes.length) {
22290 nodes= other_nodes;
22292 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22298 createRange: function(sel)
22300 // this has strange effects when using with
22301 // top toolbar - not sure if it's a great idea.
22302 //this.editor.contentWindow.focus();
22303 if (typeof sel != "undefined") {
22305 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22307 return this.doc.createRange();
22310 return this.doc.createRange();
22313 getParentElement: function()
22316 this.assignDocWin();
22317 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22319 var range = this.createRange(sel);
22322 var p = range.commonAncestorContainer;
22323 while (p.nodeType == 3) { // text node
22334 * Range intersection.. the hard stuff...
22338 * [ -- selected range --- ]
22342 * if end is before start or hits it. fail.
22343 * if start is after end or hits it fail.
22345 * if either hits (but other is outside. - then it's not
22351 // @see http://www.thismuchiknow.co.uk/?p=64.
22352 rangeIntersectsNode : function(range, node)
22354 var nodeRange = node.ownerDocument.createRange();
22356 nodeRange.selectNode(node);
22358 nodeRange.selectNodeContents(node);
22361 var rangeStartRange = range.cloneRange();
22362 rangeStartRange.collapse(true);
22364 var rangeEndRange = range.cloneRange();
22365 rangeEndRange.collapse(false);
22367 var nodeStartRange = nodeRange.cloneRange();
22368 nodeStartRange.collapse(true);
22370 var nodeEndRange = nodeRange.cloneRange();
22371 nodeEndRange.collapse(false);
22373 return rangeStartRange.compareBoundaryPoints(
22374 Range.START_TO_START, nodeEndRange) == -1 &&
22375 rangeEndRange.compareBoundaryPoints(
22376 Range.START_TO_START, nodeStartRange) == 1;
22380 rangeCompareNode : function(range, node)
22382 var nodeRange = node.ownerDocument.createRange();
22384 nodeRange.selectNode(node);
22386 nodeRange.selectNodeContents(node);
22390 range.collapse(true);
22392 nodeRange.collapse(true);
22394 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22395 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22397 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22399 var nodeIsBefore = ss == 1;
22400 var nodeIsAfter = ee == -1;
22402 if (nodeIsBefore && nodeIsAfter) {
22405 if (!nodeIsBefore && nodeIsAfter) {
22406 return 1; //right trailed.
22409 if (nodeIsBefore && !nodeIsAfter) {
22410 return 2; // left trailed.
22416 // private? - in a new class?
22417 cleanUpPaste : function()
22419 // cleans up the whole document..
22420 Roo.log('cleanuppaste');
22422 this.cleanUpChildren(this.doc.body);
22423 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22424 if (clean != this.doc.body.innerHTML) {
22425 this.doc.body.innerHTML = clean;
22430 cleanWordChars : function(input) {// change the chars to hex code
22431 var he = Roo.HtmlEditorCore;
22433 var output = input;
22434 Roo.each(he.swapCodes, function(sw) {
22435 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22437 output = output.replace(swapper, sw[1]);
22444 cleanUpChildren : function (n)
22446 if (!n.childNodes.length) {
22449 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22450 this.cleanUpChild(n.childNodes[i]);
22457 cleanUpChild : function (node)
22460 //console.log(node);
22461 if (node.nodeName == "#text") {
22462 // clean up silly Windows -- stuff?
22465 if (node.nodeName == "#comment") {
22466 node.parentNode.removeChild(node);
22467 // clean up silly Windows -- stuff?
22470 var lcname = node.tagName.toLowerCase();
22471 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22472 // whitelist of tags..
22474 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22476 node.parentNode.removeChild(node);
22481 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22483 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22484 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22486 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22487 // remove_keep_children = true;
22490 if (remove_keep_children) {
22491 this.cleanUpChildren(node);
22492 // inserts everything just before this node...
22493 while (node.childNodes.length) {
22494 var cn = node.childNodes[0];
22495 node.removeChild(cn);
22496 node.parentNode.insertBefore(cn, node);
22498 node.parentNode.removeChild(node);
22502 if (!node.attributes || !node.attributes.length) {
22503 this.cleanUpChildren(node);
22507 function cleanAttr(n,v)
22510 if (v.match(/^\./) || v.match(/^\//)) {
22513 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22516 if (v.match(/^#/)) {
22519 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22520 node.removeAttribute(n);
22524 var cwhite = this.cwhite;
22525 var cblack = this.cblack;
22527 function cleanStyle(n,v)
22529 if (v.match(/expression/)) { //XSS?? should we even bother..
22530 node.removeAttribute(n);
22534 var parts = v.split(/;/);
22537 Roo.each(parts, function(p) {
22538 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22542 var l = p.split(':').shift().replace(/\s+/g,'');
22543 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22545 if ( cwhite.length && cblack.indexOf(l) > -1) {
22546 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22547 //node.removeAttribute(n);
22551 // only allow 'c whitelisted system attributes'
22552 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22553 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22554 //node.removeAttribute(n);
22564 if (clean.length) {
22565 node.setAttribute(n, clean.join(';'));
22567 node.removeAttribute(n);
22573 for (var i = node.attributes.length-1; i > -1 ; i--) {
22574 var a = node.attributes[i];
22577 if (a.name.toLowerCase().substr(0,2)=='on') {
22578 node.removeAttribute(a.name);
22581 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22582 node.removeAttribute(a.name);
22585 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22586 cleanAttr(a.name,a.value); // fixme..
22589 if (a.name == 'style') {
22590 cleanStyle(a.name,a.value);
22593 /// clean up MS crap..
22594 // tecnically this should be a list of valid class'es..
22597 if (a.name == 'class') {
22598 if (a.value.match(/^Mso/)) {
22599 node.className = '';
22602 if (a.value.match(/^body$/)) {
22603 node.className = '';
22614 this.cleanUpChildren(node);
22620 * Clean up MS wordisms...
22622 cleanWord : function(node)
22627 this.cleanWord(this.doc.body);
22630 if (node.nodeName == "#text") {
22631 // clean up silly Windows -- stuff?
22634 if (node.nodeName == "#comment") {
22635 node.parentNode.removeChild(node);
22636 // clean up silly Windows -- stuff?
22640 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22641 node.parentNode.removeChild(node);
22645 // remove - but keep children..
22646 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22647 while (node.childNodes.length) {
22648 var cn = node.childNodes[0];
22649 node.removeChild(cn);
22650 node.parentNode.insertBefore(cn, node);
22652 node.parentNode.removeChild(node);
22653 this.iterateChildren(node, this.cleanWord);
22657 if (node.className.length) {
22659 var cn = node.className.split(/\W+/);
22661 Roo.each(cn, function(cls) {
22662 if (cls.match(/Mso[a-zA-Z]+/)) {
22667 node.className = cna.length ? cna.join(' ') : '';
22669 node.removeAttribute("class");
22673 if (node.hasAttribute("lang")) {
22674 node.removeAttribute("lang");
22677 if (node.hasAttribute("style")) {
22679 var styles = node.getAttribute("style").split(";");
22681 Roo.each(styles, function(s) {
22682 if (!s.match(/:/)) {
22685 var kv = s.split(":");
22686 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22689 // what ever is left... we allow.
22692 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22693 if (!nstyle.length) {
22694 node.removeAttribute('style');
22697 this.iterateChildren(node, this.cleanWord);
22703 * iterateChildren of a Node, calling fn each time, using this as the scole..
22704 * @param {DomNode} node node to iterate children of.
22705 * @param {Function} fn method of this class to call on each item.
22707 iterateChildren : function(node, fn)
22709 if (!node.childNodes.length) {
22712 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22713 fn.call(this, node.childNodes[i])
22719 * cleanTableWidths.
22721 * Quite often pasting from word etc.. results in tables with column and widths.
22722 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22725 cleanTableWidths : function(node)
22730 this.cleanTableWidths(this.doc.body);
22735 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22738 Roo.log(node.tagName);
22739 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22740 this.iterateChildren(node, this.cleanTableWidths);
22743 if (node.hasAttribute('width')) {
22744 node.removeAttribute('width');
22748 if (node.hasAttribute("style")) {
22751 var styles = node.getAttribute("style").split(";");
22753 Roo.each(styles, function(s) {
22754 if (!s.match(/:/)) {
22757 var kv = s.split(":");
22758 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22761 // what ever is left... we allow.
22764 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22765 if (!nstyle.length) {
22766 node.removeAttribute('style');
22770 this.iterateChildren(node, this.cleanTableWidths);
22778 domToHTML : function(currentElement, depth, nopadtext) {
22780 depth = depth || 0;
22781 nopadtext = nopadtext || false;
22783 if (!currentElement) {
22784 return this.domToHTML(this.doc.body);
22787 //Roo.log(currentElement);
22789 var allText = false;
22790 var nodeName = currentElement.nodeName;
22791 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22793 if (nodeName == '#text') {
22795 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22800 if (nodeName != 'BODY') {
22803 // Prints the node tagName, such as <A>, <IMG>, etc
22806 for(i = 0; i < currentElement.attributes.length;i++) {
22808 var aname = currentElement.attributes.item(i).name;
22809 if (!currentElement.attributes.item(i).value.length) {
22812 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22815 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22824 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22827 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22832 // Traverse the tree
22834 var currentElementChild = currentElement.childNodes.item(i);
22835 var allText = true;
22836 var innerHTML = '';
22838 while (currentElementChild) {
22839 // Formatting code (indent the tree so it looks nice on the screen)
22840 var nopad = nopadtext;
22841 if (lastnode == 'SPAN') {
22845 if (currentElementChild.nodeName == '#text') {
22846 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22847 toadd = nopadtext ? toadd : toadd.trim();
22848 if (!nopad && toadd.length > 80) {
22849 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22851 innerHTML += toadd;
22854 currentElementChild = currentElement.childNodes.item(i);
22860 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22862 // Recursively traverse the tree structure of the child node
22863 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22864 lastnode = currentElementChild.nodeName;
22866 currentElementChild=currentElement.childNodes.item(i);
22872 // The remaining code is mostly for formatting the tree
22873 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22878 ret+= "</"+tagName+">";
22884 applyBlacklists : function()
22886 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22887 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22891 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22892 if (b.indexOf(tag) > -1) {
22895 this.white.push(tag);
22899 Roo.each(w, function(tag) {
22900 if (b.indexOf(tag) > -1) {
22903 if (this.white.indexOf(tag) > -1) {
22906 this.white.push(tag);
22911 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22912 if (w.indexOf(tag) > -1) {
22915 this.black.push(tag);
22919 Roo.each(b, function(tag) {
22920 if (w.indexOf(tag) > -1) {
22923 if (this.black.indexOf(tag) > -1) {
22926 this.black.push(tag);
22931 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22932 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22936 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22937 if (b.indexOf(tag) > -1) {
22940 this.cwhite.push(tag);
22944 Roo.each(w, function(tag) {
22945 if (b.indexOf(tag) > -1) {
22948 if (this.cwhite.indexOf(tag) > -1) {
22951 this.cwhite.push(tag);
22956 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22957 if (w.indexOf(tag) > -1) {
22960 this.cblack.push(tag);
22964 Roo.each(b, function(tag) {
22965 if (w.indexOf(tag) > -1) {
22968 if (this.cblack.indexOf(tag) > -1) {
22971 this.cblack.push(tag);
22976 setStylesheets : function(stylesheets)
22978 if(typeof(stylesheets) == 'string'){
22979 Roo.get(this.iframe.contentDocument.head).createChild({
22981 rel : 'stylesheet',
22990 Roo.each(stylesheets, function(s) {
22995 Roo.get(_this.iframe.contentDocument.head).createChild({
22997 rel : 'stylesheet',
23006 removeStylesheets : function()
23010 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23015 setStyle : function(style)
23017 Roo.get(this.iframe.contentDocument.head).createChild({
23026 // hide stuff that is not compatible
23040 * @event specialkey
23044 * @cfg {String} fieldClass @hide
23047 * @cfg {String} focusClass @hide
23050 * @cfg {String} autoCreate @hide
23053 * @cfg {String} inputType @hide
23056 * @cfg {String} invalidClass @hide
23059 * @cfg {String} invalidText @hide
23062 * @cfg {String} msgFx @hide
23065 * @cfg {String} validateOnBlur @hide
23069 Roo.HtmlEditorCore.white = [
23070 'area', 'br', 'img', 'input', 'hr', 'wbr',
23072 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23073 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23074 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23075 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23076 'table', 'ul', 'xmp',
23078 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23081 'dir', 'menu', 'ol', 'ul', 'dl',
23087 Roo.HtmlEditorCore.black = [
23088 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23090 'base', 'basefont', 'bgsound', 'blink', 'body',
23091 'frame', 'frameset', 'head', 'html', 'ilayer',
23092 'iframe', 'layer', 'link', 'meta', 'object',
23093 'script', 'style' ,'title', 'xml' // clean later..
23095 Roo.HtmlEditorCore.clean = [
23096 'script', 'style', 'title', 'xml'
23098 Roo.HtmlEditorCore.remove = [
23103 Roo.HtmlEditorCore.ablack = [
23107 Roo.HtmlEditorCore.aclean = [
23108 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23112 Roo.HtmlEditorCore.pwhite= [
23113 'http', 'https', 'mailto'
23116 // white listed style attributes.
23117 Roo.HtmlEditorCore.cwhite= [
23118 // 'text-align', /// default is to allow most things..
23124 // black listed style attributes.
23125 Roo.HtmlEditorCore.cblack= [
23126 // 'font-size' -- this can be set by the project
23130 Roo.HtmlEditorCore.swapCodes =[
23149 * @class Roo.bootstrap.HtmlEditor
23150 * @extends Roo.bootstrap.TextArea
23151 * Bootstrap HtmlEditor class
23154 * Create a new HtmlEditor
23155 * @param {Object} config The config object
23158 Roo.bootstrap.HtmlEditor = function(config){
23159 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23160 if (!this.toolbars) {
23161 this.toolbars = [];
23164 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23167 * @event initialize
23168 * Fires when the editor is fully initialized (including the iframe)
23169 * @param {HtmlEditor} this
23174 * Fires when the editor is first receives the focus. Any insertion must wait
23175 * until after this event.
23176 * @param {HtmlEditor} this
23180 * @event beforesync
23181 * Fires before the textarea is updated with content from the editor iframe. Return false
23182 * to cancel the sync.
23183 * @param {HtmlEditor} this
23184 * @param {String} html
23188 * @event beforepush
23189 * Fires before the iframe editor is updated with content from the textarea. Return false
23190 * to cancel the push.
23191 * @param {HtmlEditor} this
23192 * @param {String} html
23197 * Fires when the textarea is updated with content from the editor iframe.
23198 * @param {HtmlEditor} this
23199 * @param {String} html
23204 * Fires when the iframe editor is updated with content from the textarea.
23205 * @param {HtmlEditor} this
23206 * @param {String} html
23210 * @event editmodechange
23211 * Fires when the editor switches edit modes
23212 * @param {HtmlEditor} this
23213 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23215 editmodechange: true,
23217 * @event editorevent
23218 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23219 * @param {HtmlEditor} this
23223 * @event firstfocus
23224 * Fires when on first focus - needed by toolbars..
23225 * @param {HtmlEditor} this
23230 * Auto save the htmlEditor value as a file into Events
23231 * @param {HtmlEditor} this
23235 * @event savedpreview
23236 * preview the saved version of htmlEditor
23237 * @param {HtmlEditor} this
23244 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23248 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23253 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23258 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23263 * @cfg {Number} height (in pixels)
23267 * @cfg {Number} width (in pixels)
23272 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23275 stylesheets: false,
23280 // private properties
23281 validationEvent : false,
23283 initialized : false,
23286 onFocus : Roo.emptyFn,
23288 hideMode:'offsets',
23290 tbContainer : false,
23294 toolbarContainer :function() {
23295 return this.wrap.select('.x-html-editor-tb',true).first();
23299 * Protected method that will not generally be called directly. It
23300 * is called when the editor creates its toolbar. Override this method if you need to
23301 * add custom toolbar buttons.
23302 * @param {HtmlEditor} editor
23304 createToolbar : function(){
23305 Roo.log('renewing');
23306 Roo.log("create toolbars");
23308 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23309 this.toolbars[0].render(this.toolbarContainer());
23313 // if (!editor.toolbars || !editor.toolbars.length) {
23314 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23317 // for (var i =0 ; i < editor.toolbars.length;i++) {
23318 // editor.toolbars[i] = Roo.factory(
23319 // typeof(editor.toolbars[i]) == 'string' ?
23320 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23321 // Roo.bootstrap.HtmlEditor);
23322 // editor.toolbars[i].init(editor);
23328 onRender : function(ct, position)
23330 // Roo.log("Call onRender: " + this.xtype);
23332 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23334 this.wrap = this.inputEl().wrap({
23335 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23338 this.editorcore.onRender(ct, position);
23340 if (this.resizable) {
23341 this.resizeEl = new Roo.Resizable(this.wrap, {
23345 minHeight : this.height,
23346 height: this.height,
23347 handles : this.resizable,
23350 resize : function(r, w, h) {
23351 _t.onResize(w,h); // -something
23357 this.createToolbar(this);
23360 if(!this.width && this.resizable){
23361 this.setSize(this.wrap.getSize());
23363 if (this.resizeEl) {
23364 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23365 // should trigger onReize..
23371 onResize : function(w, h)
23373 Roo.log('resize: ' +w + ',' + h );
23374 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23378 if(this.inputEl() ){
23379 if(typeof w == 'number'){
23380 var aw = w - this.wrap.getFrameWidth('lr');
23381 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23384 if(typeof h == 'number'){
23385 var tbh = -11; // fixme it needs to tool bar size!
23386 for (var i =0; i < this.toolbars.length;i++) {
23387 // fixme - ask toolbars for heights?
23388 tbh += this.toolbars[i].el.getHeight();
23389 //if (this.toolbars[i].footer) {
23390 // tbh += this.toolbars[i].footer.el.getHeight();
23398 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23399 ah -= 5; // knock a few pixes off for look..
23400 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23404 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23405 this.editorcore.onResize(ew,eh);
23410 * Toggles the editor between standard and source edit mode.
23411 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23413 toggleSourceEdit : function(sourceEditMode)
23415 this.editorcore.toggleSourceEdit(sourceEditMode);
23417 if(this.editorcore.sourceEditMode){
23418 Roo.log('editor - showing textarea');
23421 // Roo.log(this.syncValue());
23423 this.inputEl().removeClass(['hide', 'x-hidden']);
23424 this.inputEl().dom.removeAttribute('tabIndex');
23425 this.inputEl().focus();
23427 Roo.log('editor - hiding textarea');
23429 // Roo.log(this.pushValue());
23432 this.inputEl().addClass(['hide', 'x-hidden']);
23433 this.inputEl().dom.setAttribute('tabIndex', -1);
23434 //this.deferFocus();
23437 if(this.resizable){
23438 this.setSize(this.wrap.getSize());
23441 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23444 // private (for BoxComponent)
23445 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23447 // private (for BoxComponent)
23448 getResizeEl : function(){
23452 // private (for BoxComponent)
23453 getPositionEl : function(){
23458 initEvents : function(){
23459 this.originalValue = this.getValue();
23463 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23466 // markInvalid : Roo.emptyFn,
23468 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23471 // clearInvalid : Roo.emptyFn,
23473 setValue : function(v){
23474 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23475 this.editorcore.pushValue();
23480 deferFocus : function(){
23481 this.focus.defer(10, this);
23485 focus : function(){
23486 this.editorcore.focus();
23492 onDestroy : function(){
23498 for (var i =0; i < this.toolbars.length;i++) {
23499 // fixme - ask toolbars for heights?
23500 this.toolbars[i].onDestroy();
23503 this.wrap.dom.innerHTML = '';
23504 this.wrap.remove();
23509 onFirstFocus : function(){
23510 //Roo.log("onFirstFocus");
23511 this.editorcore.onFirstFocus();
23512 for (var i =0; i < this.toolbars.length;i++) {
23513 this.toolbars[i].onFirstFocus();
23519 syncValue : function()
23521 this.editorcore.syncValue();
23524 pushValue : function()
23526 this.editorcore.pushValue();
23530 // hide stuff that is not compatible
23544 * @event specialkey
23548 * @cfg {String} fieldClass @hide
23551 * @cfg {String} focusClass @hide
23554 * @cfg {String} autoCreate @hide
23557 * @cfg {String} inputType @hide
23560 * @cfg {String} invalidClass @hide
23563 * @cfg {String} invalidText @hide
23566 * @cfg {String} msgFx @hide
23569 * @cfg {String} validateOnBlur @hide
23578 Roo.namespace('Roo.bootstrap.htmleditor');
23580 * @class Roo.bootstrap.HtmlEditorToolbar1
23585 new Roo.bootstrap.HtmlEditor({
23588 new Roo.bootstrap.HtmlEditorToolbar1({
23589 disable : { fonts: 1 , format: 1, ..., ... , ...],
23595 * @cfg {Object} disable List of elements to disable..
23596 * @cfg {Array} btns List of additional buttons.
23600 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23603 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23606 Roo.apply(this, config);
23608 // default disabled, based on 'good practice'..
23609 this.disable = this.disable || {};
23610 Roo.applyIf(this.disable, {
23613 specialElements : true
23615 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23617 this.editor = config.editor;
23618 this.editorcore = config.editor.editorcore;
23620 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23622 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23623 // dont call parent... till later.
23625 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23630 editorcore : false,
23635 "h1","h2","h3","h4","h5","h6",
23637 "abbr", "acronym", "address", "cite", "samp", "var",
23641 onRender : function(ct, position)
23643 // Roo.log("Call onRender: " + this.xtype);
23645 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23647 this.el.dom.style.marginBottom = '0';
23649 var editorcore = this.editorcore;
23650 var editor= this.editor;
23653 var btn = function(id,cmd , toggle, handler, html){
23655 var event = toggle ? 'toggle' : 'click';
23660 xns: Roo.bootstrap,
23663 enableToggle:toggle !== false,
23665 pressed : toggle ? false : null,
23668 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23669 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23675 // var cb_box = function...
23680 xns: Roo.bootstrap,
23681 glyphicon : 'font',
23685 xns: Roo.bootstrap,
23689 Roo.each(this.formats, function(f) {
23690 style.menu.items.push({
23692 xns: Roo.bootstrap,
23693 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23698 editorcore.insertTag(this.tagname);
23705 children.push(style);
23707 btn('bold',false,true);
23708 btn('italic',false,true);
23709 btn('align-left', 'justifyleft',true);
23710 btn('align-center', 'justifycenter',true);
23711 btn('align-right' , 'justifyright',true);
23712 btn('link', false, false, function(btn) {
23713 //Roo.log("create link?");
23714 var url = prompt(this.createLinkText, this.defaultLinkValue);
23715 if(url && url != 'http:/'+'/'){
23716 this.editorcore.relayCmd('createlink', url);
23719 btn('list','insertunorderedlist',true);
23720 btn('pencil', false,true, function(btn){
23722 this.toggleSourceEdit(btn.pressed);
23725 if (this.editor.btns.length > 0) {
23726 for (var i = 0; i<this.editor.btns.length; i++) {
23727 children.push(this.editor.btns[i]);
23735 xns: Roo.bootstrap,
23740 xns: Roo.bootstrap,
23745 cog.menu.items.push({
23747 xns: Roo.bootstrap,
23748 html : Clean styles,
23753 editorcore.insertTag(this.tagname);
23762 this.xtype = 'NavSimplebar';
23764 for(var i=0;i< children.length;i++) {
23766 this.buttons.add(this.addxtypeChild(children[i]));
23770 editor.on('editorevent', this.updateToolbar, this);
23772 onBtnClick : function(id)
23774 this.editorcore.relayCmd(id);
23775 this.editorcore.focus();
23779 * Protected method that will not generally be called directly. It triggers
23780 * a toolbar update by reading the markup state of the current selection in the editor.
23782 updateToolbar: function(){
23784 if(!this.editorcore.activated){
23785 this.editor.onFirstFocus(); // is this neeed?
23789 var btns = this.buttons;
23790 var doc = this.editorcore.doc;
23791 btns.get('bold').setActive(doc.queryCommandState('bold'));
23792 btns.get('italic').setActive(doc.queryCommandState('italic'));
23793 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23795 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23796 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23797 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23799 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23800 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23803 var ans = this.editorcore.getAllAncestors();
23804 if (this.formatCombo) {
23807 var store = this.formatCombo.store;
23808 this.formatCombo.setValue("");
23809 for (var i =0; i < ans.length;i++) {
23810 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23812 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23820 // hides menus... - so this cant be on a menu...
23821 Roo.bootstrap.MenuMgr.hideAll();
23823 Roo.bootstrap.MenuMgr.hideAll();
23824 //this.editorsyncValue();
23826 onFirstFocus: function() {
23827 this.buttons.each(function(item){
23831 toggleSourceEdit : function(sourceEditMode){
23834 if(sourceEditMode){
23835 Roo.log("disabling buttons");
23836 this.buttons.each( function(item){
23837 if(item.cmd != 'pencil'){
23843 Roo.log("enabling buttons");
23844 if(this.editorcore.initialized){
23845 this.buttons.each( function(item){
23851 Roo.log("calling toggole on editor");
23852 // tell the editor that it's been pressed..
23853 this.editor.toggleSourceEdit(sourceEditMode);
23863 * @class Roo.bootstrap.Table.AbstractSelectionModel
23864 * @extends Roo.util.Observable
23865 * Abstract base class for grid SelectionModels. It provides the interface that should be
23866 * implemented by descendant classes. This class should not be directly instantiated.
23869 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23870 this.locked = false;
23871 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23875 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23876 /** @ignore Called by the grid automatically. Do not call directly. */
23877 init : function(grid){
23883 * Locks the selections.
23886 this.locked = true;
23890 * Unlocks the selections.
23892 unlock : function(){
23893 this.locked = false;
23897 * Returns true if the selections are locked.
23898 * @return {Boolean}
23900 isLocked : function(){
23901 return this.locked;
23905 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23906 * @class Roo.bootstrap.Table.RowSelectionModel
23907 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23908 * It supports multiple selections and keyboard selection/navigation.
23910 * @param {Object} config
23913 Roo.bootstrap.Table.RowSelectionModel = function(config){
23914 Roo.apply(this, config);
23915 this.selections = new Roo.util.MixedCollection(false, function(o){
23920 this.lastActive = false;
23924 * @event selectionchange
23925 * Fires when the selection changes
23926 * @param {SelectionModel} this
23928 "selectionchange" : true,
23930 * @event afterselectionchange
23931 * Fires after the selection changes (eg. by key press or clicking)
23932 * @param {SelectionModel} this
23934 "afterselectionchange" : true,
23936 * @event beforerowselect
23937 * Fires when a row is selected being selected, return false to cancel.
23938 * @param {SelectionModel} this
23939 * @param {Number} rowIndex The selected index
23940 * @param {Boolean} keepExisting False if other selections will be cleared
23942 "beforerowselect" : true,
23945 * Fires when a row is selected.
23946 * @param {SelectionModel} this
23947 * @param {Number} rowIndex The selected index
23948 * @param {Roo.data.Record} r The record
23950 "rowselect" : true,
23952 * @event rowdeselect
23953 * Fires when a row is deselected.
23954 * @param {SelectionModel} this
23955 * @param {Number} rowIndex The selected index
23957 "rowdeselect" : true
23959 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23960 this.locked = false;
23963 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23965 * @cfg {Boolean} singleSelect
23966 * True to allow selection of only one row at a time (defaults to false)
23968 singleSelect : false,
23971 initEvents : function()
23974 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23975 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23976 //}else{ // allow click to work like normal
23977 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23979 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23980 this.grid.on("rowclick", this.handleMouseDown, this);
23982 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23983 "up" : function(e){
23985 this.selectPrevious(e.shiftKey);
23986 }else if(this.last !== false && this.lastActive !== false){
23987 var last = this.last;
23988 this.selectRange(this.last, this.lastActive-1);
23989 this.grid.getView().focusRow(this.lastActive);
23990 if(last !== false){
23994 this.selectFirstRow();
23996 this.fireEvent("afterselectionchange", this);
23998 "down" : function(e){
24000 this.selectNext(e.shiftKey);
24001 }else if(this.last !== false && this.lastActive !== false){
24002 var last = this.last;
24003 this.selectRange(this.last, this.lastActive+1);
24004 this.grid.getView().focusRow(this.lastActive);
24005 if(last !== false){
24009 this.selectFirstRow();
24011 this.fireEvent("afterselectionchange", this);
24015 this.grid.store.on('load', function(){
24016 this.selections.clear();
24019 var view = this.grid.view;
24020 view.on("refresh", this.onRefresh, this);
24021 view.on("rowupdated", this.onRowUpdated, this);
24022 view.on("rowremoved", this.onRemove, this);
24027 onRefresh : function()
24029 var ds = this.grid.store, i, v = this.grid.view;
24030 var s = this.selections;
24031 s.each(function(r){
24032 if((i = ds.indexOfId(r.id)) != -1){
24041 onRemove : function(v, index, r){
24042 this.selections.remove(r);
24046 onRowUpdated : function(v, index, r){
24047 if(this.isSelected(r)){
24048 v.onRowSelect(index);
24054 * @param {Array} records The records to select
24055 * @param {Boolean} keepExisting (optional) True to keep existing selections
24057 selectRecords : function(records, keepExisting)
24060 this.clearSelections();
24062 var ds = this.grid.store;
24063 for(var i = 0, len = records.length; i < len; i++){
24064 this.selectRow(ds.indexOf(records[i]), true);
24069 * Gets the number of selected rows.
24072 getCount : function(){
24073 return this.selections.length;
24077 * Selects the first row in the grid.
24079 selectFirstRow : function(){
24084 * Select the last row.
24085 * @param {Boolean} keepExisting (optional) True to keep existing selections
24087 selectLastRow : function(keepExisting){
24088 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24089 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24093 * Selects the row immediately following the last selected row.
24094 * @param {Boolean} keepExisting (optional) True to keep existing selections
24096 selectNext : function(keepExisting)
24098 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24099 this.selectRow(this.last+1, keepExisting);
24100 this.grid.getView().focusRow(this.last);
24105 * Selects the row that precedes the last selected row.
24106 * @param {Boolean} keepExisting (optional) True to keep existing selections
24108 selectPrevious : function(keepExisting){
24110 this.selectRow(this.last-1, keepExisting);
24111 this.grid.getView().focusRow(this.last);
24116 * Returns the selected records
24117 * @return {Array} Array of selected records
24119 getSelections : function(){
24120 return [].concat(this.selections.items);
24124 * Returns the first selected record.
24127 getSelected : function(){
24128 return this.selections.itemAt(0);
24133 * Clears all selections.
24135 clearSelections : function(fast)
24141 var ds = this.grid.store;
24142 var s = this.selections;
24143 s.each(function(r){
24144 this.deselectRow(ds.indexOfId(r.id));
24148 this.selections.clear();
24155 * Selects all rows.
24157 selectAll : function(){
24161 this.selections.clear();
24162 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24163 this.selectRow(i, true);
24168 * Returns True if there is a selection.
24169 * @return {Boolean}
24171 hasSelection : function(){
24172 return this.selections.length > 0;
24176 * Returns True if the specified row is selected.
24177 * @param {Number/Record} record The record or index of the record to check
24178 * @return {Boolean}
24180 isSelected : function(index){
24181 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24182 return (r && this.selections.key(r.id) ? true : false);
24186 * Returns True if the specified record id is selected.
24187 * @param {String} id The id of record to check
24188 * @return {Boolean}
24190 isIdSelected : function(id){
24191 return (this.selections.key(id) ? true : false);
24196 handleMouseDBClick : function(e, t){
24200 handleMouseDown : function(e, t)
24202 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24203 if(this.isLocked() || rowIndex < 0 ){
24206 if(e.shiftKey && this.last !== false){
24207 var last = this.last;
24208 this.selectRange(last, rowIndex, e.ctrlKey);
24209 this.last = last; // reset the last
24213 var isSelected = this.isSelected(rowIndex);
24214 //Roo.log("select row:" + rowIndex);
24216 this.deselectRow(rowIndex);
24218 this.selectRow(rowIndex, true);
24222 if(e.button !== 0 && isSelected){
24223 alert('rowIndex 2: ' + rowIndex);
24224 view.focusRow(rowIndex);
24225 }else if(e.ctrlKey && isSelected){
24226 this.deselectRow(rowIndex);
24227 }else if(!isSelected){
24228 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24229 view.focusRow(rowIndex);
24233 this.fireEvent("afterselectionchange", this);
24236 handleDragableRowClick : function(grid, rowIndex, e)
24238 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24239 this.selectRow(rowIndex, false);
24240 grid.view.focusRow(rowIndex);
24241 this.fireEvent("afterselectionchange", this);
24246 * Selects multiple rows.
24247 * @param {Array} rows Array of the indexes of the row to select
24248 * @param {Boolean} keepExisting (optional) True to keep existing selections
24250 selectRows : function(rows, keepExisting){
24252 this.clearSelections();
24254 for(var i = 0, len = rows.length; i < len; i++){
24255 this.selectRow(rows[i], true);
24260 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24261 * @param {Number} startRow The index of the first row in the range
24262 * @param {Number} endRow The index of the last row in the range
24263 * @param {Boolean} keepExisting (optional) True to retain existing selections
24265 selectRange : function(startRow, endRow, keepExisting){
24270 this.clearSelections();
24272 if(startRow <= endRow){
24273 for(var i = startRow; i <= endRow; i++){
24274 this.selectRow(i, true);
24277 for(var i = startRow; i >= endRow; i--){
24278 this.selectRow(i, true);
24284 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24285 * @param {Number} startRow The index of the first row in the range
24286 * @param {Number} endRow The index of the last row in the range
24288 deselectRange : function(startRow, endRow, preventViewNotify){
24292 for(var i = startRow; i <= endRow; i++){
24293 this.deselectRow(i, preventViewNotify);
24299 * @param {Number} row The index of the row to select
24300 * @param {Boolean} keepExisting (optional) True to keep existing selections
24302 selectRow : function(index, keepExisting, preventViewNotify)
24304 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24307 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24308 if(!keepExisting || this.singleSelect){
24309 this.clearSelections();
24312 var r = this.grid.store.getAt(index);
24313 //console.log('selectRow - record id :' + r.id);
24315 this.selections.add(r);
24316 this.last = this.lastActive = index;
24317 if(!preventViewNotify){
24318 var proxy = new Roo.Element(
24319 this.grid.getRowDom(index)
24321 proxy.addClass('bg-info info');
24323 this.fireEvent("rowselect", this, index, r);
24324 this.fireEvent("selectionchange", this);
24330 * @param {Number} row The index of the row to deselect
24332 deselectRow : function(index, preventViewNotify)
24337 if(this.last == index){
24340 if(this.lastActive == index){
24341 this.lastActive = false;
24344 var r = this.grid.store.getAt(index);
24349 this.selections.remove(r);
24350 //.console.log('deselectRow - record id :' + r.id);
24351 if(!preventViewNotify){
24353 var proxy = new Roo.Element(
24354 this.grid.getRowDom(index)
24356 proxy.removeClass('bg-info info');
24358 this.fireEvent("rowdeselect", this, index);
24359 this.fireEvent("selectionchange", this);
24363 restoreLast : function(){
24365 this.last = this._last;
24370 acceptsNav : function(row, col, cm){
24371 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24375 onEditorKey : function(field, e){
24376 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24381 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24383 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24385 }else if(k == e.ENTER && !e.ctrlKey){
24389 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24391 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24393 }else if(k == e.ESC){
24397 g.startEditing(newCell[0], newCell[1]);
24403 * Ext JS Library 1.1.1
24404 * Copyright(c) 2006-2007, Ext JS, LLC.
24406 * Originally Released Under LGPL - original licence link has changed is not relivant.
24409 * <script type="text/javascript">
24413 * @class Roo.bootstrap.PagingToolbar
24414 * @extends Roo.bootstrap.NavSimplebar
24415 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24417 * Create a new PagingToolbar
24418 * @param {Object} config The config object
24419 * @param {Roo.data.Store} store
24421 Roo.bootstrap.PagingToolbar = function(config)
24423 // old args format still supported... - xtype is prefered..
24424 // created from xtype...
24426 this.ds = config.dataSource;
24428 if (config.store && !this.ds) {
24429 this.store= Roo.factory(config.store, Roo.data);
24430 this.ds = this.store;
24431 this.ds.xmodule = this.xmodule || false;
24434 this.toolbarItems = [];
24435 if (config.items) {
24436 this.toolbarItems = config.items;
24439 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24444 this.bind(this.ds);
24447 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24451 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24453 * @cfg {Roo.data.Store} dataSource
24454 * The underlying data store providing the paged data
24457 * @cfg {String/HTMLElement/Element} container
24458 * container The id or element that will contain the toolbar
24461 * @cfg {Boolean} displayInfo
24462 * True to display the displayMsg (defaults to false)
24465 * @cfg {Number} pageSize
24466 * The number of records to display per page (defaults to 20)
24470 * @cfg {String} displayMsg
24471 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24473 displayMsg : 'Displaying {0} - {1} of {2}',
24475 * @cfg {String} emptyMsg
24476 * The message to display when no records are found (defaults to "No data to display")
24478 emptyMsg : 'No data to display',
24480 * Customizable piece of the default paging text (defaults to "Page")
24483 beforePageText : "Page",
24485 * Customizable piece of the default paging text (defaults to "of %0")
24488 afterPageText : "of {0}",
24490 * Customizable piece of the default paging text (defaults to "First Page")
24493 firstText : "First Page",
24495 * Customizable piece of the default paging text (defaults to "Previous Page")
24498 prevText : "Previous Page",
24500 * Customizable piece of the default paging text (defaults to "Next Page")
24503 nextText : "Next Page",
24505 * Customizable piece of the default paging text (defaults to "Last Page")
24508 lastText : "Last Page",
24510 * Customizable piece of the default paging text (defaults to "Refresh")
24513 refreshText : "Refresh",
24517 onRender : function(ct, position)
24519 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24520 this.navgroup.parentId = this.id;
24521 this.navgroup.onRender(this.el, null);
24522 // add the buttons to the navgroup
24524 if(this.displayInfo){
24525 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24526 this.displayEl = this.el.select('.x-paging-info', true).first();
24527 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24528 // this.displayEl = navel.el.select('span',true).first();
24534 Roo.each(_this.buttons, function(e){ // this might need to use render????
24535 Roo.factory(e).render(_this.el);
24539 Roo.each(_this.toolbarItems, function(e) {
24540 _this.navgroup.addItem(e);
24544 this.first = this.navgroup.addItem({
24545 tooltip: this.firstText,
24547 icon : 'fa fa-backward',
24549 preventDefault: true,
24550 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24553 this.prev = this.navgroup.addItem({
24554 tooltip: this.prevText,
24556 icon : 'fa fa-step-backward',
24558 preventDefault: true,
24559 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24561 //this.addSeparator();
24564 var field = this.navgroup.addItem( {
24566 cls : 'x-paging-position',
24568 html : this.beforePageText +
24569 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24570 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24573 this.field = field.el.select('input', true).first();
24574 this.field.on("keydown", this.onPagingKeydown, this);
24575 this.field.on("focus", function(){this.dom.select();});
24578 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24579 //this.field.setHeight(18);
24580 //this.addSeparator();
24581 this.next = this.navgroup.addItem({
24582 tooltip: this.nextText,
24584 html : ' <i class="fa fa-step-forward">',
24586 preventDefault: true,
24587 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24589 this.last = this.navgroup.addItem({
24590 tooltip: this.lastText,
24591 icon : 'fa fa-forward',
24594 preventDefault: true,
24595 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24597 //this.addSeparator();
24598 this.loading = this.navgroup.addItem({
24599 tooltip: this.refreshText,
24600 icon: 'fa fa-refresh',
24601 preventDefault: true,
24602 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24608 updateInfo : function(){
24609 if(this.displayEl){
24610 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24611 var msg = count == 0 ?
24615 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24617 this.displayEl.update(msg);
24622 onLoad : function(ds, r, o)
24624 this.cursor = o.params.start ? o.params.start : 0;
24626 var d = this.getPageData(),
24631 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24632 this.field.dom.value = ap;
24633 this.first.setDisabled(ap == 1);
24634 this.prev.setDisabled(ap == 1);
24635 this.next.setDisabled(ap == ps);
24636 this.last.setDisabled(ap == ps);
24637 this.loading.enable();
24642 getPageData : function(){
24643 var total = this.ds.getTotalCount();
24646 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24647 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24652 onLoadError : function(){
24653 this.loading.enable();
24657 onPagingKeydown : function(e){
24658 var k = e.getKey();
24659 var d = this.getPageData();
24661 var v = this.field.dom.value, pageNum;
24662 if(!v || isNaN(pageNum = parseInt(v, 10))){
24663 this.field.dom.value = d.activePage;
24666 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24667 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24670 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))
24672 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24673 this.field.dom.value = pageNum;
24674 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24677 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24679 var v = this.field.dom.value, pageNum;
24680 var increment = (e.shiftKey) ? 10 : 1;
24681 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24684 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24685 this.field.dom.value = d.activePage;
24688 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24690 this.field.dom.value = parseInt(v, 10) + increment;
24691 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24692 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24699 beforeLoad : function(){
24701 this.loading.disable();
24706 onClick : function(which){
24715 ds.load({params:{start: 0, limit: this.pageSize}});
24718 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24721 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24724 var total = ds.getTotalCount();
24725 var extra = total % this.pageSize;
24726 var lastStart = extra ? (total - extra) : total-this.pageSize;
24727 ds.load({params:{start: lastStart, limit: this.pageSize}});
24730 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24736 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24737 * @param {Roo.data.Store} store The data store to unbind
24739 unbind : function(ds){
24740 ds.un("beforeload", this.beforeLoad, this);
24741 ds.un("load", this.onLoad, this);
24742 ds.un("loadexception", this.onLoadError, this);
24743 ds.un("remove", this.updateInfo, this);
24744 ds.un("add", this.updateInfo, this);
24745 this.ds = undefined;
24749 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24750 * @param {Roo.data.Store} store The data store to bind
24752 bind : function(ds){
24753 ds.on("beforeload", this.beforeLoad, this);
24754 ds.on("load", this.onLoad, this);
24755 ds.on("loadexception", this.onLoadError, this);
24756 ds.on("remove", this.updateInfo, this);
24757 ds.on("add", this.updateInfo, this);
24768 * @class Roo.bootstrap.MessageBar
24769 * @extends Roo.bootstrap.Component
24770 * Bootstrap MessageBar class
24771 * @cfg {String} html contents of the MessageBar
24772 * @cfg {String} weight (info | success | warning | danger) default info
24773 * @cfg {String} beforeClass insert the bar before the given class
24774 * @cfg {Boolean} closable (true | false) default false
24775 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24778 * Create a new Element
24779 * @param {Object} config The config object
24782 Roo.bootstrap.MessageBar = function(config){
24783 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24786 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24792 beforeClass: 'bootstrap-sticky-wrap',
24794 getAutoCreate : function(){
24798 cls: 'alert alert-dismissable alert-' + this.weight,
24803 html: this.html || ''
24809 cfg.cls += ' alert-messages-fixed';
24823 onRender : function(ct, position)
24825 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24828 var cfg = Roo.apply({}, this.getAutoCreate());
24832 cfg.cls += ' ' + this.cls;
24835 cfg.style = this.style;
24837 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24839 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24842 this.el.select('>button.close').on('click', this.hide, this);
24848 if (!this.rendered) {
24854 this.fireEvent('show', this);
24860 if (!this.rendered) {
24866 this.fireEvent('hide', this);
24869 update : function()
24871 // var e = this.el.dom.firstChild;
24873 // if(this.closable){
24874 // e = e.nextSibling;
24877 // e.data = this.html || '';
24879 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24895 * @class Roo.bootstrap.Graph
24896 * @extends Roo.bootstrap.Component
24897 * Bootstrap Graph class
24901 @cfg {String} graphtype bar | vbar | pie
24902 @cfg {number} g_x coodinator | centre x (pie)
24903 @cfg {number} g_y coodinator | centre y (pie)
24904 @cfg {number} g_r radius (pie)
24905 @cfg {number} g_height height of the chart (respected by all elements in the set)
24906 @cfg {number} g_width width of the chart (respected by all elements in the set)
24907 @cfg {Object} title The title of the chart
24910 -opts (object) options for the chart
24912 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24913 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24915 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.
24916 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24918 o stretch (boolean)
24920 -opts (object) options for the pie
24923 o startAngle (number)
24924 o endAngle (number)
24928 * Create a new Input
24929 * @param {Object} config The config object
24932 Roo.bootstrap.Graph = function(config){
24933 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24939 * The img click event for the img.
24940 * @param {Roo.EventObject} e
24946 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24957 //g_colors: this.colors,
24964 getAutoCreate : function(){
24975 onRender : function(ct,position){
24978 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24980 if (typeof(Raphael) == 'undefined') {
24981 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24985 this.raphael = Raphael(this.el.dom);
24987 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24988 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24989 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24990 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24992 r.text(160, 10, "Single Series Chart").attr(txtattr);
24993 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24994 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24995 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24997 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24998 r.barchart(330, 10, 300, 220, data1);
24999 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25000 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25003 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25004 // r.barchart(30, 30, 560, 250, xdata, {
25005 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25006 // axis : "0 0 1 1",
25007 // axisxlabels : xdata
25008 // //yvalues : cols,
25011 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25013 // this.load(null,xdata,{
25014 // axis : "0 0 1 1",
25015 // axisxlabels : xdata
25020 load : function(graphtype,xdata,opts)
25022 this.raphael.clear();
25024 graphtype = this.graphtype;
25029 var r = this.raphael,
25030 fin = function () {
25031 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25033 fout = function () {
25034 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25036 pfin = function() {
25037 this.sector.stop();
25038 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25041 this.label[0].stop();
25042 this.label[0].attr({ r: 7.5 });
25043 this.label[1].attr({ "font-weight": 800 });
25046 pfout = function() {
25047 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25050 this.label[0].animate({ r: 5 }, 500, "bounce");
25051 this.label[1].attr({ "font-weight": 400 });
25057 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25060 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25063 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25064 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25066 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25073 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25078 setTitle: function(o)
25083 initEvents: function() {
25086 this.el.on('click', this.onClick, this);
25090 onClick : function(e)
25092 Roo.log('img onclick');
25093 this.fireEvent('click', this, e);
25105 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25108 * @class Roo.bootstrap.dash.NumberBox
25109 * @extends Roo.bootstrap.Component
25110 * Bootstrap NumberBox class
25111 * @cfg {String} headline Box headline
25112 * @cfg {String} content Box content
25113 * @cfg {String} icon Box icon
25114 * @cfg {String} footer Footer text
25115 * @cfg {String} fhref Footer href
25118 * Create a new NumberBox
25119 * @param {Object} config The config object
25123 Roo.bootstrap.dash.NumberBox = function(config){
25124 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25128 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25137 getAutoCreate : function(){
25141 cls : 'small-box ',
25149 cls : 'roo-headline',
25150 html : this.headline
25154 cls : 'roo-content',
25155 html : this.content
25169 cls : 'ion ' + this.icon
25178 cls : 'small-box-footer',
25179 href : this.fhref || '#',
25183 cfg.cn.push(footer);
25190 onRender : function(ct,position){
25191 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25198 setHeadline: function (value)
25200 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25203 setFooter: function (value, href)
25205 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25208 this.el.select('a.small-box-footer',true).first().attr('href', href);
25213 setContent: function (value)
25215 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25218 initEvents: function()
25232 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25235 * @class Roo.bootstrap.dash.TabBox
25236 * @extends Roo.bootstrap.Component
25237 * Bootstrap TabBox class
25238 * @cfg {String} title Title of the TabBox
25239 * @cfg {String} icon Icon of the TabBox
25240 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25241 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25244 * Create a new TabBox
25245 * @param {Object} config The config object
25249 Roo.bootstrap.dash.TabBox = function(config){
25250 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25255 * When a pane is added
25256 * @param {Roo.bootstrap.dash.TabPane} pane
25260 * @event activatepane
25261 * When a pane is activated
25262 * @param {Roo.bootstrap.dash.TabPane} pane
25264 "activatepane" : true
25272 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25277 tabScrollable : false,
25279 getChildContainer : function()
25281 return this.el.select('.tab-content', true).first();
25284 getAutoCreate : function(){
25288 cls: 'pull-left header',
25296 cls: 'fa ' + this.icon
25302 cls: 'nav nav-tabs pull-right',
25308 if(this.tabScrollable){
25315 cls: 'nav nav-tabs pull-right',
25326 cls: 'nav-tabs-custom',
25331 cls: 'tab-content no-padding',
25339 initEvents : function()
25341 //Roo.log('add add pane handler');
25342 this.on('addpane', this.onAddPane, this);
25345 * Updates the box title
25346 * @param {String} html to set the title to.
25348 setTitle : function(value)
25350 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25352 onAddPane : function(pane)
25354 this.panes.push(pane);
25355 //Roo.log('addpane');
25357 // tabs are rendere left to right..
25358 if(!this.showtabs){
25362 var ctr = this.el.select('.nav-tabs', true).first();
25365 var existing = ctr.select('.nav-tab',true);
25366 var qty = existing.getCount();;
25369 var tab = ctr.createChild({
25371 cls : 'nav-tab' + (qty ? '' : ' active'),
25379 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25382 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25384 pane.el.addClass('active');
25389 onTabClick : function(ev,un,ob,pane)
25391 //Roo.log('tab - prev default');
25392 ev.preventDefault();
25395 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25396 pane.tab.addClass('active');
25397 //Roo.log(pane.title);
25398 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25399 // technically we should have a deactivate event.. but maybe add later.
25400 // and it should not de-activate the selected tab...
25401 this.fireEvent('activatepane', pane);
25402 pane.el.addClass('active');
25403 pane.fireEvent('activate');
25408 getActivePane : function()
25411 Roo.each(this.panes, function(p) {
25412 if(p.el.hasClass('active')){
25433 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25435 * @class Roo.bootstrap.TabPane
25436 * @extends Roo.bootstrap.Component
25437 * Bootstrap TabPane class
25438 * @cfg {Boolean} active (false | true) Default false
25439 * @cfg {String} title title of panel
25443 * Create a new TabPane
25444 * @param {Object} config The config object
25447 Roo.bootstrap.dash.TabPane = function(config){
25448 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25454 * When a pane is activated
25455 * @param {Roo.bootstrap.dash.TabPane} pane
25462 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25467 // the tabBox that this is attached to.
25470 getAutoCreate : function()
25478 cfg.cls += ' active';
25483 initEvents : function()
25485 //Roo.log('trigger add pane handler');
25486 this.parent().fireEvent('addpane', this)
25490 * Updates the tab title
25491 * @param {String} html to set the title to.
25493 setTitle: function(str)
25499 this.tab.select('a', true).first().dom.innerHTML = str;
25516 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25519 * @class Roo.bootstrap.menu.Menu
25520 * @extends Roo.bootstrap.Component
25521 * Bootstrap Menu class - container for Menu
25522 * @cfg {String} html Text of the menu
25523 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25524 * @cfg {String} icon Font awesome icon
25525 * @cfg {String} pos Menu align to (top | bottom) default bottom
25529 * Create a new Menu
25530 * @param {Object} config The config object
25534 Roo.bootstrap.menu.Menu = function(config){
25535 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25539 * @event beforeshow
25540 * Fires before this menu is displayed
25541 * @param {Roo.bootstrap.menu.Menu} this
25545 * @event beforehide
25546 * Fires before this menu is hidden
25547 * @param {Roo.bootstrap.menu.Menu} this
25552 * Fires after this menu is displayed
25553 * @param {Roo.bootstrap.menu.Menu} this
25558 * Fires after this menu is hidden
25559 * @param {Roo.bootstrap.menu.Menu} this
25564 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25565 * @param {Roo.bootstrap.menu.Menu} this
25566 * @param {Roo.EventObject} e
25573 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25577 weight : 'default',
25582 getChildContainer : function() {
25583 if(this.isSubMenu){
25587 return this.el.select('ul.dropdown-menu', true).first();
25590 getAutoCreate : function()
25595 cls : 'roo-menu-text',
25603 cls : 'fa ' + this.icon
25614 cls : 'dropdown-button btn btn-' + this.weight,
25619 cls : 'dropdown-toggle btn btn-' + this.weight,
25629 cls : 'dropdown-menu'
25635 if(this.pos == 'top'){
25636 cfg.cls += ' dropup';
25639 if(this.isSubMenu){
25642 cls : 'dropdown-menu'
25649 onRender : function(ct, position)
25651 this.isSubMenu = ct.hasClass('dropdown-submenu');
25653 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25656 initEvents : function()
25658 if(this.isSubMenu){
25662 this.hidden = true;
25664 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25665 this.triggerEl.on('click', this.onTriggerPress, this);
25667 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25668 this.buttonEl.on('click', this.onClick, this);
25674 if(this.isSubMenu){
25678 return this.el.select('ul.dropdown-menu', true).first();
25681 onClick : function(e)
25683 this.fireEvent("click", this, e);
25686 onTriggerPress : function(e)
25688 if (this.isVisible()) {
25695 isVisible : function(){
25696 return !this.hidden;
25701 this.fireEvent("beforeshow", this);
25703 this.hidden = false;
25704 this.el.addClass('open');
25706 Roo.get(document).on("mouseup", this.onMouseUp, this);
25708 this.fireEvent("show", this);
25715 this.fireEvent("beforehide", this);
25717 this.hidden = true;
25718 this.el.removeClass('open');
25720 Roo.get(document).un("mouseup", this.onMouseUp);
25722 this.fireEvent("hide", this);
25725 onMouseUp : function()
25739 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25742 * @class Roo.bootstrap.menu.Item
25743 * @extends Roo.bootstrap.Component
25744 * Bootstrap MenuItem class
25745 * @cfg {Boolean} submenu (true | false) default false
25746 * @cfg {String} html text of the item
25747 * @cfg {String} href the link
25748 * @cfg {Boolean} disable (true | false) default false
25749 * @cfg {Boolean} preventDefault (true | false) default true
25750 * @cfg {String} icon Font awesome icon
25751 * @cfg {String} pos Submenu align to (left | right) default right
25755 * Create a new Item
25756 * @param {Object} config The config object
25760 Roo.bootstrap.menu.Item = function(config){
25761 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25765 * Fires when the mouse is hovering over this menu
25766 * @param {Roo.bootstrap.menu.Item} this
25767 * @param {Roo.EventObject} e
25772 * Fires when the mouse exits this menu
25773 * @param {Roo.bootstrap.menu.Item} this
25774 * @param {Roo.EventObject} e
25780 * The raw click event for the entire grid.
25781 * @param {Roo.EventObject} e
25787 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25792 preventDefault: true,
25797 getAutoCreate : function()
25802 cls : 'roo-menu-item-text',
25810 cls : 'fa ' + this.icon
25819 href : this.href || '#',
25826 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25830 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25832 if(this.pos == 'left'){
25833 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25840 initEvents : function()
25842 this.el.on('mouseover', this.onMouseOver, this);
25843 this.el.on('mouseout', this.onMouseOut, this);
25845 this.el.select('a', true).first().on('click', this.onClick, this);
25849 onClick : function(e)
25851 if(this.preventDefault){
25852 e.preventDefault();
25855 this.fireEvent("click", this, e);
25858 onMouseOver : function(e)
25860 if(this.submenu && this.pos == 'left'){
25861 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25864 this.fireEvent("mouseover", this, e);
25867 onMouseOut : function(e)
25869 this.fireEvent("mouseout", this, e);
25881 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25884 * @class Roo.bootstrap.menu.Separator
25885 * @extends Roo.bootstrap.Component
25886 * Bootstrap Separator class
25889 * Create a new Separator
25890 * @param {Object} config The config object
25894 Roo.bootstrap.menu.Separator = function(config){
25895 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25898 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25900 getAutoCreate : function(){
25921 * @class Roo.bootstrap.Tooltip
25922 * Bootstrap Tooltip class
25923 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25924 * to determine which dom element triggers the tooltip.
25926 * It needs to add support for additional attributes like tooltip-position
25929 * Create a new Toolti
25930 * @param {Object} config The config object
25933 Roo.bootstrap.Tooltip = function(config){
25934 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25936 this.alignment = Roo.bootstrap.Tooltip.alignment;
25938 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25939 this.alignment = config.alignment;
25944 Roo.apply(Roo.bootstrap.Tooltip, {
25946 * @function init initialize tooltip monitoring.
25950 currentTip : false,
25951 currentRegion : false,
25957 Roo.get(document).on('mouseover', this.enter ,this);
25958 Roo.get(document).on('mouseout', this.leave, this);
25961 this.currentTip = new Roo.bootstrap.Tooltip();
25964 enter : function(ev)
25966 var dom = ev.getTarget();
25968 //Roo.log(['enter',dom]);
25969 var el = Roo.fly(dom);
25970 if (this.currentEl) {
25972 //Roo.log(this.currentEl);
25973 //Roo.log(this.currentEl.contains(dom));
25974 if (this.currentEl == el) {
25977 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25983 if (this.currentTip.el) {
25984 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25988 if(!el || el.dom == document){
25994 // you can not look for children, as if el is the body.. then everythign is the child..
25995 if (!el.attr('tooltip')) { //
25996 if (!el.select("[tooltip]").elements.length) {
25999 // is the mouse over this child...?
26000 bindEl = el.select("[tooltip]").first();
26001 var xy = ev.getXY();
26002 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26003 //Roo.log("not in region.");
26006 //Roo.log("child element over..");
26009 this.currentEl = bindEl;
26010 this.currentTip.bind(bindEl);
26011 this.currentRegion = Roo.lib.Region.getRegion(dom);
26012 this.currentTip.enter();
26015 leave : function(ev)
26017 var dom = ev.getTarget();
26018 //Roo.log(['leave',dom]);
26019 if (!this.currentEl) {
26024 if (dom != this.currentEl.dom) {
26027 var xy = ev.getXY();
26028 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26031 // only activate leave if mouse cursor is outside... bounding box..
26036 if (this.currentTip) {
26037 this.currentTip.leave();
26039 //Roo.log('clear currentEl');
26040 this.currentEl = false;
26045 'left' : ['r-l', [-2,0], 'right'],
26046 'right' : ['l-r', [2,0], 'left'],
26047 'bottom' : ['t-b', [0,2], 'top'],
26048 'top' : [ 'b-t', [0,-2], 'bottom']
26054 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26059 delay : null, // can be { show : 300 , hide: 500}
26063 hoverState : null, //???
26065 placement : 'bottom',
26069 getAutoCreate : function(){
26076 cls : 'tooltip-arrow'
26079 cls : 'tooltip-inner'
26086 bind : function(el)
26092 enter : function () {
26094 if (this.timeout != null) {
26095 clearTimeout(this.timeout);
26098 this.hoverState = 'in';
26099 //Roo.log("enter - show");
26100 if (!this.delay || !this.delay.show) {
26105 this.timeout = setTimeout(function () {
26106 if (_t.hoverState == 'in') {
26109 }, this.delay.show);
26113 clearTimeout(this.timeout);
26115 this.hoverState = 'out';
26116 if (!this.delay || !this.delay.hide) {
26122 this.timeout = setTimeout(function () {
26123 //Roo.log("leave - timeout");
26125 if (_t.hoverState == 'out') {
26127 Roo.bootstrap.Tooltip.currentEl = false;
26132 show : function (msg)
26135 this.render(document.body);
26138 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26140 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26142 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26144 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26146 var placement = typeof this.placement == 'function' ?
26147 this.placement.call(this, this.el, on_el) :
26150 var autoToken = /\s?auto?\s?/i;
26151 var autoPlace = autoToken.test(placement);
26153 placement = placement.replace(autoToken, '') || 'top';
26157 //this.el.setXY([0,0]);
26159 //this.el.dom.style.display='block';
26161 //this.el.appendTo(on_el);
26163 var p = this.getPosition();
26164 var box = this.el.getBox();
26170 var align = this.alignment[placement];
26172 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26174 if(placement == 'top' || placement == 'bottom'){
26176 placement = 'right';
26179 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26180 placement = 'left';
26183 var scroll = Roo.select('body', true).first().getScroll();
26185 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26191 this.el.alignTo(this.bindEl, align[0],align[1]);
26192 //var arrow = this.el.select('.arrow',true).first();
26193 //arrow.set(align[2],
26195 this.el.addClass(placement);
26197 this.el.addClass('in fade');
26199 this.hoverState = null;
26201 if (this.el.hasClass('fade')) {
26212 //this.el.setXY([0,0]);
26213 this.el.removeClass('in');
26229 * @class Roo.bootstrap.LocationPicker
26230 * @extends Roo.bootstrap.Component
26231 * Bootstrap LocationPicker class
26232 * @cfg {Number} latitude Position when init default 0
26233 * @cfg {Number} longitude Position when init default 0
26234 * @cfg {Number} zoom default 15
26235 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26236 * @cfg {Boolean} mapTypeControl default false
26237 * @cfg {Boolean} disableDoubleClickZoom default false
26238 * @cfg {Boolean} scrollwheel default true
26239 * @cfg {Boolean} streetViewControl default false
26240 * @cfg {Number} radius default 0
26241 * @cfg {String} locationName
26242 * @cfg {Boolean} draggable default true
26243 * @cfg {Boolean} enableAutocomplete default false
26244 * @cfg {Boolean} enableReverseGeocode default true
26245 * @cfg {String} markerTitle
26248 * Create a new LocationPicker
26249 * @param {Object} config The config object
26253 Roo.bootstrap.LocationPicker = function(config){
26255 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26260 * Fires when the picker initialized.
26261 * @param {Roo.bootstrap.LocationPicker} this
26262 * @param {Google Location} location
26266 * @event positionchanged
26267 * Fires when the picker position changed.
26268 * @param {Roo.bootstrap.LocationPicker} this
26269 * @param {Google Location} location
26271 positionchanged : true,
26274 * Fires when the map resize.
26275 * @param {Roo.bootstrap.LocationPicker} this
26280 * Fires when the map show.
26281 * @param {Roo.bootstrap.LocationPicker} this
26286 * Fires when the map hide.
26287 * @param {Roo.bootstrap.LocationPicker} this
26292 * Fires when click the map.
26293 * @param {Roo.bootstrap.LocationPicker} this
26294 * @param {Map event} e
26298 * @event mapRightClick
26299 * Fires when right click the map.
26300 * @param {Roo.bootstrap.LocationPicker} this
26301 * @param {Map event} e
26303 mapRightClick : true,
26305 * @event markerClick
26306 * Fires when click the marker.
26307 * @param {Roo.bootstrap.LocationPicker} this
26308 * @param {Map event} e
26310 markerClick : true,
26312 * @event markerRightClick
26313 * Fires when right click the marker.
26314 * @param {Roo.bootstrap.LocationPicker} this
26315 * @param {Map event} e
26317 markerRightClick : true,
26319 * @event OverlayViewDraw
26320 * Fires when OverlayView Draw
26321 * @param {Roo.bootstrap.LocationPicker} this
26323 OverlayViewDraw : true,
26325 * @event OverlayViewOnAdd
26326 * Fires when OverlayView Draw
26327 * @param {Roo.bootstrap.LocationPicker} this
26329 OverlayViewOnAdd : true,
26331 * @event OverlayViewOnRemove
26332 * Fires when OverlayView Draw
26333 * @param {Roo.bootstrap.LocationPicker} this
26335 OverlayViewOnRemove : true,
26337 * @event OverlayViewShow
26338 * Fires when OverlayView Draw
26339 * @param {Roo.bootstrap.LocationPicker} this
26340 * @param {Pixel} cpx
26342 OverlayViewShow : true,
26344 * @event OverlayViewHide
26345 * Fires when OverlayView Draw
26346 * @param {Roo.bootstrap.LocationPicker} this
26348 OverlayViewHide : true,
26350 * @event loadexception
26351 * Fires when load google lib failed.
26352 * @param {Roo.bootstrap.LocationPicker} this
26354 loadexception : true
26359 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26361 gMapContext: false,
26367 mapTypeControl: false,
26368 disableDoubleClickZoom: false,
26370 streetViewControl: false,
26374 enableAutocomplete: false,
26375 enableReverseGeocode: true,
26378 getAutoCreate: function()
26383 cls: 'roo-location-picker'
26389 initEvents: function(ct, position)
26391 if(!this.el.getWidth() || this.isApplied()){
26395 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26400 initial: function()
26402 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26403 this.fireEvent('loadexception', this);
26407 if(!this.mapTypeId){
26408 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26411 this.gMapContext = this.GMapContext();
26413 this.initOverlayView();
26415 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26419 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26420 _this.setPosition(_this.gMapContext.marker.position);
26423 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26424 _this.fireEvent('mapClick', this, event);
26428 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26429 _this.fireEvent('mapRightClick', this, event);
26433 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26434 _this.fireEvent('markerClick', this, event);
26438 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26439 _this.fireEvent('markerRightClick', this, event);
26443 this.setPosition(this.gMapContext.location);
26445 this.fireEvent('initial', this, this.gMapContext.location);
26448 initOverlayView: function()
26452 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26456 _this.fireEvent('OverlayViewDraw', _this);
26461 _this.fireEvent('OverlayViewOnAdd', _this);
26464 onRemove: function()
26466 _this.fireEvent('OverlayViewOnRemove', _this);
26469 show: function(cpx)
26471 _this.fireEvent('OverlayViewShow', _this, cpx);
26476 _this.fireEvent('OverlayViewHide', _this);
26482 fromLatLngToContainerPixel: function(event)
26484 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26487 isApplied: function()
26489 return this.getGmapContext() == false ? false : true;
26492 getGmapContext: function()
26494 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26497 GMapContext: function()
26499 var position = new google.maps.LatLng(this.latitude, this.longitude);
26501 var _map = new google.maps.Map(this.el.dom, {
26504 mapTypeId: this.mapTypeId,
26505 mapTypeControl: this.mapTypeControl,
26506 disableDoubleClickZoom: this.disableDoubleClickZoom,
26507 scrollwheel: this.scrollwheel,
26508 streetViewControl: this.streetViewControl,
26509 locationName: this.locationName,
26510 draggable: this.draggable,
26511 enableAutocomplete: this.enableAutocomplete,
26512 enableReverseGeocode: this.enableReverseGeocode
26515 var _marker = new google.maps.Marker({
26516 position: position,
26518 title: this.markerTitle,
26519 draggable: this.draggable
26526 location: position,
26527 radius: this.radius,
26528 locationName: this.locationName,
26529 addressComponents: {
26530 formatted_address: null,
26531 addressLine1: null,
26532 addressLine2: null,
26534 streetNumber: null,
26538 stateOrProvince: null
26541 domContainer: this.el.dom,
26542 geodecoder: new google.maps.Geocoder()
26546 drawCircle: function(center, radius, options)
26548 if (this.gMapContext.circle != null) {
26549 this.gMapContext.circle.setMap(null);
26553 options = Roo.apply({}, options, {
26554 strokeColor: "#0000FF",
26555 strokeOpacity: .35,
26557 fillColor: "#0000FF",
26561 options.map = this.gMapContext.map;
26562 options.radius = radius;
26563 options.center = center;
26564 this.gMapContext.circle = new google.maps.Circle(options);
26565 return this.gMapContext.circle;
26571 setPosition: function(location)
26573 this.gMapContext.location = location;
26574 this.gMapContext.marker.setPosition(location);
26575 this.gMapContext.map.panTo(location);
26576 this.drawCircle(location, this.gMapContext.radius, {});
26580 if (this.gMapContext.settings.enableReverseGeocode) {
26581 this.gMapContext.geodecoder.geocode({
26582 latLng: this.gMapContext.location
26583 }, function(results, status) {
26585 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26586 _this.gMapContext.locationName = results[0].formatted_address;
26587 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26589 _this.fireEvent('positionchanged', this, location);
26596 this.fireEvent('positionchanged', this, location);
26601 google.maps.event.trigger(this.gMapContext.map, "resize");
26603 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26605 this.fireEvent('resize', this);
26608 setPositionByLatLng: function(latitude, longitude)
26610 this.setPosition(new google.maps.LatLng(latitude, longitude));
26613 getCurrentPosition: function()
26616 latitude: this.gMapContext.location.lat(),
26617 longitude: this.gMapContext.location.lng()
26621 getAddressName: function()
26623 return this.gMapContext.locationName;
26626 getAddressComponents: function()
26628 return this.gMapContext.addressComponents;
26631 address_component_from_google_geocode: function(address_components)
26635 for (var i = 0; i < address_components.length; i++) {
26636 var component = address_components[i];
26637 if (component.types.indexOf("postal_code") >= 0) {
26638 result.postalCode = component.short_name;
26639 } else if (component.types.indexOf("street_number") >= 0) {
26640 result.streetNumber = component.short_name;
26641 } else if (component.types.indexOf("route") >= 0) {
26642 result.streetName = component.short_name;
26643 } else if (component.types.indexOf("neighborhood") >= 0) {
26644 result.city = component.short_name;
26645 } else if (component.types.indexOf("locality") >= 0) {
26646 result.city = component.short_name;
26647 } else if (component.types.indexOf("sublocality") >= 0) {
26648 result.district = component.short_name;
26649 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26650 result.stateOrProvince = component.short_name;
26651 } else if (component.types.indexOf("country") >= 0) {
26652 result.country = component.short_name;
26656 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26657 result.addressLine2 = "";
26661 setZoomLevel: function(zoom)
26663 this.gMapContext.map.setZoom(zoom);
26676 this.fireEvent('show', this);
26687 this.fireEvent('hide', this);
26692 Roo.apply(Roo.bootstrap.LocationPicker, {
26694 OverlayView : function(map, options)
26696 options = options || {};
26710 * @class Roo.bootstrap.Alert
26711 * @extends Roo.bootstrap.Component
26712 * Bootstrap Alert class
26713 * @cfg {String} title The title of alert
26714 * @cfg {String} html The content of alert
26715 * @cfg {String} weight ( success | info | warning | danger )
26716 * @cfg {String} faicon font-awesomeicon
26719 * Create a new alert
26720 * @param {Object} config The config object
26724 Roo.bootstrap.Alert = function(config){
26725 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26729 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26736 getAutoCreate : function()
26745 cls : 'roo-alert-icon'
26750 cls : 'roo-alert-title',
26755 cls : 'roo-alert-text',
26762 cfg.cn[0].cls += ' fa ' + this.faicon;
26766 cfg.cls += ' alert-' + this.weight;
26772 initEvents: function()
26774 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26777 setTitle : function(str)
26779 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26782 setText : function(str)
26784 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26787 setWeight : function(weight)
26790 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26793 this.weight = weight;
26795 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26798 setIcon : function(icon)
26801 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26804 this.faicon = icon;
26806 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26827 * @class Roo.bootstrap.UploadCropbox
26828 * @extends Roo.bootstrap.Component
26829 * Bootstrap UploadCropbox class
26830 * @cfg {String} emptyText show when image has been loaded
26831 * @cfg {String} rotateNotify show when image too small to rotate
26832 * @cfg {Number} errorTimeout default 3000
26833 * @cfg {Number} minWidth default 300
26834 * @cfg {Number} minHeight default 300
26835 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26836 * @cfg {Boolean} isDocument (true|false) default false
26837 * @cfg {String} url action url
26838 * @cfg {String} paramName default 'imageUpload'
26839 * @cfg {String} method default POST
26840 * @cfg {Boolean} loadMask (true|false) default true
26841 * @cfg {Boolean} loadingText default 'Loading...'
26844 * Create a new UploadCropbox
26845 * @param {Object} config The config object
26848 Roo.bootstrap.UploadCropbox = function(config){
26849 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26853 * @event beforeselectfile
26854 * Fire before select file
26855 * @param {Roo.bootstrap.UploadCropbox} this
26857 "beforeselectfile" : true,
26860 * Fire after initEvent
26861 * @param {Roo.bootstrap.UploadCropbox} this
26866 * Fire after initEvent
26867 * @param {Roo.bootstrap.UploadCropbox} this
26868 * @param {String} data
26873 * Fire when preparing the file data
26874 * @param {Roo.bootstrap.UploadCropbox} this
26875 * @param {Object} file
26880 * Fire when get exception
26881 * @param {Roo.bootstrap.UploadCropbox} this
26882 * @param {XMLHttpRequest} xhr
26884 "exception" : true,
26886 * @event beforeloadcanvas
26887 * Fire before load the canvas
26888 * @param {Roo.bootstrap.UploadCropbox} this
26889 * @param {String} src
26891 "beforeloadcanvas" : true,
26894 * Fire when trash image
26895 * @param {Roo.bootstrap.UploadCropbox} this
26900 * Fire when download the image
26901 * @param {Roo.bootstrap.UploadCropbox} this
26905 * @event footerbuttonclick
26906 * Fire when footerbuttonclick
26907 * @param {Roo.bootstrap.UploadCropbox} this
26908 * @param {String} type
26910 "footerbuttonclick" : true,
26914 * @param {Roo.bootstrap.UploadCropbox} this
26919 * Fire when rotate the image
26920 * @param {Roo.bootstrap.UploadCropbox} this
26921 * @param {String} pos
26926 * Fire when inspect the file
26927 * @param {Roo.bootstrap.UploadCropbox} this
26928 * @param {Object} file
26933 * Fire when xhr upload the file
26934 * @param {Roo.bootstrap.UploadCropbox} this
26935 * @param {Object} data
26940 * Fire when arrange the file data
26941 * @param {Roo.bootstrap.UploadCropbox} this
26942 * @param {Object} formData
26947 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26950 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26952 emptyText : 'Click to upload image',
26953 rotateNotify : 'Image is too small to rotate',
26954 errorTimeout : 3000,
26968 cropType : 'image/jpeg',
26970 canvasLoaded : false,
26971 isDocument : false,
26973 paramName : 'imageUpload',
26975 loadingText : 'Loading...',
26978 getAutoCreate : function()
26982 cls : 'roo-upload-cropbox',
26986 cls : 'roo-upload-cropbox-selector',
26991 cls : 'roo-upload-cropbox-body',
26992 style : 'cursor:pointer',
26996 cls : 'roo-upload-cropbox-preview'
27000 cls : 'roo-upload-cropbox-thumb'
27004 cls : 'roo-upload-cropbox-empty-notify',
27005 html : this.emptyText
27009 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27010 html : this.rotateNotify
27016 cls : 'roo-upload-cropbox-footer',
27019 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27029 onRender : function(ct, position)
27031 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27033 if (this.buttons.length) {
27035 Roo.each(this.buttons, function(bb) {
27037 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27039 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27045 this.maskEl = this.el;
27049 initEvents : function()
27051 this.urlAPI = (window.createObjectURL && window) ||
27052 (window.URL && URL.revokeObjectURL && URL) ||
27053 (window.webkitURL && webkitURL);
27055 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27056 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27058 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27059 this.selectorEl.hide();
27061 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27062 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27064 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27065 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27066 this.thumbEl.hide();
27068 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27069 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27071 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27072 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27073 this.errorEl.hide();
27075 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27076 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27077 this.footerEl.hide();
27079 this.setThumbBoxSize();
27085 this.fireEvent('initial', this);
27092 window.addEventListener("resize", function() { _this.resize(); } );
27094 this.bodyEl.on('click', this.beforeSelectFile, this);
27097 this.bodyEl.on('touchstart', this.onTouchStart, this);
27098 this.bodyEl.on('touchmove', this.onTouchMove, this);
27099 this.bodyEl.on('touchend', this.onTouchEnd, this);
27103 this.bodyEl.on('mousedown', this.onMouseDown, this);
27104 this.bodyEl.on('mousemove', this.onMouseMove, this);
27105 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27106 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27107 Roo.get(document).on('mouseup', this.onMouseUp, this);
27110 this.selectorEl.on('change', this.onFileSelected, this);
27116 this.baseScale = 1;
27118 this.baseRotate = 1;
27119 this.dragable = false;
27120 this.pinching = false;
27123 this.cropData = false;
27124 this.notifyEl.dom.innerHTML = this.emptyText;
27126 this.selectorEl.dom.value = '';
27130 resize : function()
27132 if(this.fireEvent('resize', this) != false){
27133 this.setThumbBoxPosition();
27134 this.setCanvasPosition();
27138 onFooterButtonClick : function(e, el, o, type)
27141 case 'rotate-left' :
27142 this.onRotateLeft(e);
27144 case 'rotate-right' :
27145 this.onRotateRight(e);
27148 this.beforeSelectFile(e);
27163 this.fireEvent('footerbuttonclick', this, type);
27166 beforeSelectFile : function(e)
27168 e.preventDefault();
27170 if(this.fireEvent('beforeselectfile', this) != false){
27171 this.selectorEl.dom.click();
27175 onFileSelected : function(e)
27177 e.preventDefault();
27179 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27183 var file = this.selectorEl.dom.files[0];
27185 if(this.fireEvent('inspect', this, file) != false){
27186 this.prepare(file);
27191 trash : function(e)
27193 this.fireEvent('trash', this);
27196 download : function(e)
27198 this.fireEvent('download', this);
27201 loadCanvas : function(src)
27203 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27207 this.imageEl = document.createElement('img');
27211 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27213 this.imageEl.src = src;
27217 onLoadCanvas : function()
27219 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27220 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27222 this.bodyEl.un('click', this.beforeSelectFile, this);
27224 this.notifyEl.hide();
27225 this.thumbEl.show();
27226 this.footerEl.show();
27228 this.baseRotateLevel();
27230 if(this.isDocument){
27231 this.setThumbBoxSize();
27234 this.setThumbBoxPosition();
27236 this.baseScaleLevel();
27242 this.canvasLoaded = true;
27245 this.maskEl.unmask();
27250 setCanvasPosition : function()
27252 if(!this.canvasEl){
27256 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27257 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27259 this.previewEl.setLeft(pw);
27260 this.previewEl.setTop(ph);
27264 onMouseDown : function(e)
27268 this.dragable = true;
27269 this.pinching = false;
27271 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27272 this.dragable = false;
27276 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27277 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27281 onMouseMove : function(e)
27285 if(!this.canvasLoaded){
27289 if (!this.dragable){
27293 var minX = Math.ceil(this.thumbEl.getLeft(true));
27294 var minY = Math.ceil(this.thumbEl.getTop(true));
27296 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27297 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27299 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27300 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27302 x = x - this.mouseX;
27303 y = y - this.mouseY;
27305 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27306 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27308 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27309 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27311 this.previewEl.setLeft(bgX);
27312 this.previewEl.setTop(bgY);
27314 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27315 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27318 onMouseUp : function(e)
27322 this.dragable = false;
27325 onMouseWheel : function(e)
27329 this.startScale = this.scale;
27331 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27333 if(!this.zoomable()){
27334 this.scale = this.startScale;
27343 zoomable : function()
27345 var minScale = this.thumbEl.getWidth() / this.minWidth;
27347 if(this.minWidth < this.minHeight){
27348 minScale = this.thumbEl.getHeight() / this.minHeight;
27351 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27352 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27356 (this.rotate == 0 || this.rotate == 180) &&
27358 width > this.imageEl.OriginWidth ||
27359 height > this.imageEl.OriginHeight ||
27360 (width < this.minWidth && height < this.minHeight)
27368 (this.rotate == 90 || this.rotate == 270) &&
27370 width > this.imageEl.OriginWidth ||
27371 height > this.imageEl.OriginHeight ||
27372 (width < this.minHeight && height < this.minWidth)
27379 !this.isDocument &&
27380 (this.rotate == 0 || this.rotate == 180) &&
27382 width < this.minWidth ||
27383 width > this.imageEl.OriginWidth ||
27384 height < this.minHeight ||
27385 height > this.imageEl.OriginHeight
27392 !this.isDocument &&
27393 (this.rotate == 90 || this.rotate == 270) &&
27395 width < this.minHeight ||
27396 width > this.imageEl.OriginWidth ||
27397 height < this.minWidth ||
27398 height > this.imageEl.OriginHeight
27408 onRotateLeft : function(e)
27410 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27412 var minScale = this.thumbEl.getWidth() / this.minWidth;
27414 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27415 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27417 this.startScale = this.scale;
27419 while (this.getScaleLevel() < minScale){
27421 this.scale = this.scale + 1;
27423 if(!this.zoomable()){
27428 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27429 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27434 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27441 this.scale = this.startScale;
27443 this.onRotateFail();
27448 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27450 if(this.isDocument){
27451 this.setThumbBoxSize();
27452 this.setThumbBoxPosition();
27453 this.setCanvasPosition();
27458 this.fireEvent('rotate', this, 'left');
27462 onRotateRight : function(e)
27464 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27466 var minScale = this.thumbEl.getWidth() / this.minWidth;
27468 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27469 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27471 this.startScale = this.scale;
27473 while (this.getScaleLevel() < minScale){
27475 this.scale = this.scale + 1;
27477 if(!this.zoomable()){
27482 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27483 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27488 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27495 this.scale = this.startScale;
27497 this.onRotateFail();
27502 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27504 if(this.isDocument){
27505 this.setThumbBoxSize();
27506 this.setThumbBoxPosition();
27507 this.setCanvasPosition();
27512 this.fireEvent('rotate', this, 'right');
27515 onRotateFail : function()
27517 this.errorEl.show(true);
27521 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27526 this.previewEl.dom.innerHTML = '';
27528 var canvasEl = document.createElement("canvas");
27530 var contextEl = canvasEl.getContext("2d");
27532 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27533 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27534 var center = this.imageEl.OriginWidth / 2;
27536 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27537 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27538 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27539 center = this.imageEl.OriginHeight / 2;
27542 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27544 contextEl.translate(center, center);
27545 contextEl.rotate(this.rotate * Math.PI / 180);
27547 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27549 this.canvasEl = document.createElement("canvas");
27551 this.contextEl = this.canvasEl.getContext("2d");
27553 switch (this.rotate) {
27556 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27557 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27559 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27564 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27565 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27567 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27568 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);
27572 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27577 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27578 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27580 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27581 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);
27585 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);
27590 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27591 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27593 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27594 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27598 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);
27605 this.previewEl.appendChild(this.canvasEl);
27607 this.setCanvasPosition();
27612 if(!this.canvasLoaded){
27616 var imageCanvas = document.createElement("canvas");
27618 var imageContext = imageCanvas.getContext("2d");
27620 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27621 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27623 var center = imageCanvas.width / 2;
27625 imageContext.translate(center, center);
27627 imageContext.rotate(this.rotate * Math.PI / 180);
27629 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27631 var canvas = document.createElement("canvas");
27633 var context = canvas.getContext("2d");
27635 canvas.width = this.minWidth;
27636 canvas.height = this.minHeight;
27638 switch (this.rotate) {
27641 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27642 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27644 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27645 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27647 var targetWidth = this.minWidth - 2 * x;
27648 var targetHeight = this.minHeight - 2 * y;
27652 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27653 scale = targetWidth / width;
27656 if(x > 0 && y == 0){
27657 scale = targetHeight / height;
27660 if(x > 0 && y > 0){
27661 scale = targetWidth / width;
27663 if(width < height){
27664 scale = targetHeight / height;
27668 context.scale(scale, scale);
27670 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27671 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27673 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27674 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27676 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27681 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27682 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27684 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27685 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27687 var targetWidth = this.minWidth - 2 * x;
27688 var targetHeight = this.minHeight - 2 * y;
27692 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27693 scale = targetWidth / width;
27696 if(x > 0 && y == 0){
27697 scale = targetHeight / height;
27700 if(x > 0 && y > 0){
27701 scale = targetWidth / width;
27703 if(width < height){
27704 scale = targetHeight / height;
27708 context.scale(scale, scale);
27710 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27711 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27713 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27714 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27716 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27718 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27723 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27724 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27726 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27727 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27729 var targetWidth = this.minWidth - 2 * x;
27730 var targetHeight = this.minHeight - 2 * y;
27734 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27735 scale = targetWidth / width;
27738 if(x > 0 && y == 0){
27739 scale = targetHeight / height;
27742 if(x > 0 && y > 0){
27743 scale = targetWidth / width;
27745 if(width < height){
27746 scale = targetHeight / height;
27750 context.scale(scale, scale);
27752 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27753 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27755 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27756 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27758 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27759 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27761 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27766 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27767 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27769 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27770 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27772 var targetWidth = this.minWidth - 2 * x;
27773 var targetHeight = this.minHeight - 2 * y;
27777 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27778 scale = targetWidth / width;
27781 if(x > 0 && y == 0){
27782 scale = targetHeight / height;
27785 if(x > 0 && y > 0){
27786 scale = targetWidth / width;
27788 if(width < height){
27789 scale = targetHeight / height;
27793 context.scale(scale, scale);
27795 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27796 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27798 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27799 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27801 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27803 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27810 this.cropData = canvas.toDataURL(this.cropType);
27812 if(this.fireEvent('crop', this, this.cropData) !== false){
27813 this.process(this.file, this.cropData);
27820 setThumbBoxSize : function()
27824 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27825 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27826 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27828 this.minWidth = width;
27829 this.minHeight = height;
27831 if(this.rotate == 90 || this.rotate == 270){
27832 this.minWidth = height;
27833 this.minHeight = width;
27838 width = Math.ceil(this.minWidth * height / this.minHeight);
27840 if(this.minWidth > this.minHeight){
27842 height = Math.ceil(this.minHeight * width / this.minWidth);
27845 this.thumbEl.setStyle({
27846 width : width + 'px',
27847 height : height + 'px'
27854 setThumbBoxPosition : function()
27856 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27857 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27859 this.thumbEl.setLeft(x);
27860 this.thumbEl.setTop(y);
27864 baseRotateLevel : function()
27866 this.baseRotate = 1;
27869 typeof(this.exif) != 'undefined' &&
27870 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27871 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27873 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27876 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27880 baseScaleLevel : function()
27884 if(this.isDocument){
27886 if(this.baseRotate == 6 || this.baseRotate == 8){
27888 height = this.thumbEl.getHeight();
27889 this.baseScale = height / this.imageEl.OriginWidth;
27891 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27892 width = this.thumbEl.getWidth();
27893 this.baseScale = width / this.imageEl.OriginHeight;
27899 height = this.thumbEl.getHeight();
27900 this.baseScale = height / this.imageEl.OriginHeight;
27902 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27903 width = this.thumbEl.getWidth();
27904 this.baseScale = width / this.imageEl.OriginWidth;
27910 if(this.baseRotate == 6 || this.baseRotate == 8){
27912 width = this.thumbEl.getHeight();
27913 this.baseScale = width / this.imageEl.OriginHeight;
27915 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27916 height = this.thumbEl.getWidth();
27917 this.baseScale = height / this.imageEl.OriginHeight;
27920 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27921 height = this.thumbEl.getWidth();
27922 this.baseScale = height / this.imageEl.OriginHeight;
27924 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27925 width = this.thumbEl.getHeight();
27926 this.baseScale = width / this.imageEl.OriginWidth;
27933 width = this.thumbEl.getWidth();
27934 this.baseScale = width / this.imageEl.OriginWidth;
27936 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27937 height = this.thumbEl.getHeight();
27938 this.baseScale = height / this.imageEl.OriginHeight;
27941 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27943 height = this.thumbEl.getHeight();
27944 this.baseScale = height / this.imageEl.OriginHeight;
27946 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27947 width = this.thumbEl.getWidth();
27948 this.baseScale = width / this.imageEl.OriginWidth;
27956 getScaleLevel : function()
27958 return this.baseScale * Math.pow(1.1, this.scale);
27961 onTouchStart : function(e)
27963 if(!this.canvasLoaded){
27964 this.beforeSelectFile(e);
27968 var touches = e.browserEvent.touches;
27974 if(touches.length == 1){
27975 this.onMouseDown(e);
27979 if(touches.length != 2){
27985 for(var i = 0, finger; finger = touches[i]; i++){
27986 coords.push(finger.pageX, finger.pageY);
27989 var x = Math.pow(coords[0] - coords[2], 2);
27990 var y = Math.pow(coords[1] - coords[3], 2);
27992 this.startDistance = Math.sqrt(x + y);
27994 this.startScale = this.scale;
27996 this.pinching = true;
27997 this.dragable = false;
28001 onTouchMove : function(e)
28003 if(!this.pinching && !this.dragable){
28007 var touches = e.browserEvent.touches;
28014 this.onMouseMove(e);
28020 for(var i = 0, finger; finger = touches[i]; i++){
28021 coords.push(finger.pageX, finger.pageY);
28024 var x = Math.pow(coords[0] - coords[2], 2);
28025 var y = Math.pow(coords[1] - coords[3], 2);
28027 this.endDistance = Math.sqrt(x + y);
28029 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28031 if(!this.zoomable()){
28032 this.scale = this.startScale;
28040 onTouchEnd : function(e)
28042 this.pinching = false;
28043 this.dragable = false;
28047 process : function(file, crop)
28050 this.maskEl.mask(this.loadingText);
28053 this.xhr = new XMLHttpRequest();
28055 file.xhr = this.xhr;
28057 this.xhr.open(this.method, this.url, true);
28060 "Accept": "application/json",
28061 "Cache-Control": "no-cache",
28062 "X-Requested-With": "XMLHttpRequest"
28065 for (var headerName in headers) {
28066 var headerValue = headers[headerName];
28068 this.xhr.setRequestHeader(headerName, headerValue);
28074 this.xhr.onload = function()
28076 _this.xhrOnLoad(_this.xhr);
28079 this.xhr.onerror = function()
28081 _this.xhrOnError(_this.xhr);
28084 var formData = new FormData();
28086 formData.append('returnHTML', 'NO');
28089 formData.append('crop', crop);
28092 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28093 formData.append(this.paramName, file, file.name);
28096 if(typeof(file.filename) != 'undefined'){
28097 formData.append('filename', file.filename);
28100 if(typeof(file.mimetype) != 'undefined'){
28101 formData.append('mimetype', file.mimetype);
28104 if(this.fireEvent('arrange', this, formData) != false){
28105 this.xhr.send(formData);
28109 xhrOnLoad : function(xhr)
28112 this.maskEl.unmask();
28115 if (xhr.readyState !== 4) {
28116 this.fireEvent('exception', this, xhr);
28120 var response = Roo.decode(xhr.responseText);
28122 if(!response.success){
28123 this.fireEvent('exception', this, xhr);
28127 var response = Roo.decode(xhr.responseText);
28129 this.fireEvent('upload', this, response);
28133 xhrOnError : function()
28136 this.maskEl.unmask();
28139 Roo.log('xhr on error');
28141 var response = Roo.decode(xhr.responseText);
28147 prepare : function(file)
28150 this.maskEl.mask(this.loadingText);
28156 if(typeof(file) === 'string'){
28157 this.loadCanvas(file);
28161 if(!file || !this.urlAPI){
28166 this.cropType = file.type;
28170 if(this.fireEvent('prepare', this, this.file) != false){
28172 var reader = new FileReader();
28174 reader.onload = function (e) {
28175 if (e.target.error) {
28176 Roo.log(e.target.error);
28180 var buffer = e.target.result,
28181 dataView = new DataView(buffer),
28183 maxOffset = dataView.byteLength - 4,
28187 if (dataView.getUint16(0) === 0xffd8) {
28188 while (offset < maxOffset) {
28189 markerBytes = dataView.getUint16(offset);
28191 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28192 markerLength = dataView.getUint16(offset + 2) + 2;
28193 if (offset + markerLength > dataView.byteLength) {
28194 Roo.log('Invalid meta data: Invalid segment size.');
28198 if(markerBytes == 0xffe1){
28199 _this.parseExifData(
28206 offset += markerLength;
28216 var url = _this.urlAPI.createObjectURL(_this.file);
28218 _this.loadCanvas(url);
28223 reader.readAsArrayBuffer(this.file);
28229 parseExifData : function(dataView, offset, length)
28231 var tiffOffset = offset + 10,
28235 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28236 // No Exif data, might be XMP data instead
28240 // Check for the ASCII code for "Exif" (0x45786966):
28241 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28242 // No Exif data, might be XMP data instead
28245 if (tiffOffset + 8 > dataView.byteLength) {
28246 Roo.log('Invalid Exif data: Invalid segment size.');
28249 // Check for the two null bytes:
28250 if (dataView.getUint16(offset + 8) !== 0x0000) {
28251 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28254 // Check the byte alignment:
28255 switch (dataView.getUint16(tiffOffset)) {
28257 littleEndian = true;
28260 littleEndian = false;
28263 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28266 // Check for the TIFF tag marker (0x002A):
28267 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28268 Roo.log('Invalid Exif data: Missing TIFF marker.');
28271 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28272 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28274 this.parseExifTags(
28277 tiffOffset + dirOffset,
28282 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28287 if (dirOffset + 6 > dataView.byteLength) {
28288 Roo.log('Invalid Exif data: Invalid directory offset.');
28291 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28292 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28293 if (dirEndOffset + 4 > dataView.byteLength) {
28294 Roo.log('Invalid Exif data: Invalid directory size.');
28297 for (i = 0; i < tagsNumber; i += 1) {
28301 dirOffset + 2 + 12 * i, // tag offset
28305 // Return the offset to the next directory:
28306 return dataView.getUint32(dirEndOffset, littleEndian);
28309 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28311 var tag = dataView.getUint16(offset, littleEndian);
28313 this.exif[tag] = this.getExifValue(
28317 dataView.getUint16(offset + 2, littleEndian), // tag type
28318 dataView.getUint32(offset + 4, littleEndian), // tag length
28323 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28325 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28334 Roo.log('Invalid Exif data: Invalid tag type.');
28338 tagSize = tagType.size * length;
28339 // Determine if the value is contained in the dataOffset bytes,
28340 // or if the value at the dataOffset is a pointer to the actual data:
28341 dataOffset = tagSize > 4 ?
28342 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28343 if (dataOffset + tagSize > dataView.byteLength) {
28344 Roo.log('Invalid Exif data: Invalid data offset.');
28347 if (length === 1) {
28348 return tagType.getValue(dataView, dataOffset, littleEndian);
28351 for (i = 0; i < length; i += 1) {
28352 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28355 if (tagType.ascii) {
28357 // Concatenate the chars:
28358 for (i = 0; i < values.length; i += 1) {
28360 // Ignore the terminating NULL byte(s):
28361 if (c === '\u0000') {
28373 Roo.apply(Roo.bootstrap.UploadCropbox, {
28375 'Orientation': 0x0112
28379 1: 0, //'top-left',
28381 3: 180, //'bottom-right',
28382 // 4: 'bottom-left',
28384 6: 90, //'right-top',
28385 // 7: 'right-bottom',
28386 8: 270 //'left-bottom'
28390 // byte, 8-bit unsigned int:
28392 getValue: function (dataView, dataOffset) {
28393 return dataView.getUint8(dataOffset);
28397 // ascii, 8-bit byte:
28399 getValue: function (dataView, dataOffset) {
28400 return String.fromCharCode(dataView.getUint8(dataOffset));
28405 // short, 16 bit int:
28407 getValue: function (dataView, dataOffset, littleEndian) {
28408 return dataView.getUint16(dataOffset, littleEndian);
28412 // long, 32 bit int:
28414 getValue: function (dataView, dataOffset, littleEndian) {
28415 return dataView.getUint32(dataOffset, littleEndian);
28419 // rational = two long values, first is numerator, second is denominator:
28421 getValue: function (dataView, dataOffset, littleEndian) {
28422 return dataView.getUint32(dataOffset, littleEndian) /
28423 dataView.getUint32(dataOffset + 4, littleEndian);
28427 // slong, 32 bit signed int:
28429 getValue: function (dataView, dataOffset, littleEndian) {
28430 return dataView.getInt32(dataOffset, littleEndian);
28434 // srational, two slongs, first is numerator, second is denominator:
28436 getValue: function (dataView, dataOffset, littleEndian) {
28437 return dataView.getInt32(dataOffset, littleEndian) /
28438 dataView.getInt32(dataOffset + 4, littleEndian);
28448 cls : 'btn-group roo-upload-cropbox-rotate-left',
28449 action : 'rotate-left',
28453 cls : 'btn btn-default',
28454 html : '<i class="fa fa-undo"></i>'
28460 cls : 'btn-group roo-upload-cropbox-picture',
28461 action : 'picture',
28465 cls : 'btn btn-default',
28466 html : '<i class="fa fa-picture-o"></i>'
28472 cls : 'btn-group roo-upload-cropbox-rotate-right',
28473 action : 'rotate-right',
28477 cls : 'btn btn-default',
28478 html : '<i class="fa fa-repeat"></i>'
28486 cls : 'btn-group roo-upload-cropbox-rotate-left',
28487 action : 'rotate-left',
28491 cls : 'btn btn-default',
28492 html : '<i class="fa fa-undo"></i>'
28498 cls : 'btn-group roo-upload-cropbox-download',
28499 action : 'download',
28503 cls : 'btn btn-default',
28504 html : '<i class="fa fa-download"></i>'
28510 cls : 'btn-group roo-upload-cropbox-crop',
28515 cls : 'btn btn-default',
28516 html : '<i class="fa fa-crop"></i>'
28522 cls : 'btn-group roo-upload-cropbox-trash',
28527 cls : 'btn btn-default',
28528 html : '<i class="fa fa-trash"></i>'
28534 cls : 'btn-group roo-upload-cropbox-rotate-right',
28535 action : 'rotate-right',
28539 cls : 'btn btn-default',
28540 html : '<i class="fa fa-repeat"></i>'
28548 cls : 'btn-group roo-upload-cropbox-rotate-left',
28549 action : 'rotate-left',
28553 cls : 'btn btn-default',
28554 html : '<i class="fa fa-undo"></i>'
28560 cls : 'btn-group roo-upload-cropbox-rotate-right',
28561 action : 'rotate-right',
28565 cls : 'btn btn-default',
28566 html : '<i class="fa fa-repeat"></i>'
28579 * @class Roo.bootstrap.DocumentManager
28580 * @extends Roo.bootstrap.Component
28581 * Bootstrap DocumentManager class
28582 * @cfg {String} paramName default 'imageUpload'
28583 * @cfg {String} toolTipName default 'filename'
28584 * @cfg {String} method default POST
28585 * @cfg {String} url action url
28586 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28587 * @cfg {Boolean} multiple multiple upload default true
28588 * @cfg {Number} thumbSize default 300
28589 * @cfg {String} fieldLabel
28590 * @cfg {Number} labelWidth default 4
28591 * @cfg {String} labelAlign (left|top) default left
28592 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28593 * @cfg {Number} labellg set the width of label (1-12)
28594 * @cfg {Number} labelmd set the width of label (1-12)
28595 * @cfg {Number} labelsm set the width of label (1-12)
28596 * @cfg {Number} labelxs set the width of label (1-12)
28599 * Create a new DocumentManager
28600 * @param {Object} config The config object
28603 Roo.bootstrap.DocumentManager = function(config){
28604 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28607 this.delegates = [];
28612 * Fire when initial the DocumentManager
28613 * @param {Roo.bootstrap.DocumentManager} this
28618 * inspect selected file
28619 * @param {Roo.bootstrap.DocumentManager} this
28620 * @param {File} file
28625 * Fire when xhr load exception
28626 * @param {Roo.bootstrap.DocumentManager} this
28627 * @param {XMLHttpRequest} xhr
28629 "exception" : true,
28631 * @event afterupload
28632 * Fire when xhr load exception
28633 * @param {Roo.bootstrap.DocumentManager} this
28634 * @param {XMLHttpRequest} xhr
28636 "afterupload" : true,
28639 * prepare the form data
28640 * @param {Roo.bootstrap.DocumentManager} this
28641 * @param {Object} formData
28646 * Fire when remove the file
28647 * @param {Roo.bootstrap.DocumentManager} this
28648 * @param {Object} file
28653 * Fire after refresh the file
28654 * @param {Roo.bootstrap.DocumentManager} this
28659 * Fire after click the image
28660 * @param {Roo.bootstrap.DocumentManager} this
28661 * @param {Object} file
28666 * Fire when upload a image and editable set to true
28667 * @param {Roo.bootstrap.DocumentManager} this
28668 * @param {Object} file
28672 * @event beforeselectfile
28673 * Fire before select file
28674 * @param {Roo.bootstrap.DocumentManager} this
28676 "beforeselectfile" : true,
28679 * Fire before process file
28680 * @param {Roo.bootstrap.DocumentManager} this
28681 * @param {Object} file
28685 * @event previewrendered
28686 * Fire when preview rendered
28687 * @param {Roo.bootstrap.DocumentManager} this
28688 * @param {Object} file
28690 "previewrendered" : true
28695 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28704 paramName : 'imageUpload',
28705 toolTipName : 'filename',
28708 labelAlign : 'left',
28718 getAutoCreate : function()
28720 var managerWidget = {
28722 cls : 'roo-document-manager',
28726 cls : 'roo-document-manager-selector',
28731 cls : 'roo-document-manager-uploader',
28735 cls : 'roo-document-manager-upload-btn',
28736 html : '<i class="fa fa-plus"></i>'
28747 cls : 'column col-md-12',
28752 if(this.fieldLabel.length){
28757 cls : 'column col-md-12',
28758 html : this.fieldLabel
28762 cls : 'column col-md-12',
28767 if(this.labelAlign == 'left'){
28772 html : this.fieldLabel
28781 if(this.labelWidth > 12){
28782 content[0].style = "width: " + this.labelWidth + 'px';
28785 if(this.labelWidth < 13 && this.labelmd == 0){
28786 this.labelmd = this.labelWidth;
28789 if(this.labellg > 0){
28790 content[0].cls += ' col-lg-' + this.labellg;
28791 content[1].cls += ' col-lg-' + (12 - this.labellg);
28794 if(this.labelmd > 0){
28795 content[0].cls += ' col-md-' + this.labelmd;
28796 content[1].cls += ' col-md-' + (12 - this.labelmd);
28799 if(this.labelsm > 0){
28800 content[0].cls += ' col-sm-' + this.labelsm;
28801 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28804 if(this.labelxs > 0){
28805 content[0].cls += ' col-xs-' + this.labelxs;
28806 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28814 cls : 'row clearfix',
28822 initEvents : function()
28824 this.managerEl = this.el.select('.roo-document-manager', true).first();
28825 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28827 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28828 this.selectorEl.hide();
28831 this.selectorEl.attr('multiple', 'multiple');
28834 this.selectorEl.on('change', this.onFileSelected, this);
28836 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28837 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28839 this.uploader.on('click', this.onUploaderClick, this);
28841 this.renderProgressDialog();
28845 window.addEventListener("resize", function() { _this.refresh(); } );
28847 this.fireEvent('initial', this);
28850 renderProgressDialog : function()
28854 this.progressDialog = new Roo.bootstrap.Modal({
28855 cls : 'roo-document-manager-progress-dialog',
28856 allow_close : false,
28866 btnclick : function() {
28867 _this.uploadCancel();
28873 this.progressDialog.render(Roo.get(document.body));
28875 this.progress = new Roo.bootstrap.Progress({
28876 cls : 'roo-document-manager-progress',
28881 this.progress.render(this.progressDialog.getChildContainer());
28883 this.progressBar = new Roo.bootstrap.ProgressBar({
28884 cls : 'roo-document-manager-progress-bar',
28887 aria_valuemax : 12,
28891 this.progressBar.render(this.progress.getChildContainer());
28894 onUploaderClick : function(e)
28896 e.preventDefault();
28898 if(this.fireEvent('beforeselectfile', this) != false){
28899 this.selectorEl.dom.click();
28904 onFileSelected : function(e)
28906 e.preventDefault();
28908 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28912 Roo.each(this.selectorEl.dom.files, function(file){
28913 if(this.fireEvent('inspect', this, file) != false){
28914 this.files.push(file);
28924 this.selectorEl.dom.value = '';
28926 if(!this.files || !this.files.length){
28930 if(this.boxes > 0 && this.files.length > this.boxes){
28931 this.files = this.files.slice(0, this.boxes);
28934 this.uploader.show();
28936 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28937 this.uploader.hide();
28946 Roo.each(this.files, function(file){
28948 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28949 var f = this.renderPreview(file);
28954 if(file.type.indexOf('image') != -1){
28955 this.delegates.push(
28957 _this.process(file);
28958 }).createDelegate(this)
28966 _this.process(file);
28967 }).createDelegate(this)
28972 this.files = files;
28974 this.delegates = this.delegates.concat(docs);
28976 if(!this.delegates.length){
28981 this.progressBar.aria_valuemax = this.delegates.length;
28988 arrange : function()
28990 if(!this.delegates.length){
28991 this.progressDialog.hide();
28996 var delegate = this.delegates.shift();
28998 this.progressDialog.show();
29000 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29002 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29007 refresh : function()
29009 this.uploader.show();
29011 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29012 this.uploader.hide();
29015 Roo.isTouch ? this.closable(false) : this.closable(true);
29017 this.fireEvent('refresh', this);
29020 onRemove : function(e, el, o)
29022 e.preventDefault();
29024 this.fireEvent('remove', this, o);
29028 remove : function(o)
29032 Roo.each(this.files, function(file){
29033 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29042 this.files = files;
29049 Roo.each(this.files, function(file){
29054 file.target.remove();
29063 onClick : function(e, el, o)
29065 e.preventDefault();
29067 this.fireEvent('click', this, o);
29071 closable : function(closable)
29073 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29075 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29087 xhrOnLoad : function(xhr)
29089 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29093 if (xhr.readyState !== 4) {
29095 this.fireEvent('exception', this, xhr);
29099 var response = Roo.decode(xhr.responseText);
29101 if(!response.success){
29103 this.fireEvent('exception', this, xhr);
29107 var file = this.renderPreview(response.data);
29109 this.files.push(file);
29113 this.fireEvent('afterupload', this, xhr);
29117 xhrOnError : function(xhr)
29119 Roo.log('xhr on error');
29121 var response = Roo.decode(xhr.responseText);
29128 process : function(file)
29130 if(this.fireEvent('process', this, file) !== false){
29131 if(this.editable && file.type.indexOf('image') != -1){
29132 this.fireEvent('edit', this, file);
29136 this.uploadStart(file, false);
29143 uploadStart : function(file, crop)
29145 this.xhr = new XMLHttpRequest();
29147 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29152 file.xhr = this.xhr;
29154 this.managerEl.createChild({
29156 cls : 'roo-document-manager-loading',
29160 tooltip : file.name,
29161 cls : 'roo-document-manager-thumb',
29162 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29168 this.xhr.open(this.method, this.url, true);
29171 "Accept": "application/json",
29172 "Cache-Control": "no-cache",
29173 "X-Requested-With": "XMLHttpRequest"
29176 for (var headerName in headers) {
29177 var headerValue = headers[headerName];
29179 this.xhr.setRequestHeader(headerName, headerValue);
29185 this.xhr.onload = function()
29187 _this.xhrOnLoad(_this.xhr);
29190 this.xhr.onerror = function()
29192 _this.xhrOnError(_this.xhr);
29195 var formData = new FormData();
29197 formData.append('returnHTML', 'NO');
29200 formData.append('crop', crop);
29203 formData.append(this.paramName, file, file.name);
29210 if(this.fireEvent('prepare', this, formData, options) != false){
29212 if(options.manually){
29216 this.xhr.send(formData);
29220 this.uploadCancel();
29223 uploadCancel : function()
29229 this.delegates = [];
29231 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29238 renderPreview : function(file)
29240 if(typeof(file.target) != 'undefined' && file.target){
29244 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29246 var previewEl = this.managerEl.createChild({
29248 cls : 'roo-document-manager-preview',
29252 tooltip : file[this.toolTipName],
29253 cls : 'roo-document-manager-thumb',
29254 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29259 html : '<i class="fa fa-times-circle"></i>'
29264 var close = previewEl.select('button.close', true).first();
29266 close.on('click', this.onRemove, this, file);
29268 file.target = previewEl;
29270 var image = previewEl.select('img', true).first();
29274 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29276 image.on('click', this.onClick, this, file);
29278 this.fireEvent('previewrendered', this, file);
29284 onPreviewLoad : function(file, image)
29286 if(typeof(file.target) == 'undefined' || !file.target){
29290 var width = image.dom.naturalWidth || image.dom.width;
29291 var height = image.dom.naturalHeight || image.dom.height;
29293 if(width > height){
29294 file.target.addClass('wide');
29298 file.target.addClass('tall');
29303 uploadFromSource : function(file, crop)
29305 this.xhr = new XMLHttpRequest();
29307 this.managerEl.createChild({
29309 cls : 'roo-document-manager-loading',
29313 tooltip : file.name,
29314 cls : 'roo-document-manager-thumb',
29315 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29321 this.xhr.open(this.method, this.url, true);
29324 "Accept": "application/json",
29325 "Cache-Control": "no-cache",
29326 "X-Requested-With": "XMLHttpRequest"
29329 for (var headerName in headers) {
29330 var headerValue = headers[headerName];
29332 this.xhr.setRequestHeader(headerName, headerValue);
29338 this.xhr.onload = function()
29340 _this.xhrOnLoad(_this.xhr);
29343 this.xhr.onerror = function()
29345 _this.xhrOnError(_this.xhr);
29348 var formData = new FormData();
29350 formData.append('returnHTML', 'NO');
29352 formData.append('crop', crop);
29354 if(typeof(file.filename) != 'undefined'){
29355 formData.append('filename', file.filename);
29358 if(typeof(file.mimetype) != 'undefined'){
29359 formData.append('mimetype', file.mimetype);
29364 if(this.fireEvent('prepare', this, formData) != false){
29365 this.xhr.send(formData);
29375 * @class Roo.bootstrap.DocumentViewer
29376 * @extends Roo.bootstrap.Component
29377 * Bootstrap DocumentViewer class
29378 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29379 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29382 * Create a new DocumentViewer
29383 * @param {Object} config The config object
29386 Roo.bootstrap.DocumentViewer = function(config){
29387 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29392 * Fire after initEvent
29393 * @param {Roo.bootstrap.DocumentViewer} this
29399 * @param {Roo.bootstrap.DocumentViewer} this
29404 * Fire after download button
29405 * @param {Roo.bootstrap.DocumentViewer} this
29410 * Fire after trash button
29411 * @param {Roo.bootstrap.DocumentViewer} this
29418 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29420 showDownload : true,
29424 getAutoCreate : function()
29428 cls : 'roo-document-viewer',
29432 cls : 'roo-document-viewer-body',
29436 cls : 'roo-document-viewer-thumb',
29440 cls : 'roo-document-viewer-image'
29448 cls : 'roo-document-viewer-footer',
29451 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29455 cls : 'btn-group roo-document-viewer-download',
29459 cls : 'btn btn-default',
29460 html : '<i class="fa fa-download"></i>'
29466 cls : 'btn-group roo-document-viewer-trash',
29470 cls : 'btn btn-default',
29471 html : '<i class="fa fa-trash"></i>'
29484 initEvents : function()
29486 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29487 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29489 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29490 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29492 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29493 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29495 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29496 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29498 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29499 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29501 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29502 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29504 this.bodyEl.on('click', this.onClick, this);
29505 this.downloadBtn.on('click', this.onDownload, this);
29506 this.trashBtn.on('click', this.onTrash, this);
29508 this.downloadBtn.hide();
29509 this.trashBtn.hide();
29511 if(this.showDownload){
29512 this.downloadBtn.show();
29515 if(this.showTrash){
29516 this.trashBtn.show();
29519 if(!this.showDownload && !this.showTrash) {
29520 this.footerEl.hide();
29525 initial : function()
29527 this.fireEvent('initial', this);
29531 onClick : function(e)
29533 e.preventDefault();
29535 this.fireEvent('click', this);
29538 onDownload : function(e)
29540 e.preventDefault();
29542 this.fireEvent('download', this);
29545 onTrash : function(e)
29547 e.preventDefault();
29549 this.fireEvent('trash', this);
29561 * @class Roo.bootstrap.NavProgressBar
29562 * @extends Roo.bootstrap.Component
29563 * Bootstrap NavProgressBar class
29566 * Create a new nav progress bar
29567 * @param {Object} config The config object
29570 Roo.bootstrap.NavProgressBar = function(config){
29571 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29573 this.bullets = this.bullets || [];
29575 // Roo.bootstrap.NavProgressBar.register(this);
29579 * Fires when the active item changes
29580 * @param {Roo.bootstrap.NavProgressBar} this
29581 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29582 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29589 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29594 getAutoCreate : function()
29596 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29600 cls : 'roo-navigation-bar-group',
29604 cls : 'roo-navigation-top-bar'
29608 cls : 'roo-navigation-bullets-bar',
29612 cls : 'roo-navigation-bar'
29619 cls : 'roo-navigation-bottom-bar'
29629 initEvents: function()
29634 onRender : function(ct, position)
29636 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29638 if(this.bullets.length){
29639 Roo.each(this.bullets, function(b){
29648 addItem : function(cfg)
29650 var item = new Roo.bootstrap.NavProgressItem(cfg);
29652 item.parentId = this.id;
29653 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29656 var top = new Roo.bootstrap.Element({
29658 cls : 'roo-navigation-bar-text'
29661 var bottom = new Roo.bootstrap.Element({
29663 cls : 'roo-navigation-bar-text'
29666 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29667 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29669 var topText = new Roo.bootstrap.Element({
29671 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29674 var bottomText = new Roo.bootstrap.Element({
29676 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29679 topText.onRender(top.el, null);
29680 bottomText.onRender(bottom.el, null);
29683 item.bottomEl = bottom;
29686 this.barItems.push(item);
29691 getActive : function()
29693 var active = false;
29695 Roo.each(this.barItems, function(v){
29697 if (!v.isActive()) {
29709 setActiveItem : function(item)
29713 Roo.each(this.barItems, function(v){
29714 if (v.rid == item.rid) {
29718 if (v.isActive()) {
29719 v.setActive(false);
29724 item.setActive(true);
29726 this.fireEvent('changed', this, item, prev);
29729 getBarItem: function(rid)
29733 Roo.each(this.barItems, function(e) {
29734 if (e.rid != rid) {
29745 indexOfItem : function(item)
29749 Roo.each(this.barItems, function(v, i){
29751 if (v.rid != item.rid) {
29762 setActiveNext : function()
29764 var i = this.indexOfItem(this.getActive());
29766 if (i > this.barItems.length) {
29770 this.setActiveItem(this.barItems[i+1]);
29773 setActivePrev : function()
29775 var i = this.indexOfItem(this.getActive());
29781 this.setActiveItem(this.barItems[i-1]);
29784 format : function()
29786 if(!this.barItems.length){
29790 var width = 100 / this.barItems.length;
29792 Roo.each(this.barItems, function(i){
29793 i.el.setStyle('width', width + '%');
29794 i.topEl.el.setStyle('width', width + '%');
29795 i.bottomEl.el.setStyle('width', width + '%');
29804 * Nav Progress Item
29809 * @class Roo.bootstrap.NavProgressItem
29810 * @extends Roo.bootstrap.Component
29811 * Bootstrap NavProgressItem class
29812 * @cfg {String} rid the reference id
29813 * @cfg {Boolean} active (true|false) Is item active default false
29814 * @cfg {Boolean} disabled (true|false) Is item active default false
29815 * @cfg {String} html
29816 * @cfg {String} position (top|bottom) text position default bottom
29817 * @cfg {String} icon show icon instead of number
29820 * Create a new NavProgressItem
29821 * @param {Object} config The config object
29823 Roo.bootstrap.NavProgressItem = function(config){
29824 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29829 * The raw click event for the entire grid.
29830 * @param {Roo.bootstrap.NavProgressItem} this
29831 * @param {Roo.EventObject} e
29838 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29844 position : 'bottom',
29847 getAutoCreate : function()
29849 var iconCls = 'roo-navigation-bar-item-icon';
29851 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29855 cls: 'roo-navigation-bar-item',
29865 cfg.cls += ' active';
29868 cfg.cls += ' disabled';
29874 disable : function()
29876 this.setDisabled(true);
29879 enable : function()
29881 this.setDisabled(false);
29884 initEvents: function()
29886 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29888 this.iconEl.on('click', this.onClick, this);
29891 onClick : function(e)
29893 e.preventDefault();
29899 if(this.fireEvent('click', this, e) === false){
29903 this.parent().setActiveItem(this);
29906 isActive: function ()
29908 return this.active;
29911 setActive : function(state)
29913 if(this.active == state){
29917 this.active = state;
29920 this.el.addClass('active');
29924 this.el.removeClass('active');
29929 setDisabled : function(state)
29931 if(this.disabled == state){
29935 this.disabled = state;
29938 this.el.addClass('disabled');
29942 this.el.removeClass('disabled');
29945 tooltipEl : function()
29947 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29960 * @class Roo.bootstrap.FieldLabel
29961 * @extends Roo.bootstrap.Component
29962 * Bootstrap FieldLabel class
29963 * @cfg {String} html contents of the element
29964 * @cfg {String} tag tag of the element default label
29965 * @cfg {String} cls class of the element
29966 * @cfg {String} target label target
29967 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29968 * @cfg {String} invalidClass default "text-warning"
29969 * @cfg {String} validClass default "text-success"
29970 * @cfg {String} iconTooltip default "This field is required"
29971 * @cfg {String} indicatorpos (left|right) default left
29974 * Create a new FieldLabel
29975 * @param {Object} config The config object
29978 Roo.bootstrap.FieldLabel = function(config){
29979 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29984 * Fires after the field has been marked as invalid.
29985 * @param {Roo.form.FieldLabel} this
29986 * @param {String} msg The validation message
29991 * Fires after the field has been validated with no errors.
29992 * @param {Roo.form.FieldLabel} this
29998 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30005 invalidClass : 'has-warning',
30006 validClass : 'has-success',
30007 iconTooltip : 'This field is required',
30008 indicatorpos : 'left',
30010 getAutoCreate : function(){
30014 cls : 'roo-bootstrap-field-label ' + this.cls,
30019 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30020 tooltip : this.iconTooltip
30029 if(this.indicatorpos == 'right'){
30032 cls : 'roo-bootstrap-field-label ' + this.cls,
30041 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30042 tooltip : this.iconTooltip
30051 initEvents: function()
30053 Roo.bootstrap.Element.superclass.initEvents.call(this);
30055 this.indicator = this.indicatorEl();
30057 if(this.indicator){
30058 this.indicator.removeClass('visible');
30059 this.indicator.addClass('invisible');
30062 Roo.bootstrap.FieldLabel.register(this);
30065 indicatorEl : function()
30067 var indicator = this.el.select('i.roo-required-indicator',true).first();
30078 * Mark this field as valid
30080 markValid : function()
30082 if(this.indicator){
30083 this.indicator.removeClass('visible');
30084 this.indicator.addClass('invisible');
30087 this.el.removeClass(this.invalidClass);
30089 this.el.addClass(this.validClass);
30091 this.fireEvent('valid', this);
30095 * Mark this field as invalid
30096 * @param {String} msg The validation message
30098 markInvalid : function(msg)
30100 if(this.indicator){
30101 this.indicator.removeClass('invisible');
30102 this.indicator.addClass('visible');
30105 this.el.removeClass(this.validClass);
30107 this.el.addClass(this.invalidClass);
30109 this.fireEvent('invalid', this, msg);
30115 Roo.apply(Roo.bootstrap.FieldLabel, {
30120 * register a FieldLabel Group
30121 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30123 register : function(label)
30125 if(this.groups.hasOwnProperty(label.target)){
30129 this.groups[label.target] = label;
30133 * fetch a FieldLabel Group based on the target
30134 * @param {string} target
30135 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30137 get: function(target) {
30138 if (typeof(this.groups[target]) == 'undefined') {
30142 return this.groups[target] ;
30151 * page DateSplitField.
30157 * @class Roo.bootstrap.DateSplitField
30158 * @extends Roo.bootstrap.Component
30159 * Bootstrap DateSplitField class
30160 * @cfg {string} fieldLabel - the label associated
30161 * @cfg {Number} labelWidth set the width of label (0-12)
30162 * @cfg {String} labelAlign (top|left)
30163 * @cfg {Boolean} dayAllowBlank (true|false) default false
30164 * @cfg {Boolean} monthAllowBlank (true|false) default false
30165 * @cfg {Boolean} yearAllowBlank (true|false) default false
30166 * @cfg {string} dayPlaceholder
30167 * @cfg {string} monthPlaceholder
30168 * @cfg {string} yearPlaceholder
30169 * @cfg {string} dayFormat default 'd'
30170 * @cfg {string} monthFormat default 'm'
30171 * @cfg {string} yearFormat default 'Y'
30172 * @cfg {Number} labellg set the width of label (1-12)
30173 * @cfg {Number} labelmd set the width of label (1-12)
30174 * @cfg {Number} labelsm set the width of label (1-12)
30175 * @cfg {Number} labelxs set the width of label (1-12)
30179 * Create a new DateSplitField
30180 * @param {Object} config The config object
30183 Roo.bootstrap.DateSplitField = function(config){
30184 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30190 * getting the data of years
30191 * @param {Roo.bootstrap.DateSplitField} this
30192 * @param {Object} years
30197 * getting the data of days
30198 * @param {Roo.bootstrap.DateSplitField} this
30199 * @param {Object} days
30204 * Fires after the field has been marked as invalid.
30205 * @param {Roo.form.Field} this
30206 * @param {String} msg The validation message
30211 * Fires after the field has been validated with no errors.
30212 * @param {Roo.form.Field} this
30218 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30221 labelAlign : 'top',
30223 dayAllowBlank : false,
30224 monthAllowBlank : false,
30225 yearAllowBlank : false,
30226 dayPlaceholder : '',
30227 monthPlaceholder : '',
30228 yearPlaceholder : '',
30232 isFormField : true,
30238 getAutoCreate : function()
30242 cls : 'row roo-date-split-field-group',
30247 cls : 'form-hidden-field roo-date-split-field-group-value',
30253 var labelCls = 'col-md-12';
30254 var contentCls = 'col-md-4';
30256 if(this.fieldLabel){
30260 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30264 html : this.fieldLabel
30269 if(this.labelAlign == 'left'){
30271 if(this.labelWidth > 12){
30272 label.style = "width: " + this.labelWidth + 'px';
30275 if(this.labelWidth < 13 && this.labelmd == 0){
30276 this.labelmd = this.labelWidth;
30279 if(this.labellg > 0){
30280 labelCls = ' col-lg-' + this.labellg;
30281 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30284 if(this.labelmd > 0){
30285 labelCls = ' col-md-' + this.labelmd;
30286 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30289 if(this.labelsm > 0){
30290 labelCls = ' col-sm-' + this.labelsm;
30291 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30294 if(this.labelxs > 0){
30295 labelCls = ' col-xs-' + this.labelxs;
30296 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30300 label.cls += ' ' + labelCls;
30302 cfg.cn.push(label);
30305 Roo.each(['day', 'month', 'year'], function(t){
30308 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30315 inputEl: function ()
30317 return this.el.select('.roo-date-split-field-group-value', true).first();
30320 onRender : function(ct, position)
30324 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30326 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30328 this.dayField = new Roo.bootstrap.ComboBox({
30329 allowBlank : this.dayAllowBlank,
30330 alwaysQuery : true,
30331 displayField : 'value',
30334 forceSelection : true,
30336 placeholder : this.dayPlaceholder,
30337 selectOnFocus : true,
30338 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30339 triggerAction : 'all',
30341 valueField : 'value',
30342 store : new Roo.data.SimpleStore({
30343 data : (function() {
30345 _this.fireEvent('days', _this, days);
30348 fields : [ 'value' ]
30351 select : function (_self, record, index)
30353 _this.setValue(_this.getValue());
30358 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30360 this.monthField = new Roo.bootstrap.MonthField({
30361 after : '<i class=\"fa fa-calendar\"></i>',
30362 allowBlank : this.monthAllowBlank,
30363 placeholder : this.monthPlaceholder,
30366 render : function (_self)
30368 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30369 e.preventDefault();
30373 select : function (_self, oldvalue, newvalue)
30375 _this.setValue(_this.getValue());
30380 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30382 this.yearField = new Roo.bootstrap.ComboBox({
30383 allowBlank : this.yearAllowBlank,
30384 alwaysQuery : true,
30385 displayField : 'value',
30388 forceSelection : true,
30390 placeholder : this.yearPlaceholder,
30391 selectOnFocus : true,
30392 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30393 triggerAction : 'all',
30395 valueField : 'value',
30396 store : new Roo.data.SimpleStore({
30397 data : (function() {
30399 _this.fireEvent('years', _this, years);
30402 fields : [ 'value' ]
30405 select : function (_self, record, index)
30407 _this.setValue(_this.getValue());
30412 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30415 setValue : function(v, format)
30417 this.inputEl.dom.value = v;
30419 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30421 var d = Date.parseDate(v, f);
30428 this.setDay(d.format(this.dayFormat));
30429 this.setMonth(d.format(this.monthFormat));
30430 this.setYear(d.format(this.yearFormat));
30437 setDay : function(v)
30439 this.dayField.setValue(v);
30440 this.inputEl.dom.value = this.getValue();
30445 setMonth : function(v)
30447 this.monthField.setValue(v, true);
30448 this.inputEl.dom.value = this.getValue();
30453 setYear : function(v)
30455 this.yearField.setValue(v);
30456 this.inputEl.dom.value = this.getValue();
30461 getDay : function()
30463 return this.dayField.getValue();
30466 getMonth : function()
30468 return this.monthField.getValue();
30471 getYear : function()
30473 return this.yearField.getValue();
30476 getValue : function()
30478 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30480 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30490 this.inputEl.dom.value = '';
30495 validate : function()
30497 var d = this.dayField.validate();
30498 var m = this.monthField.validate();
30499 var y = this.yearField.validate();
30504 (!this.dayAllowBlank && !d) ||
30505 (!this.monthAllowBlank && !m) ||
30506 (!this.yearAllowBlank && !y)
30511 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30520 this.markInvalid();
30525 markValid : function()
30528 var label = this.el.select('label', true).first();
30529 var icon = this.el.select('i.fa-star', true).first();
30535 this.fireEvent('valid', this);
30539 * Mark this field as invalid
30540 * @param {String} msg The validation message
30542 markInvalid : function(msg)
30545 var label = this.el.select('label', true).first();
30546 var icon = this.el.select('i.fa-star', true).first();
30548 if(label && !icon){
30549 this.el.select('.roo-date-split-field-label', true).createChild({
30551 cls : 'text-danger fa fa-lg fa-star',
30552 tooltip : 'This field is required',
30553 style : 'margin-right:5px;'
30557 this.fireEvent('invalid', this, msg);
30560 clearInvalid : function()
30562 var label = this.el.select('label', true).first();
30563 var icon = this.el.select('i.fa-star', true).first();
30569 this.fireEvent('valid', this);
30572 getName: function()
30582 * http://masonry.desandro.com
30584 * The idea is to render all the bricks based on vertical width...
30586 * The original code extends 'outlayer' - we might need to use that....
30592 * @class Roo.bootstrap.LayoutMasonry
30593 * @extends Roo.bootstrap.Component
30594 * Bootstrap Layout Masonry class
30597 * Create a new Element
30598 * @param {Object} config The config object
30601 Roo.bootstrap.LayoutMasonry = function(config){
30603 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30607 Roo.bootstrap.LayoutMasonry.register(this);
30613 * Fire after layout the items
30614 * @param {Roo.bootstrap.LayoutMasonry} this
30615 * @param {Roo.EventObject} e
30622 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30625 * @cfg {Boolean} isLayoutInstant = no animation?
30627 isLayoutInstant : false, // needed?
30630 * @cfg {Number} boxWidth width of the columns
30635 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30640 * @cfg {Number} padWidth padding below box..
30645 * @cfg {Number} gutter gutter width..
30650 * @cfg {Number} maxCols maximum number of columns
30656 * @cfg {Boolean} isAutoInitial defalut true
30658 isAutoInitial : true,
30663 * @cfg {Boolean} isHorizontal defalut false
30665 isHorizontal : false,
30667 currentSize : null,
30673 bricks: null, //CompositeElement
30677 _isLayoutInited : false,
30679 // isAlternative : false, // only use for vertical layout...
30682 * @cfg {Number} alternativePadWidth padding below box..
30684 alternativePadWidth : 50,
30686 selectedBrick : [],
30688 getAutoCreate : function(){
30690 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30694 cls: 'blog-masonary-wrapper ' + this.cls,
30696 cls : 'mas-boxes masonary'
30703 getChildContainer: function( )
30705 if (this.boxesEl) {
30706 return this.boxesEl;
30709 this.boxesEl = this.el.select('.mas-boxes').first();
30711 return this.boxesEl;
30715 initEvents : function()
30719 if(this.isAutoInitial){
30720 Roo.log('hook children rendered');
30721 this.on('childrenrendered', function() {
30722 Roo.log('children rendered');
30728 initial : function()
30730 this.selectedBrick = [];
30732 this.currentSize = this.el.getBox(true);
30734 Roo.EventManager.onWindowResize(this.resize, this);
30736 if(!this.isAutoInitial){
30744 //this.layout.defer(500,this);
30748 resize : function()
30750 var cs = this.el.getBox(true);
30753 this.currentSize.width == cs.width &&
30754 this.currentSize.x == cs.x &&
30755 this.currentSize.height == cs.height &&
30756 this.currentSize.y == cs.y
30758 Roo.log("no change in with or X or Y");
30762 this.currentSize = cs;
30768 layout : function()
30770 this._resetLayout();
30772 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30774 this.layoutItems( isInstant );
30776 this._isLayoutInited = true;
30778 this.fireEvent('layout', this);
30782 _resetLayout : function()
30784 if(this.isHorizontal){
30785 this.horizontalMeasureColumns();
30789 this.verticalMeasureColumns();
30793 verticalMeasureColumns : function()
30795 this.getContainerWidth();
30797 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30798 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30802 var boxWidth = this.boxWidth + this.padWidth;
30804 if(this.containerWidth < this.boxWidth){
30805 boxWidth = this.containerWidth
30808 var containerWidth = this.containerWidth;
30810 var cols = Math.floor(containerWidth / boxWidth);
30812 this.cols = Math.max( cols, 1 );
30814 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30816 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30818 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30820 this.colWidth = boxWidth + avail - this.padWidth;
30822 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30823 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30826 horizontalMeasureColumns : function()
30828 this.getContainerWidth();
30830 var boxWidth = this.boxWidth;
30832 if(this.containerWidth < boxWidth){
30833 boxWidth = this.containerWidth;
30836 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30838 this.el.setHeight(boxWidth);
30842 getContainerWidth : function()
30844 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30847 layoutItems : function( isInstant )
30849 Roo.log(this.bricks);
30851 var items = Roo.apply([], this.bricks);
30853 if(this.isHorizontal){
30854 this._horizontalLayoutItems( items , isInstant );
30858 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30859 // this._verticalAlternativeLayoutItems( items , isInstant );
30863 this._verticalLayoutItems( items , isInstant );
30867 _verticalLayoutItems : function ( items , isInstant)
30869 if ( !items || !items.length ) {
30874 ['xs', 'xs', 'xs', 'tall'],
30875 ['xs', 'xs', 'tall'],
30876 ['xs', 'xs', 'sm'],
30877 ['xs', 'xs', 'xs'],
30883 ['sm', 'xs', 'xs'],
30887 ['tall', 'xs', 'xs', 'xs'],
30888 ['tall', 'xs', 'xs'],
30900 Roo.each(items, function(item, k){
30902 switch (item.size) {
30903 // these layouts take up a full box,
30914 boxes.push([item]);
30937 var filterPattern = function(box, length)
30945 var pattern = box.slice(0, length);
30949 Roo.each(pattern, function(i){
30950 format.push(i.size);
30953 Roo.each(standard, function(s){
30955 if(String(s) != String(format)){
30964 if(!match && length == 1){
30969 filterPattern(box, length - 1);
30973 queue.push(pattern);
30975 box = box.slice(length, box.length);
30977 filterPattern(box, 4);
30983 Roo.each(boxes, function(box, k){
30989 if(box.length == 1){
30994 filterPattern(box, 4);
30998 this._processVerticalLayoutQueue( queue, isInstant );
31002 // _verticalAlternativeLayoutItems : function( items , isInstant )
31004 // if ( !items || !items.length ) {
31008 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31012 _horizontalLayoutItems : function ( items , isInstant)
31014 if ( !items || !items.length || items.length < 3) {
31020 var eItems = items.slice(0, 3);
31022 items = items.slice(3, items.length);
31025 ['xs', 'xs', 'xs', 'wide'],
31026 ['xs', 'xs', 'wide'],
31027 ['xs', 'xs', 'sm'],
31028 ['xs', 'xs', 'xs'],
31034 ['sm', 'xs', 'xs'],
31038 ['wide', 'xs', 'xs', 'xs'],
31039 ['wide', 'xs', 'xs'],
31052 Roo.each(items, function(item, k){
31054 switch (item.size) {
31065 boxes.push([item]);
31089 var filterPattern = function(box, length)
31097 var pattern = box.slice(0, length);
31101 Roo.each(pattern, function(i){
31102 format.push(i.size);
31105 Roo.each(standard, function(s){
31107 if(String(s) != String(format)){
31116 if(!match && length == 1){
31121 filterPattern(box, length - 1);
31125 queue.push(pattern);
31127 box = box.slice(length, box.length);
31129 filterPattern(box, 4);
31135 Roo.each(boxes, function(box, k){
31141 if(box.length == 1){
31146 filterPattern(box, 4);
31153 var pos = this.el.getBox(true);
31157 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31159 var hit_end = false;
31161 Roo.each(queue, function(box){
31165 Roo.each(box, function(b){
31167 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31177 Roo.each(box, function(b){
31179 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31182 mx = Math.max(mx, b.x);
31186 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31190 Roo.each(box, function(b){
31192 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31206 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31209 /** Sets position of item in DOM
31210 * @param {Element} item
31211 * @param {Number} x - horizontal position
31212 * @param {Number} y - vertical position
31213 * @param {Boolean} isInstant - disables transitions
31215 _processVerticalLayoutQueue : function( queue, isInstant )
31217 var pos = this.el.getBox(true);
31222 for (var i = 0; i < this.cols; i++){
31226 Roo.each(queue, function(box, k){
31228 var col = k % this.cols;
31230 Roo.each(box, function(b,kk){
31232 b.el.position('absolute');
31234 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31235 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31237 if(b.size == 'md-left' || b.size == 'md-right'){
31238 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31239 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31242 b.el.setWidth(width);
31243 b.el.setHeight(height);
31245 b.el.select('iframe',true).setSize(width,height);
31249 for (var i = 0; i < this.cols; i++){
31251 if(maxY[i] < maxY[col]){
31256 col = Math.min(col, i);
31260 x = pos.x + col * (this.colWidth + this.padWidth);
31264 var positions = [];
31266 switch (box.length){
31268 positions = this.getVerticalOneBoxColPositions(x, y, box);
31271 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31274 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31277 positions = this.getVerticalFourBoxColPositions(x, y, box);
31283 Roo.each(box, function(b,kk){
31285 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31287 var sz = b.el.getSize();
31289 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31297 for (var i = 0; i < this.cols; i++){
31298 mY = Math.max(mY, maxY[i]);
31301 this.el.setHeight(mY - pos.y);
31305 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31307 // var pos = this.el.getBox(true);
31310 // var maxX = pos.right;
31312 // var maxHeight = 0;
31314 // Roo.each(items, function(item, k){
31318 // item.el.position('absolute');
31320 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31322 // item.el.setWidth(width);
31324 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31326 // item.el.setHeight(height);
31329 // item.el.setXY([x, y], isInstant ? false : true);
31331 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31334 // y = y + height + this.alternativePadWidth;
31336 // maxHeight = maxHeight + height + this.alternativePadWidth;
31340 // this.el.setHeight(maxHeight);
31344 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31346 var pos = this.el.getBox(true);
31351 var maxX = pos.right;
31353 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31355 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31357 Roo.each(queue, function(box, k){
31359 Roo.each(box, function(b, kk){
31361 b.el.position('absolute');
31363 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31364 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31366 if(b.size == 'md-left' || b.size == 'md-right'){
31367 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31368 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31371 b.el.setWidth(width);
31372 b.el.setHeight(height);
31380 var positions = [];
31382 switch (box.length){
31384 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31387 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31390 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31393 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31399 Roo.each(box, function(b,kk){
31401 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31403 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31411 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31413 Roo.each(eItems, function(b,k){
31415 b.size = (k == 0) ? 'sm' : 'xs';
31416 b.x = (k == 0) ? 2 : 1;
31417 b.y = (k == 0) ? 2 : 1;
31419 b.el.position('absolute');
31421 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31423 b.el.setWidth(width);
31425 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31427 b.el.setHeight(height);
31431 var positions = [];
31434 x : maxX - this.unitWidth * 2 - this.gutter,
31439 x : maxX - this.unitWidth,
31440 y : minY + (this.unitWidth + this.gutter) * 2
31444 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31448 Roo.each(eItems, function(b,k){
31450 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31456 getVerticalOneBoxColPositions : function(x, y, box)
31460 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31462 if(box[0].size == 'md-left'){
31466 if(box[0].size == 'md-right'){
31471 x : x + (this.unitWidth + this.gutter) * rand,
31478 getVerticalTwoBoxColPositions : function(x, y, box)
31482 if(box[0].size == 'xs'){
31486 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31490 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31504 x : x + (this.unitWidth + this.gutter) * 2,
31505 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31512 getVerticalThreeBoxColPositions : function(x, y, box)
31516 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31524 x : x + (this.unitWidth + this.gutter) * 1,
31529 x : x + (this.unitWidth + this.gutter) * 2,
31537 if(box[0].size == 'xs' && box[1].size == 'xs'){
31546 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31550 x : x + (this.unitWidth + this.gutter) * 1,
31564 x : x + (this.unitWidth + this.gutter) * 2,
31569 x : x + (this.unitWidth + this.gutter) * 2,
31570 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31577 getVerticalFourBoxColPositions : function(x, y, box)
31581 if(box[0].size == 'xs'){
31590 y : y + (this.unitHeight + this.gutter) * 1
31595 y : y + (this.unitHeight + this.gutter) * 2
31599 x : x + (this.unitWidth + this.gutter) * 1,
31613 x : x + (this.unitWidth + this.gutter) * 2,
31618 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31619 y : y + (this.unitHeight + this.gutter) * 1
31623 x : x + (this.unitWidth + this.gutter) * 2,
31624 y : y + (this.unitWidth + this.gutter) * 2
31631 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31635 if(box[0].size == 'md-left'){
31637 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31644 if(box[0].size == 'md-right'){
31646 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31647 y : minY + (this.unitWidth + this.gutter) * 1
31653 var rand = Math.floor(Math.random() * (4 - box[0].y));
31656 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31657 y : minY + (this.unitWidth + this.gutter) * rand
31664 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31668 if(box[0].size == 'xs'){
31671 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31676 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31677 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31685 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31690 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31691 y : minY + (this.unitWidth + this.gutter) * 2
31698 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31702 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31705 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31710 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31711 y : minY + (this.unitWidth + this.gutter) * 1
31715 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31716 y : minY + (this.unitWidth + this.gutter) * 2
31723 if(box[0].size == 'xs' && box[1].size == 'xs'){
31726 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31731 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31736 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31737 y : minY + (this.unitWidth + this.gutter) * 1
31745 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31750 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31751 y : minY + (this.unitWidth + this.gutter) * 2
31755 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31756 y : minY + (this.unitWidth + this.gutter) * 2
31763 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31767 if(box[0].size == 'xs'){
31770 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31775 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31780 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),
31785 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31786 y : minY + (this.unitWidth + this.gutter) * 1
31794 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31799 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31800 y : minY + (this.unitWidth + this.gutter) * 2
31804 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31805 y : minY + (this.unitWidth + this.gutter) * 2
31809 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),
31810 y : minY + (this.unitWidth + this.gutter) * 2
31818 * remove a Masonry Brick
31819 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31821 removeBrick : function(brick_id)
31827 for (var i = 0; i<this.bricks.length; i++) {
31828 if (this.bricks[i].id == brick_id) {
31829 this.bricks.splice(i,1);
31830 this.el.dom.removeChild(Roo.get(brick_id).dom);
31837 * adds a Masonry Brick
31838 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31840 addBrick : function(cfg)
31842 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31843 //this.register(cn);
31844 cn.parentId = this.id;
31845 cn.onRender(this.el, null);
31850 * register a Masonry Brick
31851 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31854 register : function(brick)
31856 this.bricks.push(brick);
31857 brick.masonryId = this.id;
31861 * clear all the Masonry Brick
31863 clearAll : function()
31866 //this.getChildContainer().dom.innerHTML = "";
31867 this.el.dom.innerHTML = '';
31870 getSelected : function()
31872 if (!this.selectedBrick) {
31876 return this.selectedBrick;
31880 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31884 * register a Masonry Layout
31885 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31888 register : function(layout)
31890 this.groups[layout.id] = layout;
31893 * fetch a Masonry Layout based on the masonry layout ID
31894 * @param {string} the masonry layout to add
31895 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31898 get: function(layout_id) {
31899 if (typeof(this.groups[layout_id]) == 'undefined') {
31902 return this.groups[layout_id] ;
31914 * http://masonry.desandro.com
31916 * The idea is to render all the bricks based on vertical width...
31918 * The original code extends 'outlayer' - we might need to use that....
31924 * @class Roo.bootstrap.LayoutMasonryAuto
31925 * @extends Roo.bootstrap.Component
31926 * Bootstrap Layout Masonry class
31929 * Create a new Element
31930 * @param {Object} config The config object
31933 Roo.bootstrap.LayoutMasonryAuto = function(config){
31934 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31937 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31940 * @cfg {Boolean} isFitWidth - resize the width..
31942 isFitWidth : false, // options..
31944 * @cfg {Boolean} isOriginLeft = left align?
31946 isOriginLeft : true,
31948 * @cfg {Boolean} isOriginTop = top align?
31950 isOriginTop : false,
31952 * @cfg {Boolean} isLayoutInstant = no animation?
31954 isLayoutInstant : false, // needed?
31956 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31958 isResizingContainer : true,
31960 * @cfg {Number} columnWidth width of the columns
31966 * @cfg {Number} maxCols maximum number of columns
31971 * @cfg {Number} padHeight padding below box..
31977 * @cfg {Boolean} isAutoInitial defalut true
31980 isAutoInitial : true,
31986 initialColumnWidth : 0,
31987 currentSize : null,
31989 colYs : null, // array.
31996 bricks: null, //CompositeElement
31997 cols : 0, // array?
31998 // element : null, // wrapped now this.el
31999 _isLayoutInited : null,
32002 getAutoCreate : function(){
32006 cls: 'blog-masonary-wrapper ' + this.cls,
32008 cls : 'mas-boxes masonary'
32015 getChildContainer: function( )
32017 if (this.boxesEl) {
32018 return this.boxesEl;
32021 this.boxesEl = this.el.select('.mas-boxes').first();
32023 return this.boxesEl;
32027 initEvents : function()
32031 if(this.isAutoInitial){
32032 Roo.log('hook children rendered');
32033 this.on('childrenrendered', function() {
32034 Roo.log('children rendered');
32041 initial : function()
32043 this.reloadItems();
32045 this.currentSize = this.el.getBox(true);
32047 /// was window resize... - let's see if this works..
32048 Roo.EventManager.onWindowResize(this.resize, this);
32050 if(!this.isAutoInitial){
32055 this.layout.defer(500,this);
32058 reloadItems: function()
32060 this.bricks = this.el.select('.masonry-brick', true);
32062 this.bricks.each(function(b) {
32063 //Roo.log(b.getSize());
32064 if (!b.attr('originalwidth')) {
32065 b.attr('originalwidth', b.getSize().width);
32070 Roo.log(this.bricks.elements.length);
32073 resize : function()
32076 var cs = this.el.getBox(true);
32078 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32079 Roo.log("no change in with or X");
32082 this.currentSize = cs;
32086 layout : function()
32089 this._resetLayout();
32090 //this._manageStamps();
32092 // don't animate first layout
32093 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32094 this.layoutItems( isInstant );
32096 // flag for initalized
32097 this._isLayoutInited = true;
32100 layoutItems : function( isInstant )
32102 //var items = this._getItemsForLayout( this.items );
32103 // original code supports filtering layout items.. we just ignore it..
32105 this._layoutItems( this.bricks , isInstant );
32107 this._postLayout();
32109 _layoutItems : function ( items , isInstant)
32111 //this.fireEvent( 'layout', this, items );
32114 if ( !items || !items.elements.length ) {
32115 // no items, emit event with empty array
32120 items.each(function(item) {
32121 Roo.log("layout item");
32123 // get x/y object from method
32124 var position = this._getItemLayoutPosition( item );
32126 position.item = item;
32127 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32128 queue.push( position );
32131 this._processLayoutQueue( queue );
32133 /** Sets position of item in DOM
32134 * @param {Element} item
32135 * @param {Number} x - horizontal position
32136 * @param {Number} y - vertical position
32137 * @param {Boolean} isInstant - disables transitions
32139 _processLayoutQueue : function( queue )
32141 for ( var i=0, len = queue.length; i < len; i++ ) {
32142 var obj = queue[i];
32143 obj.item.position('absolute');
32144 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32150 * Any logic you want to do after each layout,
32151 * i.e. size the container
32153 _postLayout : function()
32155 this.resizeContainer();
32158 resizeContainer : function()
32160 if ( !this.isResizingContainer ) {
32163 var size = this._getContainerSize();
32165 this.el.setSize(size.width,size.height);
32166 this.boxesEl.setSize(size.width,size.height);
32172 _resetLayout : function()
32174 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32175 this.colWidth = this.el.getWidth();
32176 //this.gutter = this.el.getWidth();
32178 this.measureColumns();
32184 this.colYs.push( 0 );
32190 measureColumns : function()
32192 this.getContainerWidth();
32193 // if columnWidth is 0, default to outerWidth of first item
32194 if ( !this.columnWidth ) {
32195 var firstItem = this.bricks.first();
32196 Roo.log(firstItem);
32197 this.columnWidth = this.containerWidth;
32198 if (firstItem && firstItem.attr('originalwidth') ) {
32199 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32201 // columnWidth fall back to item of first element
32202 Roo.log("set column width?");
32203 this.initialColumnWidth = this.columnWidth ;
32205 // if first elem has no width, default to size of container
32210 if (this.initialColumnWidth) {
32211 this.columnWidth = this.initialColumnWidth;
32216 // column width is fixed at the top - however if container width get's smaller we should
32219 // this bit calcs how man columns..
32221 var columnWidth = this.columnWidth += this.gutter;
32223 // calculate columns
32224 var containerWidth = this.containerWidth + this.gutter;
32226 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32227 // fix rounding errors, typically with gutters
32228 var excess = columnWidth - containerWidth % columnWidth;
32231 // if overshoot is less than a pixel, round up, otherwise floor it
32232 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32233 cols = Math[ mathMethod ]( cols );
32234 this.cols = Math.max( cols, 1 );
32235 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32237 // padding positioning..
32238 var totalColWidth = this.cols * this.columnWidth;
32239 var padavail = this.containerWidth - totalColWidth;
32240 // so for 2 columns - we need 3 'pads'
32242 var padNeeded = (1+this.cols) * this.padWidth;
32244 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32246 this.columnWidth += padExtra
32247 //this.padWidth = Math.floor(padavail / ( this.cols));
32249 // adjust colum width so that padding is fixed??
32251 // we have 3 columns ... total = width * 3
32252 // we have X left over... that should be used by
32254 //if (this.expandC) {
32262 getContainerWidth : function()
32264 /* // container is parent if fit width
32265 var container = this.isFitWidth ? this.element.parentNode : this.element;
32266 // check that this.size and size are there
32267 // IE8 triggers resize on body size change, so they might not be
32269 var size = getSize( container ); //FIXME
32270 this.containerWidth = size && size.innerWidth; //FIXME
32273 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32277 _getItemLayoutPosition : function( item ) // what is item?
32279 // we resize the item to our columnWidth..
32281 item.setWidth(this.columnWidth);
32282 item.autoBoxAdjust = false;
32284 var sz = item.getSize();
32286 // how many columns does this brick span
32287 var remainder = this.containerWidth % this.columnWidth;
32289 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32290 // round if off by 1 pixel, otherwise use ceil
32291 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32292 colSpan = Math.min( colSpan, this.cols );
32294 // normally this should be '1' as we dont' currently allow multi width columns..
32296 var colGroup = this._getColGroup( colSpan );
32297 // get the minimum Y value from the columns
32298 var minimumY = Math.min.apply( Math, colGroup );
32299 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32301 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32303 // position the brick
32305 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32306 y: this.currentSize.y + minimumY + this.padHeight
32310 // apply setHeight to necessary columns
32311 var setHeight = minimumY + sz.height + this.padHeight;
32312 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32314 var setSpan = this.cols + 1 - colGroup.length;
32315 for ( var i = 0; i < setSpan; i++ ) {
32316 this.colYs[ shortColIndex + i ] = setHeight ;
32323 * @param {Number} colSpan - number of columns the element spans
32324 * @returns {Array} colGroup
32326 _getColGroup : function( colSpan )
32328 if ( colSpan < 2 ) {
32329 // if brick spans only one column, use all the column Ys
32334 // how many different places could this brick fit horizontally
32335 var groupCount = this.cols + 1 - colSpan;
32336 // for each group potential horizontal position
32337 for ( var i = 0; i < groupCount; i++ ) {
32338 // make an array of colY values for that one group
32339 var groupColYs = this.colYs.slice( i, i + colSpan );
32340 // and get the max value of the array
32341 colGroup[i] = Math.max.apply( Math, groupColYs );
32346 _manageStamp : function( stamp )
32348 var stampSize = stamp.getSize();
32349 var offset = stamp.getBox();
32350 // get the columns that this stamp affects
32351 var firstX = this.isOriginLeft ? offset.x : offset.right;
32352 var lastX = firstX + stampSize.width;
32353 var firstCol = Math.floor( firstX / this.columnWidth );
32354 firstCol = Math.max( 0, firstCol );
32356 var lastCol = Math.floor( lastX / this.columnWidth );
32357 // lastCol should not go over if multiple of columnWidth #425
32358 lastCol -= lastX % this.columnWidth ? 0 : 1;
32359 lastCol = Math.min( this.cols - 1, lastCol );
32361 // set colYs to bottom of the stamp
32362 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32365 for ( var i = firstCol; i <= lastCol; i++ ) {
32366 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32371 _getContainerSize : function()
32373 this.maxY = Math.max.apply( Math, this.colYs );
32378 if ( this.isFitWidth ) {
32379 size.width = this._getContainerFitWidth();
32385 _getContainerFitWidth : function()
32387 var unusedCols = 0;
32388 // count unused columns
32391 if ( this.colYs[i] !== 0 ) {
32396 // fit container to columns that have been used
32397 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32400 needsResizeLayout : function()
32402 var previousWidth = this.containerWidth;
32403 this.getContainerWidth();
32404 return previousWidth !== this.containerWidth;
32419 * @class Roo.bootstrap.MasonryBrick
32420 * @extends Roo.bootstrap.Component
32421 * Bootstrap MasonryBrick class
32424 * Create a new MasonryBrick
32425 * @param {Object} config The config object
32428 Roo.bootstrap.MasonryBrick = function(config){
32430 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32432 Roo.bootstrap.MasonryBrick.register(this);
32438 * When a MasonryBrick is clcik
32439 * @param {Roo.bootstrap.MasonryBrick} this
32440 * @param {Roo.EventObject} e
32446 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32449 * @cfg {String} title
32453 * @cfg {String} html
32457 * @cfg {String} bgimage
32461 * @cfg {String} videourl
32465 * @cfg {String} cls
32469 * @cfg {String} href
32473 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32478 * @cfg {String} placetitle (center|bottom)
32483 * @cfg {Boolean} isFitContainer defalut true
32485 isFitContainer : true,
32488 * @cfg {Boolean} preventDefault defalut false
32490 preventDefault : false,
32493 * @cfg {Boolean} inverse defalut false
32495 maskInverse : false,
32497 getAutoCreate : function()
32499 if(!this.isFitContainer){
32500 return this.getSplitAutoCreate();
32503 var cls = 'masonry-brick masonry-brick-full';
32505 if(this.href.length){
32506 cls += ' masonry-brick-link';
32509 if(this.bgimage.length){
32510 cls += ' masonry-brick-image';
32513 if(this.maskInverse){
32514 cls += ' mask-inverse';
32517 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32518 cls += ' enable-mask';
32522 cls += ' masonry-' + this.size + '-brick';
32525 if(this.placetitle.length){
32527 switch (this.placetitle) {
32529 cls += ' masonry-center-title';
32532 cls += ' masonry-bottom-title';
32539 if(!this.html.length && !this.bgimage.length){
32540 cls += ' masonry-center-title';
32543 if(!this.html.length && this.bgimage.length){
32544 cls += ' masonry-bottom-title';
32549 cls += ' ' + this.cls;
32553 tag: (this.href.length) ? 'a' : 'div',
32558 cls: 'masonry-brick-mask'
32562 cls: 'masonry-brick-paragraph',
32568 if(this.href.length){
32569 cfg.href = this.href;
32572 var cn = cfg.cn[1].cn;
32574 if(this.title.length){
32577 cls: 'masonry-brick-title',
32582 if(this.html.length){
32585 cls: 'masonry-brick-text',
32590 if (!this.title.length && !this.html.length) {
32591 cfg.cn[1].cls += ' hide';
32594 if(this.bgimage.length){
32597 cls: 'masonry-brick-image-view',
32602 if(this.videourl.length){
32603 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32604 // youtube support only?
32607 cls: 'masonry-brick-image-view',
32610 allowfullscreen : true
32618 getSplitAutoCreate : function()
32620 var cls = 'masonry-brick masonry-brick-split';
32622 if(this.href.length){
32623 cls += ' masonry-brick-link';
32626 if(this.bgimage.length){
32627 cls += ' masonry-brick-image';
32631 cls += ' masonry-' + this.size + '-brick';
32634 switch (this.placetitle) {
32636 cls += ' masonry-center-title';
32639 cls += ' masonry-bottom-title';
32642 if(!this.bgimage.length){
32643 cls += ' masonry-center-title';
32646 if(this.bgimage.length){
32647 cls += ' masonry-bottom-title';
32653 cls += ' ' + this.cls;
32657 tag: (this.href.length) ? 'a' : 'div',
32662 cls: 'masonry-brick-split-head',
32666 cls: 'masonry-brick-paragraph',
32673 cls: 'masonry-brick-split-body',
32679 if(this.href.length){
32680 cfg.href = this.href;
32683 if(this.title.length){
32684 cfg.cn[0].cn[0].cn.push({
32686 cls: 'masonry-brick-title',
32691 if(this.html.length){
32692 cfg.cn[1].cn.push({
32694 cls: 'masonry-brick-text',
32699 if(this.bgimage.length){
32700 cfg.cn[0].cn.push({
32702 cls: 'masonry-brick-image-view',
32707 if(this.videourl.length){
32708 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32709 // youtube support only?
32710 cfg.cn[0].cn.cn.push({
32712 cls: 'masonry-brick-image-view',
32715 allowfullscreen : true
32722 initEvents: function()
32724 switch (this.size) {
32757 this.el.on('touchstart', this.onTouchStart, this);
32758 this.el.on('touchmove', this.onTouchMove, this);
32759 this.el.on('touchend', this.onTouchEnd, this);
32760 this.el.on('contextmenu', this.onContextMenu, this);
32762 this.el.on('mouseenter' ,this.enter, this);
32763 this.el.on('mouseleave', this.leave, this);
32764 this.el.on('click', this.onClick, this);
32767 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32768 this.parent().bricks.push(this);
32773 onClick: function(e, el)
32775 var time = this.endTimer - this.startTimer;
32776 // Roo.log(e.preventDefault());
32779 e.preventDefault();
32784 if(!this.preventDefault){
32788 e.preventDefault();
32790 if (this.activeClass != '') {
32791 this.selectBrick();
32794 this.fireEvent('click', this, e);
32797 enter: function(e, el)
32799 e.preventDefault();
32801 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32805 if(this.bgimage.length && this.html.length){
32806 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32810 leave: function(e, el)
32812 e.preventDefault();
32814 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32818 if(this.bgimage.length && this.html.length){
32819 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32823 onTouchStart: function(e, el)
32825 // e.preventDefault();
32827 this.touchmoved = false;
32829 if(!this.isFitContainer){
32833 if(!this.bgimage.length || !this.html.length){
32837 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32839 this.timer = new Date().getTime();
32843 onTouchMove: function(e, el)
32845 this.touchmoved = true;
32848 onContextMenu : function(e,el)
32850 e.preventDefault();
32851 e.stopPropagation();
32855 onTouchEnd: function(e, el)
32857 // e.preventDefault();
32859 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32866 if(!this.bgimage.length || !this.html.length){
32868 if(this.href.length){
32869 window.location.href = this.href;
32875 if(!this.isFitContainer){
32879 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32881 window.location.href = this.href;
32884 //selection on single brick only
32885 selectBrick : function() {
32887 if (!this.parentId) {
32891 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32892 var index = m.selectedBrick.indexOf(this.id);
32895 m.selectedBrick.splice(index,1);
32896 this.el.removeClass(this.activeClass);
32900 for(var i = 0; i < m.selectedBrick.length; i++) {
32901 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32902 b.el.removeClass(b.activeClass);
32905 m.selectedBrick = [];
32907 m.selectedBrick.push(this.id);
32908 this.el.addClass(this.activeClass);
32912 isSelected : function(){
32913 return this.el.hasClass(this.activeClass);
32918 Roo.apply(Roo.bootstrap.MasonryBrick, {
32921 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32923 * register a Masonry Brick
32924 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32927 register : function(brick)
32929 //this.groups[brick.id] = brick;
32930 this.groups.add(brick.id, brick);
32933 * fetch a masonry brick based on the masonry brick ID
32934 * @param {string} the masonry brick to add
32935 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32938 get: function(brick_id)
32940 // if (typeof(this.groups[brick_id]) == 'undefined') {
32943 // return this.groups[brick_id] ;
32945 if(this.groups.key(brick_id)) {
32946 return this.groups.key(brick_id);
32964 * @class Roo.bootstrap.Brick
32965 * @extends Roo.bootstrap.Component
32966 * Bootstrap Brick class
32969 * Create a new Brick
32970 * @param {Object} config The config object
32973 Roo.bootstrap.Brick = function(config){
32974 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32980 * When a Brick is click
32981 * @param {Roo.bootstrap.Brick} this
32982 * @param {Roo.EventObject} e
32988 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32991 * @cfg {String} title
32995 * @cfg {String} html
32999 * @cfg {String} bgimage
33003 * @cfg {String} cls
33007 * @cfg {String} href
33011 * @cfg {String} video
33015 * @cfg {Boolean} square
33019 getAutoCreate : function()
33021 var cls = 'roo-brick';
33023 if(this.href.length){
33024 cls += ' roo-brick-link';
33027 if(this.bgimage.length){
33028 cls += ' roo-brick-image';
33031 if(!this.html.length && !this.bgimage.length){
33032 cls += ' roo-brick-center-title';
33035 if(!this.html.length && this.bgimage.length){
33036 cls += ' roo-brick-bottom-title';
33040 cls += ' ' + this.cls;
33044 tag: (this.href.length) ? 'a' : 'div',
33049 cls: 'roo-brick-paragraph',
33055 if(this.href.length){
33056 cfg.href = this.href;
33059 var cn = cfg.cn[0].cn;
33061 if(this.title.length){
33064 cls: 'roo-brick-title',
33069 if(this.html.length){
33072 cls: 'roo-brick-text',
33079 if(this.bgimage.length){
33082 cls: 'roo-brick-image-view',
33090 initEvents: function()
33092 if(this.title.length || this.html.length){
33093 this.el.on('mouseenter' ,this.enter, this);
33094 this.el.on('mouseleave', this.leave, this);
33097 Roo.EventManager.onWindowResize(this.resize, this);
33099 if(this.bgimage.length){
33100 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33101 this.imageEl.on('load', this.onImageLoad, this);
33108 onImageLoad : function()
33113 resize : function()
33115 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33117 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33119 if(this.bgimage.length){
33120 var image = this.el.select('.roo-brick-image-view', true).first();
33122 image.setWidth(paragraph.getWidth());
33125 image.setHeight(paragraph.getWidth());
33128 this.el.setHeight(image.getHeight());
33129 paragraph.setHeight(image.getHeight());
33135 enter: function(e, el)
33137 e.preventDefault();
33139 if(this.bgimage.length){
33140 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33141 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33145 leave: function(e, el)
33147 e.preventDefault();
33149 if(this.bgimage.length){
33150 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33151 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33166 * @class Roo.bootstrap.NumberField
33167 * @extends Roo.bootstrap.Input
33168 * Bootstrap NumberField class
33174 * Create a new NumberField
33175 * @param {Object} config The config object
33178 Roo.bootstrap.NumberField = function(config){
33179 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33182 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33185 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33187 allowDecimals : true,
33189 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33191 decimalSeparator : ".",
33193 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33195 decimalPrecision : 2,
33197 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33199 allowNegative : true,
33202 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33206 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33208 minValue : Number.NEGATIVE_INFINITY,
33210 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33212 maxValue : Number.MAX_VALUE,
33214 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33216 minText : "The minimum value for this field is {0}",
33218 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33220 maxText : "The maximum value for this field is {0}",
33222 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33223 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33225 nanText : "{0} is not a valid number",
33227 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33231 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33233 thousandsDelimiter : false,
33235 * @cfg {String} valueAlign alignment of value
33237 valueAlign : "left",
33239 getAutoCreate : function()
33241 var hiddenInput = {
33245 cls: 'hidden-number-input'
33249 hiddenInput.name = this.name;
33254 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33256 this.name = hiddenInput.name;
33258 if(cfg.cn.length > 0) {
33259 cfg.cn.push(hiddenInput);
33266 initEvents : function()
33268 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33270 var allowed = "0123456789";
33272 if(this.allowDecimals){
33273 allowed += this.decimalSeparator;
33276 if(this.allowNegative){
33280 if(this.thousandsDelimiter) {
33284 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33286 var keyPress = function(e){
33288 var k = e.getKey();
33290 var c = e.getCharCode();
33293 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33294 allowed.indexOf(String.fromCharCode(c)) === -1
33300 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33304 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33309 this.el.on("keypress", keyPress, this);
33312 validateValue : function(value)
33315 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33319 var num = this.parseValue(value);
33322 this.markInvalid(String.format(this.nanText, value));
33326 if(num < this.minValue){
33327 this.markInvalid(String.format(this.minText, this.minValue));
33331 if(num > this.maxValue){
33332 this.markInvalid(String.format(this.maxText, this.maxValue));
33339 getValue : function()
33341 var v = this.hiddenEl().getValue();
33343 return this.fixPrecision(this.parseValue(v));
33346 parseValue : function(value)
33348 if(this.thousandsDelimiter) {
33350 r = new RegExp(",", "g");
33351 value = value.replace(r, "");
33354 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33355 return isNaN(value) ? '' : value;
33358 fixPrecision : function(value)
33360 if(this.thousandsDelimiter) {
33362 r = new RegExp(",", "g");
33363 value = value.replace(r, "");
33366 var nan = isNaN(value);
33368 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33369 return nan ? '' : value;
33371 return parseFloat(value).toFixed(this.decimalPrecision);
33374 setValue : function(v)
33376 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33382 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33384 this.inputEl().dom.value = (v == '') ? '' :
33385 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33387 if(!this.allowZero && v === '0') {
33388 this.hiddenEl().dom.value = '';
33389 this.inputEl().dom.value = '';
33396 decimalPrecisionFcn : function(v)
33398 return Math.floor(v);
33401 beforeBlur : function()
33407 var v = this.parseValue(this.getRawValue());
33414 hiddenEl : function()
33416 return this.el.select('input.hidden-number-input',true).first();
33428 * @class Roo.bootstrap.DocumentSlider
33429 * @extends Roo.bootstrap.Component
33430 * Bootstrap DocumentSlider class
33433 * Create a new DocumentViewer
33434 * @param {Object} config The config object
33437 Roo.bootstrap.DocumentSlider = function(config){
33438 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33445 * Fire after initEvent
33446 * @param {Roo.bootstrap.DocumentSlider} this
33451 * Fire after update
33452 * @param {Roo.bootstrap.DocumentSlider} this
33458 * @param {Roo.bootstrap.DocumentSlider} this
33464 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33470 getAutoCreate : function()
33474 cls : 'roo-document-slider',
33478 cls : 'roo-document-slider-header',
33482 cls : 'roo-document-slider-header-title'
33488 cls : 'roo-document-slider-body',
33492 cls : 'roo-document-slider-prev',
33496 cls : 'fa fa-chevron-left'
33502 cls : 'roo-document-slider-thumb',
33506 cls : 'roo-document-slider-image'
33512 cls : 'roo-document-slider-next',
33516 cls : 'fa fa-chevron-right'
33528 initEvents : function()
33530 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33531 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33533 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33534 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33536 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33537 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33539 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33540 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33542 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33543 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33545 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33546 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33548 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33549 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33551 this.thumbEl.on('click', this.onClick, this);
33553 this.prevIndicator.on('click', this.prev, this);
33555 this.nextIndicator.on('click', this.next, this);
33559 initial : function()
33561 if(this.files.length){
33562 this.indicator = 1;
33566 this.fireEvent('initial', this);
33569 update : function()
33571 this.imageEl.attr('src', this.files[this.indicator - 1]);
33573 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33575 this.prevIndicator.show();
33577 if(this.indicator == 1){
33578 this.prevIndicator.hide();
33581 this.nextIndicator.show();
33583 if(this.indicator == this.files.length){
33584 this.nextIndicator.hide();
33587 this.thumbEl.scrollTo('top');
33589 this.fireEvent('update', this);
33592 onClick : function(e)
33594 e.preventDefault();
33596 this.fireEvent('click', this);
33601 e.preventDefault();
33603 this.indicator = Math.max(1, this.indicator - 1);
33610 e.preventDefault();
33612 this.indicator = Math.min(this.files.length, this.indicator + 1);
33626 * @class Roo.bootstrap.RadioSet
33627 * @extends Roo.bootstrap.Input
33628 * Bootstrap RadioSet class
33629 * @cfg {String} indicatorpos (left|right) default left
33630 * @cfg {Boolean} inline (true|false) inline the element (default true)
33631 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33633 * Create a new RadioSet
33634 * @param {Object} config The config object
33637 Roo.bootstrap.RadioSet = function(config){
33639 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33643 Roo.bootstrap.RadioSet.register(this);
33648 * Fires when the element is checked or unchecked.
33649 * @param {Roo.bootstrap.RadioSet} this This radio
33650 * @param {Roo.bootstrap.Radio} item The checked item
33655 * Fires when the element is click.
33656 * @param {Roo.bootstrap.RadioSet} this This radio set
33657 * @param {Roo.bootstrap.Radio} item The checked item
33658 * @param {Roo.EventObject} e The event object
33665 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33673 indicatorpos : 'left',
33675 getAutoCreate : function()
33679 cls : 'roo-radio-set-label',
33683 html : this.fieldLabel
33688 if(this.indicatorpos == 'left'){
33691 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33692 tooltip : 'This field is required'
33697 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33698 tooltip : 'This field is required'
33704 cls : 'roo-radio-set-items'
33707 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33709 if (align === 'left' && this.fieldLabel.length) {
33712 cls : "roo-radio-set-right",
33718 if(this.labelWidth > 12){
33719 label.style = "width: " + this.labelWidth + 'px';
33722 if(this.labelWidth < 13 && this.labelmd == 0){
33723 this.labelmd = this.labelWidth;
33726 if(this.labellg > 0){
33727 label.cls += ' col-lg-' + this.labellg;
33728 items.cls += ' col-lg-' + (12 - this.labellg);
33731 if(this.labelmd > 0){
33732 label.cls += ' col-md-' + this.labelmd;
33733 items.cls += ' col-md-' + (12 - this.labelmd);
33736 if(this.labelsm > 0){
33737 label.cls += ' col-sm-' + this.labelsm;
33738 items.cls += ' col-sm-' + (12 - this.labelsm);
33741 if(this.labelxs > 0){
33742 label.cls += ' col-xs-' + this.labelxs;
33743 items.cls += ' col-xs-' + (12 - this.labelxs);
33749 cls : 'roo-radio-set',
33753 cls : 'roo-radio-set-input',
33756 value : this.value ? this.value : ''
33763 if(this.weight.length){
33764 cfg.cls += ' roo-radio-' + this.weight;
33768 cfg.cls += ' roo-radio-set-inline';
33772 ['xs','sm','md','lg'].map(function(size){
33773 if (settings[size]) {
33774 cfg.cls += ' col-' + size + '-' + settings[size];
33782 initEvents : function()
33784 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33785 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33787 if(!this.fieldLabel.length){
33788 this.labelEl.hide();
33791 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33792 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33794 this.indicator = this.indicatorEl();
33796 if(this.indicator){
33797 this.indicator.addClass('invisible');
33800 this.originalValue = this.getValue();
33804 inputEl: function ()
33806 return this.el.select('.roo-radio-set-input', true).first();
33809 getChildContainer : function()
33811 return this.itemsEl;
33814 register : function(item)
33816 this.radioes.push(item);
33820 validate : function()
33822 if(this.getVisibilityEl().hasClass('hidden')){
33828 Roo.each(this.radioes, function(i){
33837 if(this.allowBlank) {
33841 if(this.disabled || valid){
33846 this.markInvalid();
33851 markValid : function()
33853 if(this.labelEl.isVisible(true)){
33854 this.indicatorEl().removeClass('visible');
33855 this.indicatorEl().addClass('invisible');
33858 this.el.removeClass([this.invalidClass, this.validClass]);
33859 this.el.addClass(this.validClass);
33861 this.fireEvent('valid', this);
33864 markInvalid : function(msg)
33866 if(this.allowBlank || this.disabled){
33870 if(this.labelEl.isVisible(true)){
33871 this.indicatorEl().removeClass('invisible');
33872 this.indicatorEl().addClass('visible');
33875 this.el.removeClass([this.invalidClass, this.validClass]);
33876 this.el.addClass(this.invalidClass);
33878 this.fireEvent('invalid', this, msg);
33882 setValue : function(v, suppressEvent)
33884 if(this.value === v){
33891 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33894 Roo.each(this.radioes, function(i){
33896 i.el.removeClass('checked');
33899 Roo.each(this.radioes, function(i){
33901 if(i.value === v || i.value.toString() === v.toString()){
33903 i.el.addClass('checked');
33905 if(suppressEvent !== true){
33906 this.fireEvent('check', this, i);
33917 clearInvalid : function(){
33919 if(!this.el || this.preventMark){
33923 this.el.removeClass([this.invalidClass]);
33925 this.fireEvent('valid', this);
33930 Roo.apply(Roo.bootstrap.RadioSet, {
33934 register : function(set)
33936 this.groups[set.name] = set;
33939 get: function(name)
33941 if (typeof(this.groups[name]) == 'undefined') {
33945 return this.groups[name] ;
33951 * Ext JS Library 1.1.1
33952 * Copyright(c) 2006-2007, Ext JS, LLC.
33954 * Originally Released Under LGPL - original licence link has changed is not relivant.
33957 * <script type="text/javascript">
33962 * @class Roo.bootstrap.SplitBar
33963 * @extends Roo.util.Observable
33964 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33968 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33969 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33970 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33971 split.minSize = 100;
33972 split.maxSize = 600;
33973 split.animate = true;
33974 split.on('moved', splitterMoved);
33977 * Create a new SplitBar
33978 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33979 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33980 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33981 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33982 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33983 position of the SplitBar).
33985 Roo.bootstrap.SplitBar = function(cfg){
33990 // dragElement : elm
33991 // resizingElement: el,
33993 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33994 // placement : Roo.bootstrap.SplitBar.LEFT ,
33995 // existingProxy ???
33998 this.el = Roo.get(cfg.dragElement, true);
33999 this.el.dom.unselectable = "on";
34001 this.resizingEl = Roo.get(cfg.resizingElement, true);
34005 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34006 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34009 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34012 * The minimum size of the resizing element. (Defaults to 0)
34018 * The maximum size of the resizing element. (Defaults to 2000)
34021 this.maxSize = 2000;
34024 * Whether to animate the transition to the new size
34027 this.animate = false;
34030 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34033 this.useShim = false;
34038 if(!cfg.existingProxy){
34040 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34042 this.proxy = Roo.get(cfg.existingProxy).dom;
34045 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34048 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34051 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34054 this.dragSpecs = {};
34057 * @private The adapter to use to positon and resize elements
34059 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34060 this.adapter.init(this);
34062 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34064 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34065 this.el.addClass("roo-splitbar-h");
34068 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34069 this.el.addClass("roo-splitbar-v");
34075 * Fires when the splitter is moved (alias for {@link #event-moved})
34076 * @param {Roo.bootstrap.SplitBar} this
34077 * @param {Number} newSize the new width or height
34082 * Fires when the splitter is moved
34083 * @param {Roo.bootstrap.SplitBar} this
34084 * @param {Number} newSize the new width or height
34088 * @event beforeresize
34089 * Fires before the splitter is dragged
34090 * @param {Roo.bootstrap.SplitBar} this
34092 "beforeresize" : true,
34094 "beforeapply" : true
34097 Roo.util.Observable.call(this);
34100 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34101 onStartProxyDrag : function(x, y){
34102 this.fireEvent("beforeresize", this);
34104 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34106 o.enableDisplayMode("block");
34107 // all splitbars share the same overlay
34108 Roo.bootstrap.SplitBar.prototype.overlay = o;
34110 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34111 this.overlay.show();
34112 Roo.get(this.proxy).setDisplayed("block");
34113 var size = this.adapter.getElementSize(this);
34114 this.activeMinSize = this.getMinimumSize();;
34115 this.activeMaxSize = this.getMaximumSize();;
34116 var c1 = size - this.activeMinSize;
34117 var c2 = Math.max(this.activeMaxSize - size, 0);
34118 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34119 this.dd.resetConstraints();
34120 this.dd.setXConstraint(
34121 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34122 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34124 this.dd.setYConstraint(0, 0);
34126 this.dd.resetConstraints();
34127 this.dd.setXConstraint(0, 0);
34128 this.dd.setYConstraint(
34129 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34130 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34133 this.dragSpecs.startSize = size;
34134 this.dragSpecs.startPoint = [x, y];
34135 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34139 * @private Called after the drag operation by the DDProxy
34141 onEndProxyDrag : function(e){
34142 Roo.get(this.proxy).setDisplayed(false);
34143 var endPoint = Roo.lib.Event.getXY(e);
34145 this.overlay.hide();
34148 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34149 newSize = this.dragSpecs.startSize +
34150 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34151 endPoint[0] - this.dragSpecs.startPoint[0] :
34152 this.dragSpecs.startPoint[0] - endPoint[0]
34155 newSize = this.dragSpecs.startSize +
34156 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34157 endPoint[1] - this.dragSpecs.startPoint[1] :
34158 this.dragSpecs.startPoint[1] - endPoint[1]
34161 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34162 if(newSize != this.dragSpecs.startSize){
34163 if(this.fireEvent('beforeapply', this, newSize) !== false){
34164 this.adapter.setElementSize(this, newSize);
34165 this.fireEvent("moved", this, newSize);
34166 this.fireEvent("resize", this, newSize);
34172 * Get the adapter this SplitBar uses
34173 * @return The adapter object
34175 getAdapter : function(){
34176 return this.adapter;
34180 * Set the adapter this SplitBar uses
34181 * @param {Object} adapter A SplitBar adapter object
34183 setAdapter : function(adapter){
34184 this.adapter = adapter;
34185 this.adapter.init(this);
34189 * Gets the minimum size for the resizing element
34190 * @return {Number} The minimum size
34192 getMinimumSize : function(){
34193 return this.minSize;
34197 * Sets the minimum size for the resizing element
34198 * @param {Number} minSize The minimum size
34200 setMinimumSize : function(minSize){
34201 this.minSize = minSize;
34205 * Gets the maximum size for the resizing element
34206 * @return {Number} The maximum size
34208 getMaximumSize : function(){
34209 return this.maxSize;
34213 * Sets the maximum size for the resizing element
34214 * @param {Number} maxSize The maximum size
34216 setMaximumSize : function(maxSize){
34217 this.maxSize = maxSize;
34221 * Sets the initialize size for the resizing element
34222 * @param {Number} size The initial size
34224 setCurrentSize : function(size){
34225 var oldAnimate = this.animate;
34226 this.animate = false;
34227 this.adapter.setElementSize(this, size);
34228 this.animate = oldAnimate;
34232 * Destroy this splitbar.
34233 * @param {Boolean} removeEl True to remove the element
34235 destroy : function(removeEl){
34237 this.shim.remove();
34240 this.proxy.parentNode.removeChild(this.proxy);
34248 * @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.
34250 Roo.bootstrap.SplitBar.createProxy = function(dir){
34251 var proxy = new Roo.Element(document.createElement("div"));
34252 proxy.unselectable();
34253 var cls = 'roo-splitbar-proxy';
34254 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34255 document.body.appendChild(proxy.dom);
34260 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34261 * Default Adapter. It assumes the splitter and resizing element are not positioned
34262 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34264 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34267 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34268 // do nothing for now
34269 init : function(s){
34273 * Called before drag operations to get the current size of the resizing element.
34274 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34276 getElementSize : function(s){
34277 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34278 return s.resizingEl.getWidth();
34280 return s.resizingEl.getHeight();
34285 * Called after drag operations to set the size of the resizing element.
34286 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34287 * @param {Number} newSize The new size to set
34288 * @param {Function} onComplete A function to be invoked when resizing is complete
34290 setElementSize : function(s, newSize, onComplete){
34291 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34293 s.resizingEl.setWidth(newSize);
34295 onComplete(s, newSize);
34298 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34303 s.resizingEl.setHeight(newSize);
34305 onComplete(s, newSize);
34308 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34315 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34316 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34317 * Adapter that moves the splitter element to align with the resized sizing element.
34318 * Used with an absolute positioned SplitBar.
34319 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34320 * document.body, make sure you assign an id to the body element.
34322 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34323 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34324 this.container = Roo.get(container);
34327 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34328 init : function(s){
34329 this.basic.init(s);
34332 getElementSize : function(s){
34333 return this.basic.getElementSize(s);
34336 setElementSize : function(s, newSize, onComplete){
34337 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34340 moveSplitter : function(s){
34341 var yes = Roo.bootstrap.SplitBar;
34342 switch(s.placement){
34344 s.el.setX(s.resizingEl.getRight());
34347 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34350 s.el.setY(s.resizingEl.getBottom());
34353 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34360 * Orientation constant - Create a vertical SplitBar
34364 Roo.bootstrap.SplitBar.VERTICAL = 1;
34367 * Orientation constant - Create a horizontal SplitBar
34371 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34374 * Placement constant - The resizing element is to the left of the splitter element
34378 Roo.bootstrap.SplitBar.LEFT = 1;
34381 * Placement constant - The resizing element is to the right of the splitter element
34385 Roo.bootstrap.SplitBar.RIGHT = 2;
34388 * Placement constant - The resizing element is positioned above the splitter element
34392 Roo.bootstrap.SplitBar.TOP = 3;
34395 * Placement constant - The resizing element is positioned under splitter element
34399 Roo.bootstrap.SplitBar.BOTTOM = 4;
34400 Roo.namespace("Roo.bootstrap.layout");/*
34402 * Ext JS Library 1.1.1
34403 * Copyright(c) 2006-2007, Ext JS, LLC.
34405 * Originally Released Under LGPL - original licence link has changed is not relivant.
34408 * <script type="text/javascript">
34412 * @class Roo.bootstrap.layout.Manager
34413 * @extends Roo.bootstrap.Component
34414 * Base class for layout managers.
34416 Roo.bootstrap.layout.Manager = function(config)
34418 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34424 /** false to disable window resize monitoring @type Boolean */
34425 this.monitorWindowResize = true;
34430 * Fires when a layout is performed.
34431 * @param {Roo.LayoutManager} this
34435 * @event regionresized
34436 * Fires when the user resizes a region.
34437 * @param {Roo.LayoutRegion} region The resized region
34438 * @param {Number} newSize The new size (width for east/west, height for north/south)
34440 "regionresized" : true,
34442 * @event regioncollapsed
34443 * Fires when a region is collapsed.
34444 * @param {Roo.LayoutRegion} region The collapsed region
34446 "regioncollapsed" : true,
34448 * @event regionexpanded
34449 * Fires when a region is expanded.
34450 * @param {Roo.LayoutRegion} region The expanded region
34452 "regionexpanded" : true
34454 this.updating = false;
34457 this.el = Roo.get(config.el);
34463 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34468 monitorWindowResize : true,
34474 onRender : function(ct, position)
34477 this.el = Roo.get(ct);
34480 //this.fireEvent('render',this);
34484 initEvents: function()
34488 // ie scrollbar fix
34489 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34490 document.body.scroll = "no";
34491 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34492 this.el.position('relative');
34494 this.id = this.el.id;
34495 this.el.addClass("roo-layout-container");
34496 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34497 if(this.el.dom != document.body ) {
34498 this.el.on('resize', this.layout,this);
34499 this.el.on('show', this.layout,this);
34505 * Returns true if this layout is currently being updated
34506 * @return {Boolean}
34508 isUpdating : function(){
34509 return this.updating;
34513 * Suspend the LayoutManager from doing auto-layouts while
34514 * making multiple add or remove calls
34516 beginUpdate : function(){
34517 this.updating = true;
34521 * Restore auto-layouts and optionally disable the manager from performing a layout
34522 * @param {Boolean} noLayout true to disable a layout update
34524 endUpdate : function(noLayout){
34525 this.updating = false;
34531 layout: function(){
34535 onRegionResized : function(region, newSize){
34536 this.fireEvent("regionresized", region, newSize);
34540 onRegionCollapsed : function(region){
34541 this.fireEvent("regioncollapsed", region);
34544 onRegionExpanded : function(region){
34545 this.fireEvent("regionexpanded", region);
34549 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34550 * performs box-model adjustments.
34551 * @return {Object} The size as an object {width: (the width), height: (the height)}
34553 getViewSize : function()
34556 if(this.el.dom != document.body){
34557 size = this.el.getSize();
34559 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34561 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34562 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34567 * Returns the Element this layout is bound to.
34568 * @return {Roo.Element}
34570 getEl : function(){
34575 * Returns the specified region.
34576 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34577 * @return {Roo.LayoutRegion}
34579 getRegion : function(target){
34580 return this.regions[target.toLowerCase()];
34583 onWindowResize : function(){
34584 if(this.monitorWindowResize){
34591 * Ext JS Library 1.1.1
34592 * Copyright(c) 2006-2007, Ext JS, LLC.
34594 * Originally Released Under LGPL - original licence link has changed is not relivant.
34597 * <script type="text/javascript">
34600 * @class Roo.bootstrap.layout.Border
34601 * @extends Roo.bootstrap.layout.Manager
34602 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34603 * please see: examples/bootstrap/nested.html<br><br>
34605 <b>The container the layout is rendered into can be either the body element or any other element.
34606 If it is not the body element, the container needs to either be an absolute positioned element,
34607 or you will need to add "position:relative" to the css of the container. You will also need to specify
34608 the container size if it is not the body element.</b>
34611 * Create a new Border
34612 * @param {Object} config Configuration options
34614 Roo.bootstrap.layout.Border = function(config){
34615 config = config || {};
34616 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34620 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34621 if(config[region]){
34622 config[region].region = region;
34623 this.addRegion(config[region]);
34629 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34631 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34633 * Creates and adds a new region if it doesn't already exist.
34634 * @param {String} target The target region key (north, south, east, west or center).
34635 * @param {Object} config The regions config object
34636 * @return {BorderLayoutRegion} The new region
34638 addRegion : function(config)
34640 if(!this.regions[config.region]){
34641 var r = this.factory(config);
34642 this.bindRegion(r);
34644 return this.regions[config.region];
34648 bindRegion : function(r){
34649 this.regions[r.config.region] = r;
34651 r.on("visibilitychange", this.layout, this);
34652 r.on("paneladded", this.layout, this);
34653 r.on("panelremoved", this.layout, this);
34654 r.on("invalidated", this.layout, this);
34655 r.on("resized", this.onRegionResized, this);
34656 r.on("collapsed", this.onRegionCollapsed, this);
34657 r.on("expanded", this.onRegionExpanded, this);
34661 * Performs a layout update.
34663 layout : function()
34665 if(this.updating) {
34669 // render all the rebions if they have not been done alreayd?
34670 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34671 if(this.regions[region] && !this.regions[region].bodyEl){
34672 this.regions[region].onRender(this.el)
34676 var size = this.getViewSize();
34677 var w = size.width;
34678 var h = size.height;
34683 //var x = 0, y = 0;
34685 var rs = this.regions;
34686 var north = rs["north"];
34687 var south = rs["south"];
34688 var west = rs["west"];
34689 var east = rs["east"];
34690 var center = rs["center"];
34691 //if(this.hideOnLayout){ // not supported anymore
34692 //c.el.setStyle("display", "none");
34694 if(north && north.isVisible()){
34695 var b = north.getBox();
34696 var m = north.getMargins();
34697 b.width = w - (m.left+m.right);
34700 centerY = b.height + b.y + m.bottom;
34701 centerH -= centerY;
34702 north.updateBox(this.safeBox(b));
34704 if(south && south.isVisible()){
34705 var b = south.getBox();
34706 var m = south.getMargins();
34707 b.width = w - (m.left+m.right);
34709 var totalHeight = (b.height + m.top + m.bottom);
34710 b.y = h - totalHeight + m.top;
34711 centerH -= totalHeight;
34712 south.updateBox(this.safeBox(b));
34714 if(west && west.isVisible()){
34715 var b = west.getBox();
34716 var m = west.getMargins();
34717 b.height = centerH - (m.top+m.bottom);
34719 b.y = centerY + m.top;
34720 var totalWidth = (b.width + m.left + m.right);
34721 centerX += totalWidth;
34722 centerW -= totalWidth;
34723 west.updateBox(this.safeBox(b));
34725 if(east && east.isVisible()){
34726 var b = east.getBox();
34727 var m = east.getMargins();
34728 b.height = centerH - (m.top+m.bottom);
34729 var totalWidth = (b.width + m.left + m.right);
34730 b.x = w - totalWidth + m.left;
34731 b.y = centerY + m.top;
34732 centerW -= totalWidth;
34733 east.updateBox(this.safeBox(b));
34736 var m = center.getMargins();
34738 x: centerX + m.left,
34739 y: centerY + m.top,
34740 width: centerW - (m.left+m.right),
34741 height: centerH - (m.top+m.bottom)
34743 //if(this.hideOnLayout){
34744 //center.el.setStyle("display", "block");
34746 center.updateBox(this.safeBox(centerBox));
34749 this.fireEvent("layout", this);
34753 safeBox : function(box){
34754 box.width = Math.max(0, box.width);
34755 box.height = Math.max(0, box.height);
34760 * Adds a ContentPanel (or subclass) to this layout.
34761 * @param {String} target The target region key (north, south, east, west or center).
34762 * @param {Roo.ContentPanel} panel The panel to add
34763 * @return {Roo.ContentPanel} The added panel
34765 add : function(target, panel){
34767 target = target.toLowerCase();
34768 return this.regions[target].add(panel);
34772 * Remove a ContentPanel (or subclass) to this layout.
34773 * @param {String} target The target region key (north, south, east, west or center).
34774 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34775 * @return {Roo.ContentPanel} The removed panel
34777 remove : function(target, panel){
34778 target = target.toLowerCase();
34779 return this.regions[target].remove(panel);
34783 * Searches all regions for a panel with the specified id
34784 * @param {String} panelId
34785 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34787 findPanel : function(panelId){
34788 var rs = this.regions;
34789 for(var target in rs){
34790 if(typeof rs[target] != "function"){
34791 var p = rs[target].getPanel(panelId);
34801 * Searches all regions for a panel with the specified id and activates (shows) it.
34802 * @param {String/ContentPanel} panelId The panels id or the panel itself
34803 * @return {Roo.ContentPanel} The shown panel or null
34805 showPanel : function(panelId) {
34806 var rs = this.regions;
34807 for(var target in rs){
34808 var r = rs[target];
34809 if(typeof r != "function"){
34810 if(r.hasPanel(panelId)){
34811 return r.showPanel(panelId);
34819 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34820 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34823 restoreState : function(provider){
34825 provider = Roo.state.Manager;
34827 var sm = new Roo.LayoutStateManager();
34828 sm.init(this, provider);
34834 * Adds a xtype elements to the layout.
34838 xtype : 'ContentPanel',
34845 xtype : 'NestedLayoutPanel',
34851 items : [ ... list of content panels or nested layout panels.. ]
34855 * @param {Object} cfg Xtype definition of item to add.
34857 addxtype : function(cfg)
34859 // basically accepts a pannel...
34860 // can accept a layout region..!?!?
34861 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34864 // theory? children can only be panels??
34866 //if (!cfg.xtype.match(/Panel$/)) {
34871 if (typeof(cfg.region) == 'undefined') {
34872 Roo.log("Failed to add Panel, region was not set");
34876 var region = cfg.region;
34882 xitems = cfg.items;
34889 case 'Content': // ContentPanel (el, cfg)
34890 case 'Scroll': // ContentPanel (el, cfg)
34892 cfg.autoCreate = true;
34893 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34895 // var el = this.el.createChild();
34896 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34899 this.add(region, ret);
34903 case 'TreePanel': // our new panel!
34904 cfg.el = this.el.createChild();
34905 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34906 this.add(region, ret);
34911 // create a new Layout (which is a Border Layout...
34913 var clayout = cfg.layout;
34914 clayout.el = this.el.createChild();
34915 clayout.items = clayout.items || [];
34919 // replace this exitems with the clayout ones..
34920 xitems = clayout.items;
34922 // force background off if it's in center...
34923 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34924 cfg.background = false;
34926 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34929 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34930 //console.log('adding nested layout panel ' + cfg.toSource());
34931 this.add(region, ret);
34932 nb = {}; /// find first...
34937 // needs grid and region
34939 //var el = this.getRegion(region).el.createChild();
34941 *var el = this.el.createChild();
34942 // create the grid first...
34943 cfg.grid.container = el;
34944 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34947 if (region == 'center' && this.active ) {
34948 cfg.background = false;
34951 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34953 this.add(region, ret);
34955 if (cfg.background) {
34956 // render grid on panel activation (if panel background)
34957 ret.on('activate', function(gp) {
34958 if (!gp.grid.rendered) {
34959 // gp.grid.render(el);
34963 // cfg.grid.render(el);
34969 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34970 // it was the old xcomponent building that caused this before.
34971 // espeically if border is the top element in the tree.
34981 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34983 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34984 this.add(region, ret);
34988 throw "Can not add '" + cfg.xtype + "' to Border";
34994 this.beginUpdate();
34998 Roo.each(xitems, function(i) {
34999 region = nb && i.region ? i.region : false;
35001 var add = ret.addxtype(i);
35004 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35005 if (!i.background) {
35006 abn[region] = nb[region] ;
35013 // make the last non-background panel active..
35014 //if (nb) { Roo.log(abn); }
35017 for(var r in abn) {
35018 region = this.getRegion(r);
35020 // tried using nb[r], but it does not work..
35022 region.showPanel(abn[r]);
35033 factory : function(cfg)
35036 var validRegions = Roo.bootstrap.layout.Border.regions;
35038 var target = cfg.region;
35041 var r = Roo.bootstrap.layout;
35045 return new r.North(cfg);
35047 return new r.South(cfg);
35049 return new r.East(cfg);
35051 return new r.West(cfg);
35053 return new r.Center(cfg);
35055 throw 'Layout region "'+target+'" not supported.';
35062 * Ext JS Library 1.1.1
35063 * Copyright(c) 2006-2007, Ext JS, LLC.
35065 * Originally Released Under LGPL - original licence link has changed is not relivant.
35068 * <script type="text/javascript">
35072 * @class Roo.bootstrap.layout.Basic
35073 * @extends Roo.util.Observable
35074 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35075 * and does not have a titlebar, tabs or any other features. All it does is size and position
35076 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35077 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35078 * @cfg {string} region the region that it inhabits..
35079 * @cfg {bool} skipConfig skip config?
35083 Roo.bootstrap.layout.Basic = function(config){
35085 this.mgr = config.mgr;
35087 this.position = config.region;
35089 var skipConfig = config.skipConfig;
35093 * @scope Roo.BasicLayoutRegion
35097 * @event beforeremove
35098 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35099 * @param {Roo.LayoutRegion} this
35100 * @param {Roo.ContentPanel} panel The panel
35101 * @param {Object} e The cancel event object
35103 "beforeremove" : true,
35105 * @event invalidated
35106 * Fires when the layout for this region is changed.
35107 * @param {Roo.LayoutRegion} this
35109 "invalidated" : true,
35111 * @event visibilitychange
35112 * Fires when this region is shown or hidden
35113 * @param {Roo.LayoutRegion} this
35114 * @param {Boolean} visibility true or false
35116 "visibilitychange" : true,
35118 * @event paneladded
35119 * Fires when a panel is added.
35120 * @param {Roo.LayoutRegion} this
35121 * @param {Roo.ContentPanel} panel The panel
35123 "paneladded" : true,
35125 * @event panelremoved
35126 * Fires when a panel is removed.
35127 * @param {Roo.LayoutRegion} this
35128 * @param {Roo.ContentPanel} panel The panel
35130 "panelremoved" : true,
35132 * @event beforecollapse
35133 * Fires when this region before collapse.
35134 * @param {Roo.LayoutRegion} this
35136 "beforecollapse" : true,
35139 * Fires when this region is collapsed.
35140 * @param {Roo.LayoutRegion} this
35142 "collapsed" : true,
35145 * Fires when this region is expanded.
35146 * @param {Roo.LayoutRegion} this
35151 * Fires when this region is slid into view.
35152 * @param {Roo.LayoutRegion} this
35154 "slideshow" : true,
35157 * Fires when this region slides out of view.
35158 * @param {Roo.LayoutRegion} this
35160 "slidehide" : true,
35162 * @event panelactivated
35163 * Fires when a panel is activated.
35164 * @param {Roo.LayoutRegion} this
35165 * @param {Roo.ContentPanel} panel The activated panel
35167 "panelactivated" : true,
35170 * Fires when the user resizes this region.
35171 * @param {Roo.LayoutRegion} this
35172 * @param {Number} newSize The new size (width for east/west, height for north/south)
35176 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35177 this.panels = new Roo.util.MixedCollection();
35178 this.panels.getKey = this.getPanelId.createDelegate(this);
35180 this.activePanel = null;
35181 // ensure listeners are added...
35183 if (config.listeners || config.events) {
35184 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35185 listeners : config.listeners || {},
35186 events : config.events || {}
35190 if(skipConfig !== true){
35191 this.applyConfig(config);
35195 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35197 getPanelId : function(p){
35201 applyConfig : function(config){
35202 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35203 this.config = config;
35208 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35209 * the width, for horizontal (north, south) the height.
35210 * @param {Number} newSize The new width or height
35212 resizeTo : function(newSize){
35213 var el = this.el ? this.el :
35214 (this.activePanel ? this.activePanel.getEl() : null);
35216 switch(this.position){
35219 el.setWidth(newSize);
35220 this.fireEvent("resized", this, newSize);
35224 el.setHeight(newSize);
35225 this.fireEvent("resized", this, newSize);
35231 getBox : function(){
35232 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35235 getMargins : function(){
35236 return this.margins;
35239 updateBox : function(box){
35241 var el = this.activePanel.getEl();
35242 el.dom.style.left = box.x + "px";
35243 el.dom.style.top = box.y + "px";
35244 this.activePanel.setSize(box.width, box.height);
35248 * Returns the container element for this region.
35249 * @return {Roo.Element}
35251 getEl : function(){
35252 return this.activePanel;
35256 * Returns true if this region is currently visible.
35257 * @return {Boolean}
35259 isVisible : function(){
35260 return this.activePanel ? true : false;
35263 setActivePanel : function(panel){
35264 panel = this.getPanel(panel);
35265 if(this.activePanel && this.activePanel != panel){
35266 this.activePanel.setActiveState(false);
35267 this.activePanel.getEl().setLeftTop(-10000,-10000);
35269 this.activePanel = panel;
35270 panel.setActiveState(true);
35272 panel.setSize(this.box.width, this.box.height);
35274 this.fireEvent("panelactivated", this, panel);
35275 this.fireEvent("invalidated");
35279 * Show the specified panel.
35280 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35281 * @return {Roo.ContentPanel} The shown panel or null
35283 showPanel : function(panel){
35284 panel = this.getPanel(panel);
35286 this.setActivePanel(panel);
35292 * Get the active panel for this region.
35293 * @return {Roo.ContentPanel} The active panel or null
35295 getActivePanel : function(){
35296 return this.activePanel;
35300 * Add the passed ContentPanel(s)
35301 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35302 * @return {Roo.ContentPanel} The panel added (if only one was added)
35304 add : function(panel){
35305 if(arguments.length > 1){
35306 for(var i = 0, len = arguments.length; i < len; i++) {
35307 this.add(arguments[i]);
35311 if(this.hasPanel(panel)){
35312 this.showPanel(panel);
35315 var el = panel.getEl();
35316 if(el.dom.parentNode != this.mgr.el.dom){
35317 this.mgr.el.dom.appendChild(el.dom);
35319 if(panel.setRegion){
35320 panel.setRegion(this);
35322 this.panels.add(panel);
35323 el.setStyle("position", "absolute");
35324 if(!panel.background){
35325 this.setActivePanel(panel);
35326 if(this.config.initialSize && this.panels.getCount()==1){
35327 this.resizeTo(this.config.initialSize);
35330 this.fireEvent("paneladded", this, panel);
35335 * Returns true if the panel is in this region.
35336 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35337 * @return {Boolean}
35339 hasPanel : function(panel){
35340 if(typeof panel == "object"){ // must be panel obj
35341 panel = panel.getId();
35343 return this.getPanel(panel) ? true : false;
35347 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35348 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35349 * @param {Boolean} preservePanel Overrides the config preservePanel option
35350 * @return {Roo.ContentPanel} The panel that was removed
35352 remove : function(panel, preservePanel){
35353 panel = this.getPanel(panel);
35358 this.fireEvent("beforeremove", this, panel, e);
35359 if(e.cancel === true){
35362 var panelId = panel.getId();
35363 this.panels.removeKey(panelId);
35368 * Returns the panel specified or null if it's not in this region.
35369 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35370 * @return {Roo.ContentPanel}
35372 getPanel : function(id){
35373 if(typeof id == "object"){ // must be panel obj
35376 return this.panels.get(id);
35380 * Returns this regions position (north/south/east/west/center).
35383 getPosition: function(){
35384 return this.position;
35388 * Ext JS Library 1.1.1
35389 * Copyright(c) 2006-2007, Ext JS, LLC.
35391 * Originally Released Under LGPL - original licence link has changed is not relivant.
35394 * <script type="text/javascript">
35398 * @class Roo.bootstrap.layout.Region
35399 * @extends Roo.bootstrap.layout.Basic
35400 * This class represents a region in a layout manager.
35402 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35403 * @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})
35404 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35405 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35406 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35407 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35408 * @cfg {String} title The title for the region (overrides panel titles)
35409 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35410 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35411 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35412 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35413 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35414 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35415 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35416 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35417 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35418 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35420 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35421 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35422 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35423 * @cfg {Number} width For East/West panels
35424 * @cfg {Number} height For North/South panels
35425 * @cfg {Boolean} split To show the splitter
35426 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35428 * @cfg {string} cls Extra CSS classes to add to region
35430 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35431 * @cfg {string} region the region that it inhabits..
35434 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35435 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35437 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35438 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35439 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35441 Roo.bootstrap.layout.Region = function(config)
35443 this.applyConfig(config);
35445 var mgr = config.mgr;
35446 var pos = config.region;
35447 config.skipConfig = true;
35448 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35451 this.onRender(mgr.el);
35454 this.visible = true;
35455 this.collapsed = false;
35456 this.unrendered_panels = [];
35459 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35461 position: '', // set by wrapper (eg. north/south etc..)
35462 unrendered_panels : null, // unrendered panels.
35463 createBody : function(){
35464 /** This region's body element
35465 * @type Roo.Element */
35466 this.bodyEl = this.el.createChild({
35468 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35472 onRender: function(ctr, pos)
35474 var dh = Roo.DomHelper;
35475 /** This region's container element
35476 * @type Roo.Element */
35477 this.el = dh.append(ctr.dom, {
35479 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35481 /** This region's title element
35482 * @type Roo.Element */
35484 this.titleEl = dh.append(this.el.dom,
35487 unselectable: "on",
35488 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35490 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35491 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35494 this.titleEl.enableDisplayMode();
35495 /** This region's title text element
35496 * @type HTMLElement */
35497 this.titleTextEl = this.titleEl.dom.firstChild;
35498 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35500 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35501 this.closeBtn.enableDisplayMode();
35502 this.closeBtn.on("click", this.closeClicked, this);
35503 this.closeBtn.hide();
35505 this.createBody(this.config);
35506 if(this.config.hideWhenEmpty){
35508 this.on("paneladded", this.validateVisibility, this);
35509 this.on("panelremoved", this.validateVisibility, this);
35511 if(this.autoScroll){
35512 this.bodyEl.setStyle("overflow", "auto");
35514 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35516 //if(c.titlebar !== false){
35517 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35518 this.titleEl.hide();
35520 this.titleEl.show();
35521 if(this.config.title){
35522 this.titleTextEl.innerHTML = this.config.title;
35526 if(this.config.collapsed){
35527 this.collapse(true);
35529 if(this.config.hidden){
35533 if (this.unrendered_panels && this.unrendered_panels.length) {
35534 for (var i =0;i< this.unrendered_panels.length; i++) {
35535 this.add(this.unrendered_panels[i]);
35537 this.unrendered_panels = null;
35543 applyConfig : function(c)
35546 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35547 var dh = Roo.DomHelper;
35548 if(c.titlebar !== false){
35549 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35550 this.collapseBtn.on("click", this.collapse, this);
35551 this.collapseBtn.enableDisplayMode();
35553 if(c.showPin === true || this.showPin){
35554 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35555 this.stickBtn.enableDisplayMode();
35556 this.stickBtn.on("click", this.expand, this);
35557 this.stickBtn.hide();
35562 /** This region's collapsed element
35563 * @type Roo.Element */
35566 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35567 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35570 if(c.floatable !== false){
35571 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35572 this.collapsedEl.on("click", this.collapseClick, this);
35575 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35576 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35577 id: "message", unselectable: "on", style:{"float":"left"}});
35578 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35580 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35581 this.expandBtn.on("click", this.expand, this);
35585 if(this.collapseBtn){
35586 this.collapseBtn.setVisible(c.collapsible == true);
35589 this.cmargins = c.cmargins || this.cmargins ||
35590 (this.position == "west" || this.position == "east" ?
35591 {top: 0, left: 2, right:2, bottom: 0} :
35592 {top: 2, left: 0, right:0, bottom: 2});
35594 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35597 this.bottomTabs = c.tabPosition != "top";
35599 this.autoScroll = c.autoScroll || false;
35604 this.duration = c.duration || .30;
35605 this.slideDuration = c.slideDuration || .45;
35610 * Returns true if this region is currently visible.
35611 * @return {Boolean}
35613 isVisible : function(){
35614 return this.visible;
35618 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35619 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35621 //setCollapsedTitle : function(title){
35622 // title = title || " ";
35623 // if(this.collapsedTitleTextEl){
35624 // this.collapsedTitleTextEl.innerHTML = title;
35628 getBox : function(){
35630 // if(!this.collapsed){
35631 b = this.el.getBox(false, true);
35633 // b = this.collapsedEl.getBox(false, true);
35638 getMargins : function(){
35639 return this.margins;
35640 //return this.collapsed ? this.cmargins : this.margins;
35643 highlight : function(){
35644 this.el.addClass("x-layout-panel-dragover");
35647 unhighlight : function(){
35648 this.el.removeClass("x-layout-panel-dragover");
35651 updateBox : function(box)
35653 if (!this.bodyEl) {
35654 return; // not rendered yet..
35658 if(!this.collapsed){
35659 this.el.dom.style.left = box.x + "px";
35660 this.el.dom.style.top = box.y + "px";
35661 this.updateBody(box.width, box.height);
35663 this.collapsedEl.dom.style.left = box.x + "px";
35664 this.collapsedEl.dom.style.top = box.y + "px";
35665 this.collapsedEl.setSize(box.width, box.height);
35668 this.tabs.autoSizeTabs();
35672 updateBody : function(w, h)
35675 this.el.setWidth(w);
35676 w -= this.el.getBorderWidth("rl");
35677 if(this.config.adjustments){
35678 w += this.config.adjustments[0];
35681 if(h !== null && h > 0){
35682 this.el.setHeight(h);
35683 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35684 h -= this.el.getBorderWidth("tb");
35685 if(this.config.adjustments){
35686 h += this.config.adjustments[1];
35688 this.bodyEl.setHeight(h);
35690 h = this.tabs.syncHeight(h);
35693 if(this.panelSize){
35694 w = w !== null ? w : this.panelSize.width;
35695 h = h !== null ? h : this.panelSize.height;
35697 if(this.activePanel){
35698 var el = this.activePanel.getEl();
35699 w = w !== null ? w : el.getWidth();
35700 h = h !== null ? h : el.getHeight();
35701 this.panelSize = {width: w, height: h};
35702 this.activePanel.setSize(w, h);
35704 if(Roo.isIE && this.tabs){
35705 this.tabs.el.repaint();
35710 * Returns the container element for this region.
35711 * @return {Roo.Element}
35713 getEl : function(){
35718 * Hides this region.
35721 //if(!this.collapsed){
35722 this.el.dom.style.left = "-2000px";
35725 // this.collapsedEl.dom.style.left = "-2000px";
35726 // this.collapsedEl.hide();
35728 this.visible = false;
35729 this.fireEvent("visibilitychange", this, false);
35733 * Shows this region if it was previously hidden.
35736 //if(!this.collapsed){
35739 // this.collapsedEl.show();
35741 this.visible = true;
35742 this.fireEvent("visibilitychange", this, true);
35745 closeClicked : function(){
35746 if(this.activePanel){
35747 this.remove(this.activePanel);
35751 collapseClick : function(e){
35753 e.stopPropagation();
35756 e.stopPropagation();
35762 * Collapses this region.
35763 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35766 collapse : function(skipAnim, skipCheck = false){
35767 if(this.collapsed) {
35771 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35773 this.collapsed = true;
35775 this.split.el.hide();
35777 if(this.config.animate && skipAnim !== true){
35778 this.fireEvent("invalidated", this);
35779 this.animateCollapse();
35781 this.el.setLocation(-20000,-20000);
35783 this.collapsedEl.show();
35784 this.fireEvent("collapsed", this);
35785 this.fireEvent("invalidated", this);
35791 animateCollapse : function(){
35796 * Expands this region if it was previously collapsed.
35797 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35798 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35801 expand : function(e, skipAnim){
35803 e.stopPropagation();
35805 if(!this.collapsed || this.el.hasActiveFx()) {
35809 this.afterSlideIn();
35812 this.collapsed = false;
35813 if(this.config.animate && skipAnim !== true){
35814 this.animateExpand();
35818 this.split.el.show();
35820 this.collapsedEl.setLocation(-2000,-2000);
35821 this.collapsedEl.hide();
35822 this.fireEvent("invalidated", this);
35823 this.fireEvent("expanded", this);
35827 animateExpand : function(){
35831 initTabs : function()
35833 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35835 var ts = new Roo.bootstrap.panel.Tabs({
35836 el: this.bodyEl.dom,
35837 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35838 disableTooltips: this.config.disableTabTips,
35839 toolbar : this.config.toolbar
35842 if(this.config.hideTabs){
35843 ts.stripWrap.setDisplayed(false);
35846 ts.resizeTabs = this.config.resizeTabs === true;
35847 ts.minTabWidth = this.config.minTabWidth || 40;
35848 ts.maxTabWidth = this.config.maxTabWidth || 250;
35849 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35850 ts.monitorResize = false;
35851 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35852 ts.bodyEl.addClass('roo-layout-tabs-body');
35853 this.panels.each(this.initPanelAsTab, this);
35856 initPanelAsTab : function(panel){
35857 var ti = this.tabs.addTab(
35861 this.config.closeOnTab && panel.isClosable(),
35864 if(panel.tabTip !== undefined){
35865 ti.setTooltip(panel.tabTip);
35867 ti.on("activate", function(){
35868 this.setActivePanel(panel);
35871 if(this.config.closeOnTab){
35872 ti.on("beforeclose", function(t, e){
35874 this.remove(panel);
35878 panel.tabItem = ti;
35883 updatePanelTitle : function(panel, title)
35885 if(this.activePanel == panel){
35886 this.updateTitle(title);
35889 var ti = this.tabs.getTab(panel.getEl().id);
35891 if(panel.tabTip !== undefined){
35892 ti.setTooltip(panel.tabTip);
35897 updateTitle : function(title){
35898 if(this.titleTextEl && !this.config.title){
35899 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35903 setActivePanel : function(panel)
35905 panel = this.getPanel(panel);
35906 if(this.activePanel && this.activePanel != panel){
35907 if(this.activePanel.setActiveState(false) === false){
35911 this.activePanel = panel;
35912 panel.setActiveState(true);
35913 if(this.panelSize){
35914 panel.setSize(this.panelSize.width, this.panelSize.height);
35917 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35919 this.updateTitle(panel.getTitle());
35921 this.fireEvent("invalidated", this);
35923 this.fireEvent("panelactivated", this, panel);
35927 * Shows the specified panel.
35928 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35929 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35931 showPanel : function(panel)
35933 panel = this.getPanel(panel);
35936 var tab = this.tabs.getTab(panel.getEl().id);
35937 if(tab.isHidden()){
35938 this.tabs.unhideTab(tab.id);
35942 this.setActivePanel(panel);
35949 * Get the active panel for this region.
35950 * @return {Roo.ContentPanel} The active panel or null
35952 getActivePanel : function(){
35953 return this.activePanel;
35956 validateVisibility : function(){
35957 if(this.panels.getCount() < 1){
35958 this.updateTitle(" ");
35959 this.closeBtn.hide();
35962 if(!this.isVisible()){
35969 * Adds the passed ContentPanel(s) to this region.
35970 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35971 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35973 add : function(panel)
35975 if(arguments.length > 1){
35976 for(var i = 0, len = arguments.length; i < len; i++) {
35977 this.add(arguments[i]);
35982 // if we have not been rendered yet, then we can not really do much of this..
35983 if (!this.bodyEl) {
35984 this.unrendered_panels.push(panel);
35991 if(this.hasPanel(panel)){
35992 this.showPanel(panel);
35995 panel.setRegion(this);
35996 this.panels.add(panel);
35997 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35998 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35999 // and hide them... ???
36000 this.bodyEl.dom.appendChild(panel.getEl().dom);
36001 if(panel.background !== true){
36002 this.setActivePanel(panel);
36004 this.fireEvent("paneladded", this, panel);
36011 this.initPanelAsTab(panel);
36015 if(panel.background !== true){
36016 this.tabs.activate(panel.getEl().id);
36018 this.fireEvent("paneladded", this, panel);
36023 * Hides the tab for the specified panel.
36024 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36026 hidePanel : function(panel){
36027 if(this.tabs && (panel = this.getPanel(panel))){
36028 this.tabs.hideTab(panel.getEl().id);
36033 * Unhides the tab for a previously hidden panel.
36034 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36036 unhidePanel : function(panel){
36037 if(this.tabs && (panel = this.getPanel(panel))){
36038 this.tabs.unhideTab(panel.getEl().id);
36042 clearPanels : function(){
36043 while(this.panels.getCount() > 0){
36044 this.remove(this.panels.first());
36049 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36050 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36051 * @param {Boolean} preservePanel Overrides the config preservePanel option
36052 * @return {Roo.ContentPanel} The panel that was removed
36054 remove : function(panel, preservePanel)
36056 panel = this.getPanel(panel);
36061 this.fireEvent("beforeremove", this, panel, e);
36062 if(e.cancel === true){
36065 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36066 var panelId = panel.getId();
36067 this.panels.removeKey(panelId);
36069 document.body.appendChild(panel.getEl().dom);
36072 this.tabs.removeTab(panel.getEl().id);
36073 }else if (!preservePanel){
36074 this.bodyEl.dom.removeChild(panel.getEl().dom);
36076 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36077 var p = this.panels.first();
36078 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36079 tempEl.appendChild(p.getEl().dom);
36080 this.bodyEl.update("");
36081 this.bodyEl.dom.appendChild(p.getEl().dom);
36083 this.updateTitle(p.getTitle());
36085 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36086 this.setActivePanel(p);
36088 panel.setRegion(null);
36089 if(this.activePanel == panel){
36090 this.activePanel = null;
36092 if(this.config.autoDestroy !== false && preservePanel !== true){
36093 try{panel.destroy();}catch(e){}
36095 this.fireEvent("panelremoved", this, panel);
36100 * Returns the TabPanel component used by this region
36101 * @return {Roo.TabPanel}
36103 getTabs : function(){
36107 createTool : function(parentEl, className){
36108 var btn = Roo.DomHelper.append(parentEl, {
36110 cls: "x-layout-tools-button",
36113 cls: "roo-layout-tools-button-inner " + className,
36117 btn.addClassOnOver("roo-layout-tools-button-over");
36122 * Ext JS Library 1.1.1
36123 * Copyright(c) 2006-2007, Ext JS, LLC.
36125 * Originally Released Under LGPL - original licence link has changed is not relivant.
36128 * <script type="text/javascript">
36134 * @class Roo.SplitLayoutRegion
36135 * @extends Roo.LayoutRegion
36136 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36138 Roo.bootstrap.layout.Split = function(config){
36139 this.cursor = config.cursor;
36140 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36143 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36145 splitTip : "Drag to resize.",
36146 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36147 useSplitTips : false,
36149 applyConfig : function(config){
36150 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36153 onRender : function(ctr,pos) {
36155 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36156 if(!this.config.split){
36161 var splitEl = Roo.DomHelper.append(ctr.dom, {
36163 id: this.el.id + "-split",
36164 cls: "roo-layout-split roo-layout-split-"+this.position,
36167 /** The SplitBar for this region
36168 * @type Roo.SplitBar */
36169 // does not exist yet...
36170 Roo.log([this.position, this.orientation]);
36172 this.split = new Roo.bootstrap.SplitBar({
36173 dragElement : splitEl,
36174 resizingElement: this.el,
36175 orientation : this.orientation
36178 this.split.on("moved", this.onSplitMove, this);
36179 this.split.useShim = this.config.useShim === true;
36180 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36181 if(this.useSplitTips){
36182 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36184 //if(config.collapsible){
36185 // this.split.el.on("dblclick", this.collapse, this);
36188 if(typeof this.config.minSize != "undefined"){
36189 this.split.minSize = this.config.minSize;
36191 if(typeof this.config.maxSize != "undefined"){
36192 this.split.maxSize = this.config.maxSize;
36194 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36195 this.hideSplitter();
36200 getHMaxSize : function(){
36201 var cmax = this.config.maxSize || 10000;
36202 var center = this.mgr.getRegion("center");
36203 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36206 getVMaxSize : function(){
36207 var cmax = this.config.maxSize || 10000;
36208 var center = this.mgr.getRegion("center");
36209 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36212 onSplitMove : function(split, newSize){
36213 this.fireEvent("resized", this, newSize);
36217 * Returns the {@link Roo.SplitBar} for this region.
36218 * @return {Roo.SplitBar}
36220 getSplitBar : function(){
36225 this.hideSplitter();
36226 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36229 hideSplitter : function(){
36231 this.split.el.setLocation(-2000,-2000);
36232 this.split.el.hide();
36238 this.split.el.show();
36240 Roo.bootstrap.layout.Split.superclass.show.call(this);
36243 beforeSlide: function(){
36244 if(Roo.isGecko){// firefox overflow auto bug workaround
36245 this.bodyEl.clip();
36247 this.tabs.bodyEl.clip();
36249 if(this.activePanel){
36250 this.activePanel.getEl().clip();
36252 if(this.activePanel.beforeSlide){
36253 this.activePanel.beforeSlide();
36259 afterSlide : function(){
36260 if(Roo.isGecko){// firefox overflow auto bug workaround
36261 this.bodyEl.unclip();
36263 this.tabs.bodyEl.unclip();
36265 if(this.activePanel){
36266 this.activePanel.getEl().unclip();
36267 if(this.activePanel.afterSlide){
36268 this.activePanel.afterSlide();
36274 initAutoHide : function(){
36275 if(this.autoHide !== false){
36276 if(!this.autoHideHd){
36277 var st = new Roo.util.DelayedTask(this.slideIn, this);
36278 this.autoHideHd = {
36279 "mouseout": function(e){
36280 if(!e.within(this.el, true)){
36284 "mouseover" : function(e){
36290 this.el.on(this.autoHideHd);
36294 clearAutoHide : function(){
36295 if(this.autoHide !== false){
36296 this.el.un("mouseout", this.autoHideHd.mouseout);
36297 this.el.un("mouseover", this.autoHideHd.mouseover);
36301 clearMonitor : function(){
36302 Roo.get(document).un("click", this.slideInIf, this);
36305 // these names are backwards but not changed for compat
36306 slideOut : function(){
36307 if(this.isSlid || this.el.hasActiveFx()){
36310 this.isSlid = true;
36311 if(this.collapseBtn){
36312 this.collapseBtn.hide();
36314 this.closeBtnState = this.closeBtn.getStyle('display');
36315 this.closeBtn.hide();
36317 this.stickBtn.show();
36320 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36321 this.beforeSlide();
36322 this.el.setStyle("z-index", 10001);
36323 this.el.slideIn(this.getSlideAnchor(), {
36324 callback: function(){
36326 this.initAutoHide();
36327 Roo.get(document).on("click", this.slideInIf, this);
36328 this.fireEvent("slideshow", this);
36335 afterSlideIn : function(){
36336 this.clearAutoHide();
36337 this.isSlid = false;
36338 this.clearMonitor();
36339 this.el.setStyle("z-index", "");
36340 if(this.collapseBtn){
36341 this.collapseBtn.show();
36343 this.closeBtn.setStyle('display', this.closeBtnState);
36345 this.stickBtn.hide();
36347 this.fireEvent("slidehide", this);
36350 slideIn : function(cb){
36351 if(!this.isSlid || this.el.hasActiveFx()){
36355 this.isSlid = false;
36356 this.beforeSlide();
36357 this.el.slideOut(this.getSlideAnchor(), {
36358 callback: function(){
36359 this.el.setLeftTop(-10000, -10000);
36361 this.afterSlideIn();
36369 slideInIf : function(e){
36370 if(!e.within(this.el)){
36375 animateCollapse : function(){
36376 this.beforeSlide();
36377 this.el.setStyle("z-index", 20000);
36378 var anchor = this.getSlideAnchor();
36379 this.el.slideOut(anchor, {
36380 callback : function(){
36381 this.el.setStyle("z-index", "");
36382 this.collapsedEl.slideIn(anchor, {duration:.3});
36384 this.el.setLocation(-10000,-10000);
36386 this.fireEvent("collapsed", this);
36393 animateExpand : function(){
36394 this.beforeSlide();
36395 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36396 this.el.setStyle("z-index", 20000);
36397 this.collapsedEl.hide({
36400 this.el.slideIn(this.getSlideAnchor(), {
36401 callback : function(){
36402 this.el.setStyle("z-index", "");
36405 this.split.el.show();
36407 this.fireEvent("invalidated", this);
36408 this.fireEvent("expanded", this);
36436 getAnchor : function(){
36437 return this.anchors[this.position];
36440 getCollapseAnchor : function(){
36441 return this.canchors[this.position];
36444 getSlideAnchor : function(){
36445 return this.sanchors[this.position];
36448 getAlignAdj : function(){
36449 var cm = this.cmargins;
36450 switch(this.position){
36466 getExpandAdj : function(){
36467 var c = this.collapsedEl, cm = this.cmargins;
36468 switch(this.position){
36470 return [-(cm.right+c.getWidth()+cm.left), 0];
36473 return [cm.right+c.getWidth()+cm.left, 0];
36476 return [0, -(cm.top+cm.bottom+c.getHeight())];
36479 return [0, cm.top+cm.bottom+c.getHeight()];
36485 * Ext JS Library 1.1.1
36486 * Copyright(c) 2006-2007, Ext JS, LLC.
36488 * Originally Released Under LGPL - original licence link has changed is not relivant.
36491 * <script type="text/javascript">
36494 * These classes are private internal classes
36496 Roo.bootstrap.layout.Center = function(config){
36497 config.region = "center";
36498 Roo.bootstrap.layout.Region.call(this, config);
36499 this.visible = true;
36500 this.minWidth = config.minWidth || 20;
36501 this.minHeight = config.minHeight || 20;
36504 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36506 // center panel can't be hidden
36510 // center panel can't be hidden
36513 getMinWidth: function(){
36514 return this.minWidth;
36517 getMinHeight: function(){
36518 return this.minHeight;
36531 Roo.bootstrap.layout.North = function(config)
36533 config.region = 'north';
36534 config.cursor = 'n-resize';
36536 Roo.bootstrap.layout.Split.call(this, config);
36540 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36541 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36542 this.split.el.addClass("roo-layout-split-v");
36544 var size = config.initialSize || config.height;
36545 if(typeof size != "undefined"){
36546 this.el.setHeight(size);
36549 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36551 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36555 getBox : function(){
36556 if(this.collapsed){
36557 return this.collapsedEl.getBox();
36559 var box = this.el.getBox();
36561 box.height += this.split.el.getHeight();
36566 updateBox : function(box){
36567 if(this.split && !this.collapsed){
36568 box.height -= this.split.el.getHeight();
36569 this.split.el.setLeft(box.x);
36570 this.split.el.setTop(box.y+box.height);
36571 this.split.el.setWidth(box.width);
36573 if(this.collapsed){
36574 this.updateBody(box.width, null);
36576 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36584 Roo.bootstrap.layout.South = function(config){
36585 config.region = 'south';
36586 config.cursor = 's-resize';
36587 Roo.bootstrap.layout.Split.call(this, config);
36589 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36590 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36591 this.split.el.addClass("roo-layout-split-v");
36593 var size = config.initialSize || config.height;
36594 if(typeof size != "undefined"){
36595 this.el.setHeight(size);
36599 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36600 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36601 getBox : function(){
36602 if(this.collapsed){
36603 return this.collapsedEl.getBox();
36605 var box = this.el.getBox();
36607 var sh = this.split.el.getHeight();
36614 updateBox : function(box){
36615 if(this.split && !this.collapsed){
36616 var sh = this.split.el.getHeight();
36619 this.split.el.setLeft(box.x);
36620 this.split.el.setTop(box.y-sh);
36621 this.split.el.setWidth(box.width);
36623 if(this.collapsed){
36624 this.updateBody(box.width, null);
36626 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36630 Roo.bootstrap.layout.East = function(config){
36631 config.region = "east";
36632 config.cursor = "e-resize";
36633 Roo.bootstrap.layout.Split.call(this, config);
36635 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36636 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36637 this.split.el.addClass("roo-layout-split-h");
36639 var size = config.initialSize || config.width;
36640 if(typeof size != "undefined"){
36641 this.el.setWidth(size);
36644 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36645 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36646 getBox : function(){
36647 if(this.collapsed){
36648 return this.collapsedEl.getBox();
36650 var box = this.el.getBox();
36652 var sw = this.split.el.getWidth();
36659 updateBox : function(box){
36660 if(this.split && !this.collapsed){
36661 var sw = this.split.el.getWidth();
36663 this.split.el.setLeft(box.x);
36664 this.split.el.setTop(box.y);
36665 this.split.el.setHeight(box.height);
36668 if(this.collapsed){
36669 this.updateBody(null, box.height);
36671 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36675 Roo.bootstrap.layout.West = function(config){
36676 config.region = "west";
36677 config.cursor = "w-resize";
36679 Roo.bootstrap.layout.Split.call(this, config);
36681 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36682 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36683 this.split.el.addClass("roo-layout-split-h");
36687 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36688 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36690 onRender: function(ctr, pos)
36692 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36693 var size = this.config.initialSize || this.config.width;
36694 if(typeof size != "undefined"){
36695 this.el.setWidth(size);
36699 getBox : function(){
36700 if(this.collapsed){
36701 return this.collapsedEl.getBox();
36703 var box = this.el.getBox();
36705 box.width += this.split.el.getWidth();
36710 updateBox : function(box){
36711 if(this.split && !this.collapsed){
36712 var sw = this.split.el.getWidth();
36714 this.split.el.setLeft(box.x+box.width);
36715 this.split.el.setTop(box.y);
36716 this.split.el.setHeight(box.height);
36718 if(this.collapsed){
36719 this.updateBody(null, box.height);
36721 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36724 Roo.namespace("Roo.bootstrap.panel");/*
36726 * Ext JS Library 1.1.1
36727 * Copyright(c) 2006-2007, Ext JS, LLC.
36729 * Originally Released Under LGPL - original licence link has changed is not relivant.
36732 * <script type="text/javascript">
36735 * @class Roo.ContentPanel
36736 * @extends Roo.util.Observable
36737 * A basic ContentPanel element.
36738 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36739 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36740 * @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
36741 * @cfg {Boolean} closable True if the panel can be closed/removed
36742 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36743 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36744 * @cfg {Toolbar} toolbar A toolbar for this panel
36745 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36746 * @cfg {String} title The title for this panel
36747 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36748 * @cfg {String} url Calls {@link #setUrl} with this value
36749 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36750 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36751 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36752 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36753 * @cfg {Boolean} badges render the badges
36756 * Create a new ContentPanel.
36757 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36758 * @param {String/Object} config A string to set only the title or a config object
36759 * @param {String} content (optional) Set the HTML content for this panel
36760 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36762 Roo.bootstrap.panel.Content = function( config){
36764 this.tpl = config.tpl || false;
36766 var el = config.el;
36767 var content = config.content;
36769 if(config.autoCreate){ // xtype is available if this is called from factory
36772 this.el = Roo.get(el);
36773 if(!this.el && config && config.autoCreate){
36774 if(typeof config.autoCreate == "object"){
36775 if(!config.autoCreate.id){
36776 config.autoCreate.id = config.id||el;
36778 this.el = Roo.DomHelper.append(document.body,
36779 config.autoCreate, true);
36781 var elcfg = { tag: "div",
36782 cls: "roo-layout-inactive-content",
36786 elcfg.html = config.html;
36790 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36793 this.closable = false;
36794 this.loaded = false;
36795 this.active = false;
36798 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36800 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36802 this.wrapEl = this.el; //this.el.wrap();
36804 if (config.toolbar.items) {
36805 ti = config.toolbar.items ;
36806 delete config.toolbar.items ;
36810 this.toolbar.render(this.wrapEl, 'before');
36811 for(var i =0;i < ti.length;i++) {
36812 // Roo.log(['add child', items[i]]);
36813 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36815 this.toolbar.items = nitems;
36816 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36817 delete config.toolbar;
36821 // xtype created footer. - not sure if will work as we normally have to render first..
36822 if (this.footer && !this.footer.el && this.footer.xtype) {
36823 if (!this.wrapEl) {
36824 this.wrapEl = this.el.wrap();
36827 this.footer.container = this.wrapEl.createChild();
36829 this.footer = Roo.factory(this.footer, Roo);
36834 if(typeof config == "string"){
36835 this.title = config;
36837 Roo.apply(this, config);
36841 this.resizeEl = Roo.get(this.resizeEl, true);
36843 this.resizeEl = this.el;
36845 // handle view.xtype
36853 * Fires when this panel is activated.
36854 * @param {Roo.ContentPanel} this
36858 * @event deactivate
36859 * Fires when this panel is activated.
36860 * @param {Roo.ContentPanel} this
36862 "deactivate" : true,
36866 * Fires when this panel is resized if fitToFrame is true.
36867 * @param {Roo.ContentPanel} this
36868 * @param {Number} width The width after any component adjustments
36869 * @param {Number} height The height after any component adjustments
36875 * Fires when this tab is created
36876 * @param {Roo.ContentPanel} this
36887 if(this.autoScroll){
36888 this.resizeEl.setStyle("overflow", "auto");
36890 // fix randome scrolling
36891 //this.el.on('scroll', function() {
36892 // Roo.log('fix random scolling');
36893 // this.scrollTo('top',0);
36896 content = content || this.content;
36898 this.setContent(content);
36900 if(config && config.url){
36901 this.setUrl(this.url, this.params, this.loadOnce);
36906 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36908 if (this.view && typeof(this.view.xtype) != 'undefined') {
36909 this.view.el = this.el.appendChild(document.createElement("div"));
36910 this.view = Roo.factory(this.view);
36911 this.view.render && this.view.render(false, '');
36915 this.fireEvent('render', this);
36918 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36922 setRegion : function(region){
36923 this.region = region;
36924 this.setActiveClass(region && !this.background);
36928 setActiveClass: function(state)
36931 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36932 this.el.setStyle('position','relative');
36934 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36935 this.el.setStyle('position', 'absolute');
36940 * Returns the toolbar for this Panel if one was configured.
36941 * @return {Roo.Toolbar}
36943 getToolbar : function(){
36944 return this.toolbar;
36947 setActiveState : function(active)
36949 this.active = active;
36950 this.setActiveClass(active);
36952 if(this.fireEvent("deactivate", this) === false){
36957 this.fireEvent("activate", this);
36961 * Updates this panel's element
36962 * @param {String} content The new content
36963 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36965 setContent : function(content, loadScripts){
36966 this.el.update(content, loadScripts);
36969 ignoreResize : function(w, h){
36970 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36973 this.lastSize = {width: w, height: h};
36978 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36979 * @return {Roo.UpdateManager} The UpdateManager
36981 getUpdateManager : function(){
36982 return this.el.getUpdateManager();
36985 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36986 * @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:
36989 url: "your-url.php",
36990 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36991 callback: yourFunction,
36992 scope: yourObject, //(optional scope)
36995 text: "Loading...",
37000 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37001 * 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.
37002 * @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}
37003 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37004 * @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.
37005 * @return {Roo.ContentPanel} this
37008 var um = this.el.getUpdateManager();
37009 um.update.apply(um, arguments);
37015 * 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.
37016 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37017 * @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)
37018 * @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)
37019 * @return {Roo.UpdateManager} The UpdateManager
37021 setUrl : function(url, params, loadOnce){
37022 if(this.refreshDelegate){
37023 this.removeListener("activate", this.refreshDelegate);
37025 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37026 this.on("activate", this.refreshDelegate);
37027 return this.el.getUpdateManager();
37030 _handleRefresh : function(url, params, loadOnce){
37031 if(!loadOnce || !this.loaded){
37032 var updater = this.el.getUpdateManager();
37033 updater.update(url, params, this._setLoaded.createDelegate(this));
37037 _setLoaded : function(){
37038 this.loaded = true;
37042 * Returns this panel's id
37045 getId : function(){
37050 * Returns this panel's element - used by regiosn to add.
37051 * @return {Roo.Element}
37053 getEl : function(){
37054 return this.wrapEl || this.el;
37059 adjustForComponents : function(width, height)
37061 //Roo.log('adjustForComponents ');
37062 if(this.resizeEl != this.el){
37063 width -= this.el.getFrameWidth('lr');
37064 height -= this.el.getFrameWidth('tb');
37067 var te = this.toolbar.getEl();
37068 te.setWidth(width);
37069 height -= te.getHeight();
37072 var te = this.footer.getEl();
37073 te.setWidth(width);
37074 height -= te.getHeight();
37078 if(this.adjustments){
37079 width += this.adjustments[0];
37080 height += this.adjustments[1];
37082 return {"width": width, "height": height};
37085 setSize : function(width, height){
37086 if(this.fitToFrame && !this.ignoreResize(width, height)){
37087 if(this.fitContainer && this.resizeEl != this.el){
37088 this.el.setSize(width, height);
37090 var size = this.adjustForComponents(width, height);
37091 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37092 this.fireEvent('resize', this, size.width, size.height);
37097 * Returns this panel's title
37100 getTitle : function(){
37102 if (typeof(this.title) != 'object') {
37107 for (var k in this.title) {
37108 if (!this.title.hasOwnProperty(k)) {
37112 if (k.indexOf('-') >= 0) {
37113 var s = k.split('-');
37114 for (var i = 0; i<s.length; i++) {
37115 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37118 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37125 * Set this panel's title
37126 * @param {String} title
37128 setTitle : function(title){
37129 this.title = title;
37131 this.region.updatePanelTitle(this, title);
37136 * Returns true is this panel was configured to be closable
37137 * @return {Boolean}
37139 isClosable : function(){
37140 return this.closable;
37143 beforeSlide : function(){
37145 this.resizeEl.clip();
37148 afterSlide : function(){
37150 this.resizeEl.unclip();
37154 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37155 * Will fail silently if the {@link #setUrl} method has not been called.
37156 * This does not activate the panel, just updates its content.
37158 refresh : function(){
37159 if(this.refreshDelegate){
37160 this.loaded = false;
37161 this.refreshDelegate();
37166 * Destroys this panel
37168 destroy : function(){
37169 this.el.removeAllListeners();
37170 var tempEl = document.createElement("span");
37171 tempEl.appendChild(this.el.dom);
37172 tempEl.innerHTML = "";
37178 * form - if the content panel contains a form - this is a reference to it.
37179 * @type {Roo.form.Form}
37183 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37184 * This contains a reference to it.
37190 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37200 * @param {Object} cfg Xtype definition of item to add.
37204 getChildContainer: function () {
37205 return this.getEl();
37210 var ret = new Roo.factory(cfg);
37215 if (cfg.xtype.match(/^Form$/)) {
37218 //if (this.footer) {
37219 // el = this.footer.container.insertSibling(false, 'before');
37221 el = this.el.createChild();
37224 this.form = new Roo.form.Form(cfg);
37227 if ( this.form.allItems.length) {
37228 this.form.render(el.dom);
37232 // should only have one of theses..
37233 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37234 // views.. should not be just added - used named prop 'view''
37236 cfg.el = this.el.appendChild(document.createElement("div"));
37239 var ret = new Roo.factory(cfg);
37241 ret.render && ret.render(false, ''); // render blank..
37251 * @class Roo.bootstrap.panel.Grid
37252 * @extends Roo.bootstrap.panel.Content
37254 * Create a new GridPanel.
37255 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37256 * @param {Object} config A the config object
37262 Roo.bootstrap.panel.Grid = function(config)
37266 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37267 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37269 config.el = this.wrapper;
37270 //this.el = this.wrapper;
37272 if (config.container) {
37273 // ctor'ed from a Border/panel.grid
37276 this.wrapper.setStyle("overflow", "hidden");
37277 this.wrapper.addClass('roo-grid-container');
37282 if(config.toolbar){
37283 var tool_el = this.wrapper.createChild();
37284 this.toolbar = Roo.factory(config.toolbar);
37286 if (config.toolbar.items) {
37287 ti = config.toolbar.items ;
37288 delete config.toolbar.items ;
37292 this.toolbar.render(tool_el);
37293 for(var i =0;i < ti.length;i++) {
37294 // Roo.log(['add child', items[i]]);
37295 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37297 this.toolbar.items = nitems;
37299 delete config.toolbar;
37302 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37303 config.grid.scrollBody = true;;
37304 config.grid.monitorWindowResize = false; // turn off autosizing
37305 config.grid.autoHeight = false;
37306 config.grid.autoWidth = false;
37308 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37310 if (config.background) {
37311 // render grid on panel activation (if panel background)
37312 this.on('activate', function(gp) {
37313 if (!gp.grid.rendered) {
37314 gp.grid.render(this.wrapper);
37315 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37320 this.grid.render(this.wrapper);
37321 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37324 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37325 // ??? needed ??? config.el = this.wrapper;
37330 // xtype created footer. - not sure if will work as we normally have to render first..
37331 if (this.footer && !this.footer.el && this.footer.xtype) {
37333 var ctr = this.grid.getView().getFooterPanel(true);
37334 this.footer.dataSource = this.grid.dataSource;
37335 this.footer = Roo.factory(this.footer, Roo);
37336 this.footer.render(ctr);
37346 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37347 getId : function(){
37348 return this.grid.id;
37352 * Returns the grid for this panel
37353 * @return {Roo.bootstrap.Table}
37355 getGrid : function(){
37359 setSize : function(width, height){
37360 if(!this.ignoreResize(width, height)){
37361 var grid = this.grid;
37362 var size = this.adjustForComponents(width, height);
37363 var gridel = grid.getGridEl();
37364 gridel.setSize(size.width, size.height);
37366 var thd = grid.getGridEl().select('thead',true).first();
37367 var tbd = grid.getGridEl().select('tbody', true).first();
37369 tbd.setSize(width, height - thd.getHeight());
37378 beforeSlide : function(){
37379 this.grid.getView().scroller.clip();
37382 afterSlide : function(){
37383 this.grid.getView().scroller.unclip();
37386 destroy : function(){
37387 this.grid.destroy();
37389 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37394 * @class Roo.bootstrap.panel.Nest
37395 * @extends Roo.bootstrap.panel.Content
37397 * Create a new Panel, that can contain a layout.Border.
37400 * @param {Roo.BorderLayout} layout The layout for this panel
37401 * @param {String/Object} config A string to set only the title or a config object
37403 Roo.bootstrap.panel.Nest = function(config)
37405 // construct with only one argument..
37406 /* FIXME - implement nicer consturctors
37407 if (layout.layout) {
37409 layout = config.layout;
37410 delete config.layout;
37412 if (layout.xtype && !layout.getEl) {
37413 // then layout needs constructing..
37414 layout = Roo.factory(layout, Roo);
37418 config.el = config.layout.getEl();
37420 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37422 config.layout.monitorWindowResize = false; // turn off autosizing
37423 this.layout = config.layout;
37424 this.layout.getEl().addClass("roo-layout-nested-layout");
37431 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37433 setSize : function(width, height){
37434 if(!this.ignoreResize(width, height)){
37435 var size = this.adjustForComponents(width, height);
37436 var el = this.layout.getEl();
37437 if (size.height < 1) {
37438 el.setWidth(size.width);
37440 el.setSize(size.width, size.height);
37442 var touch = el.dom.offsetWidth;
37443 this.layout.layout();
37444 // ie requires a double layout on the first pass
37445 if(Roo.isIE && !this.initialized){
37446 this.initialized = true;
37447 this.layout.layout();
37452 // activate all subpanels if not currently active..
37454 setActiveState : function(active){
37455 this.active = active;
37456 this.setActiveClass(active);
37459 this.fireEvent("deactivate", this);
37463 this.fireEvent("activate", this);
37464 // not sure if this should happen before or after..
37465 if (!this.layout) {
37466 return; // should not happen..
37469 for (var r in this.layout.regions) {
37470 reg = this.layout.getRegion(r);
37471 if (reg.getActivePanel()) {
37472 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37473 reg.setActivePanel(reg.getActivePanel());
37476 if (!reg.panels.length) {
37479 reg.showPanel(reg.getPanel(0));
37488 * Returns the nested BorderLayout for this panel
37489 * @return {Roo.BorderLayout}
37491 getLayout : function(){
37492 return this.layout;
37496 * Adds a xtype elements to the layout of the nested panel
37500 xtype : 'ContentPanel',
37507 xtype : 'NestedLayoutPanel',
37513 items : [ ... list of content panels or nested layout panels.. ]
37517 * @param {Object} cfg Xtype definition of item to add.
37519 addxtype : function(cfg) {
37520 return this.layout.addxtype(cfg);
37525 * Ext JS Library 1.1.1
37526 * Copyright(c) 2006-2007, Ext JS, LLC.
37528 * Originally Released Under LGPL - original licence link has changed is not relivant.
37531 * <script type="text/javascript">
37534 * @class Roo.TabPanel
37535 * @extends Roo.util.Observable
37536 * A lightweight tab container.
37540 // basic tabs 1, built from existing content
37541 var tabs = new Roo.TabPanel("tabs1");
37542 tabs.addTab("script", "View Script");
37543 tabs.addTab("markup", "View Markup");
37544 tabs.activate("script");
37546 // more advanced tabs, built from javascript
37547 var jtabs = new Roo.TabPanel("jtabs");
37548 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37550 // set up the UpdateManager
37551 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37552 var updater = tab2.getUpdateManager();
37553 updater.setDefaultUrl("ajax1.htm");
37554 tab2.on('activate', updater.refresh, updater, true);
37556 // Use setUrl for Ajax loading
37557 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37558 tab3.setUrl("ajax2.htm", null, true);
37561 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37564 jtabs.activate("jtabs-1");
37567 * Create a new TabPanel.
37568 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37569 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37571 Roo.bootstrap.panel.Tabs = function(config){
37573 * The container element for this TabPanel.
37574 * @type Roo.Element
37576 this.el = Roo.get(config.el);
37579 if(typeof config == "boolean"){
37580 this.tabPosition = config ? "bottom" : "top";
37582 Roo.apply(this, config);
37586 if(this.tabPosition == "bottom"){
37587 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37588 this.el.addClass("roo-tabs-bottom");
37590 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37591 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37592 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37594 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37596 if(this.tabPosition != "bottom"){
37597 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37598 * @type Roo.Element
37600 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37601 this.el.addClass("roo-tabs-top");
37605 this.bodyEl.setStyle("position", "relative");
37607 this.active = null;
37608 this.activateDelegate = this.activate.createDelegate(this);
37613 * Fires when the active tab changes
37614 * @param {Roo.TabPanel} this
37615 * @param {Roo.TabPanelItem} activePanel The new active tab
37619 * @event beforetabchange
37620 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37621 * @param {Roo.TabPanel} this
37622 * @param {Object} e Set cancel to true on this object to cancel the tab change
37623 * @param {Roo.TabPanelItem} tab The tab being changed to
37625 "beforetabchange" : true
37628 Roo.EventManager.onWindowResize(this.onResize, this);
37629 this.cpad = this.el.getPadding("lr");
37630 this.hiddenCount = 0;
37633 // toolbar on the tabbar support...
37634 if (this.toolbar) {
37635 alert("no toolbar support yet");
37636 this.toolbar = false;
37638 var tcfg = this.toolbar;
37639 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37640 this.toolbar = new Roo.Toolbar(tcfg);
37641 if (Roo.isSafari) {
37642 var tbl = tcfg.container.child('table', true);
37643 tbl.setAttribute('width', '100%');
37651 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37654 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37656 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37658 tabPosition : "top",
37660 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37662 currentTabWidth : 0,
37664 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37668 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37672 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37674 preferredTabWidth : 175,
37676 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37678 resizeTabs : false,
37680 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37682 monitorResize : true,
37684 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37689 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37690 * @param {String} id The id of the div to use <b>or create</b>
37691 * @param {String} text The text for the tab
37692 * @param {String} content (optional) Content to put in the TabPanelItem body
37693 * @param {Boolean} closable (optional) True to create a close icon on the tab
37694 * @return {Roo.TabPanelItem} The created TabPanelItem
37696 addTab : function(id, text, content, closable, tpl)
37698 var item = new Roo.bootstrap.panel.TabItem({
37702 closable : closable,
37705 this.addTabItem(item);
37707 item.setContent(content);
37713 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37714 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37715 * @return {Roo.TabPanelItem}
37717 getTab : function(id){
37718 return this.items[id];
37722 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37723 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37725 hideTab : function(id){
37726 var t = this.items[id];
37729 this.hiddenCount++;
37730 this.autoSizeTabs();
37735 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37736 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37738 unhideTab : function(id){
37739 var t = this.items[id];
37741 t.setHidden(false);
37742 this.hiddenCount--;
37743 this.autoSizeTabs();
37748 * Adds an existing {@link Roo.TabPanelItem}.
37749 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37751 addTabItem : function(item){
37752 this.items[item.id] = item;
37753 this.items.push(item);
37754 // if(this.resizeTabs){
37755 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37756 // this.autoSizeTabs();
37758 // item.autoSize();
37763 * Removes a {@link Roo.TabPanelItem}.
37764 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37766 removeTab : function(id){
37767 var items = this.items;
37768 var tab = items[id];
37769 if(!tab) { return; }
37770 var index = items.indexOf(tab);
37771 if(this.active == tab && items.length > 1){
37772 var newTab = this.getNextAvailable(index);
37777 this.stripEl.dom.removeChild(tab.pnode.dom);
37778 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37779 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37781 items.splice(index, 1);
37782 delete this.items[tab.id];
37783 tab.fireEvent("close", tab);
37784 tab.purgeListeners();
37785 this.autoSizeTabs();
37788 getNextAvailable : function(start){
37789 var items = this.items;
37791 // look for a next tab that will slide over to
37792 // replace the one being removed
37793 while(index < items.length){
37794 var item = items[++index];
37795 if(item && !item.isHidden()){
37799 // if one isn't found select the previous tab (on the left)
37802 var item = items[--index];
37803 if(item && !item.isHidden()){
37811 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37812 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37814 disableTab : function(id){
37815 var tab = this.items[id];
37816 if(tab && this.active != tab){
37822 * Enables a {@link Roo.TabPanelItem} that is disabled.
37823 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37825 enableTab : function(id){
37826 var tab = this.items[id];
37831 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37832 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37833 * @return {Roo.TabPanelItem} The TabPanelItem.
37835 activate : function(id){
37836 var tab = this.items[id];
37840 if(tab == this.active || tab.disabled){
37844 this.fireEvent("beforetabchange", this, e, tab);
37845 if(e.cancel !== true && !tab.disabled){
37847 this.active.hide();
37849 this.active = this.items[id];
37850 this.active.show();
37851 this.fireEvent("tabchange", this, this.active);
37857 * Gets the active {@link Roo.TabPanelItem}.
37858 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37860 getActiveTab : function(){
37861 return this.active;
37865 * Updates the tab body element to fit the height of the container element
37866 * for overflow scrolling
37867 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37869 syncHeight : function(targetHeight){
37870 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37871 var bm = this.bodyEl.getMargins();
37872 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37873 this.bodyEl.setHeight(newHeight);
37877 onResize : function(){
37878 if(this.monitorResize){
37879 this.autoSizeTabs();
37884 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37886 beginUpdate : function(){
37887 this.updating = true;
37891 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37893 endUpdate : function(){
37894 this.updating = false;
37895 this.autoSizeTabs();
37899 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37901 autoSizeTabs : function(){
37902 var count = this.items.length;
37903 var vcount = count - this.hiddenCount;
37904 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37907 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37908 var availWidth = Math.floor(w / vcount);
37909 var b = this.stripBody;
37910 if(b.getWidth() > w){
37911 var tabs = this.items;
37912 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37913 if(availWidth < this.minTabWidth){
37914 /*if(!this.sleft){ // incomplete scrolling code
37915 this.createScrollButtons();
37918 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37921 if(this.currentTabWidth < this.preferredTabWidth){
37922 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37928 * Returns the number of tabs in this TabPanel.
37931 getCount : function(){
37932 return this.items.length;
37936 * Resizes all the tabs to the passed width
37937 * @param {Number} The new width
37939 setTabWidth : function(width){
37940 this.currentTabWidth = width;
37941 for(var i = 0, len = this.items.length; i < len; i++) {
37942 if(!this.items[i].isHidden()) {
37943 this.items[i].setWidth(width);
37949 * Destroys this TabPanel
37950 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37952 destroy : function(removeEl){
37953 Roo.EventManager.removeResizeListener(this.onResize, this);
37954 for(var i = 0, len = this.items.length; i < len; i++){
37955 this.items[i].purgeListeners();
37957 if(removeEl === true){
37958 this.el.update("");
37963 createStrip : function(container)
37965 var strip = document.createElement("nav");
37966 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37967 container.appendChild(strip);
37971 createStripList : function(strip)
37973 // div wrapper for retard IE
37974 // returns the "tr" element.
37975 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37976 //'<div class="x-tabs-strip-wrap">'+
37977 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37978 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37979 return strip.firstChild; //.firstChild.firstChild.firstChild;
37981 createBody : function(container)
37983 var body = document.createElement("div");
37984 Roo.id(body, "tab-body");
37985 //Roo.fly(body).addClass("x-tabs-body");
37986 Roo.fly(body).addClass("tab-content");
37987 container.appendChild(body);
37990 createItemBody :function(bodyEl, id){
37991 var body = Roo.getDom(id);
37993 body = document.createElement("div");
37996 //Roo.fly(body).addClass("x-tabs-item-body");
37997 Roo.fly(body).addClass("tab-pane");
37998 bodyEl.insertBefore(body, bodyEl.firstChild);
38002 createStripElements : function(stripEl, text, closable, tpl)
38004 var td = document.createElement("li"); // was td..
38007 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38010 stripEl.appendChild(td);
38012 td.className = "x-tabs-closable";
38013 if(!this.closeTpl){
38014 this.closeTpl = new Roo.Template(
38015 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38016 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38017 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38020 var el = this.closeTpl.overwrite(td, {"text": text});
38021 var close = el.getElementsByTagName("div")[0];
38022 var inner = el.getElementsByTagName("em")[0];
38023 return {"el": el, "close": close, "inner": inner};
38026 // not sure what this is..
38027 // if(!this.tabTpl){
38028 //this.tabTpl = new Roo.Template(
38029 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38030 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38032 // this.tabTpl = new Roo.Template(
38033 // '<a href="#">' +
38034 // '<span unselectable="on"' +
38035 // (this.disableTooltips ? '' : ' title="{text}"') +
38036 // ' >{text}</span></a>'
38042 var template = tpl || this.tabTpl || false;
38046 template = new Roo.Template(
38048 '<span unselectable="on"' +
38049 (this.disableTooltips ? '' : ' title="{text}"') +
38050 ' >{text}</span></a>'
38054 switch (typeof(template)) {
38058 template = new Roo.Template(template);
38064 var el = template.overwrite(td, {"text": text});
38066 var inner = el.getElementsByTagName("span")[0];
38068 return {"el": el, "inner": inner};
38076 * @class Roo.TabPanelItem
38077 * @extends Roo.util.Observable
38078 * Represents an individual item (tab plus body) in a TabPanel.
38079 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38080 * @param {String} id The id of this TabPanelItem
38081 * @param {String} text The text for the tab of this TabPanelItem
38082 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38084 Roo.bootstrap.panel.TabItem = function(config){
38086 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38087 * @type Roo.TabPanel
38089 this.tabPanel = config.panel;
38091 * The id for this TabPanelItem
38094 this.id = config.id;
38096 this.disabled = false;
38098 this.text = config.text;
38100 this.loaded = false;
38101 this.closable = config.closable;
38104 * The body element for this TabPanelItem.
38105 * @type Roo.Element
38107 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38108 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38109 this.bodyEl.setStyle("display", "block");
38110 this.bodyEl.setStyle("zoom", "1");
38111 //this.hideAction();
38113 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38115 this.el = Roo.get(els.el);
38116 this.inner = Roo.get(els.inner, true);
38117 this.textEl = Roo.get(this.el.dom.firstChild, true);
38118 this.pnode = Roo.get(els.el.parentNode, true);
38119 // this.el.on("mousedown", this.onTabMouseDown, this);
38120 this.el.on("click", this.onTabClick, this);
38122 if(config.closable){
38123 var c = Roo.get(els.close, true);
38124 c.dom.title = this.closeText;
38125 c.addClassOnOver("close-over");
38126 c.on("click", this.closeClick, this);
38132 * Fires when this tab becomes the active tab.
38133 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38134 * @param {Roo.TabPanelItem} this
38138 * @event beforeclose
38139 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38140 * @param {Roo.TabPanelItem} this
38141 * @param {Object} e Set cancel to true on this object to cancel the close.
38143 "beforeclose": true,
38146 * Fires when this tab is closed.
38147 * @param {Roo.TabPanelItem} this
38151 * @event deactivate
38152 * Fires when this tab is no longer the active tab.
38153 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38154 * @param {Roo.TabPanelItem} this
38156 "deactivate" : true
38158 this.hidden = false;
38160 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38163 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38165 purgeListeners : function(){
38166 Roo.util.Observable.prototype.purgeListeners.call(this);
38167 this.el.removeAllListeners();
38170 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38173 this.pnode.addClass("active");
38176 this.tabPanel.stripWrap.repaint();
38178 this.fireEvent("activate", this.tabPanel, this);
38182 * Returns true if this tab is the active tab.
38183 * @return {Boolean}
38185 isActive : function(){
38186 return this.tabPanel.getActiveTab() == this;
38190 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38193 this.pnode.removeClass("active");
38195 this.fireEvent("deactivate", this.tabPanel, this);
38198 hideAction : function(){
38199 this.bodyEl.hide();
38200 this.bodyEl.setStyle("position", "absolute");
38201 this.bodyEl.setLeft("-20000px");
38202 this.bodyEl.setTop("-20000px");
38205 showAction : function(){
38206 this.bodyEl.setStyle("position", "relative");
38207 this.bodyEl.setTop("");
38208 this.bodyEl.setLeft("");
38209 this.bodyEl.show();
38213 * Set the tooltip for the tab.
38214 * @param {String} tooltip The tab's tooltip
38216 setTooltip : function(text){
38217 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38218 this.textEl.dom.qtip = text;
38219 this.textEl.dom.removeAttribute('title');
38221 this.textEl.dom.title = text;
38225 onTabClick : function(e){
38226 e.preventDefault();
38227 this.tabPanel.activate(this.id);
38230 onTabMouseDown : function(e){
38231 e.preventDefault();
38232 this.tabPanel.activate(this.id);
38235 getWidth : function(){
38236 return this.inner.getWidth();
38239 setWidth : function(width){
38240 var iwidth = width - this.pnode.getPadding("lr");
38241 this.inner.setWidth(iwidth);
38242 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38243 this.pnode.setWidth(width);
38247 * Show or hide the tab
38248 * @param {Boolean} hidden True to hide or false to show.
38250 setHidden : function(hidden){
38251 this.hidden = hidden;
38252 this.pnode.setStyle("display", hidden ? "none" : "");
38256 * Returns true if this tab is "hidden"
38257 * @return {Boolean}
38259 isHidden : function(){
38260 return this.hidden;
38264 * Returns the text for this tab
38267 getText : function(){
38271 autoSize : function(){
38272 //this.el.beginMeasure();
38273 this.textEl.setWidth(1);
38275 * #2804 [new] Tabs in Roojs
38276 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38278 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38279 //this.el.endMeasure();
38283 * Sets the text for the tab (Note: this also sets the tooltip text)
38284 * @param {String} text The tab's text and tooltip
38286 setText : function(text){
38288 this.textEl.update(text);
38289 this.setTooltip(text);
38290 //if(!this.tabPanel.resizeTabs){
38291 // this.autoSize();
38295 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38297 activate : function(){
38298 this.tabPanel.activate(this.id);
38302 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38304 disable : function(){
38305 if(this.tabPanel.active != this){
38306 this.disabled = true;
38307 this.pnode.addClass("disabled");
38312 * Enables this TabPanelItem if it was previously disabled.
38314 enable : function(){
38315 this.disabled = false;
38316 this.pnode.removeClass("disabled");
38320 * Sets the content for this TabPanelItem.
38321 * @param {String} content The content
38322 * @param {Boolean} loadScripts true to look for and load scripts
38324 setContent : function(content, loadScripts){
38325 this.bodyEl.update(content, loadScripts);
38329 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38330 * @return {Roo.UpdateManager} The UpdateManager
38332 getUpdateManager : function(){
38333 return this.bodyEl.getUpdateManager();
38337 * Set a URL to be used to load the content for this TabPanelItem.
38338 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38339 * @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)
38340 * @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)
38341 * @return {Roo.UpdateManager} The UpdateManager
38343 setUrl : function(url, params, loadOnce){
38344 if(this.refreshDelegate){
38345 this.un('activate', this.refreshDelegate);
38347 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38348 this.on("activate", this.refreshDelegate);
38349 return this.bodyEl.getUpdateManager();
38353 _handleRefresh : function(url, params, loadOnce){
38354 if(!loadOnce || !this.loaded){
38355 var updater = this.bodyEl.getUpdateManager();
38356 updater.update(url, params, this._setLoaded.createDelegate(this));
38361 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38362 * Will fail silently if the setUrl method has not been called.
38363 * This does not activate the panel, just updates its content.
38365 refresh : function(){
38366 if(this.refreshDelegate){
38367 this.loaded = false;
38368 this.refreshDelegate();
38373 _setLoaded : function(){
38374 this.loaded = true;
38378 closeClick : function(e){
38381 this.fireEvent("beforeclose", this, o);
38382 if(o.cancel !== true){
38383 this.tabPanel.removeTab(this.id);
38387 * The text displayed in the tooltip for the close icon.
38390 closeText : "Close this tab"
38393 * This script refer to:
38394 * Title: International Telephone Input
38395 * Author: Jack O'Connor
38396 * Code version: v12.1.12
38397 * Availability: https://github.com/jackocnr/intl-tel-input.git
38400 Roo.bootstrap.PhoneInputData = function() {
38403 "Afghanistan (افغانستان)",
38408 "Albania (Shqipëri)",
38413 "Algeria (الجزائر)",
38438 "Antigua and Barbuda",
38448 "Armenia (Հայաստան)",
38464 "Austria (Österreich)",
38469 "Azerbaijan (Azərbaycan)",
38479 "Bahrain (البحرين)",
38484 "Bangladesh (বাংলাদেশ)",
38494 "Belarus (Беларусь)",
38499 "Belgium (België)",
38529 "Bosnia and Herzegovina (Босна и Херцеговина)",
38544 "British Indian Ocean Territory",
38549 "British Virgin Islands",
38559 "Bulgaria (България)",
38569 "Burundi (Uburundi)",
38574 "Cambodia (កម្ពុជា)",
38579 "Cameroon (Cameroun)",
38588 ["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"]
38591 "Cape Verde (Kabu Verdi)",
38596 "Caribbean Netherlands",
38607 "Central African Republic (République centrafricaine)",
38627 "Christmas Island",
38633 "Cocos (Keeling) Islands",
38644 "Comoros (جزر القمر)",
38649 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38654 "Congo (Republic) (Congo-Brazzaville)",
38674 "Croatia (Hrvatska)",
38695 "Czech Republic (Česká republika)",
38700 "Denmark (Danmark)",
38715 "Dominican Republic (República Dominicana)",
38719 ["809", "829", "849"]
38737 "Equatorial Guinea (Guinea Ecuatorial)",
38757 "Falkland Islands (Islas Malvinas)",
38762 "Faroe Islands (Føroyar)",
38783 "French Guiana (Guyane française)",
38788 "French Polynesia (Polynésie française)",
38803 "Georgia (საქართველო)",
38808 "Germany (Deutschland)",
38828 "Greenland (Kalaallit Nunaat)",
38865 "Guinea-Bissau (Guiné Bissau)",
38890 "Hungary (Magyarország)",
38895 "Iceland (Ísland)",
38915 "Iraq (العراق)",
38931 "Israel (ישראל)",
38958 "Jordan (الأردن)",
38963 "Kazakhstan (Казахстан)",
38984 "Kuwait (الكويت)",
38989 "Kyrgyzstan (Кыргызстан)",
38999 "Latvia (Latvija)",
39004 "Lebanon (لبنان)",
39019 "Libya (ليبيا)",
39029 "Lithuania (Lietuva)",
39044 "Macedonia (FYROM) (Македонија)",
39049 "Madagascar (Madagasikara)",
39079 "Marshall Islands",
39089 "Mauritania (موريتانيا)",
39094 "Mauritius (Moris)",
39115 "Moldova (Republica Moldova)",
39125 "Mongolia (Монгол)",
39130 "Montenegro (Crna Gora)",
39140 "Morocco (المغرب)",
39146 "Mozambique (Moçambique)",
39151 "Myanmar (Burma) (မြန်မာ)",
39156 "Namibia (Namibië)",
39171 "Netherlands (Nederland)",
39176 "New Caledonia (Nouvelle-Calédonie)",
39211 "North Korea (조선 민주주의 인민 공화국)",
39216 "Northern Mariana Islands",
39232 "Pakistan (پاکستان)",
39242 "Palestine (فلسطين)",
39252 "Papua New Guinea",
39294 "Réunion (La Réunion)",
39300 "Romania (România)",
39316 "Saint Barthélemy",
39327 "Saint Kitts and Nevis",
39337 "Saint Martin (Saint-Martin (partie française))",
39343 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39348 "Saint Vincent and the Grenadines",
39363 "São Tomé and Príncipe (São Tomé e Príncipe)",
39368 "Saudi Arabia (المملكة العربية السعودية)",
39373 "Senegal (Sénégal)",
39403 "Slovakia (Slovensko)",
39408 "Slovenia (Slovenija)",
39418 "Somalia (Soomaaliya)",
39428 "South Korea (대한민국)",
39433 "South Sudan (جنوب السودان)",
39443 "Sri Lanka (ශ්රී ලංකාව)",
39448 "Sudan (السودان)",
39458 "Svalbard and Jan Mayen",
39469 "Sweden (Sverige)",
39474 "Switzerland (Schweiz)",
39479 "Syria (سوريا)",
39524 "Trinidad and Tobago",
39529 "Tunisia (تونس)",
39534 "Turkey (Türkiye)",
39544 "Turks and Caicos Islands",
39554 "U.S. Virgin Islands",
39564 "Ukraine (Україна)",
39569 "United Arab Emirates (الإمارات العربية المتحدة)",
39591 "Uzbekistan (Oʻzbekiston)",
39601 "Vatican City (Città del Vaticano)",
39612 "Vietnam (Việt Nam)",
39617 "Wallis and Futuna (Wallis-et-Futuna)",
39622 "Western Sahara (الصحراء الغربية)",
39628 "Yemen (اليمن)",
39652 * This script refer to:
39653 * Title: International Telephone Input
39654 * Author: Jack O'Connor
39655 * Code version: v12.1.12
39656 * Availability: https://github.com/jackocnr/intl-tel-input.git
39660 * @class Roo.bootstrap.PhoneInput
39661 * @extends Roo.bootstrap.TriggerField
39662 * An input with International dial-code selection
39664 * @cfg {String} defaultDialCode default '+852'
39665 * @cfg {Array} preferedCountries default []
39668 * Create a new PhoneInput.
39669 * @param {Object} config Configuration options
39672 Roo.bootstrap.PhoneInput = function(config) {
39673 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39676 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39678 listWidth: undefined,
39680 selectedClass: 'active',
39682 invalidClass : "has-warning",
39684 validClass: 'has-success',
39686 allowed: '0123456789',
39689 * @cfg {String} defaultDialCode The default dial code when initializing the input
39691 defaultDialCode: '+852',
39694 * @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
39696 preferedCountries: false,
39698 getAutoCreate : function()
39700 var data = Roo.bootstrap.PhoneInputData();
39701 var align = this.labelAlign || this.parentLabelAlign();
39704 this.allCountries = [];
39705 this.dialCodeMapping = [];
39707 for (var i = 0; i < data.length; i++) {
39709 this.allCountries[i] = {
39713 priority: c[3] || 0,
39714 areaCodes: c[4] || null
39716 this.dialCodeMapping[c[2]] = {
39719 priority: c[3] || 0,
39720 areaCodes: c[4] || null
39732 cls : 'form-control tel-input',
39733 autocomplete: 'new-password'
39736 var hiddenInput = {
39739 cls: 'hidden-tel-input'
39743 hiddenInput.name = this.name;
39746 if (this.disabled) {
39747 input.disabled = true;
39750 var flag_container = {
39767 cls: this.hasFeedback ? 'has-feedback' : '',
39773 cls: 'dial-code-holder',
39780 cls: 'roo-select2-container input-group',
39787 if (this.fieldLabel.length) {
39790 tooltip: 'This field is required'
39796 cls: 'control-label',
39802 html: this.fieldLabel
39805 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39811 if(this.indicatorpos == 'right') {
39812 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39819 if(align == 'left') {
39827 if(this.labelWidth > 12){
39828 label.style = "width: " + this.labelWidth + 'px';
39830 if(this.labelWidth < 13 && this.labelmd == 0){
39831 this.labelmd = this.labelWidth;
39833 if(this.labellg > 0){
39834 label.cls += ' col-lg-' + this.labellg;
39835 input.cls += ' col-lg-' + (12 - this.labellg);
39837 if(this.labelmd > 0){
39838 label.cls += ' col-md-' + this.labelmd;
39839 container.cls += ' col-md-' + (12 - this.labelmd);
39841 if(this.labelsm > 0){
39842 label.cls += ' col-sm-' + this.labelsm;
39843 container.cls += ' col-sm-' + (12 - this.labelsm);
39845 if(this.labelxs > 0){
39846 label.cls += ' col-xs-' + this.labelxs;
39847 container.cls += ' col-xs-' + (12 - this.labelxs);
39857 var settings = this;
39859 ['xs','sm','md','lg'].map(function(size){
39860 if (settings[size]) {
39861 cfg.cls += ' col-' + size + '-' + settings[size];
39865 this.store = new Roo.data.Store({
39866 proxy : new Roo.data.MemoryProxy({}),
39867 reader : new Roo.data.JsonReader({
39878 'name' : 'dialCode',
39882 'name' : 'priority',
39886 'name' : 'areaCodes',
39893 if(!this.preferedCountries) {
39894 this.preferedCountries = [
39901 var p = this.preferedCountries.reverse();
39904 for (var i = 0; i < p.length; i++) {
39905 for (var j = 0; j < this.allCountries.length; j++) {
39906 if(this.allCountries[j].iso2 == p[i]) {
39907 var t = this.allCountries[j];
39908 this.allCountries.splice(j,1);
39909 this.allCountries.unshift(t);
39915 this.store.proxy.data = {
39917 data: this.allCountries
39923 initEvents : function()
39926 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39928 this.indicator = this.indicatorEl();
39929 this.flag = this.flagEl();
39930 this.dialCodeHolder = this.dialCodeHolderEl();
39932 this.trigger = this.el.select('div.flag-box',true).first();
39933 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39938 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39939 _this.list.setWidth(lw);
39942 this.list.on('mouseover', this.onViewOver, this);
39943 this.list.on('mousemove', this.onViewMove, this);
39944 this.inputEl().on("keyup", this.onKeyUp, this);
39946 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39948 this.view = new Roo.View(this.list, this.tpl, {
39949 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39952 this.view.on('click', this.onViewClick, this);
39953 this.setValue(this.defaultDialCode);
39956 onTriggerClick : function(e)
39958 Roo.log('trigger click');
39963 if(this.isExpanded()){
39965 this.hasFocus = false;
39967 this.store.load({});
39968 this.hasFocus = true;
39973 isExpanded : function()
39975 return this.list.isVisible();
39978 collapse : function()
39980 if(!this.isExpanded()){
39984 Roo.get(document).un('mousedown', this.collapseIf, this);
39985 Roo.get(document).un('mousewheel', this.collapseIf, this);
39986 this.fireEvent('collapse', this);
39990 expand : function()
39994 if(this.isExpanded() || !this.hasFocus){
39998 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39999 this.list.setWidth(lw);
40002 this.restrictHeight();
40004 Roo.get(document).on('mousedown', this.collapseIf, this);
40005 Roo.get(document).on('mousewheel', this.collapseIf, this);
40007 this.fireEvent('expand', this);
40010 restrictHeight : function()
40012 this.list.alignTo(this.inputEl(), this.listAlign);
40013 this.list.alignTo(this.inputEl(), this.listAlign);
40016 onViewOver : function(e, t)
40018 if(this.inKeyMode){
40021 var item = this.view.findItemFromChild(t);
40024 var index = this.view.indexOf(item);
40025 this.select(index, false);
40030 onViewClick : function(view, doFocus, el, e)
40032 var index = this.view.getSelectedIndexes()[0];
40034 var r = this.store.getAt(index);
40037 this.onSelect(r, index);
40039 if(doFocus !== false && !this.blockFocus){
40040 this.inputEl().focus();
40044 onViewMove : function(e, t)
40046 this.inKeyMode = false;
40049 select : function(index, scrollIntoView)
40051 this.selectedIndex = index;
40052 this.view.select(index);
40053 if(scrollIntoView !== false){
40054 var el = this.view.getNode(index);
40056 this.list.scrollChildIntoView(el, false);
40061 createList : function()
40063 this.list = Roo.get(document.body).createChild({
40065 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40066 style: 'display:none'
40069 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40072 collapseIf : function(e)
40074 var in_combo = e.within(this.el);
40075 var in_list = e.within(this.list);
40076 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40078 if (in_combo || in_list || is_list) {
40084 onSelect : function(record, index)
40086 if(this.fireEvent('beforeselect', this, record, index) !== false){
40088 this.setFlagClass(record.data.iso2);
40089 this.setDialCode(record.data.dialCode);
40090 this.hasFocus = false;
40092 this.fireEvent('select', this, record, index);
40096 flagEl : function()
40098 var flag = this.el.select('div.flag',true).first();
40105 dialCodeHolderEl : function()
40107 var d = this.el.select('input.dial-code-holder',true).first();
40114 setDialCode : function(v)
40116 this.dialCodeHolder.dom.value = '+'+v;
40119 setFlagClass : function(n)
40121 this.flag.dom.className = 'flag '+n;
40124 getValue : function()
40126 var v = this.inputEl().getValue();
40127 if(this.dialCodeHolder) {
40128 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40133 setValue : function(v)
40135 var d = this.getDialCode(v);
40137 //invalid dial code
40138 if(v.length == 0 || !d || d.length == 0) {
40140 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40141 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40147 this.setFlagClass(this.dialCodeMapping[d].iso2);
40148 this.setDialCode(d);
40149 this.inputEl().dom.value = v.replace('+'+d,'');
40150 this.hiddenEl().dom.value = this.getValue();
40155 getDialCode : function(v)
40159 if (v.length == 0) {
40160 return this.dialCodeHolder.dom.value;
40164 if (v.charAt(0) != "+") {
40167 var numericChars = "";
40168 for (var i = 1; i < v.length; i++) {
40169 var c = v.charAt(i);
40172 if (this.dialCodeMapping[numericChars]) {
40173 dialCode = v.substr(1, i);
40175 if (numericChars.length == 4) {
40185 this.setValue(this.defaultDialCode);
40189 hiddenEl : function()
40191 return this.el.select('input.hidden-tel-input',true).first();
40194 onKeyUp : function(e){
40196 var k = e.getKey();
40197 var c = e.getCharCode();
40200 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40201 this.allowed.indexOf(String.fromCharCode(c)) === -1
40206 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40209 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40213 this.setValue(this.getValue());
40218 * @class Roo.bootstrap.MoneyField
40219 * @extends Roo.bootstrap.ComboBox
40220 * Bootstrap MoneyField class
40223 * Create a new MoneyField.
40224 * @param {Object} config Configuration options
40227 Roo.bootstrap.MoneyField = function(config) {
40229 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40233 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40236 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40238 allowDecimals : true,
40240 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40242 decimalSeparator : ".",
40244 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40246 decimalPrecision : 0,
40248 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40250 allowNegative : true,
40252 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40256 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40258 minValue : Number.NEGATIVE_INFINITY,
40260 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40262 maxValue : Number.MAX_VALUE,
40264 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40266 minText : "The minimum value for this field is {0}",
40268 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40270 maxText : "The maximum value for this field is {0}",
40272 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40273 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40275 nanText : "{0} is not a valid number",
40277 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40281 * @cfg {String} defaults currency of the MoneyField
40282 * value should be in lkey
40284 defaultCurrency : false,
40286 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40288 thousandsDelimiter : false,
40298 getAutoCreate : function()
40300 var align = this.labelAlign || this.parentLabelAlign();
40312 cls : 'form-control roo-money-amount-input',
40313 autocomplete: 'new-password'
40316 var hiddenInput = {
40320 cls: 'hidden-number-input'
40324 hiddenInput.name = this.name;
40327 if (this.disabled) {
40328 input.disabled = true;
40331 var clg = 12 - this.inputlg;
40332 var cmd = 12 - this.inputmd;
40333 var csm = 12 - this.inputsm;
40334 var cxs = 12 - this.inputxs;
40338 cls : 'row roo-money-field',
40342 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40346 cls: 'roo-select2-container input-group',
40350 cls : 'form-control roo-money-currency-input',
40351 autocomplete: 'new-password',
40353 name : this.currencyName
40357 cls : 'input-group-addon',
40371 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40375 cls: this.hasFeedback ? 'has-feedback' : '',
40386 if (this.fieldLabel.length) {
40389 tooltip: 'This field is required'
40395 cls: 'control-label',
40401 html: this.fieldLabel
40404 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40410 if(this.indicatorpos == 'right') {
40411 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40418 if(align == 'left') {
40426 if(this.labelWidth > 12){
40427 label.style = "width: " + this.labelWidth + 'px';
40429 if(this.labelWidth < 13 && this.labelmd == 0){
40430 this.labelmd = this.labelWidth;
40432 if(this.labellg > 0){
40433 label.cls += ' col-lg-' + this.labellg;
40434 input.cls += ' col-lg-' + (12 - this.labellg);
40436 if(this.labelmd > 0){
40437 label.cls += ' col-md-' + this.labelmd;
40438 container.cls += ' col-md-' + (12 - this.labelmd);
40440 if(this.labelsm > 0){
40441 label.cls += ' col-sm-' + this.labelsm;
40442 container.cls += ' col-sm-' + (12 - this.labelsm);
40444 if(this.labelxs > 0){
40445 label.cls += ' col-xs-' + this.labelxs;
40446 container.cls += ' col-xs-' + (12 - this.labelxs);
40457 var settings = this;
40459 ['xs','sm','md','lg'].map(function(size){
40460 if (settings[size]) {
40461 cfg.cls += ' col-' + size + '-' + settings[size];
40468 initEvents : function()
40470 this.indicator = this.indicatorEl();
40472 this.initCurrencyEvent();
40474 this.initNumberEvent();
40477 initCurrencyEvent : function()
40480 throw "can not find store for combo";
40483 this.store = Roo.factory(this.store, Roo.data);
40484 this.store.parent = this;
40488 this.triggerEl = this.el.select('.input-group-addon', true).first();
40490 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40495 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40496 _this.list.setWidth(lw);
40499 this.list.on('mouseover', this.onViewOver, this);
40500 this.list.on('mousemove', this.onViewMove, this);
40501 this.list.on('scroll', this.onViewScroll, this);
40504 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40507 this.view = new Roo.View(this.list, this.tpl, {
40508 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40511 this.view.on('click', this.onViewClick, this);
40513 this.store.on('beforeload', this.onBeforeLoad, this);
40514 this.store.on('load', this.onLoad, this);
40515 this.store.on('loadexception', this.onLoadException, this);
40517 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40518 "up" : function(e){
40519 this.inKeyMode = true;
40523 "down" : function(e){
40524 if(!this.isExpanded()){
40525 this.onTriggerClick();
40527 this.inKeyMode = true;
40532 "enter" : function(e){
40535 if(this.fireEvent("specialkey", this, e)){
40536 this.onViewClick(false);
40542 "esc" : function(e){
40546 "tab" : function(e){
40549 if(this.fireEvent("specialkey", this, e)){
40550 this.onViewClick(false);
40558 doRelay : function(foo, bar, hname){
40559 if(hname == 'down' || this.scope.isExpanded()){
40560 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40568 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40572 initNumberEvent : function(e)
40574 this.inputEl().on("keydown" , this.fireKey, this);
40575 this.inputEl().on("focus", this.onFocus, this);
40576 this.inputEl().on("blur", this.onBlur, this);
40578 this.inputEl().relayEvent('keyup', this);
40580 if(this.indicator){
40581 this.indicator.addClass('invisible');
40584 this.originalValue = this.getValue();
40586 if(this.validationEvent == 'keyup'){
40587 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40588 this.inputEl().on('keyup', this.filterValidation, this);
40590 else if(this.validationEvent !== false){
40591 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40594 if(this.selectOnFocus){
40595 this.on("focus", this.preFocus, this);
40598 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40599 this.inputEl().on("keypress", this.filterKeys, this);
40601 this.inputEl().relayEvent('keypress', this);
40604 var allowed = "0123456789";
40606 if(this.allowDecimals){
40607 allowed += this.decimalSeparator;
40610 if(this.allowNegative){
40614 if(this.thousandsDelimiter) {
40618 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40620 var keyPress = function(e){
40622 var k = e.getKey();
40624 var c = e.getCharCode();
40627 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40628 allowed.indexOf(String.fromCharCode(c)) === -1
40634 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40638 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40643 this.inputEl().on("keypress", keyPress, this);
40647 onTriggerClick : function(e)
40654 this.loadNext = false;
40656 if(this.isExpanded()){
40661 this.hasFocus = true;
40663 if(this.triggerAction == 'all') {
40664 this.doQuery(this.allQuery, true);
40668 this.doQuery(this.getRawValue());
40671 getCurrency : function()
40673 var v = this.currencyEl().getValue();
40678 restrictHeight : function()
40680 this.list.alignTo(this.currencyEl(), this.listAlign);
40681 this.list.alignTo(this.currencyEl(), this.listAlign);
40684 onViewClick : function(view, doFocus, el, e)
40686 var index = this.view.getSelectedIndexes()[0];
40688 var r = this.store.getAt(index);
40691 this.onSelect(r, index);
40695 onSelect : function(record, index){
40697 if(this.fireEvent('beforeselect', this, record, index) !== false){
40699 this.setFromCurrencyData(index > -1 ? record.data : false);
40703 this.fireEvent('select', this, record, index);
40707 setFromCurrencyData : function(o)
40711 this.lastCurrency = o;
40713 if (this.currencyField) {
40714 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40716 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40719 this.lastSelectionText = currency;
40721 //setting default currency
40722 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40723 this.setCurrency(this.defaultCurrency);
40727 this.setCurrency(currency);
40730 setFromData : function(o)
40734 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40736 this.setFromCurrencyData(c);
40741 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40743 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40746 this.setValue(value);
40750 setCurrency : function(v)
40752 this.currencyValue = v;
40755 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40760 setValue : function(v)
40762 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40768 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40770 this.inputEl().dom.value = (v == '') ? '' :
40771 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40773 if(!this.allowZero && v === '0') {
40774 this.hiddenEl().dom.value = '';
40775 this.inputEl().dom.value = '';
40782 getRawValue : function()
40784 var v = this.inputEl().getValue();
40789 getValue : function()
40791 return this.fixPrecision(this.parseValue(this.getRawValue()));
40794 parseValue : function(value)
40796 if(this.thousandsDelimiter) {
40798 r = new RegExp(",", "g");
40799 value = value.replace(r, "");
40802 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40803 return isNaN(value) ? '' : value;
40807 fixPrecision : function(value)
40809 if(this.thousandsDelimiter) {
40811 r = new RegExp(",", "g");
40812 value = value.replace(r, "");
40815 var nan = isNaN(value);
40817 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40818 return nan ? '' : value;
40820 return parseFloat(value).toFixed(this.decimalPrecision);
40823 decimalPrecisionFcn : function(v)
40825 return Math.floor(v);
40828 validateValue : function(value)
40830 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40834 var num = this.parseValue(value);
40837 this.markInvalid(String.format(this.nanText, value));
40841 if(num < this.minValue){
40842 this.markInvalid(String.format(this.minText, this.minValue));
40846 if(num > this.maxValue){
40847 this.markInvalid(String.format(this.maxText, this.maxValue));
40854 validate : function()
40856 if(this.disabled || this.allowBlank){
40861 var currency = this.getCurrency();
40863 if(this.validateValue(this.getRawValue()) && currency.length){
40868 this.markInvalid();
40872 getName: function()
40877 beforeBlur : function()
40883 var v = this.parseValue(this.getRawValue());
40890 onBlur : function()
40894 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40895 //this.el.removeClass(this.focusClass);
40898 this.hasFocus = false;
40900 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40904 var v = this.getValue();
40906 if(String(v) !== String(this.startValue)){
40907 this.fireEvent('change', this, v, this.startValue);
40910 this.fireEvent("blur", this);
40913 inputEl : function()
40915 return this.el.select('.roo-money-amount-input', true).first();
40918 currencyEl : function()
40920 return this.el.select('.roo-money-currency-input', true).first();
40923 hiddenEl : function()
40925 return this.el.select('input.hidden-number-input',true).first();