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)
848 Roo.log('button on click ');
849 if(this.preventDefault){
853 if (this.pressed === true || this.pressed === false) {
854 this.pressed = !this.pressed;
855 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
856 this.fireEvent('toggle', this, e, this.pressed);
860 this.fireEvent('click', this, e);
864 * Enables this button
868 this.disabled = false;
869 this.el.removeClass('disabled');
873 * Disable this button
877 this.disabled = true;
878 this.el.addClass('disabled');
881 * sets the active state on/off,
882 * @param {Boolean} state (optional) Force a particular state
884 setActive : function(v) {
886 this.el[v ? 'addClass' : 'removeClass']('active');
890 * toggles the current active state
892 toggleActive : function()
894 var active = this.el.hasClass('active');
895 this.setActive(!active);
900 * get the current active state
901 * @return {boolean} true if it's active
903 isActive : function()
905 return this.el.hasClass('active');
908 * set the text of the first selected button
910 setText : function(str)
912 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
915 * get the text of the first selected button
919 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
930 setWeight : function(str)
932 this.el.removeClass(this.weightClass);
933 this.el.addClass('btn-' + str);
947 * @class Roo.bootstrap.Column
948 * @extends Roo.bootstrap.Component
949 * Bootstrap Column class
950 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
951 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
952 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
953 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
954 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
955 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
956 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
957 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
960 * @cfg {Boolean} hidden (true|false) hide the element
961 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
962 * @cfg {String} fa (ban|check|...) font awesome icon
963 * @cfg {Number} fasize (1|2|....) font awsome size
965 * @cfg {String} icon (info-sign|check|...) glyphicon name
967 * @cfg {String} html content of column.
970 * Create a new Column
971 * @param {Object} config The config object
974 Roo.bootstrap.Column = function(config){
975 Roo.bootstrap.Column.superclass.constructor.call(this, config);
978 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
996 getAutoCreate : function(){
997 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1005 ['xs','sm','md','lg'].map(function(size){
1006 //Roo.log( size + ':' + settings[size]);
1008 if (settings[size+'off'] !== false) {
1009 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1012 if (settings[size] === false) {
1016 if (!settings[size]) { // 0 = hidden
1017 cfg.cls += ' hidden-' + size;
1020 cfg.cls += ' col-' + size + '-' + settings[size];
1025 cfg.cls += ' hidden';
1028 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1029 cfg.cls +=' alert alert-' + this.alert;
1033 if (this.html.length) {
1034 cfg.html = this.html;
1038 if (this.fasize > 1) {
1039 fasize = ' fa-' + this.fasize + 'x';
1041 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1046 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1065 * @class Roo.bootstrap.Container
1066 * @extends Roo.bootstrap.Component
1067 * Bootstrap Container class
1068 * @cfg {Boolean} jumbotron is it a jumbotron element
1069 * @cfg {String} html content of element
1070 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1071 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1072 * @cfg {String} header content of header (for panel)
1073 * @cfg {String} footer content of footer (for panel)
1074 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1075 * @cfg {String} tag (header|aside|section) type of HTML tag.
1076 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1077 * @cfg {String} fa font awesome icon
1078 * @cfg {String} icon (info-sign|check|...) glyphicon name
1079 * @cfg {Boolean} hidden (true|false) hide the element
1080 * @cfg {Boolean} expandable (true|false) default false
1081 * @cfg {Boolean} expanded (true|false) default true
1082 * @cfg {String} rheader contet on the right of header
1083 * @cfg {Boolean} clickable (true|false) default false
1087 * Create a new Container
1088 * @param {Object} config The config object
1091 Roo.bootstrap.Container = function(config){
1092 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1098 * After the panel has been expand
1100 * @param {Roo.bootstrap.Container} this
1105 * After the panel has been collapsed
1107 * @param {Roo.bootstrap.Container} this
1112 * When a element is chick
1113 * @param {Roo.bootstrap.Container} this
1114 * @param {Roo.EventObject} e
1120 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1138 getChildContainer : function() {
1144 if (this.panel.length) {
1145 return this.el.select('.panel-body',true).first();
1152 getAutoCreate : function(){
1155 tag : this.tag || 'div',
1159 if (this.jumbotron) {
1160 cfg.cls = 'jumbotron';
1165 // - this is applied by the parent..
1167 // cfg.cls = this.cls + '';
1170 if (this.sticky.length) {
1172 var bd = Roo.get(document.body);
1173 if (!bd.hasClass('bootstrap-sticky')) {
1174 bd.addClass('bootstrap-sticky');
1175 Roo.select('html',true).setStyle('height', '100%');
1178 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1182 if (this.well.length) {
1183 switch (this.well) {
1186 cfg.cls +=' well well-' +this.well;
1195 cfg.cls += ' hidden';
1199 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1200 cfg.cls +=' alert alert-' + this.alert;
1205 if (this.panel.length) {
1206 cfg.cls += ' panel panel-' + this.panel;
1208 if (this.header.length) {
1212 if(this.expandable){
1214 cfg.cls = cfg.cls + ' expandable';
1218 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1226 cls : 'panel-title',
1227 html : (this.expandable ? ' ' : '') + this.header
1231 cls: 'panel-header-right',
1237 cls : 'panel-heading',
1238 style : this.expandable ? 'cursor: pointer' : '',
1246 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1251 if (this.footer.length) {
1253 cls : 'panel-footer',
1262 body.html = this.html || cfg.html;
1263 // prefix with the icons..
1265 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1268 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1273 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1274 cfg.cls = 'container';
1280 initEvents: function()
1282 if(this.expandable){
1283 var headerEl = this.headerEl();
1286 headerEl.on('click', this.onToggleClick, this);
1291 this.el.on('click', this.onClick, this);
1296 onToggleClick : function()
1298 var headerEl = this.headerEl();
1314 if(this.fireEvent('expand', this)) {
1316 this.expanded = true;
1318 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1320 this.el.select('.panel-body',true).first().removeClass('hide');
1322 var toggleEl = this.toggleEl();
1328 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1333 collapse : function()
1335 if(this.fireEvent('collapse', this)) {
1337 this.expanded = false;
1339 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1340 this.el.select('.panel-body',true).first().addClass('hide');
1342 var toggleEl = this.toggleEl();
1348 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1352 toggleEl : function()
1354 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1358 return this.el.select('.panel-heading .fa',true).first();
1361 headerEl : function()
1363 if(!this.el || !this.panel.length || !this.header.length){
1367 return this.el.select('.panel-heading',true).first()
1372 if(!this.el || !this.panel.length){
1376 return this.el.select('.panel-body',true).first()
1379 titleEl : function()
1381 if(!this.el || !this.panel.length || !this.header.length){
1385 return this.el.select('.panel-title',true).first();
1388 setTitle : function(v)
1390 var titleEl = this.titleEl();
1396 titleEl.dom.innerHTML = v;
1399 getTitle : function()
1402 var titleEl = this.titleEl();
1408 return titleEl.dom.innerHTML;
1411 setRightTitle : function(v)
1413 var t = this.el.select('.panel-header-right',true).first();
1419 t.dom.innerHTML = v;
1422 onClick : function(e)
1426 this.fireEvent('click', this, e);
1439 * @class Roo.bootstrap.Img
1440 * @extends Roo.bootstrap.Component
1441 * Bootstrap Img class
1442 * @cfg {Boolean} imgResponsive false | true
1443 * @cfg {String} border rounded | circle | thumbnail
1444 * @cfg {String} src image source
1445 * @cfg {String} alt image alternative text
1446 * @cfg {String} href a tag href
1447 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1448 * @cfg {String} xsUrl xs image source
1449 * @cfg {String} smUrl sm image source
1450 * @cfg {String} mdUrl md image source
1451 * @cfg {String} lgUrl lg image source
1454 * Create a new Input
1455 * @param {Object} config The config object
1458 Roo.bootstrap.Img = function(config){
1459 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1465 * The img click event for the img.
1466 * @param {Roo.EventObject} e
1472 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1474 imgResponsive: true,
1484 getAutoCreate : function()
1486 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1487 return this.createSingleImg();
1492 cls: 'roo-image-responsive-group',
1497 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1499 if(!_this[size + 'Url']){
1505 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1506 html: _this.html || cfg.html,
1507 src: _this[size + 'Url']
1510 img.cls += ' roo-image-responsive-' + size;
1512 var s = ['xs', 'sm', 'md', 'lg'];
1514 s.splice(s.indexOf(size), 1);
1516 Roo.each(s, function(ss){
1517 img.cls += ' hidden-' + ss;
1520 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1521 cfg.cls += ' img-' + _this.border;
1525 cfg.alt = _this.alt;
1538 a.target = _this.target;
1542 cfg.cn.push((_this.href) ? a : img);
1549 createSingleImg : function()
1553 cls: (this.imgResponsive) ? 'img-responsive' : '',
1555 src : 'about:blank' // just incase src get's set to undefined?!?
1558 cfg.html = this.html || cfg.html;
1560 cfg.src = this.src || cfg.src;
1562 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1563 cfg.cls += ' img-' + this.border;
1580 a.target = this.target;
1585 return (this.href) ? a : cfg;
1588 initEvents: function()
1591 this.el.on('click', this.onClick, this);
1596 onClick : function(e)
1598 Roo.log('img onclick');
1599 this.fireEvent('click', this, e);
1602 * Sets the url of the image - used to update it
1603 * @param {String} url the url of the image
1606 setSrc : function(url)
1610 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1611 this.el.dom.src = url;
1615 this.el.select('img', true).first().dom.src = url;
1631 * @class Roo.bootstrap.Link
1632 * @extends Roo.bootstrap.Component
1633 * Bootstrap Link Class
1634 * @cfg {String} alt image alternative text
1635 * @cfg {String} href a tag href
1636 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1637 * @cfg {String} html the content of the link.
1638 * @cfg {String} anchor name for the anchor link
1639 * @cfg {String} fa - favicon
1641 * @cfg {Boolean} preventDefault (true | false) default false
1645 * Create a new Input
1646 * @param {Object} config The config object
1649 Roo.bootstrap.Link = function(config){
1650 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1656 * The img click event for the img.
1657 * @param {Roo.EventObject} e
1663 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1667 preventDefault: false,
1673 getAutoCreate : function()
1675 var html = this.html || '';
1677 if (this.fa !== false) {
1678 html = '<i class="fa fa-' + this.fa + '"></i>';
1683 // anchor's do not require html/href...
1684 if (this.anchor === false) {
1686 cfg.href = this.href || '#';
1688 cfg.name = this.anchor;
1689 if (this.html !== false || this.fa !== false) {
1692 if (this.href !== false) {
1693 cfg.href = this.href;
1697 if(this.alt !== false){
1702 if(this.target !== false) {
1703 cfg.target = this.target;
1709 initEvents: function() {
1711 if(!this.href || this.preventDefault){
1712 this.el.on('click', this.onClick, this);
1716 onClick : function(e)
1718 if(this.preventDefault){
1721 //Roo.log('img onclick');
1722 this.fireEvent('click', this, e);
1735 * @class Roo.bootstrap.Header
1736 * @extends Roo.bootstrap.Component
1737 * Bootstrap Header class
1738 * @cfg {String} html content of header
1739 * @cfg {Number} level (1|2|3|4|5|6) default 1
1742 * Create a new Header
1743 * @param {Object} config The config object
1747 Roo.bootstrap.Header = function(config){
1748 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1751 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1759 getAutoCreate : function(){
1764 tag: 'h' + (1 *this.level),
1765 html: this.html || ''
1777 * Ext JS Library 1.1.1
1778 * Copyright(c) 2006-2007, Ext JS, LLC.
1780 * Originally Released Under LGPL - original licence link has changed is not relivant.
1783 * <script type="text/javascript">
1787 * @class Roo.bootstrap.MenuMgr
1788 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1791 Roo.bootstrap.MenuMgr = function(){
1792 var menus, active, groups = {}, attached = false, lastShow = new Date();
1794 // private - called when first menu is created
1797 active = new Roo.util.MixedCollection();
1798 Roo.get(document).addKeyListener(27, function(){
1799 if(active.length > 0){
1807 if(active && active.length > 0){
1808 var c = active.clone();
1818 if(active.length < 1){
1819 Roo.get(document).un("mouseup", onMouseDown);
1827 var last = active.last();
1828 lastShow = new Date();
1831 Roo.get(document).on("mouseup", onMouseDown);
1836 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1837 m.parentMenu.activeChild = m;
1838 }else if(last && last.isVisible()){
1839 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1844 function onBeforeHide(m){
1846 m.activeChild.hide();
1848 if(m.autoHideTimer){
1849 clearTimeout(m.autoHideTimer);
1850 delete m.autoHideTimer;
1855 function onBeforeShow(m){
1856 var pm = m.parentMenu;
1857 if(!pm && !m.allowOtherMenus){
1859 }else if(pm && pm.activeChild && active != m){
1860 pm.activeChild.hide();
1864 // private this should really trigger on mouseup..
1865 function onMouseDown(e){
1866 Roo.log("on Mouse Up");
1868 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1869 Roo.log("MenuManager hideAll");
1878 function onBeforeCheck(mi, state){
1880 var g = groups[mi.group];
1881 for(var i = 0, l = g.length; i < l; i++){
1883 g[i].setChecked(false);
1892 * Hides all menus that are currently visible
1894 hideAll : function(){
1899 register : function(menu){
1903 menus[menu.id] = menu;
1904 menu.on("beforehide", onBeforeHide);
1905 menu.on("hide", onHide);
1906 menu.on("beforeshow", onBeforeShow);
1907 menu.on("show", onShow);
1909 if(g && menu.events["checkchange"]){
1913 groups[g].push(menu);
1914 menu.on("checkchange", onCheck);
1919 * Returns a {@link Roo.menu.Menu} object
1920 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1921 * be used to generate and return a new Menu instance.
1923 get : function(menu){
1924 if(typeof menu == "string"){ // menu id
1926 }else if(menu.events){ // menu instance
1929 /*else if(typeof menu.length == 'number'){ // array of menu items?
1930 return new Roo.bootstrap.Menu({items:menu});
1931 }else{ // otherwise, must be a config
1932 return new Roo.bootstrap.Menu(menu);
1939 unregister : function(menu){
1940 delete menus[menu.id];
1941 menu.un("beforehide", onBeforeHide);
1942 menu.un("hide", onHide);
1943 menu.un("beforeshow", onBeforeShow);
1944 menu.un("show", onShow);
1946 if(g && menu.events["checkchange"]){
1947 groups[g].remove(menu);
1948 menu.un("checkchange", onCheck);
1953 registerCheckable : function(menuItem){
1954 var g = menuItem.group;
1959 groups[g].push(menuItem);
1960 menuItem.on("beforecheckchange", onBeforeCheck);
1965 unregisterCheckable : function(menuItem){
1966 var g = menuItem.group;
1968 groups[g].remove(menuItem);
1969 menuItem.un("beforecheckchange", onBeforeCheck);
1981 * @class Roo.bootstrap.Menu
1982 * @extends Roo.bootstrap.Component
1983 * Bootstrap Menu class - container for MenuItems
1984 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1985 * @cfg {bool} hidden if the menu should be hidden when rendered.
1986 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1987 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1991 * @param {Object} config The config object
1995 Roo.bootstrap.Menu = function(config){
1996 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1997 if (this.registerMenu && this.type != 'treeview') {
1998 Roo.bootstrap.MenuMgr.register(this);
2003 * Fires before this menu is displayed
2004 * @param {Roo.menu.Menu} this
2009 * Fires before this menu is hidden
2010 * @param {Roo.menu.Menu} this
2015 * Fires after this menu is displayed
2016 * @param {Roo.menu.Menu} this
2021 * Fires after this menu is hidden
2022 * @param {Roo.menu.Menu} this
2027 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2028 * @param {Roo.menu.Menu} this
2029 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2030 * @param {Roo.EventObject} e
2035 * Fires when the mouse is hovering over this menu
2036 * @param {Roo.menu.Menu} this
2037 * @param {Roo.EventObject} e
2038 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2043 * Fires when the mouse exits this menu
2044 * @param {Roo.menu.Menu} this
2045 * @param {Roo.EventObject} e
2046 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2051 * Fires when a menu item contained in this menu is clicked
2052 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2053 * @param {Roo.EventObject} e
2057 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2060 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2064 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2067 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2069 registerMenu : true,
2071 menuItems :false, // stores the menu items..
2081 getChildContainer : function() {
2085 getAutoCreate : function(){
2087 //if (['right'].indexOf(this.align)!==-1) {
2088 // cfg.cn[1].cls += ' pull-right'
2094 cls : 'dropdown-menu' ,
2095 style : 'z-index:1000'
2099 if (this.type === 'submenu') {
2100 cfg.cls = 'submenu active';
2102 if (this.type === 'treeview') {
2103 cfg.cls = 'treeview-menu';
2108 initEvents : function() {
2110 // Roo.log("ADD event");
2111 // Roo.log(this.triggerEl.dom);
2113 this.triggerEl.on('click', this.onTriggerClick, this);
2115 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2117 this.triggerEl.addClass('dropdown-toggle');
2120 this.el.on('touchstart' , this.onTouch, this);
2122 this.el.on('click' , this.onClick, this);
2124 this.el.on("mouseover", this.onMouseOver, this);
2125 this.el.on("mouseout", this.onMouseOut, this);
2129 findTargetItem : function(e)
2131 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2135 //Roo.log(t); Roo.log(t.id);
2137 //Roo.log(this.menuitems);
2138 return this.menuitems.get(t.id);
2140 //return this.items.get(t.menuItemId);
2146 onTouch : function(e)
2148 Roo.log("menu.onTouch");
2149 //e.stopEvent(); this make the user popdown broken
2153 onClick : function(e)
2155 Roo.log("menu.onClick");
2157 var t = this.findTargetItem(e);
2158 if(!t || t.isContainer){
2163 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2164 if(t == this.activeItem && t.shouldDeactivate(e)){
2165 this.activeItem.deactivate();
2166 delete this.activeItem;
2170 this.setActiveItem(t, true);
2178 Roo.log('pass click event');
2182 this.fireEvent("click", this, t, e);
2186 if(!t.href.length || t.href == '#'){
2187 (function() { _this.hide(); }).defer(100);
2192 onMouseOver : function(e){
2193 var t = this.findTargetItem(e);
2196 // if(t.canActivate && !t.disabled){
2197 // this.setActiveItem(t, true);
2201 this.fireEvent("mouseover", this, e, t);
2203 isVisible : function(){
2204 return !this.hidden;
2206 onMouseOut : function(e){
2207 var t = this.findTargetItem(e);
2210 // if(t == this.activeItem && t.shouldDeactivate(e)){
2211 // this.activeItem.deactivate();
2212 // delete this.activeItem;
2215 this.fireEvent("mouseout", this, e, t);
2220 * Displays this menu relative to another element
2221 * @param {String/HTMLElement/Roo.Element} element The element to align to
2222 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2223 * the element (defaults to this.defaultAlign)
2224 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2226 show : function(el, pos, parentMenu){
2227 this.parentMenu = parentMenu;
2231 this.fireEvent("beforeshow", this);
2232 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2235 * Displays this menu at a specific xy position
2236 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2237 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2239 showAt : function(xy, parentMenu, /* private: */_e){
2240 this.parentMenu = parentMenu;
2245 this.fireEvent("beforeshow", this);
2246 //xy = this.el.adjustForConstraints(xy);
2250 this.hideMenuItems();
2251 this.hidden = false;
2252 this.triggerEl.addClass('open');
2254 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2255 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2258 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2263 this.fireEvent("show", this);
2269 this.doFocus.defer(50, this);
2273 doFocus : function(){
2275 this.focusEl.focus();
2280 * Hides this menu and optionally all parent menus
2281 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2283 hide : function(deep)
2286 this.hideMenuItems();
2287 if(this.el && this.isVisible()){
2288 this.fireEvent("beforehide", this);
2289 if(this.activeItem){
2290 this.activeItem.deactivate();
2291 this.activeItem = null;
2293 this.triggerEl.removeClass('open');;
2295 this.fireEvent("hide", this);
2297 if(deep === true && this.parentMenu){
2298 this.parentMenu.hide(true);
2302 onTriggerClick : function(e)
2304 Roo.log('trigger click');
2306 var target = e.getTarget();
2308 Roo.log(target.nodeName.toLowerCase());
2310 if(target.nodeName.toLowerCase() === 'i'){
2316 onTriggerPress : function(e)
2318 Roo.log('trigger press');
2319 //Roo.log(e.getTarget());
2320 // Roo.log(this.triggerEl.dom);
2322 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2323 var pel = Roo.get(e.getTarget());
2324 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2325 Roo.log('is treeview or dropdown?');
2329 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2333 if (this.isVisible()) {
2338 this.show(this.triggerEl, false, false);
2341 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2348 hideMenuItems : function()
2350 Roo.log("hide Menu Items");
2354 //$(backdrop).remove()
2355 this.el.select('.open',true).each(function(aa) {
2357 aa.removeClass('open');
2358 //var parent = getParent($(this))
2359 //var relatedTarget = { relatedTarget: this }
2361 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2362 //if (e.isDefaultPrevented()) return
2363 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2366 addxtypeChild : function (tree, cntr) {
2367 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2369 this.menuitems.add(comp);
2381 this.getEl().dom.innerHTML = '';
2382 this.menuitems.clear();
2396 * @class Roo.bootstrap.MenuItem
2397 * @extends Roo.bootstrap.Component
2398 * Bootstrap MenuItem class
2399 * @cfg {String} html the menu label
2400 * @cfg {String} href the link
2401 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2402 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2403 * @cfg {Boolean} active used on sidebars to highlight active itesm
2404 * @cfg {String} fa favicon to show on left of menu item.
2405 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2409 * Create a new MenuItem
2410 * @param {Object} config The config object
2414 Roo.bootstrap.MenuItem = function(config){
2415 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2420 * The raw click event for the entire grid.
2421 * @param {Roo.bootstrap.MenuItem} this
2422 * @param {Roo.EventObject} e
2428 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2432 preventDefault: false,
2433 isContainer : false,
2437 getAutoCreate : function(){
2439 if(this.isContainer){
2442 cls: 'dropdown-menu-item'
2456 if (this.fa !== false) {
2459 cls : 'fa fa-' + this.fa
2468 cls: 'dropdown-menu-item',
2471 if (this.parent().type == 'treeview') {
2472 cfg.cls = 'treeview-menu';
2475 cfg.cls += ' active';
2480 anc.href = this.href || cfg.cn[0].href ;
2481 ctag.html = this.html || cfg.cn[0].html ;
2485 initEvents: function()
2487 if (this.parent().type == 'treeview') {
2488 this.el.select('a').on('click', this.onClick, this);
2492 this.menu.parentType = this.xtype;
2493 this.menu.triggerEl = this.el;
2494 this.menu = this.addxtype(Roo.apply({}, this.menu));
2498 onClick : function(e)
2500 Roo.log('item on click ');
2502 if(this.preventDefault){
2505 //this.parent().hideMenuItems();
2507 this.fireEvent('click', this, e);
2526 * @class Roo.bootstrap.MenuSeparator
2527 * @extends Roo.bootstrap.Component
2528 * Bootstrap MenuSeparator class
2531 * Create a new MenuItem
2532 * @param {Object} config The config object
2536 Roo.bootstrap.MenuSeparator = function(config){
2537 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2540 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2542 getAutoCreate : function(){
2561 * @class Roo.bootstrap.Modal
2562 * @extends Roo.bootstrap.Component
2563 * Bootstrap Modal class
2564 * @cfg {String} title Title of dialog
2565 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2566 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2567 * @cfg {Boolean} specificTitle default false
2568 * @cfg {Array} buttons Array of buttons or standard button set..
2569 * @cfg {String} buttonPosition (left|right|center) default right
2570 * @cfg {Boolean} animate default true
2571 * @cfg {Boolean} allow_close default true
2572 * @cfg {Boolean} fitwindow default false
2573 * @cfg {String} size (sm|lg) default empty
2577 * Create a new Modal Dialog
2578 * @param {Object} config The config object
2581 Roo.bootstrap.Modal = function(config){
2582 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2587 * The raw btnclick event for the button
2588 * @param {Roo.EventObject} e
2593 * Fire when dialog resize
2594 * @param {Roo.bootstrap.Modal} this
2595 * @param {Roo.EventObject} e
2599 this.buttons = this.buttons || [];
2602 this.tmpl = Roo.factory(this.tmpl);
2607 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2609 title : 'test dialog',
2619 specificTitle: false,
2621 buttonPosition: 'right',
2640 onRender : function(ct, position)
2642 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2645 var cfg = Roo.apply({}, this.getAutoCreate());
2648 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2650 //if (!cfg.name.length) {
2654 cfg.cls += ' ' + this.cls;
2657 cfg.style = this.style;
2659 this.el = Roo.get(document.body).createChild(cfg, position);
2661 //var type = this.el.dom.type;
2664 if(this.tabIndex !== undefined){
2665 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2668 this.dialogEl = this.el.select('.modal-dialog',true).first();
2669 this.bodyEl = this.el.select('.modal-body',true).first();
2670 this.closeEl = this.el.select('.modal-header .close', true).first();
2671 this.headerEl = this.el.select('.modal-header',true).first();
2672 this.titleEl = this.el.select('.modal-title',true).first();
2673 this.footerEl = this.el.select('.modal-footer',true).first();
2675 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2677 //this.el.addClass("x-dlg-modal");
2679 if (this.buttons.length) {
2680 Roo.each(this.buttons, function(bb) {
2681 var b = Roo.apply({}, bb);
2682 b.xns = b.xns || Roo.bootstrap;
2683 b.xtype = b.xtype || 'Button';
2684 if (typeof(b.listeners) == 'undefined') {
2685 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2688 var btn = Roo.factory(b);
2690 btn.render(this.el.select('.modal-footer div').first());
2694 // render the children.
2697 if(typeof(this.items) != 'undefined'){
2698 var items = this.items;
2701 for(var i =0;i < items.length;i++) {
2702 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2706 this.items = nitems;
2708 // where are these used - they used to be body/close/footer
2712 //this.el.addClass([this.fieldClass, this.cls]);
2716 getAutoCreate : function(){
2721 html : this.html || ''
2726 cls : 'modal-title',
2730 if(this.specificTitle){
2736 if (this.allow_close) {
2748 if(this.size.length){
2749 size = 'modal-' + this.size;
2756 cls: "modal-dialog " + size,
2759 cls : "modal-content",
2762 cls : 'modal-header',
2767 cls : 'modal-footer',
2771 cls: 'btn-' + this.buttonPosition
2788 modal.cls += ' fade';
2794 getChildContainer : function() {
2799 getButtonContainer : function() {
2800 return this.el.select('.modal-footer div',true).first();
2803 initEvents : function()
2805 if (this.allow_close) {
2806 this.closeEl.on('click', this.hide, this);
2808 Roo.EventManager.onWindowResize(this.resize, this, true);
2815 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2816 if (this.fitwindow) {
2817 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2818 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2823 setSize : function(w,h)
2833 if (!this.rendered) {
2837 //this.el.setStyle('display', 'block');
2838 this.el.removeClass('hideing');
2839 this.el.addClass('show');
2841 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2844 this.el.addClass('in');
2847 this.el.addClass('in');
2851 // not sure how we can show data in here..
2853 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2856 Roo.get(document.body).addClass("x-body-masked");
2858 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2859 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2860 this.maskEl.addClass('show');
2864 this.fireEvent('show', this);
2866 // set zindex here - otherwise it appears to be ignored...
2867 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2870 this.items.forEach( function(e) {
2871 e.layout ? e.layout() : false;
2879 if(this.fireEvent("beforehide", this) !== false){
2880 this.maskEl.removeClass('show');
2881 Roo.get(document.body).removeClass("x-body-masked");
2882 this.el.removeClass('in');
2883 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2885 if(this.animate){ // why
2886 this.el.addClass('hideing');
2888 if (!this.el.hasClass('hideing')) {
2889 return; // it's been shown again...
2891 this.el.removeClass('show');
2892 this.el.removeClass('hideing');
2896 this.el.removeClass('show');
2898 this.fireEvent('hide', this);
2901 isVisible : function()
2904 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2908 addButton : function(str, cb)
2912 var b = Roo.apply({}, { html : str } );
2913 b.xns = b.xns || Roo.bootstrap;
2914 b.xtype = b.xtype || 'Button';
2915 if (typeof(b.listeners) == 'undefined') {
2916 b.listeners = { click : cb.createDelegate(this) };
2919 var btn = Roo.factory(b);
2921 btn.render(this.el.select('.modal-footer div').first());
2927 setDefaultButton : function(btn)
2929 //this.el.select('.modal-footer').()
2933 resizeTo: function(w,h)
2937 this.dialogEl.setWidth(w);
2938 if (this.diff === false) {
2939 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2942 this.bodyEl.setHeight(h-this.diff);
2944 this.fireEvent('resize', this);
2947 setContentSize : function(w, h)
2951 onButtonClick: function(btn,e)
2954 this.fireEvent('btnclick', btn.name, e);
2957 * Set the title of the Dialog
2958 * @param {String} str new Title
2960 setTitle: function(str) {
2961 this.titleEl.dom.innerHTML = str;
2964 * Set the body of the Dialog
2965 * @param {String} str new Title
2967 setBody: function(str) {
2968 this.bodyEl.dom.innerHTML = str;
2971 * Set the body of the Dialog using the template
2972 * @param {Obj} data - apply this data to the template and replace the body contents.
2974 applyBody: function(obj)
2977 Roo.log("Error - using apply Body without a template");
2980 this.tmpl.overwrite(this.bodyEl, obj);
2986 Roo.apply(Roo.bootstrap.Modal, {
2988 * Button config that displays a single OK button
2997 * Button config that displays Yes and No buttons
3013 * Button config that displays OK and Cancel buttons
3028 * Button config that displays Yes, No and Cancel buttons
3052 * messagebox - can be used as a replace
3056 * @class Roo.MessageBox
3057 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3061 Roo.Msg.alert('Status', 'Changes saved successfully.');
3063 // Prompt for user data:
3064 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3066 // process text value...
3070 // Show a dialog using config options:
3072 title:'Save Changes?',
3073 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3074 buttons: Roo.Msg.YESNOCANCEL,
3081 Roo.bootstrap.MessageBox = function(){
3082 var dlg, opt, mask, waitTimer;
3083 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3084 var buttons, activeTextEl, bwidth;
3088 var handleButton = function(button){
3090 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3094 var handleHide = function(){
3096 dlg.el.removeClass(opt.cls);
3099 // Roo.TaskMgr.stop(waitTimer);
3100 // waitTimer = null;
3105 var updateButtons = function(b){
3108 buttons["ok"].hide();
3109 buttons["cancel"].hide();
3110 buttons["yes"].hide();
3111 buttons["no"].hide();
3112 //dlg.footer.dom.style.display = 'none';
3115 dlg.footerEl.dom.style.display = '';
3116 for(var k in buttons){
3117 if(typeof buttons[k] != "function"){
3120 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3121 width += buttons[k].el.getWidth()+15;
3131 var handleEsc = function(d, k, e){
3132 if(opt && opt.closable !== false){
3142 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3143 * @return {Roo.BasicDialog} The BasicDialog element
3145 getDialog : function(){
3147 dlg = new Roo.bootstrap.Modal( {
3150 //constraintoviewport:false,
3152 //collapsible : false,
3157 //buttonAlign:"center",
3158 closeClick : function(){
3159 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3162 handleButton("cancel");
3167 dlg.on("hide", handleHide);
3169 //dlg.addKeyListener(27, handleEsc);
3171 this.buttons = buttons;
3172 var bt = this.buttonText;
3173 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3174 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3175 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3176 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3178 bodyEl = dlg.bodyEl.createChild({
3180 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3181 '<textarea class="roo-mb-textarea"></textarea>' +
3182 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3184 msgEl = bodyEl.dom.firstChild;
3185 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3186 textboxEl.enableDisplayMode();
3187 textboxEl.addKeyListener([10,13], function(){
3188 if(dlg.isVisible() && opt && opt.buttons){
3191 }else if(opt.buttons.yes){
3192 handleButton("yes");
3196 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3197 textareaEl.enableDisplayMode();
3198 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3199 progressEl.enableDisplayMode();
3201 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3202 var pf = progressEl.dom.firstChild;
3204 pp = Roo.get(pf.firstChild);
3205 pp.setHeight(pf.offsetHeight);
3213 * Updates the message box body text
3214 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3215 * the XHTML-compliant non-breaking space character '&#160;')
3216 * @return {Roo.MessageBox} This message box
3218 updateText : function(text)
3220 if(!dlg.isVisible() && !opt.width){
3221 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3222 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3224 msgEl.innerHTML = text || ' ';
3226 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3227 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3229 Math.min(opt.width || cw , this.maxWidth),
3230 Math.max(opt.minWidth || this.minWidth, bwidth)
3233 activeTextEl.setWidth(w);
3235 if(dlg.isVisible()){
3236 dlg.fixedcenter = false;
3238 // to big, make it scroll. = But as usual stupid IE does not support
3241 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3242 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3243 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3245 bodyEl.dom.style.height = '';
3246 bodyEl.dom.style.overflowY = '';
3249 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3251 bodyEl.dom.style.overflowX = '';
3254 dlg.setContentSize(w, bodyEl.getHeight());
3255 if(dlg.isVisible()){
3256 dlg.fixedcenter = true;
3262 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3263 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3264 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3265 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3266 * @return {Roo.MessageBox} This message box
3268 updateProgress : function(value, text){
3270 this.updateText(text);
3273 if (pp) { // weird bug on my firefox - for some reason this is not defined
3274 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3275 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3281 * Returns true if the message box is currently displayed
3282 * @return {Boolean} True if the message box is visible, else false
3284 isVisible : function(){
3285 return dlg && dlg.isVisible();
3289 * Hides the message box if it is displayed
3292 if(this.isVisible()){
3298 * Displays a new message box, or reinitializes an existing message box, based on the config options
3299 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3300 * The following config object properties are supported:
3302 Property Type Description
3303 ---------- --------------- ------------------------------------------------------------------------------------
3304 animEl String/Element An id or Element from which the message box should animate as it opens and
3305 closes (defaults to undefined)
3306 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3307 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3308 closable Boolean False to hide the top-right close button (defaults to true). Note that
3309 progress and wait dialogs will ignore this property and always hide the
3310 close button as they can only be closed programmatically.
3311 cls String A custom CSS class to apply to the message box element
3312 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3313 displayed (defaults to 75)
3314 fn Function A callback function to execute after closing the dialog. The arguments to the
3315 function will be btn (the name of the button that was clicked, if applicable,
3316 e.g. "ok"), and text (the value of the active text field, if applicable).
3317 Progress and wait dialogs will ignore this option since they do not respond to
3318 user actions and can only be closed programmatically, so any required function
3319 should be called by the same code after it closes the dialog.
3320 icon String A CSS class that provides a background image to be used as an icon for
3321 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3322 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3323 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3324 modal Boolean False to allow user interaction with the page while the message box is
3325 displayed (defaults to true)
3326 msg String A string that will replace the existing message box body text (defaults
3327 to the XHTML-compliant non-breaking space character ' ')
3328 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3329 progress Boolean True to display a progress bar (defaults to false)
3330 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3331 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3332 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3333 title String The title text
3334 value String The string value to set into the active textbox element if displayed
3335 wait Boolean True to display a progress bar (defaults to false)
3336 width Number The width of the dialog in pixels
3343 msg: 'Please enter your address:',
3345 buttons: Roo.MessageBox.OKCANCEL,
3348 animEl: 'addAddressBtn'
3351 * @param {Object} config Configuration options
3352 * @return {Roo.MessageBox} This message box
3354 show : function(options)
3357 // this causes nightmares if you show one dialog after another
3358 // especially on callbacks..
3360 if(this.isVisible()){
3363 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3364 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3365 Roo.log("New Dialog Message:" + options.msg )
3366 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3367 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3370 var d = this.getDialog();
3372 d.setTitle(opt.title || " ");
3373 d.closeEl.setDisplayed(opt.closable !== false);
3374 activeTextEl = textboxEl;
3375 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3380 textareaEl.setHeight(typeof opt.multiline == "number" ?
3381 opt.multiline : this.defaultTextHeight);
3382 activeTextEl = textareaEl;
3391 progressEl.setDisplayed(opt.progress === true);
3392 this.updateProgress(0);
3393 activeTextEl.dom.value = opt.value || "";
3395 dlg.setDefaultButton(activeTextEl);
3397 var bs = opt.buttons;
3401 }else if(bs && bs.yes){
3402 db = buttons["yes"];
3404 dlg.setDefaultButton(db);
3406 bwidth = updateButtons(opt.buttons);
3407 this.updateText(opt.msg);
3409 d.el.addClass(opt.cls);
3411 d.proxyDrag = opt.proxyDrag === true;
3412 d.modal = opt.modal !== false;
3413 d.mask = opt.modal !== false ? mask : false;
3415 // force it to the end of the z-index stack so it gets a cursor in FF
3416 document.body.appendChild(dlg.el.dom);
3417 d.animateTarget = null;
3418 d.show(options.animEl);
3424 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3425 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3426 * and closing the message box when the process is complete.
3427 * @param {String} title The title bar text
3428 * @param {String} msg The message box body text
3429 * @return {Roo.MessageBox} This message box
3431 progress : function(title, msg){
3438 minWidth: this.minProgressWidth,
3445 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3446 * If a callback function is passed it will be called after the user clicks the button, and the
3447 * id of the button that was clicked will be passed as the only parameter to the callback
3448 * (could also be the top-right close button).
3449 * @param {String} title The title bar text
3450 * @param {String} msg The message box body text
3451 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3452 * @param {Object} scope (optional) The scope of the callback function
3453 * @return {Roo.MessageBox} This message box
3455 alert : function(title, msg, fn, scope)
3470 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3471 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3472 * You are responsible for closing the message box when the process is complete.
3473 * @param {String} msg The message box body text
3474 * @param {String} title (optional) The title bar text
3475 * @return {Roo.MessageBox} This message box
3477 wait : function(msg, title){
3488 waitTimer = Roo.TaskMgr.start({
3490 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3498 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3499 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3500 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3501 * @param {String} title The title bar text
3502 * @param {String} msg The message box body text
3503 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3504 * @param {Object} scope (optional) The scope of the callback function
3505 * @return {Roo.MessageBox} This message box
3507 confirm : function(title, msg, fn, scope){
3511 buttons: this.YESNO,
3520 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3521 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3522 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3523 * (could also be the top-right close button) and the text that was entered will be passed as the two
3524 * parameters to the callback.
3525 * @param {String} title The title bar text
3526 * @param {String} msg The message box body text
3527 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3528 * @param {Object} scope (optional) The scope of the callback function
3529 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3530 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3531 * @return {Roo.MessageBox} This message box
3533 prompt : function(title, msg, fn, scope, multiline){
3537 buttons: this.OKCANCEL,
3542 multiline: multiline,
3549 * Button config that displays a single OK button
3554 * Button config that displays Yes and No buttons
3557 YESNO : {yes:true, no:true},
3559 * Button config that displays OK and Cancel buttons
3562 OKCANCEL : {ok:true, cancel:true},
3564 * Button config that displays Yes, No and Cancel buttons
3567 YESNOCANCEL : {yes:true, no:true, cancel:true},
3570 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3573 defaultTextHeight : 75,
3575 * The maximum width in pixels of the message box (defaults to 600)
3580 * The minimum width in pixels of the message box (defaults to 100)
3585 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3586 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3589 minProgressWidth : 250,
3591 * An object containing the default button text strings that can be overriden for localized language support.
3592 * Supported properties are: ok, cancel, yes and no.
3593 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3606 * Shorthand for {@link Roo.MessageBox}
3608 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3609 Roo.Msg = Roo.Msg || Roo.MessageBox;
3618 * @class Roo.bootstrap.Navbar
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Navbar class
3623 * Create a new Navbar
3624 * @param {Object} config The config object
3628 Roo.bootstrap.Navbar = function(config){
3629 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3633 * @event beforetoggle
3634 * Fire before toggle the menu
3635 * @param {Roo.EventObject} e
3637 "beforetoggle" : true
3641 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3650 getAutoCreate : function(){
3653 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3657 initEvents :function ()
3659 //Roo.log(this.el.select('.navbar-toggle',true));
3660 this.el.select('.navbar-toggle',true).on('click', function() {
3661 if(this.fireEvent('beforetoggle', this) !== false){
3662 this.el.select('.navbar-collapse',true).toggleClass('in');
3672 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3674 var size = this.el.getSize();
3675 this.maskEl.setSize(size.width, size.height);
3676 this.maskEl.enableDisplayMode("block");
3685 getChildContainer : function()
3687 if (this.el.select('.collapse').getCount()) {
3688 return this.el.select('.collapse',true).first();
3721 * @class Roo.bootstrap.NavSimplebar
3722 * @extends Roo.bootstrap.Navbar
3723 * Bootstrap Sidebar class
3725 * @cfg {Boolean} inverse is inverted color
3727 * @cfg {String} type (nav | pills | tabs)
3728 * @cfg {Boolean} arrangement stacked | justified
3729 * @cfg {String} align (left | right) alignment
3731 * @cfg {Boolean} main (true|false) main nav bar? default false
3732 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3734 * @cfg {String} tag (header|footer|nav|div) default is nav
3740 * Create a new Sidebar
3741 * @param {Object} config The config object
3745 Roo.bootstrap.NavSimplebar = function(config){
3746 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3749 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3765 getAutoCreate : function(){
3769 tag : this.tag || 'div',
3782 this.type = this.type || 'nav';
3783 if (['tabs','pills'].indexOf(this.type)!==-1) {
3784 cfg.cn[0].cls += ' nav-' + this.type
3788 if (this.type!=='nav') {
3789 Roo.log('nav type must be nav/tabs/pills')
3791 cfg.cn[0].cls += ' navbar-nav'
3797 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3798 cfg.cn[0].cls += ' nav-' + this.arrangement;
3802 if (this.align === 'right') {
3803 cfg.cn[0].cls += ' navbar-right';
3807 cfg.cls += ' navbar-inverse';
3834 * @class Roo.bootstrap.NavHeaderbar
3835 * @extends Roo.bootstrap.NavSimplebar
3836 * Bootstrap Sidebar class
3838 * @cfg {String} brand what is brand
3839 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3840 * @cfg {String} brand_href href of the brand
3841 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3842 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3843 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3844 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3847 * Create a new Sidebar
3848 * @param {Object} config The config object
3852 Roo.bootstrap.NavHeaderbar = function(config){
3853 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3857 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3864 desktopCenter : false,
3867 getAutoCreate : function(){
3870 tag: this.nav || 'nav',
3877 if (this.desktopCenter) {
3878 cn.push({cls : 'container', cn : []});
3885 cls: 'navbar-header',
3890 cls: 'navbar-toggle',
3891 'data-toggle': 'collapse',
3896 html: 'Toggle navigation'
3918 cls: 'collapse navbar-collapse',
3922 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3924 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3925 cfg.cls += ' navbar-' + this.position;
3927 // tag can override this..
3929 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3932 if (this.brand !== '') {
3935 href: this.brand_href ? this.brand_href : '#',
3936 cls: 'navbar-brand',
3944 cfg.cls += ' main-nav';
3952 getHeaderChildContainer : function()
3954 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3955 return this.el.select('.navbar-header',true).first();
3958 return this.getChildContainer();
3962 initEvents : function()
3964 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3966 if (this.autohide) {
3971 Roo.get(document).on('scroll',function(e) {
3972 var ns = Roo.get(document).getScroll().top;
3973 var os = prevScroll;
3977 ft.removeClass('slideDown');
3978 ft.addClass('slideUp');
3981 ft.removeClass('slideUp');
3982 ft.addClass('slideDown');
4003 * @class Roo.bootstrap.NavSidebar
4004 * @extends Roo.bootstrap.Navbar
4005 * Bootstrap Sidebar class
4008 * Create a new Sidebar
4009 * @param {Object} config The config object
4013 Roo.bootstrap.NavSidebar = function(config){
4014 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4017 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4019 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4021 getAutoCreate : function(){
4026 cls: 'sidebar sidebar-nav'
4048 * @class Roo.bootstrap.NavGroup
4049 * @extends Roo.bootstrap.Component
4050 * Bootstrap NavGroup class
4051 * @cfg {String} align (left|right)
4052 * @cfg {Boolean} inverse
4053 * @cfg {String} type (nav|pills|tab) default nav
4054 * @cfg {String} navId - reference Id for navbar.
4058 * Create a new nav group
4059 * @param {Object} config The config object
4062 Roo.bootstrap.NavGroup = function(config){
4063 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4066 Roo.bootstrap.NavGroup.register(this);
4070 * Fires when the active item changes
4071 * @param {Roo.bootstrap.NavGroup} this
4072 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4073 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4080 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4091 getAutoCreate : function()
4093 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4100 if (['tabs','pills'].indexOf(this.type)!==-1) {
4101 cfg.cls += ' nav-' + this.type
4103 if (this.type!=='nav') {
4104 Roo.log('nav type must be nav/tabs/pills')
4106 cfg.cls += ' navbar-nav'
4109 if (this.parent() && this.parent().sidebar) {
4112 cls: 'dashboard-menu sidebar-menu'
4118 if (this.form === true) {
4124 if (this.align === 'right') {
4125 cfg.cls += ' navbar-right';
4127 cfg.cls += ' navbar-left';
4131 if (this.align === 'right') {
4132 cfg.cls += ' navbar-right';
4136 cfg.cls += ' navbar-inverse';
4144 * sets the active Navigation item
4145 * @param {Roo.bootstrap.NavItem} the new current navitem
4147 setActiveItem : function(item)
4150 Roo.each(this.navItems, function(v){
4155 v.setActive(false, true);
4162 item.setActive(true, true);
4163 this.fireEvent('changed', this, item, prev);
4168 * gets the active Navigation item
4169 * @return {Roo.bootstrap.NavItem} the current navitem
4171 getActive : function()
4175 Roo.each(this.navItems, function(v){
4186 indexOfNav : function()
4190 Roo.each(this.navItems, function(v,i){
4201 * adds a Navigation item
4202 * @param {Roo.bootstrap.NavItem} the navitem to add
4204 addItem : function(cfg)
4206 var cn = new Roo.bootstrap.NavItem(cfg);
4208 cn.parentId = this.id;
4209 cn.onRender(this.el, null);
4213 * register a Navigation item
4214 * @param {Roo.bootstrap.NavItem} the navitem to add
4216 register : function(item)
4218 this.navItems.push( item);
4219 item.navId = this.navId;
4224 * clear all the Navigation item
4227 clearAll : function()
4230 this.el.dom.innerHTML = '';
4233 getNavItem: function(tabId)
4236 Roo.each(this.navItems, function(e) {
4237 if (e.tabId == tabId) {
4247 setActiveNext : function()
4249 var i = this.indexOfNav(this.getActive());
4250 if (i > this.navItems.length) {
4253 this.setActiveItem(this.navItems[i+1]);
4255 setActivePrev : function()
4257 var i = this.indexOfNav(this.getActive());
4261 this.setActiveItem(this.navItems[i-1]);
4263 clearWasActive : function(except) {
4264 Roo.each(this.navItems, function(e) {
4265 if (e.tabId != except.tabId && e.was_active) {
4266 e.was_active = false;
4273 getWasActive : function ()
4276 Roo.each(this.navItems, function(e) {
4291 Roo.apply(Roo.bootstrap.NavGroup, {
4295 * register a Navigation Group
4296 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4298 register : function(navgrp)
4300 this.groups[navgrp.navId] = navgrp;
4304 * fetch a Navigation Group based on the navigation ID
4305 * @param {string} the navgroup to add
4306 * @returns {Roo.bootstrap.NavGroup} the navgroup
4308 get: function(navId) {
4309 if (typeof(this.groups[navId]) == 'undefined') {
4311 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4313 return this.groups[navId] ;
4328 * @class Roo.bootstrap.NavItem
4329 * @extends Roo.bootstrap.Component
4330 * Bootstrap Navbar.NavItem class
4331 * @cfg {String} href link to
4332 * @cfg {String} html content of button
4333 * @cfg {String} badge text inside badge
4334 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4335 * @cfg {String} glyphicon name of glyphicon
4336 * @cfg {String} icon name of font awesome icon
4337 * @cfg {Boolean} active Is item active
4338 * @cfg {Boolean} disabled Is item disabled
4340 * @cfg {Boolean} preventDefault (true | false) default false
4341 * @cfg {String} tabId the tab that this item activates.
4342 * @cfg {String} tagtype (a|span) render as a href or span?
4343 * @cfg {Boolean} animateRef (true|false) link to element default false
4346 * Create a new Navbar Item
4347 * @param {Object} config The config object
4349 Roo.bootstrap.NavItem = function(config){
4350 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4355 * The raw click event for the entire grid.
4356 * @param {Roo.EventObject} e
4361 * Fires when the active item active state changes
4362 * @param {Roo.bootstrap.NavItem} this
4363 * @param {boolean} state the new state
4369 * Fires when scroll to element
4370 * @param {Roo.bootstrap.NavItem} this
4371 * @param {Object} options
4372 * @param {Roo.EventObject} e
4380 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4388 preventDefault : false,
4395 getAutoCreate : function(){
4404 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4406 if (this.disabled) {
4407 cfg.cls += ' disabled';
4410 if (this.href || this.html || this.glyphicon || this.icon) {
4414 href : this.href || "#",
4415 html: this.html || ''
4420 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4423 if(this.glyphicon) {
4424 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4429 cfg.cn[0].html += " <span class='caret'></span>";
4433 if (this.badge !== '') {
4435 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4443 initEvents: function()
4445 if (typeof (this.menu) != 'undefined') {
4446 this.menu.parentType = this.xtype;
4447 this.menu.triggerEl = this.el;
4448 this.menu = this.addxtype(Roo.apply({}, this.menu));
4451 this.el.select('a',true).on('click', this.onClick, this);
4453 if(this.tagtype == 'span'){
4454 this.el.select('span',true).on('click', this.onClick, this);
4457 // at this point parent should be available..
4458 this.parent().register(this);
4461 onClick : function(e)
4463 if (e.getTarget('.dropdown-menu-item')) {
4464 // did you click on a menu itemm.... - then don't trigger onclick..
4469 this.preventDefault ||
4472 Roo.log("NavItem - prevent Default?");
4476 if (this.disabled) {
4480 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4481 if (tg && tg.transition) {
4482 Roo.log("waiting for the transitionend");
4488 //Roo.log("fire event clicked");
4489 if(this.fireEvent('click', this, e) === false){
4493 if(this.tagtype == 'span'){
4497 //Roo.log(this.href);
4498 var ael = this.el.select('a',true).first();
4501 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4502 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4503 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4504 return; // ignore... - it's a 'hash' to another page.
4506 Roo.log("NavItem - prevent Default?");
4508 this.scrollToElement(e);
4512 var p = this.parent();
4514 if (['tabs','pills'].indexOf(p.type)!==-1) {
4515 if (typeof(p.setActiveItem) !== 'undefined') {
4516 p.setActiveItem(this);
4520 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4521 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4522 // remove the collapsed menu expand...
4523 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4527 isActive: function () {
4530 setActive : function(state, fire, is_was_active)
4532 if (this.active && !state && this.navId) {
4533 this.was_active = true;
4534 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4536 nv.clearWasActive(this);
4540 this.active = state;
4543 this.el.removeClass('active');
4544 } else if (!this.el.hasClass('active')) {
4545 this.el.addClass('active');
4548 this.fireEvent('changed', this, state);
4551 // show a panel if it's registered and related..
4553 if (!this.navId || !this.tabId || !state || is_was_active) {
4557 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4561 var pan = tg.getPanelByName(this.tabId);
4565 // if we can not flip to new panel - go back to old nav highlight..
4566 if (false == tg.showPanel(pan)) {
4567 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4569 var onav = nv.getWasActive();
4571 onav.setActive(true, false, true);
4580 // this should not be here...
4581 setDisabled : function(state)
4583 this.disabled = state;
4585 this.el.removeClass('disabled');
4586 } else if (!this.el.hasClass('disabled')) {
4587 this.el.addClass('disabled');
4593 * Fetch the element to display the tooltip on.
4594 * @return {Roo.Element} defaults to this.el
4596 tooltipEl : function()
4598 return this.el.select('' + this.tagtype + '', true).first();
4601 scrollToElement : function(e)
4603 var c = document.body;
4606 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4608 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4609 c = document.documentElement;
4612 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4618 var o = target.calcOffsetsTo(c);
4625 this.fireEvent('scrollto', this, options, e);
4627 Roo.get(c).scrollTo('top', options.value, true);
4640 * <span> icon </span>
4641 * <span> text </span>
4642 * <span>badge </span>
4646 * @class Roo.bootstrap.NavSidebarItem
4647 * @extends Roo.bootstrap.NavItem
4648 * Bootstrap Navbar.NavSidebarItem class
4649 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4650 * {Boolean} open is the menu open
4651 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4652 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4653 * {String} buttonSize (sm|md|lg)the extra classes for the button
4654 * {Boolean} showArrow show arrow next to the text (default true)
4656 * Create a new Navbar Button
4657 * @param {Object} config The config object
4659 Roo.bootstrap.NavSidebarItem = function(config){
4660 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4665 * The raw click event for the entire grid.
4666 * @param {Roo.EventObject} e
4671 * Fires when the active item active state changes
4672 * @param {Roo.bootstrap.NavSidebarItem} this
4673 * @param {boolean} state the new state
4681 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4683 badgeWeight : 'default',
4689 buttonWeight : 'default',
4695 getAutoCreate : function(){
4700 href : this.href || '#',
4706 if(this.buttonView){
4709 href : this.href || '#',
4710 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4723 cfg.cls += ' active';
4726 if (this.disabled) {
4727 cfg.cls += ' disabled';
4730 cfg.cls += ' open x-open';
4733 if (this.glyphicon || this.icon) {
4734 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4735 a.cn.push({ tag : 'i', cls : c }) ;
4738 if(!this.buttonView){
4741 html : this.html || ''
4748 if (this.badge !== '') {
4749 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4755 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4758 a.cls += ' dropdown-toggle treeview' ;
4764 initEvents : function()
4766 if (typeof (this.menu) != 'undefined') {
4767 this.menu.parentType = this.xtype;
4768 this.menu.triggerEl = this.el;
4769 this.menu = this.addxtype(Roo.apply({}, this.menu));
4772 this.el.on('click', this.onClick, this);
4774 if(this.badge !== ''){
4775 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4780 onClick : function(e)
4787 if(this.preventDefault){
4791 this.fireEvent('click', this);
4794 disable : function()
4796 this.setDisabled(true);
4801 this.setDisabled(false);
4804 setDisabled : function(state)
4806 if(this.disabled == state){
4810 this.disabled = state;
4813 this.el.addClass('disabled');
4817 this.el.removeClass('disabled');
4822 setActive : function(state)
4824 if(this.active == state){
4828 this.active = state;
4831 this.el.addClass('active');
4835 this.el.removeClass('active');
4840 isActive: function ()
4845 setBadge : function(str)
4851 this.badgeEl.dom.innerHTML = str;
4868 * @class Roo.bootstrap.Row
4869 * @extends Roo.bootstrap.Component
4870 * Bootstrap Row class (contains columns...)
4874 * @param {Object} config The config object
4877 Roo.bootstrap.Row = function(config){
4878 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4881 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4883 getAutoCreate : function(){
4902 * @class Roo.bootstrap.Element
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap Element class
4905 * @cfg {String} html contents of the element
4906 * @cfg {String} tag tag of the element
4907 * @cfg {String} cls class of the element
4908 * @cfg {Boolean} preventDefault (true|false) default false
4909 * @cfg {Boolean} clickable (true|false) default false
4912 * Create a new Element
4913 * @param {Object} config The config object
4916 Roo.bootstrap.Element = function(config){
4917 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4923 * When a element is chick
4924 * @param {Roo.bootstrap.Element} this
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4936 preventDefault: false,
4939 getAutoCreate : function(){
4943 // cls: this.cls, double assign in parent class Component.js :: onRender
4950 initEvents: function()
4952 Roo.bootstrap.Element.superclass.initEvents.call(this);
4955 this.el.on('click', this.onClick, this);
4960 onClick : function(e)
4962 if(this.preventDefault){
4966 this.fireEvent('click', this, e);
4969 getValue : function()
4971 return this.el.dom.innerHTML;
4974 setValue : function(value)
4976 this.el.dom.innerHTML = value;
4991 * @class Roo.bootstrap.Pagination
4992 * @extends Roo.bootstrap.Component
4993 * Bootstrap Pagination class
4994 * @cfg {String} size xs | sm | md | lg
4995 * @cfg {Boolean} inverse false | true
4998 * Create a new Pagination
4999 * @param {Object} config The config object
5002 Roo.bootstrap.Pagination = function(config){
5003 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5006 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5012 getAutoCreate : function(){
5018 cfg.cls += ' inverse';
5024 cfg.cls += " " + this.cls;
5042 * @class Roo.bootstrap.PaginationItem
5043 * @extends Roo.bootstrap.Component
5044 * Bootstrap PaginationItem class
5045 * @cfg {String} html text
5046 * @cfg {String} href the link
5047 * @cfg {Boolean} preventDefault (true | false) default true
5048 * @cfg {Boolean} active (true | false) default false
5049 * @cfg {Boolean} disabled default false
5053 * Create a new PaginationItem
5054 * @param {Object} config The config object
5058 Roo.bootstrap.PaginationItem = function(config){
5059 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5064 * The raw click event for the entire grid.
5065 * @param {Roo.EventObject} e
5071 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5075 preventDefault: true,
5080 getAutoCreate : function(){
5086 href : this.href ? this.href : '#',
5087 html : this.html ? this.html : ''
5097 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5101 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5107 initEvents: function() {
5109 this.el.on('click', this.onClick, this);
5112 onClick : function(e)
5114 Roo.log('PaginationItem on click ');
5115 if(this.preventDefault){
5123 this.fireEvent('click', this, e);
5139 * @class Roo.bootstrap.Slider
5140 * @extends Roo.bootstrap.Component
5141 * Bootstrap Slider class
5144 * Create a new Slider
5145 * @param {Object} config The config object
5148 Roo.bootstrap.Slider = function(config){
5149 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5152 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5154 getAutoCreate : function(){
5158 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5162 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5174 * Ext JS Library 1.1.1
5175 * Copyright(c) 2006-2007, Ext JS, LLC.
5177 * Originally Released Under LGPL - original licence link has changed is not relivant.
5180 * <script type="text/javascript">
5185 * @class Roo.grid.ColumnModel
5186 * @extends Roo.util.Observable
5187 * This is the default implementation of a ColumnModel used by the Grid. It defines
5188 * the columns in the grid.
5191 var colModel = new Roo.grid.ColumnModel([
5192 {header: "Ticker", width: 60, sortable: true, locked: true},
5193 {header: "Company Name", width: 150, sortable: true},
5194 {header: "Market Cap.", width: 100, sortable: true},
5195 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5196 {header: "Employees", width: 100, sortable: true, resizable: false}
5201 * The config options listed for this class are options which may appear in each
5202 * individual column definition.
5203 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5205 * @param {Object} config An Array of column config objects. See this class's
5206 * config objects for details.
5208 Roo.grid.ColumnModel = function(config){
5210 * The config passed into the constructor
5212 this.config = config;
5215 // if no id, create one
5216 // if the column does not have a dataIndex mapping,
5217 // map it to the order it is in the config
5218 for(var i = 0, len = config.length; i < len; i++){
5220 if(typeof c.dataIndex == "undefined"){
5223 if(typeof c.renderer == "string"){
5224 c.renderer = Roo.util.Format[c.renderer];
5226 if(typeof c.id == "undefined"){
5229 if(c.editor && c.editor.xtype){
5230 c.editor = Roo.factory(c.editor, Roo.grid);
5232 if(c.editor && c.editor.isFormField){
5233 c.editor = new Roo.grid.GridEditor(c.editor);
5235 this.lookup[c.id] = c;
5239 * The width of columns which have no width specified (defaults to 100)
5242 this.defaultWidth = 100;
5245 * Default sortable of columns which have no sortable specified (defaults to false)
5248 this.defaultSortable = false;
5252 * @event widthchange
5253 * Fires when the width of a column changes.
5254 * @param {ColumnModel} this
5255 * @param {Number} columnIndex The column index
5256 * @param {Number} newWidth The new width
5258 "widthchange": true,
5260 * @event headerchange
5261 * Fires when the text of a header changes.
5262 * @param {ColumnModel} this
5263 * @param {Number} columnIndex The column index
5264 * @param {Number} newText The new header text
5266 "headerchange": true,
5268 * @event hiddenchange
5269 * Fires when a column is hidden or "unhidden".
5270 * @param {ColumnModel} this
5271 * @param {Number} columnIndex The column index
5272 * @param {Boolean} hidden true if hidden, false otherwise
5274 "hiddenchange": true,
5276 * @event columnmoved
5277 * Fires when a column is moved.
5278 * @param {ColumnModel} this
5279 * @param {Number} oldIndex
5280 * @param {Number} newIndex
5282 "columnmoved" : true,
5284 * @event columlockchange
5285 * Fires when a column's locked state is changed
5286 * @param {ColumnModel} this
5287 * @param {Number} colIndex
5288 * @param {Boolean} locked true if locked
5290 "columnlockchange" : true
5292 Roo.grid.ColumnModel.superclass.constructor.call(this);
5294 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5296 * @cfg {String} header The header text to display in the Grid view.
5299 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5300 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5301 * specified, the column's index is used as an index into the Record's data Array.
5304 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5305 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5308 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5309 * Defaults to the value of the {@link #defaultSortable} property.
5310 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5313 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5316 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5319 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5322 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5325 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5326 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5327 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5328 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5331 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5334 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5337 * @cfg {String} cursor (Optional)
5340 * @cfg {String} tooltip (Optional)
5343 * @cfg {Number} xs (Optional)
5346 * @cfg {Number} sm (Optional)
5349 * @cfg {Number} md (Optional)
5352 * @cfg {Number} lg (Optional)
5355 * Returns the id of the column at the specified index.
5356 * @param {Number} index The column index
5357 * @return {String} the id
5359 getColumnId : function(index){
5360 return this.config[index].id;
5364 * Returns the column for a specified id.
5365 * @param {String} id The column id
5366 * @return {Object} the column
5368 getColumnById : function(id){
5369 return this.lookup[id];
5374 * Returns the column for a specified dataIndex.
5375 * @param {String} dataIndex The column dataIndex
5376 * @return {Object|Boolean} the column or false if not found
5378 getColumnByDataIndex: function(dataIndex){
5379 var index = this.findColumnIndex(dataIndex);
5380 return index > -1 ? this.config[index] : false;
5384 * Returns the index for a specified column id.
5385 * @param {String} id The column id
5386 * @return {Number} the index, or -1 if not found
5388 getIndexById : function(id){
5389 for(var i = 0, len = this.config.length; i < len; i++){
5390 if(this.config[i].id == id){
5398 * Returns the index for a specified column dataIndex.
5399 * @param {String} dataIndex The column dataIndex
5400 * @return {Number} the index, or -1 if not found
5403 findColumnIndex : function(dataIndex){
5404 for(var i = 0, len = this.config.length; i < len; i++){
5405 if(this.config[i].dataIndex == dataIndex){
5413 moveColumn : function(oldIndex, newIndex){
5414 var c = this.config[oldIndex];
5415 this.config.splice(oldIndex, 1);
5416 this.config.splice(newIndex, 0, c);
5417 this.dataMap = null;
5418 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5421 isLocked : function(colIndex){
5422 return this.config[colIndex].locked === true;
5425 setLocked : function(colIndex, value, suppressEvent){
5426 if(this.isLocked(colIndex) == value){
5429 this.config[colIndex].locked = value;
5431 this.fireEvent("columnlockchange", this, colIndex, value);
5435 getTotalLockedWidth : function(){
5437 for(var i = 0; i < this.config.length; i++){
5438 if(this.isLocked(i) && !this.isHidden(i)){
5439 this.totalWidth += this.getColumnWidth(i);
5445 getLockedCount : function(){
5446 for(var i = 0, len = this.config.length; i < len; i++){
5447 if(!this.isLocked(i)){
5452 return this.config.length;
5456 * Returns the number of columns.
5459 getColumnCount : function(visibleOnly){
5460 if(visibleOnly === true){
5462 for(var i = 0, len = this.config.length; i < len; i++){
5463 if(!this.isHidden(i)){
5469 return this.config.length;
5473 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5474 * @param {Function} fn
5475 * @param {Object} scope (optional)
5476 * @return {Array} result
5478 getColumnsBy : function(fn, scope){
5480 for(var i = 0, len = this.config.length; i < len; i++){
5481 var c = this.config[i];
5482 if(fn.call(scope||this, c, i) === true){
5490 * Returns true if the specified column is sortable.
5491 * @param {Number} col The column index
5494 isSortable : function(col){
5495 if(typeof this.config[col].sortable == "undefined"){
5496 return this.defaultSortable;
5498 return this.config[col].sortable;
5502 * Returns the rendering (formatting) function defined for the column.
5503 * @param {Number} col The column index.
5504 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5506 getRenderer : function(col){
5507 if(!this.config[col].renderer){
5508 return Roo.grid.ColumnModel.defaultRenderer;
5510 return this.config[col].renderer;
5514 * Sets the rendering (formatting) function for a column.
5515 * @param {Number} col The column index
5516 * @param {Function} fn The function to use to process the cell's raw data
5517 * to return HTML markup for the grid view. The render function is called with
5518 * the following parameters:<ul>
5519 * <li>Data value.</li>
5520 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5521 * <li>css A CSS style string to apply to the table cell.</li>
5522 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5523 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5524 * <li>Row index</li>
5525 * <li>Column index</li>
5526 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5528 setRenderer : function(col, fn){
5529 this.config[col].renderer = fn;
5533 * Returns the width for the specified column.
5534 * @param {Number} col The column index
5537 getColumnWidth : function(col){
5538 return this.config[col].width * 1 || this.defaultWidth;
5542 * Sets the width for a column.
5543 * @param {Number} col The column index
5544 * @param {Number} width The new width
5546 setColumnWidth : function(col, width, suppressEvent){
5547 this.config[col].width = width;
5548 this.totalWidth = null;
5550 this.fireEvent("widthchange", this, col, width);
5555 * Returns the total width of all columns.
5556 * @param {Boolean} includeHidden True to include hidden column widths
5559 getTotalWidth : function(includeHidden){
5560 if(!this.totalWidth){
5561 this.totalWidth = 0;
5562 for(var i = 0, len = this.config.length; i < len; i++){
5563 if(includeHidden || !this.isHidden(i)){
5564 this.totalWidth += this.getColumnWidth(i);
5568 return this.totalWidth;
5572 * Returns the header for the specified column.
5573 * @param {Number} col The column index
5576 getColumnHeader : function(col){
5577 return this.config[col].header;
5581 * Sets the header for a column.
5582 * @param {Number} col The column index
5583 * @param {String} header The new header
5585 setColumnHeader : function(col, header){
5586 this.config[col].header = header;
5587 this.fireEvent("headerchange", this, col, header);
5591 * Returns the tooltip for the specified column.
5592 * @param {Number} col The column index
5595 getColumnTooltip : function(col){
5596 return this.config[col].tooltip;
5599 * Sets the tooltip for a column.
5600 * @param {Number} col The column index
5601 * @param {String} tooltip The new tooltip
5603 setColumnTooltip : function(col, tooltip){
5604 this.config[col].tooltip = tooltip;
5608 * Returns the dataIndex for the specified column.
5609 * @param {Number} col The column index
5612 getDataIndex : function(col){
5613 return this.config[col].dataIndex;
5617 * Sets the dataIndex for a column.
5618 * @param {Number} col The column index
5619 * @param {Number} dataIndex The new dataIndex
5621 setDataIndex : function(col, dataIndex){
5622 this.config[col].dataIndex = dataIndex;
5628 * Returns true if the cell is editable.
5629 * @param {Number} colIndex The column index
5630 * @param {Number} rowIndex The row index - this is nto actually used..?
5633 isCellEditable : function(colIndex, rowIndex){
5634 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5638 * Returns the editor defined for the cell/column.
5639 * return false or null to disable editing.
5640 * @param {Number} colIndex The column index
5641 * @param {Number} rowIndex The row index
5644 getCellEditor : function(colIndex, rowIndex){
5645 return this.config[colIndex].editor;
5649 * Sets if a column is editable.
5650 * @param {Number} col The column index
5651 * @param {Boolean} editable True if the column is editable
5653 setEditable : function(col, editable){
5654 this.config[col].editable = editable;
5659 * Returns true if the column is hidden.
5660 * @param {Number} colIndex The column index
5663 isHidden : function(colIndex){
5664 return this.config[colIndex].hidden;
5669 * Returns true if the column width cannot be changed
5671 isFixed : function(colIndex){
5672 return this.config[colIndex].fixed;
5676 * Returns true if the column can be resized
5679 isResizable : function(colIndex){
5680 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5683 * Sets if a column is hidden.
5684 * @param {Number} colIndex The column index
5685 * @param {Boolean} hidden True if the column is hidden
5687 setHidden : function(colIndex, hidden){
5688 this.config[colIndex].hidden = hidden;
5689 this.totalWidth = null;
5690 this.fireEvent("hiddenchange", this, colIndex, hidden);
5694 * Sets the editor for a column.
5695 * @param {Number} col The column index
5696 * @param {Object} editor The editor object
5698 setEditor : function(col, editor){
5699 this.config[col].editor = editor;
5703 Roo.grid.ColumnModel.defaultRenderer = function(value)
5705 if(typeof value == "object") {
5708 if(typeof value == "string" && value.length < 1){
5712 return String.format("{0}", value);
5715 // Alias for backwards compatibility
5716 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5719 * Ext JS Library 1.1.1
5720 * Copyright(c) 2006-2007, Ext JS, LLC.
5722 * Originally Released Under LGPL - original licence link has changed is not relivant.
5725 * <script type="text/javascript">
5729 * @class Roo.LoadMask
5730 * A simple utility class for generically masking elements while loading data. If the element being masked has
5731 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5732 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5733 * element's UpdateManager load indicator and will be destroyed after the initial load.
5735 * Create a new LoadMask
5736 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5737 * @param {Object} config The config object
5739 Roo.LoadMask = function(el, config){
5740 this.el = Roo.get(el);
5741 Roo.apply(this, config);
5743 this.store.on('beforeload', this.onBeforeLoad, this);
5744 this.store.on('load', this.onLoad, this);
5745 this.store.on('loadexception', this.onLoadException, this);
5746 this.removeMask = false;
5748 var um = this.el.getUpdateManager();
5749 um.showLoadIndicator = false; // disable the default indicator
5750 um.on('beforeupdate', this.onBeforeLoad, this);
5751 um.on('update', this.onLoad, this);
5752 um.on('failure', this.onLoad, this);
5753 this.removeMask = true;
5757 Roo.LoadMask.prototype = {
5759 * @cfg {Boolean} removeMask
5760 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5761 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5765 * The text to display in a centered loading message box (defaults to 'Loading...')
5769 * @cfg {String} msgCls
5770 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5772 msgCls : 'x-mask-loading',
5775 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5781 * Disables the mask to prevent it from being displayed
5783 disable : function(){
5784 this.disabled = true;
5788 * Enables the mask so that it can be displayed
5790 enable : function(){
5791 this.disabled = false;
5794 onLoadException : function()
5798 if (typeof(arguments[3]) != 'undefined') {
5799 Roo.MessageBox.alert("Error loading",arguments[3]);
5803 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5804 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5811 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5816 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5820 onBeforeLoad : function(){
5822 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5827 destroy : function(){
5829 this.store.un('beforeload', this.onBeforeLoad, this);
5830 this.store.un('load', this.onLoad, this);
5831 this.store.un('loadexception', this.onLoadException, this);
5833 var um = this.el.getUpdateManager();
5834 um.un('beforeupdate', this.onBeforeLoad, this);
5835 um.un('update', this.onLoad, this);
5836 um.un('failure', this.onLoad, this);
5847 * @class Roo.bootstrap.Table
5848 * @extends Roo.bootstrap.Component
5849 * Bootstrap Table class
5850 * @cfg {String} cls table class
5851 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5852 * @cfg {String} bgcolor Specifies the background color for a table
5853 * @cfg {Number} border Specifies whether the table cells should have borders or not
5854 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5855 * @cfg {Number} cellspacing Specifies the space between cells
5856 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5857 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5858 * @cfg {String} sortable Specifies that the table should be sortable
5859 * @cfg {String} summary Specifies a summary of the content of a table
5860 * @cfg {Number} width Specifies the width of a table
5861 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5863 * @cfg {boolean} striped Should the rows be alternative striped
5864 * @cfg {boolean} bordered Add borders to the table
5865 * @cfg {boolean} hover Add hover highlighting
5866 * @cfg {boolean} condensed Format condensed
5867 * @cfg {boolean} responsive Format condensed
5868 * @cfg {Boolean} loadMask (true|false) default false
5869 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5870 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5871 * @cfg {Boolean} rowSelection (true|false) default false
5872 * @cfg {Boolean} cellSelection (true|false) default false
5873 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5874 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5875 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5879 * Create a new Table
5880 * @param {Object} config The config object
5883 Roo.bootstrap.Table = function(config){
5884 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5889 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5890 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5891 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5892 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5894 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5896 this.sm.grid = this;
5897 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5898 this.sm = this.selModel;
5899 this.sm.xmodule = this.xmodule || false;
5902 if (this.cm && typeof(this.cm.config) == 'undefined') {
5903 this.colModel = new Roo.grid.ColumnModel(this.cm);
5904 this.cm = this.colModel;
5905 this.cm.xmodule = this.xmodule || false;
5908 this.store= Roo.factory(this.store, Roo.data);
5909 this.ds = this.store;
5910 this.ds.xmodule = this.xmodule || false;
5913 if (this.footer && this.store) {
5914 this.footer.dataSource = this.ds;
5915 this.footer = Roo.factory(this.footer);
5922 * Fires when a cell is clicked
5923 * @param {Roo.bootstrap.Table} this
5924 * @param {Roo.Element} el
5925 * @param {Number} rowIndex
5926 * @param {Number} columnIndex
5927 * @param {Roo.EventObject} e
5931 * @event celldblclick
5932 * Fires when a cell is double clicked
5933 * @param {Roo.bootstrap.Table} this
5934 * @param {Roo.Element} el
5935 * @param {Number} rowIndex
5936 * @param {Number} columnIndex
5937 * @param {Roo.EventObject} e
5939 "celldblclick" : true,
5942 * Fires when a row is clicked
5943 * @param {Roo.bootstrap.Table} this
5944 * @param {Roo.Element} el
5945 * @param {Number} rowIndex
5946 * @param {Roo.EventObject} e
5950 * @event rowdblclick
5951 * Fires when a row is double clicked
5952 * @param {Roo.bootstrap.Table} this
5953 * @param {Roo.Element} el
5954 * @param {Number} rowIndex
5955 * @param {Roo.EventObject} e
5957 "rowdblclick" : true,
5960 * Fires when a mouseover occur
5961 * @param {Roo.bootstrap.Table} this
5962 * @param {Roo.Element} el
5963 * @param {Number} rowIndex
5964 * @param {Number} columnIndex
5965 * @param {Roo.EventObject} e
5970 * Fires when a mouseout occur
5971 * @param {Roo.bootstrap.Table} this
5972 * @param {Roo.Element} el
5973 * @param {Number} rowIndex
5974 * @param {Number} columnIndex
5975 * @param {Roo.EventObject} e
5980 * Fires when a row is rendered, so you can change add a style to it.
5981 * @param {Roo.bootstrap.Table} this
5982 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5986 * @event rowsrendered
5987 * Fires when all the rows have been rendered
5988 * @param {Roo.bootstrap.Table} this
5990 'rowsrendered' : true,
5992 * @event contextmenu
5993 * The raw contextmenu event for the entire grid.
5994 * @param {Roo.EventObject} e
5996 "contextmenu" : true,
5998 * @event rowcontextmenu
5999 * Fires when a row is right clicked
6000 * @param {Roo.bootstrap.Table} this
6001 * @param {Number} rowIndex
6002 * @param {Roo.EventObject} e
6004 "rowcontextmenu" : true,
6006 * @event cellcontextmenu
6007 * Fires when a cell is right clicked
6008 * @param {Roo.bootstrap.Table} this
6009 * @param {Number} rowIndex
6010 * @param {Number} cellIndex
6011 * @param {Roo.EventObject} e
6013 "cellcontextmenu" : true,
6015 * @event headercontextmenu
6016 * Fires when a header is right clicked
6017 * @param {Roo.bootstrap.Table} this
6018 * @param {Number} columnIndex
6019 * @param {Roo.EventObject} e
6021 "headercontextmenu" : true
6025 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6051 rowSelection : false,
6052 cellSelection : false,
6055 // Roo.Element - the tbody
6057 // Roo.Element - thead element
6060 container: false, // used by gridpanel...
6066 getAutoCreate : function()
6068 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6075 if (this.scrollBody) {
6076 cfg.cls += ' table-body-fixed';
6079 cfg.cls += ' table-striped';
6083 cfg.cls += ' table-hover';
6085 if (this.bordered) {
6086 cfg.cls += ' table-bordered';
6088 if (this.condensed) {
6089 cfg.cls += ' table-condensed';
6091 if (this.responsive) {
6092 cfg.cls += ' table-responsive';
6096 cfg.cls+= ' ' +this.cls;
6099 // this lot should be simplifed...
6102 cfg.align=this.align;
6105 cfg.bgcolor=this.bgcolor;
6108 cfg.border=this.border;
6110 if (this.cellpadding) {
6111 cfg.cellpadding=this.cellpadding;
6113 if (this.cellspacing) {
6114 cfg.cellspacing=this.cellspacing;
6117 cfg.frame=this.frame;
6120 cfg.rules=this.rules;
6122 if (this.sortable) {
6123 cfg.sortable=this.sortable;
6126 cfg.summary=this.summary;
6129 cfg.width=this.width;
6132 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6135 if(this.store || this.cm){
6136 if(this.headerShow){
6137 cfg.cn.push(this.renderHeader());
6140 cfg.cn.push(this.renderBody());
6142 if(this.footerShow){
6143 cfg.cn.push(this.renderFooter());
6145 // where does this come from?
6146 //cfg.cls+= ' TableGrid';
6149 return { cn : [ cfg ] };
6152 initEvents : function()
6154 if(!this.store || !this.cm){
6157 if (this.selModel) {
6158 this.selModel.initEvents();
6162 //Roo.log('initEvents with ds!!!!');
6164 this.mainBody = this.el.select('tbody', true).first();
6165 this.mainHead = this.el.select('thead', true).first();
6172 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6173 e.on('click', _this.sort, _this);
6176 this.mainBody.on("click", this.onClick, this);
6177 this.mainBody.on("dblclick", this.onDblClick, this);
6179 // why is this done????? = it breaks dialogs??
6180 //this.parent().el.setStyle('position', 'relative');
6184 this.footer.parentId = this.id;
6185 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6188 this.el.select('tfoot tr td').first().addClass('hide');
6192 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6194 this.store.on('load', this.onLoad, this);
6195 this.store.on('beforeload', this.onBeforeLoad, this);
6196 this.store.on('update', this.onUpdate, this);
6197 this.store.on('add', this.onAdd, this);
6198 this.store.on("clear", this.clear, this);
6200 this.el.on("contextmenu", this.onContextMenu, this);
6202 this.mainBody.on('scroll', this.onBodyScroll, this);
6204 this.cm.on("headerchange", this.onHeaderChange, this);
6206 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6210 onContextMenu : function(e, t)
6212 this.processEvent("contextmenu", e);
6215 processEvent : function(name, e)
6217 if (name != 'touchstart' ) {
6218 this.fireEvent(name, e);
6221 var t = e.getTarget();
6223 var cell = Roo.get(t);
6229 if(cell.findParent('tfoot', false, true)){
6233 if(cell.findParent('thead', false, true)){
6235 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6236 cell = Roo.get(t).findParent('th', false, true);
6238 Roo.log("failed to find th in thead?");
6239 Roo.log(e.getTarget());
6244 var cellIndex = cell.dom.cellIndex;
6246 var ename = name == 'touchstart' ? 'click' : name;
6247 this.fireEvent("header" + ename, this, cellIndex, e);
6252 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6253 cell = Roo.get(t).findParent('td', false, true);
6255 Roo.log("failed to find th in tbody?");
6256 Roo.log(e.getTarget());
6261 var row = cell.findParent('tr', false, true);
6262 var cellIndex = cell.dom.cellIndex;
6263 var rowIndex = row.dom.rowIndex - 1;
6267 this.fireEvent("row" + name, this, rowIndex, e);
6271 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6277 onMouseover : function(e, el)
6279 var cell = Roo.get(el);
6285 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6286 cell = cell.findParent('td', false, true);
6289 var row = cell.findParent('tr', false, true);
6290 var cellIndex = cell.dom.cellIndex;
6291 var rowIndex = row.dom.rowIndex - 1; // start from 0
6293 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6297 onMouseout : function(e, el)
6299 var cell = Roo.get(el);
6305 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6306 cell = cell.findParent('td', false, true);
6309 var row = cell.findParent('tr', false, true);
6310 var cellIndex = cell.dom.cellIndex;
6311 var rowIndex = row.dom.rowIndex - 1; // start from 0
6313 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6317 onClick : function(e, el)
6319 var cell = Roo.get(el);
6321 if(!cell || (!this.cellSelection && !this.rowSelection)){
6325 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6326 cell = cell.findParent('td', false, true);
6329 if(!cell || typeof(cell) == 'undefined'){
6333 var row = cell.findParent('tr', false, true);
6335 if(!row || typeof(row) == 'undefined'){
6339 var cellIndex = cell.dom.cellIndex;
6340 var rowIndex = this.getRowIndex(row);
6342 // why??? - should these not be based on SelectionModel?
6343 if(this.cellSelection){
6344 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6347 if(this.rowSelection){
6348 this.fireEvent('rowclick', this, row, rowIndex, e);
6354 onDblClick : function(e,el)
6356 var cell = Roo.get(el);
6358 if(!cell || (!this.cellSelection && !this.rowSelection)){
6362 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6363 cell = cell.findParent('td', false, true);
6366 if(!cell || typeof(cell) == 'undefined'){
6370 var row = cell.findParent('tr', false, true);
6372 if(!row || typeof(row) == 'undefined'){
6376 var cellIndex = cell.dom.cellIndex;
6377 var rowIndex = this.getRowIndex(row);
6379 if(this.cellSelection){
6380 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6383 if(this.rowSelection){
6384 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6388 sort : function(e,el)
6390 var col = Roo.get(el);
6392 if(!col.hasClass('sortable')){
6396 var sort = col.attr('sort');
6399 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6403 this.store.sortInfo = {field : sort, direction : dir};
6406 Roo.log("calling footer first");
6407 this.footer.onClick('first');
6410 this.store.load({ params : { start : 0 } });
6414 renderHeader : function()
6422 this.totalWidth = 0;
6424 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6426 var config = cm.config[i];
6430 cls : 'x-hcol-' + i,
6432 html: cm.getColumnHeader(i)
6437 if(typeof(config.sortable) != 'undefined' && config.sortable){
6439 c.html = '<i class="glyphicon"></i>' + c.html;
6442 if(typeof(config.lgHeader) != 'undefined'){
6443 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6446 if(typeof(config.mdHeader) != 'undefined'){
6447 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6450 if(typeof(config.smHeader) != 'undefined'){
6451 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6454 if(typeof(config.xsHeader) != 'undefined'){
6455 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6462 if(typeof(config.tooltip) != 'undefined'){
6463 c.tooltip = config.tooltip;
6466 if(typeof(config.colspan) != 'undefined'){
6467 c.colspan = config.colspan;
6470 if(typeof(config.hidden) != 'undefined' && config.hidden){
6471 c.style += ' display:none;';
6474 if(typeof(config.dataIndex) != 'undefined'){
6475 c.sort = config.dataIndex;
6480 if(typeof(config.align) != 'undefined' && config.align.length){
6481 c.style += ' text-align:' + config.align + ';';
6484 if(typeof(config.width) != 'undefined'){
6485 c.style += ' width:' + config.width + 'px;';
6486 this.totalWidth += config.width;
6488 this.totalWidth += 100; // assume minimum of 100 per column?
6491 if(typeof(config.cls) != 'undefined'){
6492 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6495 ['xs','sm','md','lg'].map(function(size){
6497 if(typeof(config[size]) == 'undefined'){
6501 if (!config[size]) { // 0 = hidden
6502 c.cls += ' hidden-' + size;
6506 c.cls += ' col-' + size + '-' + config[size];
6516 renderBody : function()
6526 colspan : this.cm.getColumnCount()
6536 renderFooter : function()
6546 colspan : this.cm.getColumnCount()
6560 // Roo.log('ds onload');
6565 var ds = this.store;
6567 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6568 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6569 if (_this.store.sortInfo) {
6571 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6572 e.select('i', true).addClass(['glyphicon-arrow-up']);
6575 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6576 e.select('i', true).addClass(['glyphicon-arrow-down']);
6581 var tbody = this.mainBody;
6583 if(ds.getCount() > 0){
6584 ds.data.each(function(d,rowIndex){
6585 var row = this.renderRow(cm, ds, rowIndex);
6587 tbody.createChild(row);
6591 if(row.cellObjects.length){
6592 Roo.each(row.cellObjects, function(r){
6593 _this.renderCellObject(r);
6600 Roo.each(this.el.select('tbody td', true).elements, function(e){
6601 e.on('mouseover', _this.onMouseover, _this);
6604 Roo.each(this.el.select('tbody td', true).elements, function(e){
6605 e.on('mouseout', _this.onMouseout, _this);
6607 this.fireEvent('rowsrendered', this);
6608 //if(this.loadMask){
6609 // this.maskEl.hide();
6616 onUpdate : function(ds,record)
6618 this.refreshRow(record);
6622 onRemove : function(ds, record, index, isUpdate){
6623 if(isUpdate !== true){
6624 this.fireEvent("beforerowremoved", this, index, record);
6626 var bt = this.mainBody.dom;
6628 var rows = this.el.select('tbody > tr', true).elements;
6630 if(typeof(rows[index]) != 'undefined'){
6631 bt.removeChild(rows[index].dom);
6634 // if(bt.rows[index]){
6635 // bt.removeChild(bt.rows[index]);
6638 if(isUpdate !== true){
6639 //this.stripeRows(index);
6640 //this.syncRowHeights(index, index);
6642 this.fireEvent("rowremoved", this, index, record);
6646 onAdd : function(ds, records, rowIndex)
6648 //Roo.log('on Add called');
6649 // - note this does not handle multiple adding very well..
6650 var bt = this.mainBody.dom;
6651 for (var i =0 ; i < records.length;i++) {
6652 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6653 //Roo.log(records[i]);
6654 //Roo.log(this.store.getAt(rowIndex+i));
6655 this.insertRow(this.store, rowIndex + i, false);
6662 refreshRow : function(record){
6663 var ds = this.store, index;
6664 if(typeof record == 'number'){
6666 record = ds.getAt(index);
6668 index = ds.indexOf(record);
6670 this.insertRow(ds, index, true);
6672 this.onRemove(ds, record, index+1, true);
6674 //this.syncRowHeights(index, index);
6676 this.fireEvent("rowupdated", this, index, record);
6679 insertRow : function(dm, rowIndex, isUpdate){
6682 this.fireEvent("beforerowsinserted", this, rowIndex);
6684 //var s = this.getScrollState();
6685 var row = this.renderRow(this.cm, this.store, rowIndex);
6686 // insert before rowIndex..
6687 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6691 if(row.cellObjects.length){
6692 Roo.each(row.cellObjects, function(r){
6693 _this.renderCellObject(r);
6698 this.fireEvent("rowsinserted", this, rowIndex);
6699 //this.syncRowHeights(firstRow, lastRow);
6700 //this.stripeRows(firstRow);
6707 getRowDom : function(rowIndex)
6709 var rows = this.el.select('tbody > tr', true).elements;
6711 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6714 // returns the object tree for a tr..
6717 renderRow : function(cm, ds, rowIndex)
6719 var d = ds.getAt(rowIndex);
6723 cls : 'x-row-' + rowIndex,
6727 var cellObjects = [];
6729 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6730 var config = cm.config[i];
6732 var renderer = cm.getRenderer(i);
6736 if(typeof(renderer) !== 'undefined'){
6737 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6739 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6740 // and are rendered into the cells after the row is rendered - using the id for the element.
6742 if(typeof(value) === 'object'){
6752 rowIndex : rowIndex,
6757 this.fireEvent('rowclass', this, rowcfg);
6761 cls : rowcfg.rowClass + ' x-col-' + i,
6763 html: (typeof(value) === 'object') ? '' : value
6770 if(typeof(config.colspan) != 'undefined'){
6771 td.colspan = config.colspan;
6774 if(typeof(config.hidden) != 'undefined' && config.hidden){
6775 td.style += ' display:none;';
6778 if(typeof(config.align) != 'undefined' && config.align.length){
6779 td.style += ' text-align:' + config.align + ';';
6782 if(typeof(config.width) != 'undefined'){
6783 td.style += ' width:' + config.width + 'px;';
6786 if(typeof(config.cursor) != 'undefined'){
6787 td.style += ' cursor:' + config.cursor + ';';
6790 if(typeof(config.cls) != 'undefined'){
6791 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6794 ['xs','sm','md','lg'].map(function(size){
6796 if(typeof(config[size]) == 'undefined'){
6800 if (!config[size]) { // 0 = hidden
6801 td.cls += ' hidden-' + size;
6805 td.cls += ' col-' + size + '-' + config[size];
6813 row.cellObjects = cellObjects;
6821 onBeforeLoad : function()
6823 //Roo.log('ds onBeforeLoad');
6827 //if(this.loadMask){
6828 // this.maskEl.show();
6836 this.el.select('tbody', true).first().dom.innerHTML = '';
6839 * Show or hide a row.
6840 * @param {Number} rowIndex to show or hide
6841 * @param {Boolean} state hide
6843 setRowVisibility : function(rowIndex, state)
6845 var bt = this.mainBody.dom;
6847 var rows = this.el.select('tbody > tr', true).elements;
6849 if(typeof(rows[rowIndex]) == 'undefined'){
6852 rows[rowIndex].dom.style.display = state ? '' : 'none';
6856 getSelectionModel : function(){
6858 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6860 return this.selModel;
6863 * Render the Roo.bootstrap object from renderder
6865 renderCellObject : function(r)
6869 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6871 var t = r.cfg.render(r.container);
6874 Roo.each(r.cfg.cn, function(c){
6876 container: t.getChildContainer(),
6879 _this.renderCellObject(child);
6884 getRowIndex : function(row)
6888 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6899 * Returns the grid's underlying element = used by panel.Grid
6900 * @return {Element} The element
6902 getGridEl : function(){
6906 * Forces a resize - used by panel.Grid
6907 * @return {Element} The element
6909 autoSize : function()
6911 //var ctr = Roo.get(this.container.dom.parentElement);
6912 var ctr = Roo.get(this.el.dom);
6914 var thd = this.getGridEl().select('thead',true).first();
6915 var tbd = this.getGridEl().select('tbody', true).first();
6916 var tfd = this.getGridEl().select('tfoot', true).first();
6918 var cw = ctr.getWidth();
6922 tbd.setSize(ctr.getWidth(),
6923 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6925 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6928 cw = Math.max(cw, this.totalWidth);
6929 this.getGridEl().select('tr',true).setWidth(cw);
6930 // resize 'expandable coloumn?
6932 return; // we doe not have a view in this design..
6935 onBodyScroll: function()
6937 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6939 this.mainHead.setStyle({
6940 'position' : 'relative',
6941 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6947 var scrollHeight = this.mainBody.dom.scrollHeight;
6949 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6951 var height = this.mainBody.getHeight();
6953 if(scrollHeight - height == scrollTop) {
6955 var total = this.ds.getTotalCount();
6957 if(this.footer.cursor + this.footer.pageSize < total){
6959 this.footer.ds.load({
6961 start : this.footer.cursor + this.footer.pageSize,
6962 limit : this.footer.pageSize
6972 onHeaderChange : function()
6974 var header = this.renderHeader();
6975 var table = this.el.select('table', true).first();
6977 this.mainHead.remove();
6978 this.mainHead = table.createChild(header, this.mainBody, false);
6981 onHiddenChange : function(colModel, colIndex, hidden)
6983 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6984 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6986 this.CSS.updateRule(thSelector, "display", "");
6987 this.CSS.updateRule(tdSelector, "display", "");
6990 this.CSS.updateRule(thSelector, "display", "none");
6991 this.CSS.updateRule(tdSelector, "display", "none");
6994 this.onHeaderChange();
7011 * @class Roo.bootstrap.TableCell
7012 * @extends Roo.bootstrap.Component
7013 * Bootstrap TableCell class
7014 * @cfg {String} html cell contain text
7015 * @cfg {String} cls cell class
7016 * @cfg {String} tag cell tag (td|th) default td
7017 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7018 * @cfg {String} align Aligns the content in a cell
7019 * @cfg {String} axis Categorizes cells
7020 * @cfg {String} bgcolor Specifies the background color of a cell
7021 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7022 * @cfg {Number} colspan Specifies the number of columns a cell should span
7023 * @cfg {String} headers Specifies one or more header cells a cell is related to
7024 * @cfg {Number} height Sets the height of a cell
7025 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7026 * @cfg {Number} rowspan Sets the number of rows a cell should span
7027 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7028 * @cfg {String} valign Vertical aligns the content in a cell
7029 * @cfg {Number} width Specifies the width of a cell
7032 * Create a new TableCell
7033 * @param {Object} config The config object
7036 Roo.bootstrap.TableCell = function(config){
7037 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7040 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7060 getAutoCreate : function(){
7061 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7081 cfg.align=this.align
7087 cfg.bgcolor=this.bgcolor
7090 cfg.charoff=this.charoff
7093 cfg.colspan=this.colspan
7096 cfg.headers=this.headers
7099 cfg.height=this.height
7102 cfg.nowrap=this.nowrap
7105 cfg.rowspan=this.rowspan
7108 cfg.scope=this.scope
7111 cfg.valign=this.valign
7114 cfg.width=this.width
7133 * @class Roo.bootstrap.TableRow
7134 * @extends Roo.bootstrap.Component
7135 * Bootstrap TableRow class
7136 * @cfg {String} cls row class
7137 * @cfg {String} align Aligns the content in a table row
7138 * @cfg {String} bgcolor Specifies a background color for a table row
7139 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7140 * @cfg {String} valign Vertical aligns the content in a table row
7143 * Create a new TableRow
7144 * @param {Object} config The config object
7147 Roo.bootstrap.TableRow = function(config){
7148 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7151 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7159 getAutoCreate : function(){
7160 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7170 cfg.align = this.align;
7173 cfg.bgcolor = this.bgcolor;
7176 cfg.charoff = this.charoff;
7179 cfg.valign = this.valign;
7197 * @class Roo.bootstrap.TableBody
7198 * @extends Roo.bootstrap.Component
7199 * Bootstrap TableBody class
7200 * @cfg {String} cls element class
7201 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7202 * @cfg {String} align Aligns the content inside the element
7203 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7204 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7207 * Create a new TableBody
7208 * @param {Object} config The config object
7211 Roo.bootstrap.TableBody = function(config){
7212 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7215 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7223 getAutoCreate : function(){
7224 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7238 cfg.align = this.align;
7241 cfg.charoff = this.charoff;
7244 cfg.valign = this.valign;
7251 // initEvents : function()
7258 // this.store = Roo.factory(this.store, Roo.data);
7259 // this.store.on('load', this.onLoad, this);
7261 // this.store.load();
7265 // onLoad: function ()
7267 // this.fireEvent('load', this);
7277 * Ext JS Library 1.1.1
7278 * Copyright(c) 2006-2007, Ext JS, LLC.
7280 * Originally Released Under LGPL - original licence link has changed is not relivant.
7283 * <script type="text/javascript">
7286 // as we use this in bootstrap.
7287 Roo.namespace('Roo.form');
7289 * @class Roo.form.Action
7290 * Internal Class used to handle form actions
7292 * @param {Roo.form.BasicForm} el The form element or its id
7293 * @param {Object} config Configuration options
7298 // define the action interface
7299 Roo.form.Action = function(form, options){
7301 this.options = options || {};
7304 * Client Validation Failed
7307 Roo.form.Action.CLIENT_INVALID = 'client';
7309 * Server Validation Failed
7312 Roo.form.Action.SERVER_INVALID = 'server';
7314 * Connect to Server Failed
7317 Roo.form.Action.CONNECT_FAILURE = 'connect';
7319 * Reading Data from Server Failed
7322 Roo.form.Action.LOAD_FAILURE = 'load';
7324 Roo.form.Action.prototype = {
7326 failureType : undefined,
7327 response : undefined,
7331 run : function(options){
7336 success : function(response){
7341 handleResponse : function(response){
7345 // default connection failure
7346 failure : function(response){
7348 this.response = response;
7349 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7350 this.form.afterAction(this, false);
7353 processResponse : function(response){
7354 this.response = response;
7355 if(!response.responseText){
7358 this.result = this.handleResponse(response);
7362 // utility functions used internally
7363 getUrl : function(appendParams){
7364 var url = this.options.url || this.form.url || this.form.el.dom.action;
7366 var p = this.getParams();
7368 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7374 getMethod : function(){
7375 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7378 getParams : function(){
7379 var bp = this.form.baseParams;
7380 var p = this.options.params;
7382 if(typeof p == "object"){
7383 p = Roo.urlEncode(Roo.applyIf(p, bp));
7384 }else if(typeof p == 'string' && bp){
7385 p += '&' + Roo.urlEncode(bp);
7388 p = Roo.urlEncode(bp);
7393 createCallback : function(){
7395 success: this.success,
7396 failure: this.failure,
7398 timeout: (this.form.timeout*1000),
7399 upload: this.form.fileUpload ? this.success : undefined
7404 Roo.form.Action.Submit = function(form, options){
7405 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7408 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7411 haveProgress : false,
7412 uploadComplete : false,
7414 // uploadProgress indicator.
7415 uploadProgress : function()
7417 if (!this.form.progressUrl) {
7421 if (!this.haveProgress) {
7422 Roo.MessageBox.progress("Uploading", "Uploading");
7424 if (this.uploadComplete) {
7425 Roo.MessageBox.hide();
7429 this.haveProgress = true;
7431 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7433 var c = new Roo.data.Connection();
7435 url : this.form.progressUrl,
7440 success : function(req){
7441 //console.log(data);
7445 rdata = Roo.decode(req.responseText)
7447 Roo.log("Invalid data from server..");
7451 if (!rdata || !rdata.success) {
7453 Roo.MessageBox.alert(Roo.encode(rdata));
7456 var data = rdata.data;
7458 if (this.uploadComplete) {
7459 Roo.MessageBox.hide();
7464 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7465 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7468 this.uploadProgress.defer(2000,this);
7471 failure: function(data) {
7472 Roo.log('progress url failed ');
7483 // run get Values on the form, so it syncs any secondary forms.
7484 this.form.getValues();
7486 var o = this.options;
7487 var method = this.getMethod();
7488 var isPost = method == 'POST';
7489 if(o.clientValidation === false || this.form.isValid()){
7491 if (this.form.progressUrl) {
7492 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7493 (new Date() * 1) + '' + Math.random());
7498 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7499 form:this.form.el.dom,
7500 url:this.getUrl(!isPost),
7502 params:isPost ? this.getParams() : null,
7503 isUpload: this.form.fileUpload
7506 this.uploadProgress();
7508 }else if (o.clientValidation !== false){ // client validation failed
7509 this.failureType = Roo.form.Action.CLIENT_INVALID;
7510 this.form.afterAction(this, false);
7514 success : function(response)
7516 this.uploadComplete= true;
7517 if (this.haveProgress) {
7518 Roo.MessageBox.hide();
7522 var result = this.processResponse(response);
7523 if(result === true || result.success){
7524 this.form.afterAction(this, true);
7528 this.form.markInvalid(result.errors);
7529 this.failureType = Roo.form.Action.SERVER_INVALID;
7531 this.form.afterAction(this, false);
7533 failure : function(response)
7535 this.uploadComplete= true;
7536 if (this.haveProgress) {
7537 Roo.MessageBox.hide();
7540 this.response = response;
7541 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7542 this.form.afterAction(this, false);
7545 handleResponse : function(response){
7546 if(this.form.errorReader){
7547 var rs = this.form.errorReader.read(response);
7550 for(var i = 0, len = rs.records.length; i < len; i++) {
7551 var r = rs.records[i];
7555 if(errors.length < 1){
7559 success : rs.success,
7565 ret = Roo.decode(response.responseText);
7569 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7579 Roo.form.Action.Load = function(form, options){
7580 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7581 this.reader = this.form.reader;
7584 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7589 Roo.Ajax.request(Roo.apply(
7590 this.createCallback(), {
7591 method:this.getMethod(),
7592 url:this.getUrl(false),
7593 params:this.getParams()
7597 success : function(response){
7599 var result = this.processResponse(response);
7600 if(result === true || !result.success || !result.data){
7601 this.failureType = Roo.form.Action.LOAD_FAILURE;
7602 this.form.afterAction(this, false);
7605 this.form.clearInvalid();
7606 this.form.setValues(result.data);
7607 this.form.afterAction(this, true);
7610 handleResponse : function(response){
7611 if(this.form.reader){
7612 var rs = this.form.reader.read(response);
7613 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7615 success : rs.success,
7619 return Roo.decode(response.responseText);
7623 Roo.form.Action.ACTION_TYPES = {
7624 'load' : Roo.form.Action.Load,
7625 'submit' : Roo.form.Action.Submit
7634 * @class Roo.bootstrap.Form
7635 * @extends Roo.bootstrap.Component
7636 * Bootstrap Form class
7637 * @cfg {String} method GET | POST (default POST)
7638 * @cfg {String} labelAlign top | left (default top)
7639 * @cfg {String} align left | right - for navbars
7640 * @cfg {Boolean} loadMask load mask when submit (default true)
7645 * @param {Object} config The config object
7649 Roo.bootstrap.Form = function(config){
7651 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7653 Roo.bootstrap.Form.popover.apply();
7657 * @event clientvalidation
7658 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7659 * @param {Form} this
7660 * @param {Boolean} valid true if the form has passed client-side validation
7662 clientvalidation: true,
7664 * @event beforeaction
7665 * Fires before any action is performed. Return false to cancel the action.
7666 * @param {Form} this
7667 * @param {Action} action The action to be performed
7671 * @event actionfailed
7672 * Fires when an action fails.
7673 * @param {Form} this
7674 * @param {Action} action The action that failed
7676 actionfailed : true,
7678 * @event actioncomplete
7679 * Fires when an action is completed.
7680 * @param {Form} this
7681 * @param {Action} action The action that completed
7683 actioncomplete : true
7687 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7690 * @cfg {String} method
7691 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7696 * The URL to use for form actions if one isn't supplied in the action options.
7699 * @cfg {Boolean} fileUpload
7700 * Set to true if this form is a file upload.
7704 * @cfg {Object} baseParams
7705 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7709 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7713 * @cfg {Sting} align (left|right) for navbar forms
7718 activeAction : null,
7721 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7722 * element by passing it or its id or mask the form itself by passing in true.
7725 waitMsgTarget : false,
7730 * @cfg {Boolean} errorMask (true|false) default false
7735 * @cfg {Number} maskOffset Default 100
7740 * @cfg {Boolean} maskBody
7744 getAutoCreate : function(){
7748 method : this.method || 'POST',
7749 id : this.id || Roo.id(),
7752 if (this.parent().xtype.match(/^Nav/)) {
7753 cfg.cls = 'navbar-form navbar-' + this.align;
7757 if (this.labelAlign == 'left' ) {
7758 cfg.cls += ' form-horizontal';
7764 initEvents : function()
7766 this.el.on('submit', this.onSubmit, this);
7767 // this was added as random key presses on the form where triggering form submit.
7768 this.el.on('keypress', function(e) {
7769 if (e.getCharCode() != 13) {
7772 // we might need to allow it for textareas.. and some other items.
7773 // check e.getTarget().
7775 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7779 Roo.log("keypress blocked");
7787 onSubmit : function(e){
7792 * Returns true if client-side validation on the form is successful.
7795 isValid : function(){
7796 var items = this.getItems();
7800 items.each(function(f){
7807 if(!target && f.el.isVisible(true)){
7813 if(this.errorMask && !valid){
7814 Roo.bootstrap.Form.popover.mask(this, target);
7821 * Returns true if any fields in this form have changed since their original load.
7824 isDirty : function(){
7826 var items = this.getItems();
7827 items.each(function(f){
7837 * Performs a predefined action (submit or load) or custom actions you define on this form.
7838 * @param {String} actionName The name of the action type
7839 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7840 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7841 * accept other config options):
7843 Property Type Description
7844 ---------------- --------------- ----------------------------------------------------------------------------------
7845 url String The url for the action (defaults to the form's url)
7846 method String The form method to use (defaults to the form's method, or POST if not defined)
7847 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7848 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7849 validate the form on the client (defaults to false)
7851 * @return {BasicForm} this
7853 doAction : function(action, options){
7854 if(typeof action == 'string'){
7855 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7857 if(this.fireEvent('beforeaction', this, action) !== false){
7858 this.beforeAction(action);
7859 action.run.defer(100, action);
7865 beforeAction : function(action){
7866 var o = action.options;
7871 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7873 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7876 // not really supported yet.. ??
7878 //if(this.waitMsgTarget === true){
7879 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7880 //}else if(this.waitMsgTarget){
7881 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7882 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7884 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7890 afterAction : function(action, success){
7891 this.activeAction = null;
7892 var o = action.options;
7897 Roo.get(document.body).unmask();
7903 //if(this.waitMsgTarget === true){
7904 // this.el.unmask();
7905 //}else if(this.waitMsgTarget){
7906 // this.waitMsgTarget.unmask();
7908 // Roo.MessageBox.updateProgress(1);
7909 // Roo.MessageBox.hide();
7916 Roo.callback(o.success, o.scope, [this, action]);
7917 this.fireEvent('actioncomplete', this, action);
7921 // failure condition..
7922 // we have a scenario where updates need confirming.
7923 // eg. if a locking scenario exists..
7924 // we look for { errors : { needs_confirm : true }} in the response.
7926 (typeof(action.result) != 'undefined') &&
7927 (typeof(action.result.errors) != 'undefined') &&
7928 (typeof(action.result.errors.needs_confirm) != 'undefined')
7931 Roo.log("not supported yet");
7934 Roo.MessageBox.confirm(
7935 "Change requires confirmation",
7936 action.result.errorMsg,
7941 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7951 Roo.callback(o.failure, o.scope, [this, action]);
7952 // show an error message if no failed handler is set..
7953 if (!this.hasListener('actionfailed')) {
7954 Roo.log("need to add dialog support");
7956 Roo.MessageBox.alert("Error",
7957 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7958 action.result.errorMsg :
7959 "Saving Failed, please check your entries or try again"
7964 this.fireEvent('actionfailed', this, action);
7969 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7970 * @param {String} id The value to search for
7973 findField : function(id){
7974 var items = this.getItems();
7975 var field = items.get(id);
7977 items.each(function(f){
7978 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7985 return field || null;
7988 * Mark fields in this form invalid in bulk.
7989 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7990 * @return {BasicForm} this
7992 markInvalid : function(errors){
7993 if(errors instanceof Array){
7994 for(var i = 0, len = errors.length; i < len; i++){
7995 var fieldError = errors[i];
7996 var f = this.findField(fieldError.id);
7998 f.markInvalid(fieldError.msg);
8004 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8005 field.markInvalid(errors[id]);
8009 //Roo.each(this.childForms || [], function (f) {
8010 // f.markInvalid(errors);
8017 * Set values for fields in this form in bulk.
8018 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8019 * @return {BasicForm} this
8021 setValues : function(values){
8022 if(values instanceof Array){ // array of objects
8023 for(var i = 0, len = values.length; i < len; i++){
8025 var f = this.findField(v.id);
8027 f.setValue(v.value);
8028 if(this.trackResetOnLoad){
8029 f.originalValue = f.getValue();
8033 }else{ // object hash
8036 if(typeof values[id] != 'function' && (field = this.findField(id))){
8038 if (field.setFromData &&
8040 field.displayField &&
8041 // combos' with local stores can
8042 // be queried via setValue()
8043 // to set their value..
8044 (field.store && !field.store.isLocal)
8048 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8049 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8050 field.setFromData(sd);
8052 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8054 field.setFromData(values);
8057 field.setValue(values[id]);
8061 if(this.trackResetOnLoad){
8062 field.originalValue = field.getValue();
8068 //Roo.each(this.childForms || [], function (f) {
8069 // f.setValues(values);
8076 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8077 * they are returned as an array.
8078 * @param {Boolean} asString
8081 getValues : function(asString){
8082 //if (this.childForms) {
8083 // copy values from the child forms
8084 // Roo.each(this.childForms, function (f) {
8085 // this.setValues(f.getValues());
8091 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8092 if(asString === true){
8095 return Roo.urlDecode(fs);
8099 * Returns the fields in this form as an object with key/value pairs.
8100 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8103 getFieldValues : function(with_hidden)
8105 var items = this.getItems();
8107 items.each(function(f){
8113 var v = f.getValue();
8115 if (f.inputType =='radio') {
8116 if (typeof(ret[f.getName()]) == 'undefined') {
8117 ret[f.getName()] = ''; // empty..
8120 if (!f.el.dom.checked) {
8128 if(f.xtype == 'MoneyField'){
8129 ret[f.currencyName] = f.getCurrency();
8132 // not sure if this supported any more..
8133 if ((typeof(v) == 'object') && f.getRawValue) {
8134 v = f.getRawValue() ; // dates..
8136 // combo boxes where name != hiddenName...
8137 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8138 ret[f.name] = f.getRawValue();
8140 ret[f.getName()] = v;
8147 * Clears all invalid messages in this form.
8148 * @return {BasicForm} this
8150 clearInvalid : function(){
8151 var items = this.getItems();
8153 items.each(function(f){
8162 * @return {BasicForm} this
8165 var items = this.getItems();
8166 items.each(function(f){
8170 Roo.each(this.childForms || [], function (f) {
8178 getItems : function()
8180 var r=new Roo.util.MixedCollection(false, function(o){
8181 return o.id || (o.id = Roo.id());
8183 var iter = function(el) {
8190 Roo.each(el.items,function(e) {
8199 hideFields : function(items)
8201 Roo.each(items, function(i){
8203 var f = this.findField(i);
8209 if(f.xtype == 'DateField'){
8210 f.setVisible(false);
8219 showFields : function(items)
8221 Roo.each(items, function(i){
8223 var f = this.findField(i);
8229 if(f.xtype == 'DateField'){
8241 Roo.apply(Roo.bootstrap.Form, {
8268 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8269 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8270 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8271 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8274 this.maskEl.top.enableDisplayMode("block");
8275 this.maskEl.left.enableDisplayMode("block");
8276 this.maskEl.bottom.enableDisplayMode("block");
8277 this.maskEl.right.enableDisplayMode("block");
8279 this.toolTip = new Roo.bootstrap.Tooltip({
8280 cls : 'roo-form-error-popover',
8282 'left' : ['r-l', [-2,0], 'right'],
8283 'right' : ['l-r', [2,0], 'left'],
8284 'bottom' : ['tl-bl', [0,2], 'top'],
8285 'top' : [ 'bl-tl', [0,-2], 'bottom']
8289 this.toolTip.render(Roo.get(document.body));
8291 this.toolTip.el.enableDisplayMode("block");
8293 Roo.get(document.body).on('click', function(){
8297 Roo.get(document.body).on('touchstart', function(){
8301 this.isApplied = true
8304 mask : function(form, target)
8308 this.target = target;
8310 if(!this.form.errorMask || !target.el){
8314 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8316 Roo.log(scrollable);
8318 var ot = this.target.el.calcOffsetsTo(scrollable);
8320 var scrollTo = ot[1] - this.form.maskOffset;
8322 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8324 scrollable.scrollTo('top', scrollTo);
8326 var box = this.target.el.getBox();
8328 var zIndex = Roo.bootstrap.Modal.zIndex++;
8331 this.maskEl.top.setStyle('position', 'absolute');
8332 this.maskEl.top.setStyle('z-index', zIndex);
8333 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8334 this.maskEl.top.setLeft(0);
8335 this.maskEl.top.setTop(0);
8336 this.maskEl.top.show();
8338 this.maskEl.left.setStyle('position', 'absolute');
8339 this.maskEl.left.setStyle('z-index', zIndex);
8340 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8341 this.maskEl.left.setLeft(0);
8342 this.maskEl.left.setTop(box.y - this.padding);
8343 this.maskEl.left.show();
8345 this.maskEl.bottom.setStyle('position', 'absolute');
8346 this.maskEl.bottom.setStyle('z-index', zIndex);
8347 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8348 this.maskEl.bottom.setLeft(0);
8349 this.maskEl.bottom.setTop(box.bottom + this.padding);
8350 this.maskEl.bottom.show();
8352 this.maskEl.right.setStyle('position', 'absolute');
8353 this.maskEl.right.setStyle('z-index', zIndex);
8354 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8355 this.maskEl.right.setLeft(box.right + this.padding);
8356 this.maskEl.right.setTop(box.y - this.padding);
8357 this.maskEl.right.show();
8359 this.toolTip.bindEl = this.target.el;
8361 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8363 var tip = this.target.blankText;
8365 if(this.target.getValue() !== '' ) {
8367 if (this.target.invalidText.length) {
8368 tip = this.target.invalidText;
8369 } else if (this.target.regexText.length){
8370 tip = this.target.regexText;
8374 this.toolTip.show(tip);
8376 this.intervalID = window.setInterval(function() {
8377 Roo.bootstrap.Form.popover.unmask();
8380 window.onwheel = function(){ return false;};
8382 (function(){ this.isMasked = true; }).defer(500, this);
8388 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8392 this.maskEl.top.setStyle('position', 'absolute');
8393 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8394 this.maskEl.top.hide();
8396 this.maskEl.left.setStyle('position', 'absolute');
8397 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8398 this.maskEl.left.hide();
8400 this.maskEl.bottom.setStyle('position', 'absolute');
8401 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8402 this.maskEl.bottom.hide();
8404 this.maskEl.right.setStyle('position', 'absolute');
8405 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8406 this.maskEl.right.hide();
8408 this.toolTip.hide();
8410 this.toolTip.el.hide();
8412 window.onwheel = function(){ return true;};
8414 if(this.intervalID){
8415 window.clearInterval(this.intervalID);
8416 this.intervalID = false;
8419 this.isMasked = false;
8429 * Ext JS Library 1.1.1
8430 * Copyright(c) 2006-2007, Ext JS, LLC.
8432 * Originally Released Under LGPL - original licence link has changed is not relivant.
8435 * <script type="text/javascript">
8438 * @class Roo.form.VTypes
8439 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8442 Roo.form.VTypes = function(){
8443 // closure these in so they are only created once.
8444 var alpha = /^[a-zA-Z_]+$/;
8445 var alphanum = /^[a-zA-Z0-9_]+$/;
8446 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8447 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8449 // All these messages and functions are configurable
8452 * The function used to validate email addresses
8453 * @param {String} value The email address
8455 'email' : function(v){
8456 return email.test(v);
8459 * The error text to display when the email validation function returns false
8462 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8464 * The keystroke filter mask to be applied on email input
8467 'emailMask' : /[a-z0-9_\.\-@]/i,
8470 * The function used to validate URLs
8471 * @param {String} value The URL
8473 'url' : function(v){
8477 * The error text to display when the url validation function returns false
8480 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8483 * The function used to validate alpha values
8484 * @param {String} value The value
8486 'alpha' : function(v){
8487 return alpha.test(v);
8490 * The error text to display when the alpha validation function returns false
8493 'alphaText' : 'This field should only contain letters and _',
8495 * The keystroke filter mask to be applied on alpha input
8498 'alphaMask' : /[a-z_]/i,
8501 * The function used to validate alphanumeric values
8502 * @param {String} value The value
8504 'alphanum' : function(v){
8505 return alphanum.test(v);
8508 * The error text to display when the alphanumeric validation function returns false
8511 'alphanumText' : 'This field should only contain letters, numbers and _',
8513 * The keystroke filter mask to be applied on alphanumeric input
8516 'alphanumMask' : /[a-z0-9_]/i
8526 * @class Roo.bootstrap.Input
8527 * @extends Roo.bootstrap.Component
8528 * Bootstrap Input class
8529 * @cfg {Boolean} disabled is it disabled
8530 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8531 * @cfg {String} name name of the input
8532 * @cfg {string} fieldLabel - the label associated
8533 * @cfg {string} placeholder - placeholder to put in text.
8534 * @cfg {string} before - input group add on before
8535 * @cfg {string} after - input group add on after
8536 * @cfg {string} size - (lg|sm) or leave empty..
8537 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8538 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8539 * @cfg {Number} md colspan out of 12 for computer-sized screens
8540 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8541 * @cfg {string} value default value of the input
8542 * @cfg {Number} labelWidth set the width of label
8543 * @cfg {Number} labellg set the width of label (1-12)
8544 * @cfg {Number} labelmd set the width of label (1-12)
8545 * @cfg {Number} labelsm set the width of label (1-12)
8546 * @cfg {Number} labelxs set the width of label (1-12)
8547 * @cfg {String} labelAlign (top|left)
8548 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8549 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8550 * @cfg {String} indicatorpos (left|right) default left
8551 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8553 * @cfg {String} align (left|center|right) Default left
8554 * @cfg {Boolean} forceFeedback (true|false) Default false
8557 * Create a new Input
8558 * @param {Object} config The config object
8561 Roo.bootstrap.Input = function(config){
8563 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8568 * Fires when this field receives input focus.
8569 * @param {Roo.form.Field} this
8574 * Fires when this field loses input focus.
8575 * @param {Roo.form.Field} this
8580 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8581 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8582 * @param {Roo.form.Field} this
8583 * @param {Roo.EventObject} e The event object
8588 * Fires just before the field blurs if the field value has changed.
8589 * @param {Roo.form.Field} this
8590 * @param {Mixed} newValue The new value
8591 * @param {Mixed} oldValue The original value
8596 * Fires after the field has been marked as invalid.
8597 * @param {Roo.form.Field} this
8598 * @param {String} msg The validation message
8603 * Fires after the field has been validated with no errors.
8604 * @param {Roo.form.Field} this
8609 * Fires after the key up
8610 * @param {Roo.form.Field} this
8611 * @param {Roo.EventObject} e The event Object
8617 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8619 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8620 automatic validation (defaults to "keyup").
8622 validationEvent : "keyup",
8624 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8626 validateOnBlur : true,
8628 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8630 validationDelay : 250,
8632 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8634 focusClass : "x-form-focus", // not needed???
8638 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8640 invalidClass : "has-warning",
8643 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8645 validClass : "has-success",
8648 * @cfg {Boolean} hasFeedback (true|false) default true
8653 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8655 invalidFeedbackClass : "glyphicon-warning-sign",
8658 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8660 validFeedbackClass : "glyphicon-ok",
8663 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8665 selectOnFocus : false,
8668 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8672 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8677 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8679 disableKeyFilter : false,
8682 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8686 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8690 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8692 blankText : "Please complete this mandatory field",
8695 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8699 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8701 maxLength : Number.MAX_VALUE,
8703 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8705 minLengthText : "The minimum length for this field is {0}",
8707 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8709 maxLengthText : "The maximum length for this field is {0}",
8713 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8714 * If available, this function will be called only after the basic validators all return true, and will be passed the
8715 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8719 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8720 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8721 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8725 * @cfg {String} regexText -- Depricated - use Invalid Text
8730 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8736 autocomplete: false,
8755 formatedValue : false,
8756 forceFeedback : false,
8758 indicatorpos : 'left',
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;
8807 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8810 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8811 input.maxLength = this.maxLength;
8814 if (this.disabled) {
8815 input.disabled=true;
8818 if (this.readOnly) {
8819 input.readonly=true;
8823 input.name = this.name;
8827 input.cls += ' input-' + this.size;
8831 ['xs','sm','md','lg'].map(function(size){
8832 if (settings[size]) {
8833 cfg.cls += ' col-' + size + '-' + settings[size];
8837 var inputblock = input;
8841 cls: 'glyphicon form-control-feedback'
8844 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8847 cls : 'has-feedback',
8855 if (this.before || this.after) {
8858 cls : 'input-group',
8862 if (this.before && typeof(this.before) == 'string') {
8864 inputblock.cn.push({
8866 cls : 'roo-input-before input-group-addon',
8870 if (this.before && typeof(this.before) == 'object') {
8871 this.before = Roo.factory(this.before);
8873 inputblock.cn.push({
8875 cls : 'roo-input-before input-group-' +
8876 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8880 inputblock.cn.push(input);
8882 if (this.after && typeof(this.after) == 'string') {
8883 inputblock.cn.push({
8885 cls : 'roo-input-after input-group-addon',
8889 if (this.after && typeof(this.after) == 'object') {
8890 this.after = Roo.factory(this.after);
8892 inputblock.cn.push({
8894 cls : 'roo-input-after input-group-' +
8895 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8899 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8900 inputblock.cls += ' has-feedback';
8901 inputblock.cn.push(feedback);
8905 if (align ==='left' && this.fieldLabel.length) {
8907 cfg.cls += ' roo-form-group-label-left';
8912 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8913 tooltip : 'This field is required'
8918 cls : 'control-label',
8919 html : this.fieldLabel
8930 var labelCfg = cfg.cn[1];
8931 var contentCfg = cfg.cn[2];
8933 if(this.indicatorpos == 'right'){
8938 cls : 'control-label',
8942 html : this.fieldLabel
8946 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8947 tooltip : 'This field is required'
8960 labelCfg = cfg.cn[0];
8961 contentCfg = cfg.cn[1];
8965 if(this.labelWidth > 12){
8966 labelCfg.style = "width: " + this.labelWidth + 'px';
8969 if(this.labelWidth < 13 && this.labelmd == 0){
8970 this.labelmd = this.labelWidth;
8973 if(this.labellg > 0){
8974 labelCfg.cls += ' col-lg-' + this.labellg;
8975 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8978 if(this.labelmd > 0){
8979 labelCfg.cls += ' col-md-' + this.labelmd;
8980 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8983 if(this.labelsm > 0){
8984 labelCfg.cls += ' col-sm-' + this.labelsm;
8985 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8988 if(this.labelxs > 0){
8989 labelCfg.cls += ' col-xs-' + this.labelxs;
8990 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8994 } else if ( this.fieldLabel.length) {
8999 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9000 tooltip : 'This field is required'
9004 //cls : 'input-group-addon',
9005 html : this.fieldLabel
9013 if(this.indicatorpos == 'right'){
9018 //cls : 'input-group-addon',
9019 html : this.fieldLabel
9024 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9025 tooltip : 'This field is required'
9045 if (this.parentType === 'Navbar' && this.parent().bar) {
9046 cfg.cls += ' navbar-form';
9049 if (this.parentType === 'NavGroup') {
9050 cfg.cls += ' navbar-form';
9058 * return the real input element.
9060 inputEl: function ()
9062 return this.el.select('input.form-control',true).first();
9065 tooltipEl : function()
9067 return this.inputEl();
9070 indicatorEl : function()
9072 var indicator = this.el.select('i.roo-required-indicator',true).first();
9082 setDisabled : function(v)
9084 var i = this.inputEl().dom;
9086 i.removeAttribute('disabled');
9090 i.setAttribute('disabled','true');
9092 initEvents : function()
9095 this.inputEl().on("keydown" , this.fireKey, this);
9096 this.inputEl().on("focus", this.onFocus, this);
9097 this.inputEl().on("blur", this.onBlur, this);
9099 this.inputEl().relayEvent('keyup', this);
9101 this.indicator = this.indicatorEl();
9104 this.indicator.addClass('invisible');
9107 // reference to original value for reset
9108 this.originalValue = this.getValue();
9109 //Roo.form.TextField.superclass.initEvents.call(this);
9110 if(this.validationEvent == 'keyup'){
9111 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9112 this.inputEl().on('keyup', this.filterValidation, this);
9114 else if(this.validationEvent !== false){
9115 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9118 if(this.selectOnFocus){
9119 this.on("focus", this.preFocus, this);
9122 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9123 this.inputEl().on("keypress", this.filterKeys, this);
9125 this.inputEl().relayEvent('keypress', this);
9128 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9129 this.el.on("click", this.autoSize, this);
9132 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9133 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9136 if (typeof(this.before) == 'object') {
9137 this.before.render(this.el.select('.roo-input-before',true).first());
9139 if (typeof(this.after) == 'object') {
9140 this.after.render(this.el.select('.roo-input-after',true).first());
9143 this.inputEl().on('change', this.onChange, this);
9146 filterValidation : function(e){
9147 if(!e.isNavKeyPress()){
9148 this.validationTask.delay(this.validationDelay);
9152 * Validates the field value
9153 * @return {Boolean} True if the value is valid, else false
9155 validate : function(){
9156 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9157 if(this.disabled || this.validateValue(this.getRawValue())){
9168 * Validates a value according to the field's validation rules and marks the field as invalid
9169 * if the validation fails
9170 * @param {Mixed} value The value to validate
9171 * @return {Boolean} True if the value is valid, else false
9173 validateValue : function(value)
9175 if(this.getVisibilityEl().hasClass('hidden')){
9179 if(value.length < 1) { // if it's blank
9180 if(this.allowBlank){
9186 if(value.length < this.minLength){
9189 if(value.length > this.maxLength){
9193 var vt = Roo.form.VTypes;
9194 if(!vt[this.vtype](value, this)){
9198 if(typeof this.validator == "function"){
9199 var msg = this.validator(value);
9203 if (typeof(msg) == 'string') {
9204 this.invalidText = msg;
9208 if(this.regex && !this.regex.test(value)){
9216 fireKey : function(e){
9217 //Roo.log('field ' + e.getKey());
9218 if(e.isNavKeyPress()){
9219 this.fireEvent("specialkey", this, e);
9222 focus : function (selectText){
9224 this.inputEl().focus();
9225 if(selectText === true){
9226 this.inputEl().dom.select();
9232 onFocus : function(){
9233 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9234 // this.el.addClass(this.focusClass);
9237 this.hasFocus = true;
9238 this.startValue = this.getValue();
9239 this.fireEvent("focus", this);
9243 beforeBlur : Roo.emptyFn,
9247 onBlur : function(){
9249 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9250 //this.el.removeClass(this.focusClass);
9252 this.hasFocus = false;
9253 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9256 var v = this.getValue();
9257 if(String(v) !== String(this.startValue)){
9258 this.fireEvent('change', this, v, this.startValue);
9260 this.fireEvent("blur", this);
9263 onChange : function(e)
9265 var v = this.getValue();
9266 if(String(v) !== String(this.startValue)){
9267 this.fireEvent('change', this, v, this.startValue);
9273 * Resets the current field value to the originally loaded value and clears any validation messages
9276 this.setValue(this.originalValue);
9280 * Returns the name of the field
9281 * @return {Mixed} name The name field
9283 getName: function(){
9287 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9288 * @return {Mixed} value The field value
9290 getValue : function(){
9292 var v = this.inputEl().getValue();
9297 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9298 * @return {Mixed} value The field value
9300 getRawValue : function(){
9301 var v = this.inputEl().getValue();
9307 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9308 * @param {Mixed} value The value to set
9310 setRawValue : function(v){
9311 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9314 selectText : function(start, end){
9315 var v = this.getRawValue();
9317 start = start === undefined ? 0 : start;
9318 end = end === undefined ? v.length : end;
9319 var d = this.inputEl().dom;
9320 if(d.setSelectionRange){
9321 d.setSelectionRange(start, end);
9322 }else if(d.createTextRange){
9323 var range = d.createTextRange();
9324 range.moveStart("character", start);
9325 range.moveEnd("character", v.length-end);
9332 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9333 * @param {Mixed} value The value to set
9335 setValue : function(v){
9338 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9344 processValue : function(value){
9345 if(this.stripCharsRe){
9346 var newValue = value.replace(this.stripCharsRe, '');
9347 if(newValue !== value){
9348 this.setRawValue(newValue);
9355 preFocus : function(){
9357 if(this.selectOnFocus){
9358 this.inputEl().dom.select();
9361 filterKeys : function(e){
9363 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9366 var c = e.getCharCode(), cc = String.fromCharCode(c);
9367 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9370 if(!this.maskRe.test(cc)){
9375 * Clear any invalid styles/messages for this field
9377 clearInvalid : function(){
9379 if(!this.el || this.preventMark){ // not rendered
9384 this.el.removeClass(this.invalidClass);
9386 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9388 var feedback = this.el.select('.form-control-feedback', true).first();
9391 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9396 this.fireEvent('valid', this);
9400 * Mark this field as valid
9402 markValid : function()
9404 if(!this.el || this.preventMark){ // not rendered...
9408 this.el.removeClass([this.invalidClass, this.validClass]);
9410 var feedback = this.el.select('.form-control-feedback', true).first();
9413 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9417 this.indicator.removeClass('visible');
9418 this.indicator.addClass('invisible');
9425 if(this.allowBlank && !this.getRawValue().length){
9429 this.el.addClass(this.validClass);
9431 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9433 var feedback = this.el.select('.form-control-feedback', true).first();
9436 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9437 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9442 this.fireEvent('valid', this);
9446 * Mark this field as invalid
9447 * @param {String} msg The validation message
9449 markInvalid : function(msg)
9451 if(!this.el || this.preventMark){ // not rendered
9455 this.el.removeClass([this.invalidClass, this.validClass]);
9457 var feedback = this.el.select('.form-control-feedback', true).first();
9460 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9467 if(this.allowBlank && !this.getRawValue().length){
9472 this.indicator.removeClass('invisible');
9473 this.indicator.addClass('visible');
9476 this.el.addClass(this.invalidClass);
9478 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9480 var feedback = this.el.select('.form-control-feedback', true).first();
9483 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9485 if(this.getValue().length || this.forceFeedback){
9486 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9493 this.fireEvent('invalid', this, msg);
9496 SafariOnKeyDown : function(event)
9498 // this is a workaround for a password hang bug on chrome/ webkit.
9499 if (this.inputEl().dom.type != 'password') {
9503 var isSelectAll = false;
9505 if(this.inputEl().dom.selectionEnd > 0){
9506 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9508 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9509 event.preventDefault();
9514 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9516 event.preventDefault();
9517 // this is very hacky as keydown always get's upper case.
9519 var cc = String.fromCharCode(event.getCharCode());
9520 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9524 adjustWidth : function(tag, w){
9525 tag = tag.toLowerCase();
9526 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9527 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9531 if(tag == 'textarea'){
9534 }else if(Roo.isOpera){
9538 if(tag == 'textarea'){
9546 setFieldLabel : function(v)
9553 var ar = this.el.select('label > span',true);
9555 if (ar.elements.length) {
9556 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9557 this.fieldLabel = v;
9561 var br = this.el.select('label',true);
9563 if(br.elements.length) {
9564 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9565 this.fieldLabel = v;
9569 Roo.log('Cannot Found any of label > span || label in input');
9573 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9574 this.fieldLabel = v;
9589 * @class Roo.bootstrap.TextArea
9590 * @extends Roo.bootstrap.Input
9591 * Bootstrap TextArea class
9592 * @cfg {Number} cols Specifies the visible width of a text area
9593 * @cfg {Number} rows Specifies the visible number of lines in a text area
9594 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9595 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9596 * @cfg {string} html text
9599 * Create a new TextArea
9600 * @param {Object} config The config object
9603 Roo.bootstrap.TextArea = function(config){
9604 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9608 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9618 getAutoCreate : function(){
9620 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9626 if(this.inputType != 'hidden'){
9627 cfg.cls = 'form-group' //input-group
9635 value : this.value || '',
9636 html: this.html || '',
9637 cls : 'form-control',
9638 placeholder : this.placeholder || ''
9642 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9643 input.maxLength = this.maxLength;
9647 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9651 input.cols = this.cols;
9654 if (this.readOnly) {
9655 input.readonly = true;
9659 input.name = this.name;
9663 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9667 ['xs','sm','md','lg'].map(function(size){
9668 if (settings[size]) {
9669 cfg.cls += ' col-' + size + '-' + settings[size];
9673 var inputblock = input;
9675 if(this.hasFeedback && !this.allowBlank){
9679 cls: 'glyphicon form-control-feedback'
9683 cls : 'has-feedback',
9692 if (this.before || this.after) {
9695 cls : 'input-group',
9699 inputblock.cn.push({
9701 cls : 'input-group-addon',
9706 inputblock.cn.push(input);
9708 if(this.hasFeedback && !this.allowBlank){
9709 inputblock.cls += ' has-feedback';
9710 inputblock.cn.push(feedback);
9714 inputblock.cn.push({
9716 cls : 'input-group-addon',
9723 if (align ==='left' && this.fieldLabel.length) {
9728 cls : 'control-label',
9729 html : this.fieldLabel
9740 if(this.labelWidth > 12){
9741 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9744 if(this.labelWidth < 13 && this.labelmd == 0){
9745 this.labelmd = this.labelWidth;
9748 if(this.labellg > 0){
9749 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9750 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9753 if(this.labelmd > 0){
9754 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9755 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9758 if(this.labelsm > 0){
9759 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9760 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9763 if(this.labelxs > 0){
9764 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9765 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9768 } else if ( this.fieldLabel.length) {
9773 //cls : 'input-group-addon',
9774 html : this.fieldLabel
9792 if (this.disabled) {
9793 input.disabled=true;
9800 * return the real textarea element.
9802 inputEl: function ()
9804 return this.el.select('textarea.form-control',true).first();
9808 * Clear any invalid styles/messages for this field
9810 clearInvalid : function()
9813 if(!this.el || this.preventMark){ // not rendered
9817 var label = this.el.select('label', true).first();
9818 var icon = this.el.select('i.fa-star', true).first();
9824 this.el.removeClass(this.invalidClass);
9826 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9828 var feedback = this.el.select('.form-control-feedback', true).first();
9831 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9836 this.fireEvent('valid', this);
9840 * Mark this field as valid
9842 markValid : function()
9844 if(!this.el || this.preventMark){ // not rendered
9848 this.el.removeClass([this.invalidClass, this.validClass]);
9850 var feedback = this.el.select('.form-control-feedback', true).first();
9853 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9856 if(this.disabled || this.allowBlank){
9860 var label = this.el.select('label', true).first();
9861 var icon = this.el.select('i.fa-star', true).first();
9867 this.el.addClass(this.validClass);
9869 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9871 var feedback = this.el.select('.form-control-feedback', true).first();
9874 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9875 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9880 this.fireEvent('valid', this);
9884 * Mark this field as invalid
9885 * @param {String} msg The validation message
9887 markInvalid : function(msg)
9889 if(!this.el || this.preventMark){ // not rendered
9893 this.el.removeClass([this.invalidClass, this.validClass]);
9895 var feedback = this.el.select('.form-control-feedback', true).first();
9898 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9901 if(this.disabled || this.allowBlank){
9905 var label = this.el.select('label', true).first();
9906 var icon = this.el.select('i.fa-star', true).first();
9908 if(!this.getValue().length && label && !icon){
9909 this.el.createChild({
9911 cls : 'text-danger fa fa-lg fa-star',
9912 tooltip : 'This field is required',
9913 style : 'margin-right:5px;'
9917 this.el.addClass(this.invalidClass);
9919 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9921 var feedback = this.el.select('.form-control-feedback', true).first();
9924 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9926 if(this.getValue().length || this.forceFeedback){
9927 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9934 this.fireEvent('invalid', this, msg);
9942 * trigger field - base class for combo..
9947 * @class Roo.bootstrap.TriggerField
9948 * @extends Roo.bootstrap.Input
9949 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9950 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9951 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9952 * for which you can provide a custom implementation. For example:
9954 var trigger = new Roo.bootstrap.TriggerField();
9955 trigger.onTriggerClick = myTriggerFn;
9956 trigger.applyTo('my-field');
9959 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9960 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9961 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9962 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9963 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9966 * Create a new TriggerField.
9967 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9968 * to the base TextField)
9970 Roo.bootstrap.TriggerField = function(config){
9971 this.mimicing = false;
9972 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9975 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9977 * @cfg {String} triggerClass A CSS class to apply to the trigger
9980 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9985 * @cfg {Boolean} removable (true|false) special filter default false
9989 /** @cfg {Boolean} grow @hide */
9990 /** @cfg {Number} growMin @hide */
9991 /** @cfg {Number} growMax @hide */
9997 autoSize: Roo.emptyFn,
10001 deferHeight : true,
10004 actionMode : 'wrap',
10009 getAutoCreate : function(){
10011 var align = this.labelAlign || this.parentLabelAlign();
10016 cls: 'form-group' //input-group
10023 type : this.inputType,
10024 cls : 'form-control',
10025 autocomplete: 'new-password',
10026 placeholder : this.placeholder || ''
10030 input.name = this.name;
10033 input.cls += ' input-' + this.size;
10036 if (this.disabled) {
10037 input.disabled=true;
10040 var inputblock = input;
10042 if(this.hasFeedback && !this.allowBlank){
10046 cls: 'glyphicon form-control-feedback'
10049 if(this.removable && !this.editable && !this.tickable){
10051 cls : 'has-feedback',
10057 cls : 'roo-combo-removable-btn close'
10064 cls : 'has-feedback',
10073 if(this.removable && !this.editable && !this.tickable){
10075 cls : 'roo-removable',
10081 cls : 'roo-combo-removable-btn close'
10088 if (this.before || this.after) {
10091 cls : 'input-group',
10095 inputblock.cn.push({
10097 cls : 'input-group-addon',
10102 inputblock.cn.push(input);
10104 if(this.hasFeedback && !this.allowBlank){
10105 inputblock.cls += ' has-feedback';
10106 inputblock.cn.push(feedback);
10110 inputblock.cn.push({
10112 cls : 'input-group-addon',
10125 cls: 'form-hidden-field'
10139 cls: 'form-hidden-field'
10143 cls: 'roo-select2-choices',
10147 cls: 'roo-select2-search-field',
10160 cls: 'roo-select2-container input-group',
10165 // cls: 'typeahead typeahead-long dropdown-menu',
10166 // style: 'display:none'
10171 if(!this.multiple && this.showToggleBtn){
10177 if (this.caret != false) {
10180 cls: 'fa fa-' + this.caret
10187 cls : 'input-group-addon btn dropdown-toggle',
10192 cls: 'combobox-clear',
10206 combobox.cls += ' roo-select2-container-multi';
10209 if (align ==='left' && this.fieldLabel.length) {
10211 cfg.cls += ' roo-form-group-label-left';
10216 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10217 tooltip : 'This field is required'
10222 cls : 'control-label',
10223 html : this.fieldLabel
10235 var labelCfg = cfg.cn[1];
10236 var contentCfg = cfg.cn[2];
10238 if(this.indicatorpos == 'right'){
10243 cls : 'control-label',
10247 html : this.fieldLabel
10251 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10252 tooltip : 'This field is required'
10265 labelCfg = cfg.cn[0];
10266 contentCfg = cfg.cn[1];
10269 if(this.labelWidth > 12){
10270 labelCfg.style = "width: " + this.labelWidth + 'px';
10273 if(this.labelWidth < 13 && this.labelmd == 0){
10274 this.labelmd = this.labelWidth;
10277 if(this.labellg > 0){
10278 labelCfg.cls += ' col-lg-' + this.labellg;
10279 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10282 if(this.labelmd > 0){
10283 labelCfg.cls += ' col-md-' + this.labelmd;
10284 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10287 if(this.labelsm > 0){
10288 labelCfg.cls += ' col-sm-' + this.labelsm;
10289 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10292 if(this.labelxs > 0){
10293 labelCfg.cls += ' col-xs-' + this.labelxs;
10294 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10297 } else if ( this.fieldLabel.length) {
10298 // Roo.log(" label");
10302 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10303 tooltip : 'This field is required'
10307 //cls : 'input-group-addon',
10308 html : this.fieldLabel
10316 if(this.indicatorpos == 'right'){
10324 html : this.fieldLabel
10328 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10329 tooltip : 'This field is required'
10342 // Roo.log(" no label && no align");
10349 ['xs','sm','md','lg'].map(function(size){
10350 if (settings[size]) {
10351 cfg.cls += ' col-' + size + '-' + settings[size];
10362 onResize : function(w, h){
10363 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10364 // if(typeof w == 'number'){
10365 // var x = w - this.trigger.getWidth();
10366 // this.inputEl().setWidth(this.adjustWidth('input', x));
10367 // this.trigger.setStyle('left', x+'px');
10372 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10375 getResizeEl : function(){
10376 return this.inputEl();
10380 getPositionEl : function(){
10381 return this.inputEl();
10385 alignErrorIcon : function(){
10386 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10390 initEvents : function(){
10394 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10395 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10396 if(!this.multiple && this.showToggleBtn){
10397 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10398 if(this.hideTrigger){
10399 this.trigger.setDisplayed(false);
10401 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10405 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10408 if(this.removable && !this.editable && !this.tickable){
10409 var close = this.closeTriggerEl();
10412 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10413 close.on('click', this.removeBtnClick, this, close);
10417 //this.trigger.addClassOnOver('x-form-trigger-over');
10418 //this.trigger.addClassOnClick('x-form-trigger-click');
10421 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10425 closeTriggerEl : function()
10427 var close = this.el.select('.roo-combo-removable-btn', true).first();
10428 return close ? close : false;
10431 removeBtnClick : function(e, h, el)
10433 e.preventDefault();
10435 if(this.fireEvent("remove", this) !== false){
10437 this.fireEvent("afterremove", this)
10441 createList : function()
10443 this.list = Roo.get(document.body).createChild({
10445 cls: 'typeahead typeahead-long dropdown-menu',
10446 style: 'display:none'
10449 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10454 initTrigger : function(){
10459 onDestroy : function(){
10461 this.trigger.removeAllListeners();
10462 // this.trigger.remove();
10465 // this.wrap.remove();
10467 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10471 onFocus : function(){
10472 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10474 if(!this.mimicing){
10475 this.wrap.addClass('x-trigger-wrap-focus');
10476 this.mimicing = true;
10477 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10478 if(this.monitorTab){
10479 this.el.on("keydown", this.checkTab, this);
10486 checkTab : function(e){
10487 if(e.getKey() == e.TAB){
10488 this.triggerBlur();
10493 onBlur : function(){
10498 mimicBlur : function(e, t){
10500 if(!this.wrap.contains(t) && this.validateBlur()){
10501 this.triggerBlur();
10507 triggerBlur : function(){
10508 this.mimicing = false;
10509 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10510 if(this.monitorTab){
10511 this.el.un("keydown", this.checkTab, this);
10513 //this.wrap.removeClass('x-trigger-wrap-focus');
10514 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10518 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10519 validateBlur : function(e, t){
10524 onDisable : function(){
10525 this.inputEl().dom.disabled = true;
10526 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10528 // this.wrap.addClass('x-item-disabled');
10533 onEnable : function(){
10534 this.inputEl().dom.disabled = false;
10535 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10537 // this.el.removeClass('x-item-disabled');
10542 onShow : function(){
10543 var ae = this.getActionEl();
10546 ae.dom.style.display = '';
10547 ae.dom.style.visibility = 'visible';
10553 onHide : function(){
10554 var ae = this.getActionEl();
10555 ae.dom.style.display = 'none';
10559 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10560 * by an implementing function.
10562 * @param {EventObject} e
10564 onTriggerClick : Roo.emptyFn
10568 * Ext JS Library 1.1.1
10569 * Copyright(c) 2006-2007, Ext JS, LLC.
10571 * Originally Released Under LGPL - original licence link has changed is not relivant.
10574 * <script type="text/javascript">
10579 * @class Roo.data.SortTypes
10581 * Defines the default sorting (casting?) comparison functions used when sorting data.
10583 Roo.data.SortTypes = {
10585 * Default sort that does nothing
10586 * @param {Mixed} s The value being converted
10587 * @return {Mixed} The comparison value
10589 none : function(s){
10594 * The regular expression used to strip tags
10598 stripTagsRE : /<\/?[^>]+>/gi,
10601 * Strips all HTML tags to sort on text only
10602 * @param {Mixed} s The value being converted
10603 * @return {String} The comparison value
10605 asText : function(s){
10606 return String(s).replace(this.stripTagsRE, "");
10610 * Strips all HTML tags to sort on text only - Case insensitive
10611 * @param {Mixed} s The value being converted
10612 * @return {String} The comparison value
10614 asUCText : function(s){
10615 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10619 * Case insensitive string
10620 * @param {Mixed} s The value being converted
10621 * @return {String} The comparison value
10623 asUCString : function(s) {
10624 return String(s).toUpperCase();
10629 * @param {Mixed} s The value being converted
10630 * @return {Number} The comparison value
10632 asDate : function(s) {
10636 if(s instanceof Date){
10637 return s.getTime();
10639 return Date.parse(String(s));
10644 * @param {Mixed} s The value being converted
10645 * @return {Float} The comparison value
10647 asFloat : function(s) {
10648 var val = parseFloat(String(s).replace(/,/g, ""));
10657 * @param {Mixed} s The value being converted
10658 * @return {Number} The comparison value
10660 asInt : function(s) {
10661 var val = parseInt(String(s).replace(/,/g, ""));
10669 * Ext JS Library 1.1.1
10670 * Copyright(c) 2006-2007, Ext JS, LLC.
10672 * Originally Released Under LGPL - original licence link has changed is not relivant.
10675 * <script type="text/javascript">
10679 * @class Roo.data.Record
10680 * Instances of this class encapsulate both record <em>definition</em> information, and record
10681 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10682 * to access Records cached in an {@link Roo.data.Store} object.<br>
10684 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10685 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10688 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10690 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10691 * {@link #create}. The parameters are the same.
10692 * @param {Array} data An associative Array of data values keyed by the field name.
10693 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10694 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10695 * not specified an integer id is generated.
10697 Roo.data.Record = function(data, id){
10698 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10703 * Generate a constructor for a specific record layout.
10704 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10705 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10706 * Each field definition object may contain the following properties: <ul>
10707 * <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,
10708 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10709 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10710 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10711 * is being used, then this is a string containing the javascript expression to reference the data relative to
10712 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10713 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10714 * this may be omitted.</p></li>
10715 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10716 * <ul><li>auto (Default, implies no conversion)</li>
10721 * <li>date</li></ul></p></li>
10722 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10723 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10724 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10725 * by the Reader into an object that will be stored in the Record. It is passed the
10726 * following parameters:<ul>
10727 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10729 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10731 * <br>usage:<br><pre><code>
10732 var TopicRecord = Roo.data.Record.create(
10733 {name: 'title', mapping: 'topic_title'},
10734 {name: 'author', mapping: 'username'},
10735 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10736 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10737 {name: 'lastPoster', mapping: 'user2'},
10738 {name: 'excerpt', mapping: 'post_text'}
10741 var myNewRecord = new TopicRecord({
10742 title: 'Do my job please',
10745 lastPost: new Date(),
10746 lastPoster: 'Animal',
10747 excerpt: 'No way dude!'
10749 myStore.add(myNewRecord);
10754 Roo.data.Record.create = function(o){
10755 var f = function(){
10756 f.superclass.constructor.apply(this, arguments);
10758 Roo.extend(f, Roo.data.Record);
10759 var p = f.prototype;
10760 p.fields = new Roo.util.MixedCollection(false, function(field){
10763 for(var i = 0, len = o.length; i < len; i++){
10764 p.fields.add(new Roo.data.Field(o[i]));
10766 f.getField = function(name){
10767 return p.fields.get(name);
10772 Roo.data.Record.AUTO_ID = 1000;
10773 Roo.data.Record.EDIT = 'edit';
10774 Roo.data.Record.REJECT = 'reject';
10775 Roo.data.Record.COMMIT = 'commit';
10777 Roo.data.Record.prototype = {
10779 * Readonly flag - true if this record has been modified.
10788 join : function(store){
10789 this.store = store;
10793 * Set the named field to the specified value.
10794 * @param {String} name The name of the field to set.
10795 * @param {Object} value The value to set the field to.
10797 set : function(name, value){
10798 if(this.data[name] == value){
10802 if(!this.modified){
10803 this.modified = {};
10805 if(typeof this.modified[name] == 'undefined'){
10806 this.modified[name] = this.data[name];
10808 this.data[name] = value;
10809 if(!this.editing && this.store){
10810 this.store.afterEdit(this);
10815 * Get the value of the named field.
10816 * @param {String} name The name of the field to get the value of.
10817 * @return {Object} The value of the field.
10819 get : function(name){
10820 return this.data[name];
10824 beginEdit : function(){
10825 this.editing = true;
10826 this.modified = {};
10830 cancelEdit : function(){
10831 this.editing = false;
10832 delete this.modified;
10836 endEdit : function(){
10837 this.editing = false;
10838 if(this.dirty && this.store){
10839 this.store.afterEdit(this);
10844 * Usually called by the {@link Roo.data.Store} which owns the Record.
10845 * Rejects all changes made to the Record since either creation, or the last commit operation.
10846 * Modified fields are reverted to their original values.
10848 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10849 * of reject operations.
10851 reject : function(){
10852 var m = this.modified;
10854 if(typeof m[n] != "function"){
10855 this.data[n] = m[n];
10858 this.dirty = false;
10859 delete this.modified;
10860 this.editing = false;
10862 this.store.afterReject(this);
10867 * Usually called by the {@link Roo.data.Store} which owns the Record.
10868 * Commits all changes made to the Record since either creation, or the last commit operation.
10870 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10871 * of commit operations.
10873 commit : function(){
10874 this.dirty = false;
10875 delete this.modified;
10876 this.editing = false;
10878 this.store.afterCommit(this);
10883 hasError : function(){
10884 return this.error != null;
10888 clearError : function(){
10893 * Creates a copy of this record.
10894 * @param {String} id (optional) A new record id if you don't want to use this record's id
10897 copy : function(newId) {
10898 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10902 * Ext JS Library 1.1.1
10903 * Copyright(c) 2006-2007, Ext JS, LLC.
10905 * Originally Released Under LGPL - original licence link has changed is not relivant.
10908 * <script type="text/javascript">
10914 * @class Roo.data.Store
10915 * @extends Roo.util.Observable
10916 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10917 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10919 * 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
10920 * has no knowledge of the format of the data returned by the Proxy.<br>
10922 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10923 * instances from the data object. These records are cached and made available through accessor functions.
10925 * Creates a new Store.
10926 * @param {Object} config A config object containing the objects needed for the Store to access data,
10927 * and read the data into Records.
10929 Roo.data.Store = function(config){
10930 this.data = new Roo.util.MixedCollection(false);
10931 this.data.getKey = function(o){
10934 this.baseParams = {};
10936 this.paramNames = {
10941 "multisort" : "_multisort"
10944 if(config && config.data){
10945 this.inlineData = config.data;
10946 delete config.data;
10949 Roo.apply(this, config);
10951 if(this.reader){ // reader passed
10952 this.reader = Roo.factory(this.reader, Roo.data);
10953 this.reader.xmodule = this.xmodule || false;
10954 if(!this.recordType){
10955 this.recordType = this.reader.recordType;
10957 if(this.reader.onMetaChange){
10958 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10962 if(this.recordType){
10963 this.fields = this.recordType.prototype.fields;
10965 this.modified = [];
10969 * @event datachanged
10970 * Fires when the data cache has changed, and a widget which is using this Store
10971 * as a Record cache should refresh its view.
10972 * @param {Store} this
10974 datachanged : true,
10976 * @event metachange
10977 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10978 * @param {Store} this
10979 * @param {Object} meta The JSON metadata
10984 * Fires when Records have been added to the Store
10985 * @param {Store} this
10986 * @param {Roo.data.Record[]} records The array of Records added
10987 * @param {Number} index The index at which the record(s) were added
10992 * Fires when a Record has been removed from the Store
10993 * @param {Store} this
10994 * @param {Roo.data.Record} record The Record that was removed
10995 * @param {Number} index The index at which the record was removed
11000 * Fires when a Record has been updated
11001 * @param {Store} this
11002 * @param {Roo.data.Record} record The Record that was updated
11003 * @param {String} operation The update operation being performed. Value may be one of:
11005 Roo.data.Record.EDIT
11006 Roo.data.Record.REJECT
11007 Roo.data.Record.COMMIT
11013 * Fires when the data cache has been cleared.
11014 * @param {Store} this
11018 * @event beforeload
11019 * Fires before a request is made for a new data object. If the beforeload handler returns false
11020 * the load action will be canceled.
11021 * @param {Store} this
11022 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11026 * @event beforeloadadd
11027 * Fires after a new set of Records has been loaded.
11028 * @param {Store} this
11029 * @param {Roo.data.Record[]} records The Records that were loaded
11030 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11032 beforeloadadd : true,
11035 * Fires after a new set of Records has been loaded, before they are added to the store.
11036 * @param {Store} this
11037 * @param {Roo.data.Record[]} records The Records that were loaded
11038 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11039 * @params {Object} return from reader
11043 * @event loadexception
11044 * Fires if an exception occurs in the Proxy during loading.
11045 * Called with the signature of the Proxy's "loadexception" event.
11046 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11049 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11050 * @param {Object} load options
11051 * @param {Object} jsonData from your request (normally this contains the Exception)
11053 loadexception : true
11057 this.proxy = Roo.factory(this.proxy, Roo.data);
11058 this.proxy.xmodule = this.xmodule || false;
11059 this.relayEvents(this.proxy, ["loadexception"]);
11061 this.sortToggle = {};
11062 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11064 Roo.data.Store.superclass.constructor.call(this);
11066 if(this.inlineData){
11067 this.loadData(this.inlineData);
11068 delete this.inlineData;
11072 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11074 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11075 * without a remote query - used by combo/forms at present.
11079 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11082 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11085 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11086 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11089 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11090 * on any HTTP request
11093 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11096 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11100 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11101 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11103 remoteSort : false,
11106 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11107 * loaded or when a record is removed. (defaults to false).
11109 pruneModifiedRecords : false,
11112 lastOptions : null,
11115 * Add Records to the Store and fires the add event.
11116 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11118 add : function(records){
11119 records = [].concat(records);
11120 for(var i = 0, len = records.length; i < len; i++){
11121 records[i].join(this);
11123 var index = this.data.length;
11124 this.data.addAll(records);
11125 this.fireEvent("add", this, records, index);
11129 * Remove a Record from the Store and fires the remove event.
11130 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11132 remove : function(record){
11133 var index = this.data.indexOf(record);
11134 this.data.removeAt(index);
11136 if(this.pruneModifiedRecords){
11137 this.modified.remove(record);
11139 this.fireEvent("remove", this, record, index);
11143 * Remove all Records from the Store and fires the clear event.
11145 removeAll : function(){
11147 if(this.pruneModifiedRecords){
11148 this.modified = [];
11150 this.fireEvent("clear", this);
11154 * Inserts Records to the Store at the given index and fires the add event.
11155 * @param {Number} index The start index at which to insert the passed Records.
11156 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11158 insert : function(index, records){
11159 records = [].concat(records);
11160 for(var i = 0, len = records.length; i < len; i++){
11161 this.data.insert(index, records[i]);
11162 records[i].join(this);
11164 this.fireEvent("add", this, records, index);
11168 * Get the index within the cache of the passed Record.
11169 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11170 * @return {Number} The index of the passed Record. Returns -1 if not found.
11172 indexOf : function(record){
11173 return this.data.indexOf(record);
11177 * Get the index within the cache of the Record with the passed id.
11178 * @param {String} id The id of the Record to find.
11179 * @return {Number} The index of the Record. Returns -1 if not found.
11181 indexOfId : function(id){
11182 return this.data.indexOfKey(id);
11186 * Get the Record with the specified id.
11187 * @param {String} id The id of the Record to find.
11188 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11190 getById : function(id){
11191 return this.data.key(id);
11195 * Get the Record at the specified index.
11196 * @param {Number} index The index of the Record to find.
11197 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11199 getAt : function(index){
11200 return this.data.itemAt(index);
11204 * Returns a range of Records between specified indices.
11205 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11206 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11207 * @return {Roo.data.Record[]} An array of Records
11209 getRange : function(start, end){
11210 return this.data.getRange(start, end);
11214 storeOptions : function(o){
11215 o = Roo.apply({}, o);
11218 this.lastOptions = o;
11222 * Loads the Record cache from the configured Proxy using the configured Reader.
11224 * If using remote paging, then the first load call must specify the <em>start</em>
11225 * and <em>limit</em> properties in the options.params property to establish the initial
11226 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11228 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11229 * and this call will return before the new data has been loaded. Perform any post-processing
11230 * in a callback function, or in a "load" event handler.</strong>
11232 * @param {Object} options An object containing properties which control loading options:<ul>
11233 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11234 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11235 * passed the following arguments:<ul>
11236 * <li>r : Roo.data.Record[]</li>
11237 * <li>options: Options object from the load call</li>
11238 * <li>success: Boolean success indicator</li></ul></li>
11239 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11240 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11243 load : function(options){
11244 options = options || {};
11245 if(this.fireEvent("beforeload", this, options) !== false){
11246 this.storeOptions(options);
11247 var p = Roo.apply(options.params || {}, this.baseParams);
11248 // if meta was not loaded from remote source.. try requesting it.
11249 if (!this.reader.metaFromRemote) {
11250 p._requestMeta = 1;
11252 if(this.sortInfo && this.remoteSort){
11253 var pn = this.paramNames;
11254 p[pn["sort"]] = this.sortInfo.field;
11255 p[pn["dir"]] = this.sortInfo.direction;
11257 if (this.multiSort) {
11258 var pn = this.paramNames;
11259 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11262 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11267 * Reloads the Record cache from the configured Proxy using the configured Reader and
11268 * the options from the last load operation performed.
11269 * @param {Object} options (optional) An object containing properties which may override the options
11270 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11271 * the most recently used options are reused).
11273 reload : function(options){
11274 this.load(Roo.applyIf(options||{}, this.lastOptions));
11278 // Called as a callback by the Reader during a load operation.
11279 loadRecords : function(o, options, success){
11280 if(!o || success === false){
11281 if(success !== false){
11282 this.fireEvent("load", this, [], options, o);
11284 if(options.callback){
11285 options.callback.call(options.scope || this, [], options, false);
11289 // if data returned failure - throw an exception.
11290 if (o.success === false) {
11291 // show a message if no listener is registered.
11292 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11293 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11295 // loadmask wil be hooked into this..
11296 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11299 var r = o.records, t = o.totalRecords || r.length;
11301 this.fireEvent("beforeloadadd", this, r, options, o);
11303 if(!options || options.add !== true){
11304 if(this.pruneModifiedRecords){
11305 this.modified = [];
11307 for(var i = 0, len = r.length; i < len; i++){
11311 this.data = this.snapshot;
11312 delete this.snapshot;
11315 this.data.addAll(r);
11316 this.totalLength = t;
11318 this.fireEvent("datachanged", this);
11320 this.totalLength = Math.max(t, this.data.length+r.length);
11324 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11326 var e = new Roo.data.Record({});
11328 e.set(this.parent.displayField, this.parent.emptyTitle);
11329 e.set(this.parent.valueField, '');
11334 this.fireEvent("load", this, r, options, o);
11335 if(options.callback){
11336 options.callback.call(options.scope || this, r, options, true);
11342 * Loads data from a passed data block. A Reader which understands the format of the data
11343 * must have been configured in the constructor.
11344 * @param {Object} data The data block from which to read the Records. The format of the data expected
11345 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11346 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11348 loadData : function(o, append){
11349 var r = this.reader.readRecords(o);
11350 this.loadRecords(r, {add: append}, true);
11354 * Gets the number of cached records.
11356 * <em>If using paging, this may not be the total size of the dataset. If the data object
11357 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11358 * the data set size</em>
11360 getCount : function(){
11361 return this.data.length || 0;
11365 * Gets the total number of records in the dataset as returned by the server.
11367 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11368 * the dataset size</em>
11370 getTotalCount : function(){
11371 return this.totalLength || 0;
11375 * Returns the sort state of the Store as an object with two properties:
11377 field {String} The name of the field by which the Records are sorted
11378 direction {String} The sort order, "ASC" or "DESC"
11381 getSortState : function(){
11382 return this.sortInfo;
11386 applySort : function(){
11387 if(this.sortInfo && !this.remoteSort){
11388 var s = this.sortInfo, f = s.field;
11389 var st = this.fields.get(f).sortType;
11390 var fn = function(r1, r2){
11391 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11392 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11394 this.data.sort(s.direction, fn);
11395 if(this.snapshot && this.snapshot != this.data){
11396 this.snapshot.sort(s.direction, fn);
11402 * Sets the default sort column and order to be used by the next load operation.
11403 * @param {String} fieldName The name of the field to sort by.
11404 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11406 setDefaultSort : function(field, dir){
11407 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11411 * Sort the Records.
11412 * If remote sorting is used, the sort is performed on the server, and the cache is
11413 * reloaded. If local sorting is used, the cache is sorted internally.
11414 * @param {String} fieldName The name of the field to sort by.
11415 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11417 sort : function(fieldName, dir){
11418 var f = this.fields.get(fieldName);
11420 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11422 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11423 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11428 this.sortToggle[f.name] = dir;
11429 this.sortInfo = {field: f.name, direction: dir};
11430 if(!this.remoteSort){
11432 this.fireEvent("datachanged", this);
11434 this.load(this.lastOptions);
11439 * Calls the specified function for each of the Records in the cache.
11440 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11441 * Returning <em>false</em> aborts and exits the iteration.
11442 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11444 each : function(fn, scope){
11445 this.data.each(fn, scope);
11449 * Gets all records modified since the last commit. Modified records are persisted across load operations
11450 * (e.g., during paging).
11451 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11453 getModifiedRecords : function(){
11454 return this.modified;
11458 createFilterFn : function(property, value, anyMatch){
11459 if(!value.exec){ // not a regex
11460 value = String(value);
11461 if(value.length == 0){
11464 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11466 return function(r){
11467 return value.test(r.data[property]);
11472 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11473 * @param {String} property A field on your records
11474 * @param {Number} start The record index to start at (defaults to 0)
11475 * @param {Number} end The last record index to include (defaults to length - 1)
11476 * @return {Number} The sum
11478 sum : function(property, start, end){
11479 var rs = this.data.items, v = 0;
11480 start = start || 0;
11481 end = (end || end === 0) ? end : rs.length-1;
11483 for(var i = start; i <= end; i++){
11484 v += (rs[i].data[property] || 0);
11490 * Filter the records by a specified property.
11491 * @param {String} field A field on your records
11492 * @param {String/RegExp} value Either a string that the field
11493 * should start with or a RegExp to test against the field
11494 * @param {Boolean} anyMatch True to match any part not just the beginning
11496 filter : function(property, value, anyMatch){
11497 var fn = this.createFilterFn(property, value, anyMatch);
11498 return fn ? this.filterBy(fn) : this.clearFilter();
11502 * Filter by a function. The specified function will be called with each
11503 * record in this data source. If the function returns true the record is included,
11504 * otherwise it is filtered.
11505 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11506 * @param {Object} scope (optional) The scope of the function (defaults to this)
11508 filterBy : function(fn, scope){
11509 this.snapshot = this.snapshot || this.data;
11510 this.data = this.queryBy(fn, scope||this);
11511 this.fireEvent("datachanged", this);
11515 * Query the records by a specified property.
11516 * @param {String} field A field on your records
11517 * @param {String/RegExp} value Either a string that the field
11518 * should start with or a RegExp to test against the field
11519 * @param {Boolean} anyMatch True to match any part not just the beginning
11520 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11522 query : function(property, value, anyMatch){
11523 var fn = this.createFilterFn(property, value, anyMatch);
11524 return fn ? this.queryBy(fn) : this.data.clone();
11528 * Query by a function. The specified function will be called with each
11529 * record in this data source. If the function returns true the record is included
11531 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11532 * @param {Object} scope (optional) The scope of the function (defaults to this)
11533 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11535 queryBy : function(fn, scope){
11536 var data = this.snapshot || this.data;
11537 return data.filterBy(fn, scope||this);
11541 * Collects unique values for a particular dataIndex from this store.
11542 * @param {String} dataIndex The property to collect
11543 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11544 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11545 * @return {Array} An array of the unique values
11547 collect : function(dataIndex, allowNull, bypassFilter){
11548 var d = (bypassFilter === true && this.snapshot) ?
11549 this.snapshot.items : this.data.items;
11550 var v, sv, r = [], l = {};
11551 for(var i = 0, len = d.length; i < len; i++){
11552 v = d[i].data[dataIndex];
11554 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11563 * Revert to a view of the Record cache with no filtering applied.
11564 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11566 clearFilter : function(suppressEvent){
11567 if(this.snapshot && this.snapshot != this.data){
11568 this.data = this.snapshot;
11569 delete this.snapshot;
11570 if(suppressEvent !== true){
11571 this.fireEvent("datachanged", this);
11577 afterEdit : function(record){
11578 if(this.modified.indexOf(record) == -1){
11579 this.modified.push(record);
11581 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11585 afterReject : function(record){
11586 this.modified.remove(record);
11587 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11591 afterCommit : function(record){
11592 this.modified.remove(record);
11593 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11597 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11598 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11600 commitChanges : function(){
11601 var m = this.modified.slice(0);
11602 this.modified = [];
11603 for(var i = 0, len = m.length; i < len; i++){
11609 * Cancel outstanding changes on all changed records.
11611 rejectChanges : function(){
11612 var m = this.modified.slice(0);
11613 this.modified = [];
11614 for(var i = 0, len = m.length; i < len; i++){
11619 onMetaChange : function(meta, rtype, o){
11620 this.recordType = rtype;
11621 this.fields = rtype.prototype.fields;
11622 delete this.snapshot;
11623 this.sortInfo = meta.sortInfo || this.sortInfo;
11624 this.modified = [];
11625 this.fireEvent('metachange', this, this.reader.meta);
11628 moveIndex : function(data, type)
11630 var index = this.indexOf(data);
11632 var newIndex = index + type;
11636 this.insert(newIndex, data);
11641 * Ext JS Library 1.1.1
11642 * Copyright(c) 2006-2007, Ext JS, LLC.
11644 * Originally Released Under LGPL - original licence link has changed is not relivant.
11647 * <script type="text/javascript">
11651 * @class Roo.data.SimpleStore
11652 * @extends Roo.data.Store
11653 * Small helper class to make creating Stores from Array data easier.
11654 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11655 * @cfg {Array} fields An array of field definition objects, or field name strings.
11656 * @cfg {Array} data The multi-dimensional array of data
11658 * @param {Object} config
11660 Roo.data.SimpleStore = function(config){
11661 Roo.data.SimpleStore.superclass.constructor.call(this, {
11663 reader: new Roo.data.ArrayReader({
11666 Roo.data.Record.create(config.fields)
11668 proxy : new Roo.data.MemoryProxy(config.data)
11672 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11674 * Ext JS Library 1.1.1
11675 * Copyright(c) 2006-2007, Ext JS, LLC.
11677 * Originally Released Under LGPL - original licence link has changed is not relivant.
11680 * <script type="text/javascript">
11685 * @extends Roo.data.Store
11686 * @class Roo.data.JsonStore
11687 * Small helper class to make creating Stores for JSON data easier. <br/>
11689 var store = new Roo.data.JsonStore({
11690 url: 'get-images.php',
11692 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11695 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11696 * JsonReader and HttpProxy (unless inline data is provided).</b>
11697 * @cfg {Array} fields An array of field definition objects, or field name strings.
11699 * @param {Object} config
11701 Roo.data.JsonStore = function(c){
11702 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11703 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11704 reader: new Roo.data.JsonReader(c, c.fields)
11707 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11709 * Ext JS Library 1.1.1
11710 * Copyright(c) 2006-2007, Ext JS, LLC.
11712 * Originally Released Under LGPL - original licence link has changed is not relivant.
11715 * <script type="text/javascript">
11719 Roo.data.Field = function(config){
11720 if(typeof config == "string"){
11721 config = {name: config};
11723 Roo.apply(this, config);
11726 this.type = "auto";
11729 var st = Roo.data.SortTypes;
11730 // named sortTypes are supported, here we look them up
11731 if(typeof this.sortType == "string"){
11732 this.sortType = st[this.sortType];
11735 // set default sortType for strings and dates
11736 if(!this.sortType){
11739 this.sortType = st.asUCString;
11742 this.sortType = st.asDate;
11745 this.sortType = st.none;
11750 var stripRe = /[\$,%]/g;
11752 // prebuilt conversion function for this field, instead of
11753 // switching every time we're reading a value
11755 var cv, dateFormat = this.dateFormat;
11760 cv = function(v){ return v; };
11763 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11767 return v !== undefined && v !== null && v !== '' ?
11768 parseInt(String(v).replace(stripRe, ""), 10) : '';
11773 return v !== undefined && v !== null && v !== '' ?
11774 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11779 cv = function(v){ return v === true || v === "true" || v == 1; };
11786 if(v instanceof Date){
11790 if(dateFormat == "timestamp"){
11791 return new Date(v*1000);
11793 return Date.parseDate(v, dateFormat);
11795 var parsed = Date.parse(v);
11796 return parsed ? new Date(parsed) : null;
11805 Roo.data.Field.prototype = {
11813 * Ext JS Library 1.1.1
11814 * Copyright(c) 2006-2007, Ext JS, LLC.
11816 * Originally Released Under LGPL - original licence link has changed is not relivant.
11819 * <script type="text/javascript">
11822 // Base class for reading structured data from a data source. This class is intended to be
11823 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11826 * @class Roo.data.DataReader
11827 * Base class for reading structured data from a data source. This class is intended to be
11828 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11831 Roo.data.DataReader = function(meta, recordType){
11835 this.recordType = recordType instanceof Array ?
11836 Roo.data.Record.create(recordType) : recordType;
11839 Roo.data.DataReader.prototype = {
11841 * Create an empty record
11842 * @param {Object} data (optional) - overlay some values
11843 * @return {Roo.data.Record} record created.
11845 newRow : function(d) {
11847 this.recordType.prototype.fields.each(function(c) {
11849 case 'int' : da[c.name] = 0; break;
11850 case 'date' : da[c.name] = new Date(); break;
11851 case 'float' : da[c.name] = 0.0; break;
11852 case 'boolean' : da[c.name] = false; break;
11853 default : da[c.name] = ""; break;
11857 return new this.recordType(Roo.apply(da, d));
11862 * Ext JS Library 1.1.1
11863 * Copyright(c) 2006-2007, Ext JS, LLC.
11865 * Originally Released Under LGPL - original licence link has changed is not relivant.
11868 * <script type="text/javascript">
11872 * @class Roo.data.DataProxy
11873 * @extends Roo.data.Observable
11874 * This class is an abstract base class for implementations which provide retrieval of
11875 * unformatted data objects.<br>
11877 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11878 * (of the appropriate type which knows how to parse the data object) to provide a block of
11879 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11881 * Custom implementations must implement the load method as described in
11882 * {@link Roo.data.HttpProxy#load}.
11884 Roo.data.DataProxy = function(){
11887 * @event beforeload
11888 * Fires before a network request is made to retrieve a data object.
11889 * @param {Object} This DataProxy object.
11890 * @param {Object} params The params parameter to the load function.
11895 * Fires before the load method's callback is called.
11896 * @param {Object} This DataProxy object.
11897 * @param {Object} o The data object.
11898 * @param {Object} arg The callback argument object passed to the load function.
11902 * @event loadexception
11903 * Fires if an Exception occurs during data retrieval.
11904 * @param {Object} This DataProxy object.
11905 * @param {Object} o The data object.
11906 * @param {Object} arg The callback argument object passed to the load function.
11907 * @param {Object} e The Exception.
11909 loadexception : true
11911 Roo.data.DataProxy.superclass.constructor.call(this);
11914 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11917 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11921 * Ext JS Library 1.1.1
11922 * Copyright(c) 2006-2007, Ext JS, LLC.
11924 * Originally Released Under LGPL - original licence link has changed is not relivant.
11927 * <script type="text/javascript">
11930 * @class Roo.data.MemoryProxy
11931 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11932 * to the Reader when its load method is called.
11934 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11936 Roo.data.MemoryProxy = function(data){
11940 Roo.data.MemoryProxy.superclass.constructor.call(this);
11944 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11947 * Load data from the requested source (in this case an in-memory
11948 * data object passed to the constructor), read the data object into
11949 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11950 * process that block using the passed callback.
11951 * @param {Object} params This parameter is not used by the MemoryProxy class.
11952 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11953 * object into a block of Roo.data.Records.
11954 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11955 * The function must be passed <ul>
11956 * <li>The Record block object</li>
11957 * <li>The "arg" argument from the load function</li>
11958 * <li>A boolean success indicator</li>
11960 * @param {Object} scope The scope in which to call the callback
11961 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11963 load : function(params, reader, callback, scope, arg){
11964 params = params || {};
11967 result = reader.readRecords(this.data);
11969 this.fireEvent("loadexception", this, arg, null, e);
11970 callback.call(scope, null, arg, false);
11973 callback.call(scope, result, arg, true);
11977 update : function(params, records){
11982 * Ext JS Library 1.1.1
11983 * Copyright(c) 2006-2007, Ext JS, LLC.
11985 * Originally Released Under LGPL - original licence link has changed is not relivant.
11988 * <script type="text/javascript">
11991 * @class Roo.data.HttpProxy
11992 * @extends Roo.data.DataProxy
11993 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11994 * configured to reference a certain URL.<br><br>
11996 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11997 * from which the running page was served.<br><br>
11999 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12001 * Be aware that to enable the browser to parse an XML document, the server must set
12002 * the Content-Type header in the HTTP response to "text/xml".
12004 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12005 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12006 * will be used to make the request.
12008 Roo.data.HttpProxy = function(conn){
12009 Roo.data.HttpProxy.superclass.constructor.call(this);
12010 // is conn a conn config or a real conn?
12012 this.useAjax = !conn || !conn.events;
12016 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12017 // thse are take from connection...
12020 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12023 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12024 * extra parameters to each request made by this object. (defaults to undefined)
12027 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12028 * to each request made by this object. (defaults to undefined)
12031 * @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)
12034 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12037 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12043 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12047 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12048 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12049 * a finer-grained basis than the DataProxy events.
12051 getConnection : function(){
12052 return this.useAjax ? Roo.Ajax : this.conn;
12056 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12057 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12058 * process that block using the passed callback.
12059 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12060 * for the request to the remote server.
12061 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12062 * object into a block of Roo.data.Records.
12063 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12064 * The function must be passed <ul>
12065 * <li>The Record block object</li>
12066 * <li>The "arg" argument from the load function</li>
12067 * <li>A boolean success indicator</li>
12069 * @param {Object} scope The scope in which to call the callback
12070 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12072 load : function(params, reader, callback, scope, arg){
12073 if(this.fireEvent("beforeload", this, params) !== false){
12075 params : params || {},
12077 callback : callback,
12082 callback : this.loadResponse,
12086 Roo.applyIf(o, this.conn);
12087 if(this.activeRequest){
12088 Roo.Ajax.abort(this.activeRequest);
12090 this.activeRequest = Roo.Ajax.request(o);
12092 this.conn.request(o);
12095 callback.call(scope||this, null, arg, false);
12100 loadResponse : function(o, success, response){
12101 delete this.activeRequest;
12103 this.fireEvent("loadexception", this, o, response);
12104 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12109 result = o.reader.read(response);
12111 this.fireEvent("loadexception", this, o, response, e);
12112 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12116 this.fireEvent("load", this, o, o.request.arg);
12117 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12121 update : function(dataSet){
12126 updateResponse : function(dataSet){
12131 * Ext JS Library 1.1.1
12132 * Copyright(c) 2006-2007, Ext JS, LLC.
12134 * Originally Released Under LGPL - original licence link has changed is not relivant.
12137 * <script type="text/javascript">
12141 * @class Roo.data.ScriptTagProxy
12142 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12143 * other than the originating domain of the running page.<br><br>
12145 * <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
12146 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12148 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12149 * source code that is used as the source inside a <script> tag.<br><br>
12151 * In order for the browser to process the returned data, the server must wrap the data object
12152 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12153 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12154 * depending on whether the callback name was passed:
12157 boolean scriptTag = false;
12158 String cb = request.getParameter("callback");
12161 response.setContentType("text/javascript");
12163 response.setContentType("application/x-json");
12165 Writer out = response.getWriter();
12167 out.write(cb + "(");
12169 out.print(dataBlock.toJsonString());
12176 * @param {Object} config A configuration object.
12178 Roo.data.ScriptTagProxy = function(config){
12179 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12180 Roo.apply(this, config);
12181 this.head = document.getElementsByTagName("head")[0];
12184 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12186 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12188 * @cfg {String} url The URL from which to request the data object.
12191 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12195 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12196 * the server the name of the callback function set up by the load call to process the returned data object.
12197 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12198 * javascript output which calls this named function passing the data object as its only parameter.
12200 callbackParam : "callback",
12202 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12203 * name to the request.
12208 * Load data from the configured URL, read the data object into
12209 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12210 * process that block using the passed callback.
12211 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12212 * for the request to the remote server.
12213 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12214 * object into a block of Roo.data.Records.
12215 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12216 * The function must be passed <ul>
12217 * <li>The Record block object</li>
12218 * <li>The "arg" argument from the load function</li>
12219 * <li>A boolean success indicator</li>
12221 * @param {Object} scope The scope in which to call the callback
12222 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12224 load : function(params, reader, callback, scope, arg){
12225 if(this.fireEvent("beforeload", this, params) !== false){
12227 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12229 var url = this.url;
12230 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12232 url += "&_dc=" + (new Date().getTime());
12234 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12237 cb : "stcCallback"+transId,
12238 scriptId : "stcScript"+transId,
12242 callback : callback,
12248 window[trans.cb] = function(o){
12249 conn.handleResponse(o, trans);
12252 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12254 if(this.autoAbort !== false){
12258 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12260 var script = document.createElement("script");
12261 script.setAttribute("src", url);
12262 script.setAttribute("type", "text/javascript");
12263 script.setAttribute("id", trans.scriptId);
12264 this.head.appendChild(script);
12266 this.trans = trans;
12268 callback.call(scope||this, null, arg, false);
12273 isLoading : function(){
12274 return this.trans ? true : false;
12278 * Abort the current server request.
12280 abort : function(){
12281 if(this.isLoading()){
12282 this.destroyTrans(this.trans);
12287 destroyTrans : function(trans, isLoaded){
12288 this.head.removeChild(document.getElementById(trans.scriptId));
12289 clearTimeout(trans.timeoutId);
12291 window[trans.cb] = undefined;
12293 delete window[trans.cb];
12296 // if hasn't been loaded, wait for load to remove it to prevent script error
12297 window[trans.cb] = function(){
12298 window[trans.cb] = undefined;
12300 delete window[trans.cb];
12307 handleResponse : function(o, trans){
12308 this.trans = false;
12309 this.destroyTrans(trans, true);
12312 result = trans.reader.readRecords(o);
12314 this.fireEvent("loadexception", this, o, trans.arg, e);
12315 trans.callback.call(trans.scope||window, null, trans.arg, false);
12318 this.fireEvent("load", this, o, trans.arg);
12319 trans.callback.call(trans.scope||window, result, trans.arg, true);
12323 handleFailure : function(trans){
12324 this.trans = false;
12325 this.destroyTrans(trans, false);
12326 this.fireEvent("loadexception", this, null, trans.arg);
12327 trans.callback.call(trans.scope||window, null, trans.arg, false);
12331 * Ext JS Library 1.1.1
12332 * Copyright(c) 2006-2007, Ext JS, LLC.
12334 * Originally Released Under LGPL - original licence link has changed is not relivant.
12337 * <script type="text/javascript">
12341 * @class Roo.data.JsonReader
12342 * @extends Roo.data.DataReader
12343 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12344 * based on mappings in a provided Roo.data.Record constructor.
12346 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12347 * in the reply previously.
12352 var RecordDef = Roo.data.Record.create([
12353 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12354 {name: 'occupation'} // This field will use "occupation" as the mapping.
12356 var myReader = new Roo.data.JsonReader({
12357 totalProperty: "results", // The property which contains the total dataset size (optional)
12358 root: "rows", // The property which contains an Array of row objects
12359 id: "id" // The property within each row object that provides an ID for the record (optional)
12363 * This would consume a JSON file like this:
12365 { 'results': 2, 'rows': [
12366 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12367 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12370 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12371 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12372 * paged from the remote server.
12373 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12374 * @cfg {String} root name of the property which contains the Array of row objects.
12375 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12376 * @cfg {Array} fields Array of field definition objects
12378 * Create a new JsonReader
12379 * @param {Object} meta Metadata configuration options
12380 * @param {Object} recordType Either an Array of field definition objects,
12381 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12383 Roo.data.JsonReader = function(meta, recordType){
12386 // set some defaults:
12387 Roo.applyIf(meta, {
12388 totalProperty: 'total',
12389 successProperty : 'success',
12394 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12396 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12399 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12400 * Used by Store query builder to append _requestMeta to params.
12403 metaFromRemote : false,
12405 * This method is only used by a DataProxy which has retrieved data from a remote server.
12406 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12407 * @return {Object} data A data block which is used by an Roo.data.Store object as
12408 * a cache of Roo.data.Records.
12410 read : function(response){
12411 var json = response.responseText;
12413 var o = /* eval:var:o */ eval("("+json+")");
12415 throw {message: "JsonReader.read: Json object not found"};
12421 this.metaFromRemote = true;
12422 this.meta = o.metaData;
12423 this.recordType = Roo.data.Record.create(o.metaData.fields);
12424 this.onMetaChange(this.meta, this.recordType, o);
12426 return this.readRecords(o);
12429 // private function a store will implement
12430 onMetaChange : function(meta, recordType, o){
12437 simpleAccess: function(obj, subsc) {
12444 getJsonAccessor: function(){
12446 return function(expr) {
12448 return(re.test(expr))
12449 ? new Function("obj", "return obj." + expr)
12454 return Roo.emptyFn;
12459 * Create a data block containing Roo.data.Records from an XML document.
12460 * @param {Object} o An object which contains an Array of row objects in the property specified
12461 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12462 * which contains the total size of the dataset.
12463 * @return {Object} data A data block which is used by an Roo.data.Store object as
12464 * a cache of Roo.data.Records.
12466 readRecords : function(o){
12468 * After any data loads, the raw JSON data is available for further custom processing.
12472 var s = this.meta, Record = this.recordType,
12473 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12475 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12477 if(s.totalProperty) {
12478 this.getTotal = this.getJsonAccessor(s.totalProperty);
12480 if(s.successProperty) {
12481 this.getSuccess = this.getJsonAccessor(s.successProperty);
12483 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12485 var g = this.getJsonAccessor(s.id);
12486 this.getId = function(rec) {
12488 return (r === undefined || r === "") ? null : r;
12491 this.getId = function(){return null;};
12494 for(var jj = 0; jj < fl; jj++){
12496 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12497 this.ef[jj] = this.getJsonAccessor(map);
12501 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12502 if(s.totalProperty){
12503 var vt = parseInt(this.getTotal(o), 10);
12508 if(s.successProperty){
12509 var vs = this.getSuccess(o);
12510 if(vs === false || vs === 'false'){
12515 for(var i = 0; i < c; i++){
12518 var id = this.getId(n);
12519 for(var j = 0; j < fl; j++){
12521 var v = this.ef[j](n);
12523 Roo.log('missing convert for ' + f.name);
12527 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12529 var record = new Record(values, id);
12531 records[i] = record;
12537 totalRecords : totalRecords
12542 * Ext JS Library 1.1.1
12543 * Copyright(c) 2006-2007, Ext JS, LLC.
12545 * Originally Released Under LGPL - original licence link has changed is not relivant.
12548 * <script type="text/javascript">
12552 * @class Roo.data.ArrayReader
12553 * @extends Roo.data.DataReader
12554 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12555 * Each element of that Array represents a row of data fields. The
12556 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12557 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12561 var RecordDef = Roo.data.Record.create([
12562 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12563 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12565 var myReader = new Roo.data.ArrayReader({
12566 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12570 * This would consume an Array like this:
12572 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12574 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12576 * Create a new JsonReader
12577 * @param {Object} meta Metadata configuration options.
12578 * @param {Object} recordType Either an Array of field definition objects
12579 * as specified to {@link Roo.data.Record#create},
12580 * or an {@link Roo.data.Record} object
12581 * created using {@link Roo.data.Record#create}.
12583 Roo.data.ArrayReader = function(meta, recordType){
12584 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12587 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12589 * Create a data block containing Roo.data.Records from an XML document.
12590 * @param {Object} o An Array of row objects which represents the dataset.
12591 * @return {Object} data A data block which is used by an Roo.data.Store object as
12592 * a cache of Roo.data.Records.
12594 readRecords : function(o){
12595 var sid = this.meta ? this.meta.id : null;
12596 var recordType = this.recordType, fields = recordType.prototype.fields;
12599 for(var i = 0; i < root.length; i++){
12602 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12603 for(var j = 0, jlen = fields.length; j < jlen; j++){
12604 var f = fields.items[j];
12605 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12606 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12608 values[f.name] = v;
12610 var record = new recordType(values, id);
12612 records[records.length] = record;
12616 totalRecords : records.length
12625 * @class Roo.bootstrap.ComboBox
12626 * @extends Roo.bootstrap.TriggerField
12627 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12628 * @cfg {Boolean} append (true|false) default false
12629 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12630 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12631 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12632 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12633 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12634 * @cfg {Boolean} animate default true
12635 * @cfg {Boolean} emptyResultText only for touch device
12636 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12637 * @cfg {String} emptyTitle default ''
12639 * Create a new ComboBox.
12640 * @param {Object} config Configuration options
12642 Roo.bootstrap.ComboBox = function(config){
12643 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12647 * Fires when the dropdown list is expanded
12648 * @param {Roo.bootstrap.ComboBox} combo This combo box
12653 * Fires when the dropdown list is collapsed
12654 * @param {Roo.bootstrap.ComboBox} combo This combo box
12658 * @event beforeselect
12659 * Fires before a list item is selected. Return false to cancel the selection.
12660 * @param {Roo.bootstrap.ComboBox} combo This combo box
12661 * @param {Roo.data.Record} record The data record returned from the underlying store
12662 * @param {Number} index The index of the selected item in the dropdown list
12664 'beforeselect' : true,
12667 * Fires when a list item is selected
12668 * @param {Roo.bootstrap.ComboBox} combo This combo box
12669 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12670 * @param {Number} index The index of the selected item in the dropdown list
12674 * @event beforequery
12675 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12676 * The event object passed has these properties:
12677 * @param {Roo.bootstrap.ComboBox} combo This combo box
12678 * @param {String} query The query
12679 * @param {Boolean} forceAll true to force "all" query
12680 * @param {Boolean} cancel true to cancel the query
12681 * @param {Object} e The query event object
12683 'beforequery': true,
12686 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12687 * @param {Roo.bootstrap.ComboBox} combo This combo box
12692 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12693 * @param {Roo.bootstrap.ComboBox} combo This combo box
12694 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12699 * Fires when the remove value from the combobox array
12700 * @param {Roo.bootstrap.ComboBox} combo This combo box
12704 * @event afterremove
12705 * Fires when the remove value from the combobox array
12706 * @param {Roo.bootstrap.ComboBox} combo This combo box
12708 'afterremove' : true,
12710 * @event specialfilter
12711 * Fires when specialfilter
12712 * @param {Roo.bootstrap.ComboBox} combo This combo box
12714 'specialfilter' : true,
12717 * Fires when tick the element
12718 * @param {Roo.bootstrap.ComboBox} combo This combo box
12722 * @event touchviewdisplay
12723 * Fires when touch view require special display (default is using displayField)
12724 * @param {Roo.bootstrap.ComboBox} combo This combo box
12725 * @param {Object} cfg set html .
12727 'touchviewdisplay' : true
12732 this.tickItems = [];
12734 this.selectedIndex = -1;
12735 if(this.mode == 'local'){
12736 if(config.queryDelay === undefined){
12737 this.queryDelay = 10;
12739 if(config.minChars === undefined){
12745 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12748 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12749 * rendering into an Roo.Editor, defaults to false)
12752 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12753 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12756 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12759 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12760 * the dropdown list (defaults to undefined, with no header element)
12764 * @cfg {String/Roo.Template} tpl The template to use to render the output
12768 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12770 listWidth: undefined,
12772 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12773 * mode = 'remote' or 'text' if mode = 'local')
12775 displayField: undefined,
12778 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12779 * mode = 'remote' or 'value' if mode = 'local').
12780 * Note: use of a valueField requires the user make a selection
12781 * in order for a value to be mapped.
12783 valueField: undefined,
12785 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12790 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12791 * field's data value (defaults to the underlying DOM element's name)
12793 hiddenName: undefined,
12795 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12799 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12801 selectedClass: 'active',
12804 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12808 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12809 * anchor positions (defaults to 'tl-bl')
12811 listAlign: 'tl-bl?',
12813 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12817 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12818 * query specified by the allQuery config option (defaults to 'query')
12820 triggerAction: 'query',
12822 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12823 * (defaults to 4, does not apply if editable = false)
12827 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12828 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12832 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12833 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12837 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12838 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12842 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12843 * when editable = true (defaults to false)
12845 selectOnFocus:false,
12847 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12849 queryParam: 'query',
12851 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12852 * when mode = 'remote' (defaults to 'Loading...')
12854 loadingText: 'Loading...',
12856 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12860 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12864 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12865 * traditional select (defaults to true)
12869 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12873 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12877 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12878 * listWidth has a higher value)
12882 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12883 * allow the user to set arbitrary text into the field (defaults to false)
12885 forceSelection:false,
12887 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12888 * if typeAhead = true (defaults to 250)
12890 typeAheadDelay : 250,
12892 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12893 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12895 valueNotFoundText : undefined,
12897 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12899 blockFocus : false,
12902 * @cfg {Boolean} disableClear Disable showing of clear button.
12904 disableClear : false,
12906 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12908 alwaysQuery : false,
12911 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12916 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12918 invalidClass : "has-warning",
12921 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12923 validClass : "has-success",
12926 * @cfg {Boolean} specialFilter (true|false) special filter default false
12928 specialFilter : false,
12931 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12933 mobileTouchView : true,
12936 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12938 useNativeIOS : false,
12940 ios_options : false,
12952 btnPosition : 'right',
12953 triggerList : true,
12954 showToggleBtn : true,
12956 emptyResultText: 'Empty',
12957 triggerText : 'Select',
12960 // element that contains real text value.. (when hidden is used..)
12962 getAutoCreate : function()
12967 * Render classic select for iso
12970 if(Roo.isIOS && this.useNativeIOS){
12971 cfg = this.getAutoCreateNativeIOS();
12979 if(Roo.isTouch && this.mobileTouchView){
12980 cfg = this.getAutoCreateTouchView();
12987 if(!this.tickable){
12988 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12993 * ComboBox with tickable selections
12996 var align = this.labelAlign || this.parentLabelAlign();
12999 cls : 'form-group roo-combobox-tickable' //input-group
13002 var btn_text_select = '';
13003 var btn_text_done = '';
13004 var btn_text_cancel = '';
13006 if (this.btn_text_show) {
13007 btn_text_select = 'Select';
13008 btn_text_done = 'Done';
13009 btn_text_cancel = 'Cancel';
13014 cls : 'tickable-buttons',
13019 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13020 //html : this.triggerText
13021 html: btn_text_select
13027 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13029 html: btn_text_done
13035 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13037 html: btn_text_cancel
13043 buttons.cn.unshift({
13045 cls: 'roo-select2-search-field-input'
13051 Roo.each(buttons.cn, function(c){
13053 c.cls += ' btn-' + _this.size;
13056 if (_this.disabled) {
13067 cls: 'form-hidden-field'
13071 cls: 'roo-select2-choices',
13075 cls: 'roo-select2-search-field',
13086 cls: 'roo-select2-container input-group roo-select2-container-multi',
13091 // cls: 'typeahead typeahead-long dropdown-menu',
13092 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13097 if(this.hasFeedback && !this.allowBlank){
13101 cls: 'glyphicon form-control-feedback'
13104 combobox.cn.push(feedback);
13108 if (align ==='left' && this.fieldLabel.length) {
13110 cfg.cls += ' roo-form-group-label-left';
13115 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13116 tooltip : 'This field is required'
13121 cls : 'control-label',
13122 html : this.fieldLabel
13134 var labelCfg = cfg.cn[1];
13135 var contentCfg = cfg.cn[2];
13138 if(this.indicatorpos == 'right'){
13144 cls : 'control-label',
13148 html : this.fieldLabel
13152 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13153 tooltip : 'This field is required'
13168 labelCfg = cfg.cn[0];
13169 contentCfg = cfg.cn[1];
13173 if(this.labelWidth > 12){
13174 labelCfg.style = "width: " + this.labelWidth + 'px';
13177 if(this.labelWidth < 13 && this.labelmd == 0){
13178 this.labelmd = this.labelWidth;
13181 if(this.labellg > 0){
13182 labelCfg.cls += ' col-lg-' + this.labellg;
13183 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13186 if(this.labelmd > 0){
13187 labelCfg.cls += ' col-md-' + this.labelmd;
13188 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13191 if(this.labelsm > 0){
13192 labelCfg.cls += ' col-sm-' + this.labelsm;
13193 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13196 if(this.labelxs > 0){
13197 labelCfg.cls += ' col-xs-' + this.labelxs;
13198 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13202 } else if ( this.fieldLabel.length) {
13203 // Roo.log(" label");
13207 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13208 tooltip : 'This field is required'
13212 //cls : 'input-group-addon',
13213 html : this.fieldLabel
13218 if(this.indicatorpos == 'right'){
13222 //cls : 'input-group-addon',
13223 html : this.fieldLabel
13227 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13228 tooltip : 'This field is required'
13237 // Roo.log(" no label && no align");
13244 ['xs','sm','md','lg'].map(function(size){
13245 if (settings[size]) {
13246 cfg.cls += ' col-' + size + '-' + settings[size];
13254 _initEventsCalled : false,
13257 initEvents: function()
13259 if (this._initEventsCalled) { // as we call render... prevent looping...
13262 this._initEventsCalled = true;
13265 throw "can not find store for combo";
13268 this.indicator = this.indicatorEl();
13270 this.store = Roo.factory(this.store, Roo.data);
13271 this.store.parent = this;
13273 // if we are building from html. then this element is so complex, that we can not really
13274 // use the rendered HTML.
13275 // so we have to trash and replace the previous code.
13276 if (Roo.XComponent.build_from_html) {
13277 // remove this element....
13278 var e = this.el.dom, k=0;
13279 while (e ) { e = e.previousSibling; ++k;}
13284 this.rendered = false;
13286 this.render(this.parent().getChildContainer(true), k);
13289 if(Roo.isIOS && this.useNativeIOS){
13290 this.initIOSView();
13298 if(Roo.isTouch && this.mobileTouchView){
13299 this.initTouchView();
13304 this.initTickableEvents();
13308 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13310 if(this.hiddenName){
13312 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13314 this.hiddenField.dom.value =
13315 this.hiddenValue !== undefined ? this.hiddenValue :
13316 this.value !== undefined ? this.value : '';
13318 // prevent input submission
13319 this.el.dom.removeAttribute('name');
13320 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13325 // this.el.dom.setAttribute('autocomplete', 'off');
13328 var cls = 'x-combo-list';
13330 //this.list = new Roo.Layer({
13331 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13337 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13338 _this.list.setWidth(lw);
13341 this.list.on('mouseover', this.onViewOver, this);
13342 this.list.on('mousemove', this.onViewMove, this);
13343 this.list.on('scroll', this.onViewScroll, this);
13346 this.list.swallowEvent('mousewheel');
13347 this.assetHeight = 0;
13350 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13351 this.assetHeight += this.header.getHeight();
13354 this.innerList = this.list.createChild({cls:cls+'-inner'});
13355 this.innerList.on('mouseover', this.onViewOver, this);
13356 this.innerList.on('mousemove', this.onViewMove, this);
13357 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13359 if(this.allowBlank && !this.pageSize && !this.disableClear){
13360 this.footer = this.list.createChild({cls:cls+'-ft'});
13361 this.pageTb = new Roo.Toolbar(this.footer);
13365 this.footer = this.list.createChild({cls:cls+'-ft'});
13366 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13367 {pageSize: this.pageSize});
13371 if (this.pageTb && this.allowBlank && !this.disableClear) {
13373 this.pageTb.add(new Roo.Toolbar.Fill(), {
13374 cls: 'x-btn-icon x-btn-clear',
13376 handler: function()
13379 _this.clearValue();
13380 _this.onSelect(false, -1);
13385 this.assetHeight += this.footer.getHeight();
13390 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13393 this.view = new Roo.View(this.list, this.tpl, {
13394 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13396 //this.view.wrapEl.setDisplayed(false);
13397 this.view.on('click', this.onViewClick, this);
13400 this.store.on('beforeload', this.onBeforeLoad, this);
13401 this.store.on('load', this.onLoad, this);
13402 this.store.on('loadexception', this.onLoadException, this);
13404 if(this.resizable){
13405 this.resizer = new Roo.Resizable(this.list, {
13406 pinned:true, handles:'se'
13408 this.resizer.on('resize', function(r, w, h){
13409 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13410 this.listWidth = w;
13411 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13412 this.restrictHeight();
13414 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13417 if(!this.editable){
13418 this.editable = true;
13419 this.setEditable(false);
13424 if (typeof(this.events.add.listeners) != 'undefined') {
13426 this.addicon = this.wrap.createChild(
13427 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13429 this.addicon.on('click', function(e) {
13430 this.fireEvent('add', this);
13433 if (typeof(this.events.edit.listeners) != 'undefined') {
13435 this.editicon = this.wrap.createChild(
13436 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13437 if (this.addicon) {
13438 this.editicon.setStyle('margin-left', '40px');
13440 this.editicon.on('click', function(e) {
13442 // we fire even if inothing is selected..
13443 this.fireEvent('edit', this, this.lastData );
13449 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13450 "up" : function(e){
13451 this.inKeyMode = true;
13455 "down" : function(e){
13456 if(!this.isExpanded()){
13457 this.onTriggerClick();
13459 this.inKeyMode = true;
13464 "enter" : function(e){
13465 // this.onViewClick();
13469 if(this.fireEvent("specialkey", this, e)){
13470 this.onViewClick(false);
13476 "esc" : function(e){
13480 "tab" : function(e){
13483 if(this.fireEvent("specialkey", this, e)){
13484 this.onViewClick(false);
13492 doRelay : function(foo, bar, hname){
13493 if(hname == 'down' || this.scope.isExpanded()){
13494 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13503 this.queryDelay = Math.max(this.queryDelay || 10,
13504 this.mode == 'local' ? 10 : 250);
13507 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13509 if(this.typeAhead){
13510 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13512 if(this.editable !== false){
13513 this.inputEl().on("keyup", this.onKeyUp, this);
13515 if(this.forceSelection){
13516 this.inputEl().on('blur', this.doForce, this);
13520 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13521 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13525 initTickableEvents: function()
13529 if(this.hiddenName){
13531 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13533 this.hiddenField.dom.value =
13534 this.hiddenValue !== undefined ? this.hiddenValue :
13535 this.value !== undefined ? this.value : '';
13537 // prevent input submission
13538 this.el.dom.removeAttribute('name');
13539 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13544 // this.list = this.el.select('ul.dropdown-menu',true).first();
13546 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13547 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13548 if(this.triggerList){
13549 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13552 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13553 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13555 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13556 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13558 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13559 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13561 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13562 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13563 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13566 this.cancelBtn.hide();
13571 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13572 _this.list.setWidth(lw);
13575 this.list.on('mouseover', this.onViewOver, this);
13576 this.list.on('mousemove', this.onViewMove, this);
13578 this.list.on('scroll', this.onViewScroll, this);
13581 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>';
13584 this.view = new Roo.View(this.list, this.tpl, {
13585 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13588 //this.view.wrapEl.setDisplayed(false);
13589 this.view.on('click', this.onViewClick, this);
13593 this.store.on('beforeload', this.onBeforeLoad, this);
13594 this.store.on('load', this.onLoad, this);
13595 this.store.on('loadexception', this.onLoadException, this);
13598 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13599 "up" : function(e){
13600 this.inKeyMode = true;
13604 "down" : function(e){
13605 this.inKeyMode = true;
13609 "enter" : function(e){
13610 if(this.fireEvent("specialkey", this, e)){
13611 this.onViewClick(false);
13617 "esc" : function(e){
13618 this.onTickableFooterButtonClick(e, false, false);
13621 "tab" : function(e){
13622 this.fireEvent("specialkey", this, e);
13624 this.onTickableFooterButtonClick(e, false, false);
13631 doRelay : function(e, fn, key){
13632 if(this.scope.isExpanded()){
13633 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13642 this.queryDelay = Math.max(this.queryDelay || 10,
13643 this.mode == 'local' ? 10 : 250);
13646 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13648 if(this.typeAhead){
13649 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13652 if(this.editable !== false){
13653 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13656 this.indicator = this.indicatorEl();
13658 if(this.indicator){
13659 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13660 this.indicator.hide();
13665 onDestroy : function(){
13667 this.view.setStore(null);
13668 this.view.el.removeAllListeners();
13669 this.view.el.remove();
13670 this.view.purgeListeners();
13673 this.list.dom.innerHTML = '';
13677 this.store.un('beforeload', this.onBeforeLoad, this);
13678 this.store.un('load', this.onLoad, this);
13679 this.store.un('loadexception', this.onLoadException, this);
13681 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13685 fireKey : function(e){
13686 if(e.isNavKeyPress() && !this.list.isVisible()){
13687 this.fireEvent("specialkey", this, e);
13692 onResize: function(w, h){
13693 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13695 // if(typeof w != 'number'){
13696 // // we do not handle it!?!?
13699 // var tw = this.trigger.getWidth();
13700 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13701 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13703 // this.inputEl().setWidth( this.adjustWidth('input', x));
13705 // //this.trigger.setStyle('left', x+'px');
13707 // if(this.list && this.listWidth === undefined){
13708 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13709 // this.list.setWidth(lw);
13710 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13718 * Allow or prevent the user from directly editing the field text. If false is passed,
13719 * the user will only be able to select from the items defined in the dropdown list. This method
13720 * is the runtime equivalent of setting the 'editable' config option at config time.
13721 * @param {Boolean} value True to allow the user to directly edit the field text
13723 setEditable : function(value){
13724 if(value == this.editable){
13727 this.editable = value;
13729 this.inputEl().dom.setAttribute('readOnly', true);
13730 this.inputEl().on('mousedown', this.onTriggerClick, this);
13731 this.inputEl().addClass('x-combo-noedit');
13733 this.inputEl().dom.setAttribute('readOnly', false);
13734 this.inputEl().un('mousedown', this.onTriggerClick, this);
13735 this.inputEl().removeClass('x-combo-noedit');
13741 onBeforeLoad : function(combo,opts){
13742 if(!this.hasFocus){
13746 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13748 this.restrictHeight();
13749 this.selectedIndex = -1;
13753 onLoad : function(){
13755 this.hasQuery = false;
13757 if(!this.hasFocus){
13761 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13762 this.loading.hide();
13765 if(this.store.getCount() > 0){
13768 this.restrictHeight();
13769 if(this.lastQuery == this.allQuery){
13770 if(this.editable && !this.tickable){
13771 this.inputEl().dom.select();
13775 !this.selectByValue(this.value, true) &&
13778 !this.store.lastOptions ||
13779 typeof(this.store.lastOptions.add) == 'undefined' ||
13780 this.store.lastOptions.add != true
13783 this.select(0, true);
13786 if(this.autoFocus){
13789 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13790 this.taTask.delay(this.typeAheadDelay);
13794 this.onEmptyResults();
13800 onLoadException : function()
13802 this.hasQuery = false;
13804 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13805 this.loading.hide();
13808 if(this.tickable && this.editable){
13813 // only causes errors at present
13814 //Roo.log(this.store.reader.jsonData);
13815 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13817 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13823 onTypeAhead : function(){
13824 if(this.store.getCount() > 0){
13825 var r = this.store.getAt(0);
13826 var newValue = r.data[this.displayField];
13827 var len = newValue.length;
13828 var selStart = this.getRawValue().length;
13830 if(selStart != len){
13831 this.setRawValue(newValue);
13832 this.selectText(selStart, newValue.length);
13838 onSelect : function(record, index){
13840 if(this.fireEvent('beforeselect', this, record, index) !== false){
13842 this.setFromData(index > -1 ? record.data : false);
13845 this.fireEvent('select', this, record, index);
13850 * Returns the currently selected field value or empty string if no value is set.
13851 * @return {String} value The selected value
13853 getValue : function()
13855 if(Roo.isIOS && this.useNativeIOS){
13856 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13860 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13863 if(this.valueField){
13864 return typeof this.value != 'undefined' ? this.value : '';
13866 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13870 getRawValue : function()
13872 if(Roo.isIOS && this.useNativeIOS){
13873 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13876 var v = this.inputEl().getValue();
13882 * Clears any text/value currently set in the field
13884 clearValue : function(){
13886 if(this.hiddenField){
13887 this.hiddenField.dom.value = '';
13890 this.setRawValue('');
13891 this.lastSelectionText = '';
13892 this.lastData = false;
13894 var close = this.closeTriggerEl();
13905 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13906 * will be displayed in the field. If the value does not match the data value of an existing item,
13907 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13908 * Otherwise the field will be blank (although the value will still be set).
13909 * @param {String} value The value to match
13911 setValue : function(v)
13913 if(Roo.isIOS && this.useNativeIOS){
13914 this.setIOSValue(v);
13924 if(this.valueField){
13925 var r = this.findRecord(this.valueField, v);
13927 text = r.data[this.displayField];
13928 }else if(this.valueNotFoundText !== undefined){
13929 text = this.valueNotFoundText;
13932 this.lastSelectionText = text;
13933 if(this.hiddenField){
13934 this.hiddenField.dom.value = v;
13936 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13939 var close = this.closeTriggerEl();
13942 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13948 * @property {Object} the last set data for the element
13953 * Sets the value of the field based on a object which is related to the record format for the store.
13954 * @param {Object} value the value to set as. or false on reset?
13956 setFromData : function(o){
13963 var dv = ''; // display value
13964 var vv = ''; // value value..
13966 if (this.displayField) {
13967 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13969 // this is an error condition!!!
13970 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13973 if(this.valueField){
13974 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13977 var close = this.closeTriggerEl();
13980 if(dv.length || vv * 1 > 0){
13982 this.blockFocus=true;
13988 if(this.hiddenField){
13989 this.hiddenField.dom.value = vv;
13991 this.lastSelectionText = dv;
13992 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13996 // no hidden field.. - we store the value in 'value', but still display
13997 // display field!!!!
13998 this.lastSelectionText = dv;
13999 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14006 reset : function(){
14007 // overridden so that last data is reset..
14014 this.setValue(this.originalValue);
14015 //this.clearInvalid();
14016 this.lastData = false;
14018 this.view.clearSelections();
14024 findRecord : function(prop, value){
14026 if(this.store.getCount() > 0){
14027 this.store.each(function(r){
14028 if(r.data[prop] == value){
14038 getName: function()
14040 // returns hidden if it's set..
14041 if (!this.rendered) {return ''};
14042 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14046 onViewMove : function(e, t){
14047 this.inKeyMode = false;
14051 onViewOver : function(e, t){
14052 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14055 var item = this.view.findItemFromChild(t);
14058 var index = this.view.indexOf(item);
14059 this.select(index, false);
14064 onViewClick : function(view, doFocus, el, e)
14066 var index = this.view.getSelectedIndexes()[0];
14068 var r = this.store.getAt(index);
14072 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14079 Roo.each(this.tickItems, function(v,k){
14081 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14083 _this.tickItems.splice(k, 1);
14085 if(typeof(e) == 'undefined' && view == false){
14086 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14098 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14099 this.tickItems.push(r.data);
14102 if(typeof(e) == 'undefined' && view == false){
14103 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14110 this.onSelect(r, index);
14112 if(doFocus !== false && !this.blockFocus){
14113 this.inputEl().focus();
14118 restrictHeight : function(){
14119 //this.innerList.dom.style.height = '';
14120 //var inner = this.innerList.dom;
14121 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14122 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14123 //this.list.beginUpdate();
14124 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14125 this.list.alignTo(this.inputEl(), this.listAlign);
14126 this.list.alignTo(this.inputEl(), this.listAlign);
14127 //this.list.endUpdate();
14131 onEmptyResults : function(){
14133 if(this.tickable && this.editable){
14134 this.hasFocus = false;
14135 this.restrictHeight();
14143 * Returns true if the dropdown list is expanded, else false.
14145 isExpanded : function(){
14146 return this.list.isVisible();
14150 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14151 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14152 * @param {String} value The data value of the item to select
14153 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14154 * selected item if it is not currently in view (defaults to true)
14155 * @return {Boolean} True if the value matched an item in the list, else false
14157 selectByValue : function(v, scrollIntoView){
14158 if(v !== undefined && v !== null){
14159 var r = this.findRecord(this.valueField || this.displayField, v);
14161 this.select(this.store.indexOf(r), scrollIntoView);
14169 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14170 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14171 * @param {Number} index The zero-based index of the list item to select
14172 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14173 * selected item if it is not currently in view (defaults to true)
14175 select : function(index, scrollIntoView){
14176 this.selectedIndex = index;
14177 this.view.select(index);
14178 if(scrollIntoView !== false){
14179 var el = this.view.getNode(index);
14181 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14184 this.list.scrollChildIntoView(el, false);
14190 selectNext : function(){
14191 var ct = this.store.getCount();
14193 if(this.selectedIndex == -1){
14195 }else if(this.selectedIndex < ct-1){
14196 this.select(this.selectedIndex+1);
14202 selectPrev : function(){
14203 var ct = this.store.getCount();
14205 if(this.selectedIndex == -1){
14207 }else if(this.selectedIndex != 0){
14208 this.select(this.selectedIndex-1);
14214 onKeyUp : function(e){
14215 if(this.editable !== false && !e.isSpecialKey()){
14216 this.lastKey = e.getKey();
14217 this.dqTask.delay(this.queryDelay);
14222 validateBlur : function(){
14223 return !this.list || !this.list.isVisible();
14227 initQuery : function(){
14229 var v = this.getRawValue();
14231 if(this.tickable && this.editable){
14232 v = this.tickableInputEl().getValue();
14239 doForce : function(){
14240 if(this.inputEl().dom.value.length > 0){
14241 this.inputEl().dom.value =
14242 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14248 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14249 * query allowing the query action to be canceled if needed.
14250 * @param {String} query The SQL query to execute
14251 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14252 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14253 * saved in the current store (defaults to false)
14255 doQuery : function(q, forceAll){
14257 if(q === undefined || q === null){
14262 forceAll: forceAll,
14266 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14271 forceAll = qe.forceAll;
14272 if(forceAll === true || (q.length >= this.minChars)){
14274 this.hasQuery = true;
14276 if(this.lastQuery != q || this.alwaysQuery){
14277 this.lastQuery = q;
14278 if(this.mode == 'local'){
14279 this.selectedIndex = -1;
14281 this.store.clearFilter();
14284 if(this.specialFilter){
14285 this.fireEvent('specialfilter', this);
14290 this.store.filter(this.displayField, q);
14293 this.store.fireEvent("datachanged", this.store);
14300 this.store.baseParams[this.queryParam] = q;
14302 var options = {params : this.getParams(q)};
14305 options.add = true;
14306 options.params.start = this.page * this.pageSize;
14309 this.store.load(options);
14312 * this code will make the page width larger, at the beginning, the list not align correctly,
14313 * we should expand the list on onLoad
14314 * so command out it
14319 this.selectedIndex = -1;
14324 this.loadNext = false;
14328 getParams : function(q){
14330 //p[this.queryParam] = q;
14334 p.limit = this.pageSize;
14340 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14342 collapse : function(){
14343 if(!this.isExpanded()){
14349 this.hasFocus = false;
14353 this.cancelBtn.hide();
14354 this.trigger.show();
14357 this.tickableInputEl().dom.value = '';
14358 this.tickableInputEl().blur();
14363 Roo.get(document).un('mousedown', this.collapseIf, this);
14364 Roo.get(document).un('mousewheel', this.collapseIf, this);
14365 if (!this.editable) {
14366 Roo.get(document).un('keydown', this.listKeyPress, this);
14368 this.fireEvent('collapse', this);
14374 collapseIf : function(e){
14375 var in_combo = e.within(this.el);
14376 var in_list = e.within(this.list);
14377 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14379 if (in_combo || in_list || is_list) {
14380 //e.stopPropagation();
14385 this.onTickableFooterButtonClick(e, false, false);
14393 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14395 expand : function(){
14397 if(this.isExpanded() || !this.hasFocus){
14401 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14402 this.list.setWidth(lw);
14408 this.restrictHeight();
14412 this.tickItems = Roo.apply([], this.item);
14415 this.cancelBtn.show();
14416 this.trigger.hide();
14419 this.tickableInputEl().focus();
14424 Roo.get(document).on('mousedown', this.collapseIf, this);
14425 Roo.get(document).on('mousewheel', this.collapseIf, this);
14426 if (!this.editable) {
14427 Roo.get(document).on('keydown', this.listKeyPress, this);
14430 this.fireEvent('expand', this);
14434 // Implements the default empty TriggerField.onTriggerClick function
14435 onTriggerClick : function(e)
14437 Roo.log('trigger click');
14439 if(this.disabled || !this.triggerList){
14444 this.loadNext = false;
14446 if(this.isExpanded()){
14448 if (!this.blockFocus) {
14449 this.inputEl().focus();
14453 this.hasFocus = true;
14454 if(this.triggerAction == 'all') {
14455 this.doQuery(this.allQuery, true);
14457 this.doQuery(this.getRawValue());
14459 if (!this.blockFocus) {
14460 this.inputEl().focus();
14465 onTickableTriggerClick : function(e)
14472 this.loadNext = false;
14473 this.hasFocus = true;
14475 if(this.triggerAction == 'all') {
14476 this.doQuery(this.allQuery, true);
14478 this.doQuery(this.getRawValue());
14482 onSearchFieldClick : function(e)
14484 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14485 this.onTickableFooterButtonClick(e, false, false);
14489 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14494 this.loadNext = false;
14495 this.hasFocus = true;
14497 if(this.triggerAction == 'all') {
14498 this.doQuery(this.allQuery, true);
14500 this.doQuery(this.getRawValue());
14504 listKeyPress : function(e)
14506 //Roo.log('listkeypress');
14507 // scroll to first matching element based on key pres..
14508 if (e.isSpecialKey()) {
14511 var k = String.fromCharCode(e.getKey()).toUpperCase();
14514 var csel = this.view.getSelectedNodes();
14515 var cselitem = false;
14517 var ix = this.view.indexOf(csel[0]);
14518 cselitem = this.store.getAt(ix);
14519 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14525 this.store.each(function(v) {
14527 // start at existing selection.
14528 if (cselitem.id == v.id) {
14534 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14535 match = this.store.indexOf(v);
14541 if (match === false) {
14542 return true; // no more action?
14545 this.view.select(match);
14546 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14547 sn.scrollIntoView(sn.dom.parentNode, false);
14550 onViewScroll : function(e, t){
14552 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){
14556 this.hasQuery = true;
14558 this.loading = this.list.select('.loading', true).first();
14560 if(this.loading === null){
14561 this.list.createChild({
14563 cls: 'loading roo-select2-more-results roo-select2-active',
14564 html: 'Loading more results...'
14567 this.loading = this.list.select('.loading', true).first();
14569 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14571 this.loading.hide();
14574 this.loading.show();
14579 this.loadNext = true;
14581 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14586 addItem : function(o)
14588 var dv = ''; // display value
14590 if (this.displayField) {
14591 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14593 // this is an error condition!!!
14594 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14601 var choice = this.choices.createChild({
14603 cls: 'roo-select2-search-choice',
14612 cls: 'roo-select2-search-choice-close fa fa-times',
14617 }, this.searchField);
14619 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14621 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14629 this.inputEl().dom.value = '';
14634 onRemoveItem : function(e, _self, o)
14636 e.preventDefault();
14638 this.lastItem = Roo.apply([], this.item);
14640 var index = this.item.indexOf(o.data) * 1;
14643 Roo.log('not this item?!');
14647 this.item.splice(index, 1);
14652 this.fireEvent('remove', this, e);
14658 syncValue : function()
14660 if(!this.item.length){
14667 Roo.each(this.item, function(i){
14668 if(_this.valueField){
14669 value.push(i[_this.valueField]);
14676 this.value = value.join(',');
14678 if(this.hiddenField){
14679 this.hiddenField.dom.value = this.value;
14682 this.store.fireEvent("datachanged", this.store);
14687 clearItem : function()
14689 if(!this.multiple){
14695 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14703 if(this.tickable && !Roo.isTouch){
14704 this.view.refresh();
14708 inputEl: function ()
14710 if(Roo.isIOS && this.useNativeIOS){
14711 return this.el.select('select.roo-ios-select', true).first();
14714 if(Roo.isTouch && this.mobileTouchView){
14715 return this.el.select('input.form-control',true).first();
14719 return this.searchField;
14722 return this.el.select('input.form-control',true).first();
14725 onTickableFooterButtonClick : function(e, btn, el)
14727 e.preventDefault();
14729 this.lastItem = Roo.apply([], this.item);
14731 if(btn && btn.name == 'cancel'){
14732 this.tickItems = Roo.apply([], this.item);
14741 Roo.each(this.tickItems, function(o){
14749 validate : function()
14751 if(this.getVisibilityEl().hasClass('hidden')){
14755 var v = this.getRawValue();
14758 v = this.getValue();
14761 if(this.disabled || this.allowBlank || v.length){
14766 this.markInvalid();
14770 tickableInputEl : function()
14772 if(!this.tickable || !this.editable){
14773 return this.inputEl();
14776 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14780 getAutoCreateTouchView : function()
14785 cls: 'form-group' //input-group
14791 type : this.inputType,
14792 cls : 'form-control x-combo-noedit',
14793 autocomplete: 'new-password',
14794 placeholder : this.placeholder || '',
14799 input.name = this.name;
14803 input.cls += ' input-' + this.size;
14806 if (this.disabled) {
14807 input.disabled = true;
14818 inputblock.cls += ' input-group';
14820 inputblock.cn.unshift({
14822 cls : 'input-group-addon',
14827 if(this.removable && !this.multiple){
14828 inputblock.cls += ' roo-removable';
14830 inputblock.cn.push({
14833 cls : 'roo-combo-removable-btn close'
14837 if(this.hasFeedback && !this.allowBlank){
14839 inputblock.cls += ' has-feedback';
14841 inputblock.cn.push({
14843 cls: 'glyphicon form-control-feedback'
14850 inputblock.cls += (this.before) ? '' : ' input-group';
14852 inputblock.cn.push({
14854 cls : 'input-group-addon',
14865 cls: 'form-hidden-field'
14879 cls: 'form-hidden-field'
14883 cls: 'roo-select2-choices',
14887 cls: 'roo-select2-search-field',
14900 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14906 if(!this.multiple && this.showToggleBtn){
14913 if (this.caret != false) {
14916 cls: 'fa fa-' + this.caret
14923 cls : 'input-group-addon btn dropdown-toggle',
14928 cls: 'combobox-clear',
14942 combobox.cls += ' roo-select2-container-multi';
14945 var align = this.labelAlign || this.parentLabelAlign();
14947 if (align ==='left' && this.fieldLabel.length) {
14952 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14953 tooltip : 'This field is required'
14957 cls : 'control-label',
14958 html : this.fieldLabel
14969 var labelCfg = cfg.cn[1];
14970 var contentCfg = cfg.cn[2];
14973 if(this.indicatorpos == 'right'){
14978 cls : 'control-label',
14982 html : this.fieldLabel
14986 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14987 tooltip : 'This field is required'
15000 labelCfg = cfg.cn[0];
15001 contentCfg = cfg.cn[1];
15006 if(this.labelWidth > 12){
15007 labelCfg.style = "width: " + this.labelWidth + 'px';
15010 if(this.labelWidth < 13 && this.labelmd == 0){
15011 this.labelmd = this.labelWidth;
15014 if(this.labellg > 0){
15015 labelCfg.cls += ' col-lg-' + this.labellg;
15016 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15019 if(this.labelmd > 0){
15020 labelCfg.cls += ' col-md-' + this.labelmd;
15021 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15024 if(this.labelsm > 0){
15025 labelCfg.cls += ' col-sm-' + this.labelsm;
15026 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15029 if(this.labelxs > 0){
15030 labelCfg.cls += ' col-xs-' + this.labelxs;
15031 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15035 } else if ( this.fieldLabel.length) {
15039 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15040 tooltip : 'This field is required'
15044 cls : 'control-label',
15045 html : this.fieldLabel
15056 if(this.indicatorpos == 'right'){
15060 cls : 'control-label',
15061 html : this.fieldLabel,
15065 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15066 tooltip : 'This field is required'
15083 var settings = this;
15085 ['xs','sm','md','lg'].map(function(size){
15086 if (settings[size]) {
15087 cfg.cls += ' col-' + size + '-' + settings[size];
15094 initTouchView : function()
15096 this.renderTouchView();
15098 this.touchViewEl.on('scroll', function(){
15099 this.el.dom.scrollTop = 0;
15102 this.originalValue = this.getValue();
15104 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15106 this.inputEl().on("click", this.showTouchView, this);
15107 if (this.triggerEl) {
15108 this.triggerEl.on("click", this.showTouchView, this);
15112 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15113 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15115 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15117 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15118 this.store.on('load', this.onTouchViewLoad, this);
15119 this.store.on('loadexception', this.onTouchViewLoadException, this);
15121 if(this.hiddenName){
15123 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15125 this.hiddenField.dom.value =
15126 this.hiddenValue !== undefined ? this.hiddenValue :
15127 this.value !== undefined ? this.value : '';
15129 this.el.dom.removeAttribute('name');
15130 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15134 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15135 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15138 if(this.removable && !this.multiple){
15139 var close = this.closeTriggerEl();
15141 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15142 close.on('click', this.removeBtnClick, this, close);
15146 * fix the bug in Safari iOS8
15148 this.inputEl().on("focus", function(e){
15149 document.activeElement.blur();
15157 renderTouchView : function()
15159 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15160 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15162 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15163 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15165 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15166 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15167 this.touchViewBodyEl.setStyle('overflow', 'auto');
15169 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15170 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15172 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15173 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15177 showTouchView : function()
15183 this.touchViewHeaderEl.hide();
15185 if(this.modalTitle.length){
15186 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15187 this.touchViewHeaderEl.show();
15190 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15191 this.touchViewEl.show();
15193 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15195 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15196 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15198 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15200 if(this.modalTitle.length){
15201 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15204 this.touchViewBodyEl.setHeight(bodyHeight);
15208 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15210 this.touchViewEl.addClass('in');
15213 this.doTouchViewQuery();
15217 hideTouchView : function()
15219 this.touchViewEl.removeClass('in');
15223 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15225 this.touchViewEl.setStyle('display', 'none');
15230 setTouchViewValue : function()
15237 Roo.each(this.tickItems, function(o){
15242 this.hideTouchView();
15245 doTouchViewQuery : function()
15254 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15258 if(!this.alwaysQuery || this.mode == 'local'){
15259 this.onTouchViewLoad();
15266 onTouchViewBeforeLoad : function(combo,opts)
15272 onTouchViewLoad : function()
15274 if(this.store.getCount() < 1){
15275 this.onTouchViewEmptyResults();
15279 this.clearTouchView();
15281 var rawValue = this.getRawValue();
15283 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15285 this.tickItems = [];
15287 this.store.data.each(function(d, rowIndex){
15288 var row = this.touchViewListGroup.createChild(template);
15290 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15291 row.addClass(d.data.cls);
15294 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15297 html : d.data[this.displayField]
15300 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15301 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15304 row.removeClass('selected');
15305 if(!this.multiple && this.valueField &&
15306 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15309 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15310 row.addClass('selected');
15313 if(this.multiple && this.valueField &&
15314 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15318 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15319 this.tickItems.push(d.data);
15322 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15326 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15328 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15330 if(this.modalTitle.length){
15331 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15334 var listHeight = this.touchViewListGroup.getHeight();
15338 if(firstChecked && listHeight > bodyHeight){
15339 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15344 onTouchViewLoadException : function()
15346 this.hideTouchView();
15349 onTouchViewEmptyResults : function()
15351 this.clearTouchView();
15353 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15355 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15359 clearTouchView : function()
15361 this.touchViewListGroup.dom.innerHTML = '';
15364 onTouchViewClick : function(e, el, o)
15366 e.preventDefault();
15369 var rowIndex = o.rowIndex;
15371 var r = this.store.getAt(rowIndex);
15373 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15375 if(!this.multiple){
15376 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15377 c.dom.removeAttribute('checked');
15380 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15382 this.setFromData(r.data);
15384 var close = this.closeTriggerEl();
15390 this.hideTouchView();
15392 this.fireEvent('select', this, r, rowIndex);
15397 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15398 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15399 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15403 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15404 this.addItem(r.data);
15405 this.tickItems.push(r.data);
15409 getAutoCreateNativeIOS : function()
15412 cls: 'form-group' //input-group,
15417 cls : 'roo-ios-select'
15421 combobox.name = this.name;
15424 if (this.disabled) {
15425 combobox.disabled = true;
15428 var settings = this;
15430 ['xs','sm','md','lg'].map(function(size){
15431 if (settings[size]) {
15432 cfg.cls += ' col-' + size + '-' + settings[size];
15442 initIOSView : function()
15444 this.store.on('load', this.onIOSViewLoad, this);
15449 onIOSViewLoad : function()
15451 if(this.store.getCount() < 1){
15455 this.clearIOSView();
15457 if(this.allowBlank) {
15459 var default_text = '-- SELECT --';
15461 if(this.placeholder.length){
15462 default_text = this.placeholder;
15465 if(this.emptyTitle.length){
15466 default_text += ' - ' + this.emptyTitle + ' -';
15469 var opt = this.inputEl().createChild({
15472 html : default_text
15476 o[this.valueField] = 0;
15477 o[this.displayField] = default_text;
15479 this.ios_options.push({
15486 this.store.data.each(function(d, rowIndex){
15490 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15491 html = d.data[this.displayField];
15496 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15497 value = d.data[this.valueField];
15506 if(this.value == d.data[this.valueField]){
15507 option['selected'] = true;
15510 var opt = this.inputEl().createChild(option);
15512 this.ios_options.push({
15519 this.inputEl().on('change', function(){
15520 this.fireEvent('select', this);
15525 clearIOSView: function()
15527 this.inputEl().dom.innerHTML = '';
15529 this.ios_options = [];
15532 setIOSValue: function(v)
15536 if(!this.ios_options){
15540 Roo.each(this.ios_options, function(opts){
15542 opts.el.dom.removeAttribute('selected');
15544 if(opts.data[this.valueField] != v){
15548 opts.el.dom.setAttribute('selected', true);
15554 * @cfg {Boolean} grow
15558 * @cfg {Number} growMin
15562 * @cfg {Number} growMax
15571 Roo.apply(Roo.bootstrap.ComboBox, {
15575 cls: 'modal-header',
15597 cls: 'list-group-item',
15601 cls: 'roo-combobox-list-group-item-value'
15605 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15619 listItemCheckbox : {
15621 cls: 'list-group-item',
15625 cls: 'roo-combobox-list-group-item-value'
15629 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15645 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15650 cls: 'modal-footer',
15658 cls: 'col-xs-6 text-left',
15661 cls: 'btn btn-danger roo-touch-view-cancel',
15667 cls: 'col-xs-6 text-right',
15670 cls: 'btn btn-success roo-touch-view-ok',
15681 Roo.apply(Roo.bootstrap.ComboBox, {
15683 touchViewTemplate : {
15685 cls: 'modal fade roo-combobox-touch-view',
15689 cls: 'modal-dialog',
15690 style : 'position:fixed', // we have to fix position....
15694 cls: 'modal-content',
15696 Roo.bootstrap.ComboBox.header,
15697 Roo.bootstrap.ComboBox.body,
15698 Roo.bootstrap.ComboBox.footer
15707 * Ext JS Library 1.1.1
15708 * Copyright(c) 2006-2007, Ext JS, LLC.
15710 * Originally Released Under LGPL - original licence link has changed is not relivant.
15713 * <script type="text/javascript">
15718 * @extends Roo.util.Observable
15719 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15720 * This class also supports single and multi selection modes. <br>
15721 * Create a data model bound view:
15723 var store = new Roo.data.Store(...);
15725 var view = new Roo.View({
15727 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15729 singleSelect: true,
15730 selectedClass: "ydataview-selected",
15734 // listen for node click?
15735 view.on("click", function(vw, index, node, e){
15736 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15740 dataModel.load("foobar.xml");
15742 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15744 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15745 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15747 * Note: old style constructor is still suported (container, template, config)
15750 * Create a new View
15751 * @param {Object} config The config object
15754 Roo.View = function(config, depreciated_tpl, depreciated_config){
15756 this.parent = false;
15758 if (typeof(depreciated_tpl) == 'undefined') {
15759 // new way.. - universal constructor.
15760 Roo.apply(this, config);
15761 this.el = Roo.get(this.el);
15764 this.el = Roo.get(config);
15765 this.tpl = depreciated_tpl;
15766 Roo.apply(this, depreciated_config);
15768 this.wrapEl = this.el.wrap().wrap();
15769 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15772 if(typeof(this.tpl) == "string"){
15773 this.tpl = new Roo.Template(this.tpl);
15775 // support xtype ctors..
15776 this.tpl = new Roo.factory(this.tpl, Roo);
15780 this.tpl.compile();
15785 * @event beforeclick
15786 * Fires before a click is processed. Returns false to cancel the default action.
15787 * @param {Roo.View} this
15788 * @param {Number} index The index of the target node
15789 * @param {HTMLElement} node The target node
15790 * @param {Roo.EventObject} e The raw event object
15792 "beforeclick" : true,
15795 * Fires when a template node is clicked.
15796 * @param {Roo.View} this
15797 * @param {Number} index The index of the target node
15798 * @param {HTMLElement} node The target node
15799 * @param {Roo.EventObject} e The raw event object
15804 * Fires when a template node is double clicked.
15805 * @param {Roo.View} this
15806 * @param {Number} index The index of the target node
15807 * @param {HTMLElement} node The target node
15808 * @param {Roo.EventObject} e The raw event object
15812 * @event contextmenu
15813 * Fires when a template node is right clicked.
15814 * @param {Roo.View} this
15815 * @param {Number} index The index of the target node
15816 * @param {HTMLElement} node The target node
15817 * @param {Roo.EventObject} e The raw event object
15819 "contextmenu" : true,
15821 * @event selectionchange
15822 * Fires when the selected nodes change.
15823 * @param {Roo.View} this
15824 * @param {Array} selections Array of the selected nodes
15826 "selectionchange" : true,
15829 * @event beforeselect
15830 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15831 * @param {Roo.View} this
15832 * @param {HTMLElement} node The node to be selected
15833 * @param {Array} selections Array of currently selected nodes
15835 "beforeselect" : true,
15837 * @event preparedata
15838 * Fires on every row to render, to allow you to change the data.
15839 * @param {Roo.View} this
15840 * @param {Object} data to be rendered (change this)
15842 "preparedata" : true
15850 "click": this.onClick,
15851 "dblclick": this.onDblClick,
15852 "contextmenu": this.onContextMenu,
15856 this.selections = [];
15858 this.cmp = new Roo.CompositeElementLite([]);
15860 this.store = Roo.factory(this.store, Roo.data);
15861 this.setStore(this.store, true);
15864 if ( this.footer && this.footer.xtype) {
15866 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15868 this.footer.dataSource = this.store;
15869 this.footer.container = fctr;
15870 this.footer = Roo.factory(this.footer, Roo);
15871 fctr.insertFirst(this.el);
15873 // this is a bit insane - as the paging toolbar seems to detach the el..
15874 // dom.parentNode.parentNode.parentNode
15875 // they get detached?
15879 Roo.View.superclass.constructor.call(this);
15884 Roo.extend(Roo.View, Roo.util.Observable, {
15887 * @cfg {Roo.data.Store} store Data store to load data from.
15892 * @cfg {String|Roo.Element} el The container element.
15897 * @cfg {String|Roo.Template} tpl The template used by this View
15901 * @cfg {String} dataName the named area of the template to use as the data area
15902 * Works with domtemplates roo-name="name"
15906 * @cfg {String} selectedClass The css class to add to selected nodes
15908 selectedClass : "x-view-selected",
15910 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15915 * @cfg {String} text to display on mask (default Loading)
15919 * @cfg {Boolean} multiSelect Allow multiple selection
15921 multiSelect : false,
15923 * @cfg {Boolean} singleSelect Allow single selection
15925 singleSelect: false,
15928 * @cfg {Boolean} toggleSelect - selecting
15930 toggleSelect : false,
15933 * @cfg {Boolean} tickable - selecting
15938 * Returns the element this view is bound to.
15939 * @return {Roo.Element}
15941 getEl : function(){
15942 return this.wrapEl;
15948 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15950 refresh : function(){
15951 //Roo.log('refresh');
15954 // if we are using something like 'domtemplate', then
15955 // the what gets used is:
15956 // t.applySubtemplate(NAME, data, wrapping data..)
15957 // the outer template then get' applied with
15958 // the store 'extra data'
15959 // and the body get's added to the
15960 // roo-name="data" node?
15961 // <span class='roo-tpl-{name}'></span> ?????
15965 this.clearSelections();
15966 this.el.update("");
15968 var records = this.store.getRange();
15969 if(records.length < 1) {
15971 // is this valid?? = should it render a template??
15973 this.el.update(this.emptyText);
15977 if (this.dataName) {
15978 this.el.update(t.apply(this.store.meta)); //????
15979 el = this.el.child('.roo-tpl-' + this.dataName);
15982 for(var i = 0, len = records.length; i < len; i++){
15983 var data = this.prepareData(records[i].data, i, records[i]);
15984 this.fireEvent("preparedata", this, data, i, records[i]);
15986 var d = Roo.apply({}, data);
15989 Roo.apply(d, {'roo-id' : Roo.id()});
15993 Roo.each(this.parent.item, function(item){
15994 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15997 Roo.apply(d, {'roo-data-checked' : 'checked'});
16001 html[html.length] = Roo.util.Format.trim(
16003 t.applySubtemplate(this.dataName, d, this.store.meta) :
16010 el.update(html.join(""));
16011 this.nodes = el.dom.childNodes;
16012 this.updateIndexes(0);
16017 * Function to override to reformat the data that is sent to
16018 * the template for each node.
16019 * DEPRICATED - use the preparedata event handler.
16020 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16021 * a JSON object for an UpdateManager bound view).
16023 prepareData : function(data, index, record)
16025 this.fireEvent("preparedata", this, data, index, record);
16029 onUpdate : function(ds, record){
16030 // Roo.log('on update');
16031 this.clearSelections();
16032 var index = this.store.indexOf(record);
16033 var n = this.nodes[index];
16034 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16035 n.parentNode.removeChild(n);
16036 this.updateIndexes(index, index);
16042 onAdd : function(ds, records, index)
16044 //Roo.log(['on Add', ds, records, index] );
16045 this.clearSelections();
16046 if(this.nodes.length == 0){
16050 var n = this.nodes[index];
16051 for(var i = 0, len = records.length; i < len; i++){
16052 var d = this.prepareData(records[i].data, i, records[i]);
16054 this.tpl.insertBefore(n, d);
16057 this.tpl.append(this.el, d);
16060 this.updateIndexes(index);
16063 onRemove : function(ds, record, index){
16064 // Roo.log('onRemove');
16065 this.clearSelections();
16066 var el = this.dataName ?
16067 this.el.child('.roo-tpl-' + this.dataName) :
16070 el.dom.removeChild(this.nodes[index]);
16071 this.updateIndexes(index);
16075 * Refresh an individual node.
16076 * @param {Number} index
16078 refreshNode : function(index){
16079 this.onUpdate(this.store, this.store.getAt(index));
16082 updateIndexes : function(startIndex, endIndex){
16083 var ns = this.nodes;
16084 startIndex = startIndex || 0;
16085 endIndex = endIndex || ns.length - 1;
16086 for(var i = startIndex; i <= endIndex; i++){
16087 ns[i].nodeIndex = i;
16092 * Changes the data store this view uses and refresh the view.
16093 * @param {Store} store
16095 setStore : function(store, initial){
16096 if(!initial && this.store){
16097 this.store.un("datachanged", this.refresh);
16098 this.store.un("add", this.onAdd);
16099 this.store.un("remove", this.onRemove);
16100 this.store.un("update", this.onUpdate);
16101 this.store.un("clear", this.refresh);
16102 this.store.un("beforeload", this.onBeforeLoad);
16103 this.store.un("load", this.onLoad);
16104 this.store.un("loadexception", this.onLoad);
16108 store.on("datachanged", this.refresh, this);
16109 store.on("add", this.onAdd, this);
16110 store.on("remove", this.onRemove, this);
16111 store.on("update", this.onUpdate, this);
16112 store.on("clear", this.refresh, this);
16113 store.on("beforeload", this.onBeforeLoad, this);
16114 store.on("load", this.onLoad, this);
16115 store.on("loadexception", this.onLoad, this);
16123 * onbeforeLoad - masks the loading area.
16126 onBeforeLoad : function(store,opts)
16128 //Roo.log('onBeforeLoad');
16130 this.el.update("");
16132 this.el.mask(this.mask ? this.mask : "Loading" );
16134 onLoad : function ()
16141 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16142 * @param {HTMLElement} node
16143 * @return {HTMLElement} The template node
16145 findItemFromChild : function(node){
16146 var el = this.dataName ?
16147 this.el.child('.roo-tpl-' + this.dataName,true) :
16150 if(!node || node.parentNode == el){
16153 var p = node.parentNode;
16154 while(p && p != el){
16155 if(p.parentNode == el){
16164 onClick : function(e){
16165 var item = this.findItemFromChild(e.getTarget());
16167 var index = this.indexOf(item);
16168 if(this.onItemClick(item, index, e) !== false){
16169 this.fireEvent("click", this, index, item, e);
16172 this.clearSelections();
16177 onContextMenu : function(e){
16178 var item = this.findItemFromChild(e.getTarget());
16180 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16185 onDblClick : function(e){
16186 var item = this.findItemFromChild(e.getTarget());
16188 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16192 onItemClick : function(item, index, e)
16194 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16197 if (this.toggleSelect) {
16198 var m = this.isSelected(item) ? 'unselect' : 'select';
16201 _t[m](item, true, false);
16204 if(this.multiSelect || this.singleSelect){
16205 if(this.multiSelect && e.shiftKey && this.lastSelection){
16206 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16208 this.select(item, this.multiSelect && e.ctrlKey);
16209 this.lastSelection = item;
16212 if(!this.tickable){
16213 e.preventDefault();
16221 * Get the number of selected nodes.
16224 getSelectionCount : function(){
16225 return this.selections.length;
16229 * Get the currently selected nodes.
16230 * @return {Array} An array of HTMLElements
16232 getSelectedNodes : function(){
16233 return this.selections;
16237 * Get the indexes of the selected nodes.
16240 getSelectedIndexes : function(){
16241 var indexes = [], s = this.selections;
16242 for(var i = 0, len = s.length; i < len; i++){
16243 indexes.push(s[i].nodeIndex);
16249 * Clear all selections
16250 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16252 clearSelections : function(suppressEvent){
16253 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16254 this.cmp.elements = this.selections;
16255 this.cmp.removeClass(this.selectedClass);
16256 this.selections = [];
16257 if(!suppressEvent){
16258 this.fireEvent("selectionchange", this, this.selections);
16264 * Returns true if the passed node is selected
16265 * @param {HTMLElement/Number} node The node or node index
16266 * @return {Boolean}
16268 isSelected : function(node){
16269 var s = this.selections;
16273 node = this.getNode(node);
16274 return s.indexOf(node) !== -1;
16279 * @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
16280 * @param {Boolean} keepExisting (optional) true to keep existing selections
16281 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16283 select : function(nodeInfo, keepExisting, suppressEvent){
16284 if(nodeInfo instanceof Array){
16286 this.clearSelections(true);
16288 for(var i = 0, len = nodeInfo.length; i < len; i++){
16289 this.select(nodeInfo[i], true, true);
16293 var node = this.getNode(nodeInfo);
16294 if(!node || this.isSelected(node)){
16295 return; // already selected.
16298 this.clearSelections(true);
16301 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16302 Roo.fly(node).addClass(this.selectedClass);
16303 this.selections.push(node);
16304 if(!suppressEvent){
16305 this.fireEvent("selectionchange", this, this.selections);
16313 * @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
16314 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16315 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16317 unselect : function(nodeInfo, keepExisting, suppressEvent)
16319 if(nodeInfo instanceof Array){
16320 Roo.each(this.selections, function(s) {
16321 this.unselect(s, nodeInfo);
16325 var node = this.getNode(nodeInfo);
16326 if(!node || !this.isSelected(node)){
16327 //Roo.log("not selected");
16328 return; // not selected.
16332 Roo.each(this.selections, function(s) {
16334 Roo.fly(node).removeClass(this.selectedClass);
16341 this.selections= ns;
16342 this.fireEvent("selectionchange", this, this.selections);
16346 * Gets a template node.
16347 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16348 * @return {HTMLElement} The node or null if it wasn't found
16350 getNode : function(nodeInfo){
16351 if(typeof nodeInfo == "string"){
16352 return document.getElementById(nodeInfo);
16353 }else if(typeof nodeInfo == "number"){
16354 return this.nodes[nodeInfo];
16360 * Gets a range template nodes.
16361 * @param {Number} startIndex
16362 * @param {Number} endIndex
16363 * @return {Array} An array of nodes
16365 getNodes : function(start, end){
16366 var ns = this.nodes;
16367 start = start || 0;
16368 end = typeof end == "undefined" ? ns.length - 1 : end;
16371 for(var i = start; i <= end; i++){
16375 for(var i = start; i >= end; i--){
16383 * Finds the index of the passed node
16384 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16385 * @return {Number} The index of the node or -1
16387 indexOf : function(node){
16388 node = this.getNode(node);
16389 if(typeof node.nodeIndex == "number"){
16390 return node.nodeIndex;
16392 var ns = this.nodes;
16393 for(var i = 0, len = ns.length; i < len; i++){
16404 * based on jquery fullcalendar
16408 Roo.bootstrap = Roo.bootstrap || {};
16410 * @class Roo.bootstrap.Calendar
16411 * @extends Roo.bootstrap.Component
16412 * Bootstrap Calendar class
16413 * @cfg {Boolean} loadMask (true|false) default false
16414 * @cfg {Object} header generate the user specific header of the calendar, default false
16417 * Create a new Container
16418 * @param {Object} config The config object
16423 Roo.bootstrap.Calendar = function(config){
16424 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16428 * Fires when a date is selected
16429 * @param {DatePicker} this
16430 * @param {Date} date The selected date
16434 * @event monthchange
16435 * Fires when the displayed month changes
16436 * @param {DatePicker} this
16437 * @param {Date} date The selected month
16439 'monthchange': true,
16441 * @event evententer
16442 * Fires when mouse over an event
16443 * @param {Calendar} this
16444 * @param {event} Event
16446 'evententer': true,
16448 * @event eventleave
16449 * Fires when the mouse leaves an
16450 * @param {Calendar} this
16453 'eventleave': true,
16455 * @event eventclick
16456 * Fires when the mouse click an
16457 * @param {Calendar} this
16466 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16469 * @cfg {Number} startDay
16470 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16478 getAutoCreate : function(){
16481 var fc_button = function(name, corner, style, content ) {
16482 return Roo.apply({},{
16484 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16486 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16489 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16500 style : 'width:100%',
16507 cls : 'fc-header-left',
16509 fc_button('prev', 'left', 'arrow', '‹' ),
16510 fc_button('next', 'right', 'arrow', '›' ),
16511 { tag: 'span', cls: 'fc-header-space' },
16512 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16520 cls : 'fc-header-center',
16524 cls: 'fc-header-title',
16527 html : 'month / year'
16535 cls : 'fc-header-right',
16537 /* fc_button('month', 'left', '', 'month' ),
16538 fc_button('week', '', '', 'week' ),
16539 fc_button('day', 'right', '', 'day' )
16551 header = this.header;
16554 var cal_heads = function() {
16556 // fixme - handle this.
16558 for (var i =0; i < Date.dayNames.length; i++) {
16559 var d = Date.dayNames[i];
16562 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16563 html : d.substring(0,3)
16567 ret[0].cls += ' fc-first';
16568 ret[6].cls += ' fc-last';
16571 var cal_cell = function(n) {
16574 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16579 cls: 'fc-day-number',
16583 cls: 'fc-day-content',
16587 style: 'position: relative;' // height: 17px;
16599 var cal_rows = function() {
16602 for (var r = 0; r < 6; r++) {
16609 for (var i =0; i < Date.dayNames.length; i++) {
16610 var d = Date.dayNames[i];
16611 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16614 row.cn[0].cls+=' fc-first';
16615 row.cn[0].cn[0].style = 'min-height:90px';
16616 row.cn[6].cls+=' fc-last';
16620 ret[0].cls += ' fc-first';
16621 ret[4].cls += ' fc-prev-last';
16622 ret[5].cls += ' fc-last';
16629 cls: 'fc-border-separate',
16630 style : 'width:100%',
16638 cls : 'fc-first fc-last',
16656 cls : 'fc-content',
16657 style : "position: relative;",
16660 cls : 'fc-view fc-view-month fc-grid',
16661 style : 'position: relative',
16662 unselectable : 'on',
16665 cls : 'fc-event-container',
16666 style : 'position:absolute;z-index:8;top:0;left:0;'
16684 initEvents : function()
16687 throw "can not find store for calendar";
16693 style: "text-align:center",
16697 style: "background-color:white;width:50%;margin:250 auto",
16701 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16712 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16714 var size = this.el.select('.fc-content', true).first().getSize();
16715 this.maskEl.setSize(size.width, size.height);
16716 this.maskEl.enableDisplayMode("block");
16717 if(!this.loadMask){
16718 this.maskEl.hide();
16721 this.store = Roo.factory(this.store, Roo.data);
16722 this.store.on('load', this.onLoad, this);
16723 this.store.on('beforeload', this.onBeforeLoad, this);
16727 this.cells = this.el.select('.fc-day',true);
16728 //Roo.log(this.cells);
16729 this.textNodes = this.el.query('.fc-day-number');
16730 this.cells.addClassOnOver('fc-state-hover');
16732 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16733 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16734 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16735 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16737 this.on('monthchange', this.onMonthChange, this);
16739 this.update(new Date().clearTime());
16742 resize : function() {
16743 var sz = this.el.getSize();
16745 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16746 this.el.select('.fc-day-content div',true).setHeight(34);
16751 showPrevMonth : function(e){
16752 this.update(this.activeDate.add("mo", -1));
16754 showToday : function(e){
16755 this.update(new Date().clearTime());
16758 showNextMonth : function(e){
16759 this.update(this.activeDate.add("mo", 1));
16763 showPrevYear : function(){
16764 this.update(this.activeDate.add("y", -1));
16768 showNextYear : function(){
16769 this.update(this.activeDate.add("y", 1));
16774 update : function(date)
16776 var vd = this.activeDate;
16777 this.activeDate = date;
16778 // if(vd && this.el){
16779 // var t = date.getTime();
16780 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16781 // Roo.log('using add remove');
16783 // this.fireEvent('monthchange', this, date);
16785 // this.cells.removeClass("fc-state-highlight");
16786 // this.cells.each(function(c){
16787 // if(c.dateValue == t){
16788 // c.addClass("fc-state-highlight");
16789 // setTimeout(function(){
16790 // try{c.dom.firstChild.focus();}catch(e){}
16800 var days = date.getDaysInMonth();
16802 var firstOfMonth = date.getFirstDateOfMonth();
16803 var startingPos = firstOfMonth.getDay()-this.startDay;
16805 if(startingPos < this.startDay){
16809 var pm = date.add(Date.MONTH, -1);
16810 var prevStart = pm.getDaysInMonth()-startingPos;
16812 this.cells = this.el.select('.fc-day',true);
16813 this.textNodes = this.el.query('.fc-day-number');
16814 this.cells.addClassOnOver('fc-state-hover');
16816 var cells = this.cells.elements;
16817 var textEls = this.textNodes;
16819 Roo.each(cells, function(cell){
16820 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16823 days += startingPos;
16825 // convert everything to numbers so it's fast
16826 var day = 86400000;
16827 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16830 //Roo.log(prevStart);
16832 var today = new Date().clearTime().getTime();
16833 var sel = date.clearTime().getTime();
16834 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16835 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16836 var ddMatch = this.disabledDatesRE;
16837 var ddText = this.disabledDatesText;
16838 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16839 var ddaysText = this.disabledDaysText;
16840 var format = this.format;
16842 var setCellClass = function(cal, cell){
16846 //Roo.log('set Cell Class');
16848 var t = d.getTime();
16852 cell.dateValue = t;
16854 cell.className += " fc-today";
16855 cell.className += " fc-state-highlight";
16856 cell.title = cal.todayText;
16859 // disable highlight in other month..
16860 //cell.className += " fc-state-highlight";
16865 cell.className = " fc-state-disabled";
16866 cell.title = cal.minText;
16870 cell.className = " fc-state-disabled";
16871 cell.title = cal.maxText;
16875 if(ddays.indexOf(d.getDay()) != -1){
16876 cell.title = ddaysText;
16877 cell.className = " fc-state-disabled";
16880 if(ddMatch && format){
16881 var fvalue = d.dateFormat(format);
16882 if(ddMatch.test(fvalue)){
16883 cell.title = ddText.replace("%0", fvalue);
16884 cell.className = " fc-state-disabled";
16888 if (!cell.initialClassName) {
16889 cell.initialClassName = cell.dom.className;
16892 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16897 for(; i < startingPos; i++) {
16898 textEls[i].innerHTML = (++prevStart);
16899 d.setDate(d.getDate()+1);
16901 cells[i].className = "fc-past fc-other-month";
16902 setCellClass(this, cells[i]);
16907 for(; i < days; i++){
16908 intDay = i - startingPos + 1;
16909 textEls[i].innerHTML = (intDay);
16910 d.setDate(d.getDate()+1);
16912 cells[i].className = ''; // "x-date-active";
16913 setCellClass(this, cells[i]);
16917 for(; i < 42; i++) {
16918 textEls[i].innerHTML = (++extraDays);
16919 d.setDate(d.getDate()+1);
16921 cells[i].className = "fc-future fc-other-month";
16922 setCellClass(this, cells[i]);
16925 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16927 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16929 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16930 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16932 if(totalRows != 6){
16933 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16934 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16937 this.fireEvent('monthchange', this, date);
16941 if(!this.internalRender){
16942 var main = this.el.dom.firstChild;
16943 var w = main.offsetWidth;
16944 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16945 Roo.fly(main).setWidth(w);
16946 this.internalRender = true;
16947 // opera does not respect the auto grow header center column
16948 // then, after it gets a width opera refuses to recalculate
16949 // without a second pass
16950 if(Roo.isOpera && !this.secondPass){
16951 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16952 this.secondPass = true;
16953 this.update.defer(10, this, [date]);
16960 findCell : function(dt) {
16961 dt = dt.clearTime().getTime();
16963 this.cells.each(function(c){
16964 //Roo.log("check " +c.dateValue + '?=' + dt);
16965 if(c.dateValue == dt){
16975 findCells : function(ev) {
16976 var s = ev.start.clone().clearTime().getTime();
16978 var e= ev.end.clone().clearTime().getTime();
16981 this.cells.each(function(c){
16982 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16984 if(c.dateValue > e){
16987 if(c.dateValue < s){
16996 // findBestRow: function(cells)
17000 // for (var i =0 ; i < cells.length;i++) {
17001 // ret = Math.max(cells[i].rows || 0,ret);
17008 addItem : function(ev)
17010 // look for vertical location slot in
17011 var cells = this.findCells(ev);
17013 // ev.row = this.findBestRow(cells);
17015 // work out the location.
17019 for(var i =0; i < cells.length; i++) {
17021 cells[i].row = cells[0].row;
17024 cells[i].row = cells[i].row + 1;
17034 if (crow.start.getY() == cells[i].getY()) {
17036 crow.end = cells[i];
17053 cells[0].events.push(ev);
17055 this.calevents.push(ev);
17058 clearEvents: function() {
17060 if(!this.calevents){
17064 Roo.each(this.cells.elements, function(c){
17070 Roo.each(this.calevents, function(e) {
17071 Roo.each(e.els, function(el) {
17072 el.un('mouseenter' ,this.onEventEnter, this);
17073 el.un('mouseleave' ,this.onEventLeave, this);
17078 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17084 renderEvents: function()
17088 this.cells.each(function(c) {
17097 if(c.row != c.events.length){
17098 r = 4 - (4 - (c.row - c.events.length));
17101 c.events = ev.slice(0, r);
17102 c.more = ev.slice(r);
17104 if(c.more.length && c.more.length == 1){
17105 c.events.push(c.more.pop());
17108 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17112 this.cells.each(function(c) {
17114 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17117 for (var e = 0; e < c.events.length; e++){
17118 var ev = c.events[e];
17119 var rows = ev.rows;
17121 for(var i = 0; i < rows.length; i++) {
17123 // how many rows should it span..
17126 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17127 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17129 unselectable : "on",
17132 cls: 'fc-event-inner',
17136 // cls: 'fc-event-time',
17137 // html : cells.length > 1 ? '' : ev.time
17141 cls: 'fc-event-title',
17142 html : String.format('{0}', ev.title)
17149 cls: 'ui-resizable-handle ui-resizable-e',
17150 html : '  '
17157 cfg.cls += ' fc-event-start';
17159 if ((i+1) == rows.length) {
17160 cfg.cls += ' fc-event-end';
17163 var ctr = _this.el.select('.fc-event-container',true).first();
17164 var cg = ctr.createChild(cfg);
17166 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17167 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17169 var r = (c.more.length) ? 1 : 0;
17170 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17171 cg.setWidth(ebox.right - sbox.x -2);
17173 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17174 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17175 cg.on('click', _this.onEventClick, _this, ev);
17186 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17187 style : 'position: absolute',
17188 unselectable : "on",
17191 cls: 'fc-event-inner',
17195 cls: 'fc-event-title',
17203 cls: 'ui-resizable-handle ui-resizable-e',
17204 html : '  '
17210 var ctr = _this.el.select('.fc-event-container',true).first();
17211 var cg = ctr.createChild(cfg);
17213 var sbox = c.select('.fc-day-content',true).first().getBox();
17214 var ebox = c.select('.fc-day-content',true).first().getBox();
17216 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17217 cg.setWidth(ebox.right - sbox.x -2);
17219 cg.on('click', _this.onMoreEventClick, _this, c.more);
17229 onEventEnter: function (e, el,event,d) {
17230 this.fireEvent('evententer', this, el, event);
17233 onEventLeave: function (e, el,event,d) {
17234 this.fireEvent('eventleave', this, el, event);
17237 onEventClick: function (e, el,event,d) {
17238 this.fireEvent('eventclick', this, el, event);
17241 onMonthChange: function () {
17245 onMoreEventClick: function(e, el, more)
17249 this.calpopover.placement = 'right';
17250 this.calpopover.setTitle('More');
17252 this.calpopover.setContent('');
17254 var ctr = this.calpopover.el.select('.popover-content', true).first();
17256 Roo.each(more, function(m){
17258 cls : 'fc-event-hori fc-event-draggable',
17261 var cg = ctr.createChild(cfg);
17263 cg.on('click', _this.onEventClick, _this, m);
17266 this.calpopover.show(el);
17271 onLoad: function ()
17273 this.calevents = [];
17276 if(this.store.getCount() > 0){
17277 this.store.data.each(function(d){
17280 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17281 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17282 time : d.data.start_time,
17283 title : d.data.title,
17284 description : d.data.description,
17285 venue : d.data.venue
17290 this.renderEvents();
17292 if(this.calevents.length && this.loadMask){
17293 this.maskEl.hide();
17297 onBeforeLoad: function()
17299 this.clearEvents();
17301 this.maskEl.show();
17315 * @class Roo.bootstrap.Popover
17316 * @extends Roo.bootstrap.Component
17317 * Bootstrap Popover class
17318 * @cfg {String} html contents of the popover (or false to use children..)
17319 * @cfg {String} title of popover (or false to hide)
17320 * @cfg {String} placement how it is placed
17321 * @cfg {String} trigger click || hover (or false to trigger manually)
17322 * @cfg {String} over what (parent or false to trigger manually.)
17323 * @cfg {Number} delay - delay before showing
17326 * Create a new Popover
17327 * @param {Object} config The config object
17330 Roo.bootstrap.Popover = function(config){
17331 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17337 * After the popover show
17339 * @param {Roo.bootstrap.Popover} this
17344 * After the popover hide
17346 * @param {Roo.bootstrap.Popover} this
17352 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17354 title: 'Fill in a title',
17357 placement : 'right',
17358 trigger : 'hover', // hover
17364 can_build_overlaid : false,
17366 getChildContainer : function()
17368 return this.el.select('.popover-content',true).first();
17371 getAutoCreate : function(){
17374 cls : 'popover roo-dynamic',
17375 style: 'display:block',
17381 cls : 'popover-inner',
17385 cls: 'popover-title',
17389 cls : 'popover-content',
17400 setTitle: function(str)
17403 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17405 setContent: function(str)
17408 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17410 // as it get's added to the bottom of the page.
17411 onRender : function(ct, position)
17413 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17415 var cfg = Roo.apply({}, this.getAutoCreate());
17419 cfg.cls += ' ' + this.cls;
17422 cfg.style = this.style;
17424 //Roo.log("adding to ");
17425 this.el = Roo.get(document.body).createChild(cfg, position);
17426 // Roo.log(this.el);
17431 initEvents : function()
17433 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17434 this.el.enableDisplayMode('block');
17436 if (this.over === false) {
17439 if (this.triggers === false) {
17442 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17443 var triggers = this.trigger ? this.trigger.split(' ') : [];
17444 Roo.each(triggers, function(trigger) {
17446 if (trigger == 'click') {
17447 on_el.on('click', this.toggle, this);
17448 } else if (trigger != 'manual') {
17449 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17450 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17452 on_el.on(eventIn ,this.enter, this);
17453 on_el.on(eventOut, this.leave, this);
17464 toggle : function () {
17465 this.hoverState == 'in' ? this.leave() : this.enter();
17468 enter : function () {
17470 clearTimeout(this.timeout);
17472 this.hoverState = 'in';
17474 if (!this.delay || !this.delay.show) {
17479 this.timeout = setTimeout(function () {
17480 if (_t.hoverState == 'in') {
17483 }, this.delay.show)
17486 leave : function() {
17487 clearTimeout(this.timeout);
17489 this.hoverState = 'out';
17491 if (!this.delay || !this.delay.hide) {
17496 this.timeout = setTimeout(function () {
17497 if (_t.hoverState == 'out') {
17500 }, this.delay.hide)
17503 show : function (on_el)
17506 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17510 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17511 if (this.html !== false) {
17512 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17514 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17515 if (!this.title.length) {
17516 this.el.select('.popover-title',true).hide();
17519 var placement = typeof this.placement == 'function' ?
17520 this.placement.call(this, this.el, on_el) :
17523 var autoToken = /\s?auto?\s?/i;
17524 var autoPlace = autoToken.test(placement);
17526 placement = placement.replace(autoToken, '') || 'top';
17530 //this.el.setXY([0,0]);
17532 this.el.dom.style.display='block';
17533 this.el.addClass(placement);
17535 //this.el.appendTo(on_el);
17537 var p = this.getPosition();
17538 var box = this.el.getBox();
17543 var align = Roo.bootstrap.Popover.alignment[placement];
17546 this.el.alignTo(on_el, align[0],align[1]);
17547 //var arrow = this.el.select('.arrow',true).first();
17548 //arrow.set(align[2],
17550 this.el.addClass('in');
17553 if (this.el.hasClass('fade')) {
17557 this.hoverState = 'in';
17559 this.fireEvent('show', this);
17564 this.el.setXY([0,0]);
17565 this.el.removeClass('in');
17567 this.hoverState = null;
17569 this.fireEvent('hide', this);
17574 Roo.bootstrap.Popover.alignment = {
17575 'left' : ['r-l', [-10,0], 'right'],
17576 'right' : ['l-r', [10,0], 'left'],
17577 'bottom' : ['t-b', [0,10], 'top'],
17578 'top' : [ 'b-t', [0,-10], 'bottom']
17589 * @class Roo.bootstrap.Progress
17590 * @extends Roo.bootstrap.Component
17591 * Bootstrap Progress class
17592 * @cfg {Boolean} striped striped of the progress bar
17593 * @cfg {Boolean} active animated of the progress bar
17597 * Create a new Progress
17598 * @param {Object} config The config object
17601 Roo.bootstrap.Progress = function(config){
17602 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17605 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17610 getAutoCreate : function(){
17618 cfg.cls += ' progress-striped';
17622 cfg.cls += ' active';
17641 * @class Roo.bootstrap.ProgressBar
17642 * @extends Roo.bootstrap.Component
17643 * Bootstrap ProgressBar class
17644 * @cfg {Number} aria_valuenow aria-value now
17645 * @cfg {Number} aria_valuemin aria-value min
17646 * @cfg {Number} aria_valuemax aria-value max
17647 * @cfg {String} label label for the progress bar
17648 * @cfg {String} panel (success | info | warning | danger )
17649 * @cfg {String} role role of the progress bar
17650 * @cfg {String} sr_only text
17654 * Create a new ProgressBar
17655 * @param {Object} config The config object
17658 Roo.bootstrap.ProgressBar = function(config){
17659 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17662 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17666 aria_valuemax : 100,
17672 getAutoCreate : function()
17677 cls: 'progress-bar',
17678 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17690 cfg.role = this.role;
17693 if(this.aria_valuenow){
17694 cfg['aria-valuenow'] = this.aria_valuenow;
17697 if(this.aria_valuemin){
17698 cfg['aria-valuemin'] = this.aria_valuemin;
17701 if(this.aria_valuemax){
17702 cfg['aria-valuemax'] = this.aria_valuemax;
17705 if(this.label && !this.sr_only){
17706 cfg.html = this.label;
17710 cfg.cls += ' progress-bar-' + this.panel;
17716 update : function(aria_valuenow)
17718 this.aria_valuenow = aria_valuenow;
17720 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17735 * @class Roo.bootstrap.TabGroup
17736 * @extends Roo.bootstrap.Column
17737 * Bootstrap Column class
17738 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17739 * @cfg {Boolean} carousel true to make the group behave like a carousel
17740 * @cfg {Boolean} bullets show bullets for the panels
17741 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17742 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17743 * @cfg {Boolean} showarrow (true|false) show arrow default true
17746 * Create a new TabGroup
17747 * @param {Object} config The config object
17750 Roo.bootstrap.TabGroup = function(config){
17751 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17753 this.navId = Roo.id();
17756 Roo.bootstrap.TabGroup.register(this);
17760 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17763 transition : false,
17768 slideOnTouch : false,
17771 getAutoCreate : function()
17773 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17775 cfg.cls += ' tab-content';
17777 if (this.carousel) {
17778 cfg.cls += ' carousel slide';
17781 cls : 'carousel-inner',
17785 if(this.bullets && !Roo.isTouch){
17788 cls : 'carousel-bullets',
17792 if(this.bullets_cls){
17793 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17800 cfg.cn[0].cn.push(bullets);
17803 if(this.showarrow){
17804 cfg.cn[0].cn.push({
17806 class : 'carousel-arrow',
17810 class : 'carousel-prev',
17814 class : 'fa fa-chevron-left'
17820 class : 'carousel-next',
17824 class : 'fa fa-chevron-right'
17837 initEvents: function()
17839 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17840 // this.el.on("touchstart", this.onTouchStart, this);
17843 if(this.autoslide){
17846 this.slideFn = window.setInterval(function() {
17847 _this.showPanelNext();
17851 if(this.showarrow){
17852 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17853 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17859 // onTouchStart : function(e, el, o)
17861 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17865 // this.showPanelNext();
17869 getChildContainer : function()
17871 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17875 * register a Navigation item
17876 * @param {Roo.bootstrap.NavItem} the navitem to add
17878 register : function(item)
17880 this.tabs.push( item);
17881 item.navId = this.navId; // not really needed..
17886 getActivePanel : function()
17889 Roo.each(this.tabs, function(t) {
17899 getPanelByName : function(n)
17902 Roo.each(this.tabs, function(t) {
17903 if (t.tabId == n) {
17911 indexOfPanel : function(p)
17914 Roo.each(this.tabs, function(t,i) {
17915 if (t.tabId == p.tabId) {
17924 * show a specific panel
17925 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17926 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17928 showPanel : function (pan)
17930 if(this.transition || typeof(pan) == 'undefined'){
17931 Roo.log("waiting for the transitionend");
17935 if (typeof(pan) == 'number') {
17936 pan = this.tabs[pan];
17939 if (typeof(pan) == 'string') {
17940 pan = this.getPanelByName(pan);
17943 var cur = this.getActivePanel();
17946 Roo.log('pan or acitve pan is undefined');
17950 if (pan.tabId == this.getActivePanel().tabId) {
17954 if (false === cur.fireEvent('beforedeactivate')) {
17958 if(this.bullets > 0 && !Roo.isTouch){
17959 this.setActiveBullet(this.indexOfPanel(pan));
17962 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17964 this.transition = true;
17965 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17966 var lr = dir == 'next' ? 'left' : 'right';
17967 pan.el.addClass(dir); // or prev
17968 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17969 cur.el.addClass(lr); // or right
17970 pan.el.addClass(lr);
17973 cur.el.on('transitionend', function() {
17974 Roo.log("trans end?");
17976 pan.el.removeClass([lr,dir]);
17977 pan.setActive(true);
17979 cur.el.removeClass([lr]);
17980 cur.setActive(false);
17982 _this.transition = false;
17984 }, this, { single: true } );
17989 cur.setActive(false);
17990 pan.setActive(true);
17995 showPanelNext : function()
17997 var i = this.indexOfPanel(this.getActivePanel());
17999 if (i >= this.tabs.length - 1 && !this.autoslide) {
18003 if (i >= this.tabs.length - 1 && this.autoslide) {
18007 this.showPanel(this.tabs[i+1]);
18010 showPanelPrev : function()
18012 var i = this.indexOfPanel(this.getActivePanel());
18014 if (i < 1 && !this.autoslide) {
18018 if (i < 1 && this.autoslide) {
18019 i = this.tabs.length;
18022 this.showPanel(this.tabs[i-1]);
18026 addBullet: function()
18028 if(!this.bullets || Roo.isTouch){
18031 var ctr = this.el.select('.carousel-bullets',true).first();
18032 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18033 var bullet = ctr.createChild({
18034 cls : 'bullet bullet-' + i
18035 },ctr.dom.lastChild);
18040 bullet.on('click', (function(e, el, o, ii, t){
18042 e.preventDefault();
18044 this.showPanel(ii);
18046 if(this.autoslide && this.slideFn){
18047 clearInterval(this.slideFn);
18048 this.slideFn = window.setInterval(function() {
18049 _this.showPanelNext();
18053 }).createDelegate(this, [i, bullet], true));
18058 setActiveBullet : function(i)
18064 Roo.each(this.el.select('.bullet', true).elements, function(el){
18065 el.removeClass('selected');
18068 var bullet = this.el.select('.bullet-' + i, true).first();
18074 bullet.addClass('selected');
18085 Roo.apply(Roo.bootstrap.TabGroup, {
18089 * register a Navigation Group
18090 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18092 register : function(navgrp)
18094 this.groups[navgrp.navId] = navgrp;
18098 * fetch a Navigation Group based on the navigation ID
18099 * if one does not exist , it will get created.
18100 * @param {string} the navgroup to add
18101 * @returns {Roo.bootstrap.NavGroup} the navgroup
18103 get: function(navId) {
18104 if (typeof(this.groups[navId]) == 'undefined') {
18105 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18107 return this.groups[navId] ;
18122 * @class Roo.bootstrap.TabPanel
18123 * @extends Roo.bootstrap.Component
18124 * Bootstrap TabPanel class
18125 * @cfg {Boolean} active panel active
18126 * @cfg {String} html panel content
18127 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18128 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18129 * @cfg {String} href click to link..
18133 * Create a new TabPanel
18134 * @param {Object} config The config object
18137 Roo.bootstrap.TabPanel = function(config){
18138 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18142 * Fires when the active status changes
18143 * @param {Roo.bootstrap.TabPanel} this
18144 * @param {Boolean} state the new state
18149 * @event beforedeactivate
18150 * Fires before a tab is de-activated - can be used to do validation on a form.
18151 * @param {Roo.bootstrap.TabPanel} this
18152 * @return {Boolean} false if there is an error
18155 'beforedeactivate': true
18158 this.tabId = this.tabId || Roo.id();
18162 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18170 getAutoCreate : function(){
18173 // item is needed for carousel - not sure if it has any effect otherwise
18174 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18175 html: this.html || ''
18179 cfg.cls += ' active';
18183 cfg.tabId = this.tabId;
18190 initEvents: function()
18192 var p = this.parent();
18194 this.navId = this.navId || p.navId;
18196 if (typeof(this.navId) != 'undefined') {
18197 // not really needed.. but just in case.. parent should be a NavGroup.
18198 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18202 var i = tg.tabs.length - 1;
18204 if(this.active && tg.bullets > 0 && i < tg.bullets){
18205 tg.setActiveBullet(i);
18209 this.el.on('click', this.onClick, this);
18212 this.el.on("touchstart", this.onTouchStart, this);
18213 this.el.on("touchmove", this.onTouchMove, this);
18214 this.el.on("touchend", this.onTouchEnd, this);
18219 onRender : function(ct, position)
18221 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18224 setActive : function(state)
18226 Roo.log("panel - set active " + this.tabId + "=" + state);
18228 this.active = state;
18230 this.el.removeClass('active');
18232 } else if (!this.el.hasClass('active')) {
18233 this.el.addClass('active');
18236 this.fireEvent('changed', this, state);
18239 onClick : function(e)
18241 e.preventDefault();
18243 if(!this.href.length){
18247 window.location.href = this.href;
18256 onTouchStart : function(e)
18258 this.swiping = false;
18260 this.startX = e.browserEvent.touches[0].clientX;
18261 this.startY = e.browserEvent.touches[0].clientY;
18264 onTouchMove : function(e)
18266 this.swiping = true;
18268 this.endX = e.browserEvent.touches[0].clientX;
18269 this.endY = e.browserEvent.touches[0].clientY;
18272 onTouchEnd : function(e)
18279 var tabGroup = this.parent();
18281 if(this.endX > this.startX){ // swiping right
18282 tabGroup.showPanelPrev();
18286 if(this.startX > this.endX){ // swiping left
18287 tabGroup.showPanelNext();
18306 * @class Roo.bootstrap.DateField
18307 * @extends Roo.bootstrap.Input
18308 * Bootstrap DateField class
18309 * @cfg {Number} weekStart default 0
18310 * @cfg {String} viewMode default empty, (months|years)
18311 * @cfg {String} minViewMode default empty, (months|years)
18312 * @cfg {Number} startDate default -Infinity
18313 * @cfg {Number} endDate default Infinity
18314 * @cfg {Boolean} todayHighlight default false
18315 * @cfg {Boolean} todayBtn default false
18316 * @cfg {Boolean} calendarWeeks default false
18317 * @cfg {Object} daysOfWeekDisabled default empty
18318 * @cfg {Boolean} singleMode default false (true | false)
18320 * @cfg {Boolean} keyboardNavigation default true
18321 * @cfg {String} language default en
18324 * Create a new DateField
18325 * @param {Object} config The config object
18328 Roo.bootstrap.DateField = function(config){
18329 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18333 * Fires when this field show.
18334 * @param {Roo.bootstrap.DateField} this
18335 * @param {Mixed} date The date value
18340 * Fires when this field hide.
18341 * @param {Roo.bootstrap.DateField} this
18342 * @param {Mixed} date The date value
18347 * Fires when select a date.
18348 * @param {Roo.bootstrap.DateField} this
18349 * @param {Mixed} date The date value
18353 * @event beforeselect
18354 * Fires when before select a date.
18355 * @param {Roo.bootstrap.DateField} this
18356 * @param {Mixed} date The date value
18358 beforeselect : true
18362 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18365 * @cfg {String} format
18366 * The default date format string which can be overriden for localization support. The format must be
18367 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18371 * @cfg {String} altFormats
18372 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18373 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18375 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18383 todayHighlight : false,
18389 keyboardNavigation: true,
18391 calendarWeeks: false,
18393 startDate: -Infinity,
18397 daysOfWeekDisabled: [],
18401 singleMode : false,
18403 UTCDate: function()
18405 return new Date(Date.UTC.apply(Date, arguments));
18408 UTCToday: function()
18410 var today = new Date();
18411 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18414 getDate: function() {
18415 var d = this.getUTCDate();
18416 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18419 getUTCDate: function() {
18423 setDate: function(d) {
18424 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18427 setUTCDate: function(d) {
18429 this.setValue(this.formatDate(this.date));
18432 onRender: function(ct, position)
18435 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18437 this.language = this.language || 'en';
18438 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18439 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18441 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18442 this.format = this.format || 'm/d/y';
18443 this.isInline = false;
18444 this.isInput = true;
18445 this.component = this.el.select('.add-on', true).first() || false;
18446 this.component = (this.component && this.component.length === 0) ? false : this.component;
18447 this.hasInput = this.component && this.inputEl().length;
18449 if (typeof(this.minViewMode === 'string')) {
18450 switch (this.minViewMode) {
18452 this.minViewMode = 1;
18455 this.minViewMode = 2;
18458 this.minViewMode = 0;
18463 if (typeof(this.viewMode === 'string')) {
18464 switch (this.viewMode) {
18477 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18479 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18481 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18483 this.picker().on('mousedown', this.onMousedown, this);
18484 this.picker().on('click', this.onClick, this);
18486 this.picker().addClass('datepicker-dropdown');
18488 this.startViewMode = this.viewMode;
18490 if(this.singleMode){
18491 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18492 v.setVisibilityMode(Roo.Element.DISPLAY);
18496 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18497 v.setStyle('width', '189px');
18501 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18502 if(!this.calendarWeeks){
18507 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18508 v.attr('colspan', function(i, val){
18509 return parseInt(val) + 1;
18514 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18516 this.setStartDate(this.startDate);
18517 this.setEndDate(this.endDate);
18519 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18526 if(this.isInline) {
18531 picker : function()
18533 return this.pickerEl;
18534 // return this.el.select('.datepicker', true).first();
18537 fillDow: function()
18539 var dowCnt = this.weekStart;
18548 if(this.calendarWeeks){
18556 while (dowCnt < this.weekStart + 7) {
18560 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18564 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18567 fillMonths: function()
18570 var months = this.picker().select('>.datepicker-months td', true).first();
18572 months.dom.innerHTML = '';
18578 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18581 months.createChild(month);
18588 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;
18590 if (this.date < this.startDate) {
18591 this.viewDate = new Date(this.startDate);
18592 } else if (this.date > this.endDate) {
18593 this.viewDate = new Date(this.endDate);
18595 this.viewDate = new Date(this.date);
18603 var d = new Date(this.viewDate),
18604 year = d.getUTCFullYear(),
18605 month = d.getUTCMonth(),
18606 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18607 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18608 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18609 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18610 currentDate = this.date && this.date.valueOf(),
18611 today = this.UTCToday();
18613 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18615 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18617 // this.picker.select('>tfoot th.today').
18618 // .text(dates[this.language].today)
18619 // .toggle(this.todayBtn !== false);
18621 this.updateNavArrows();
18624 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18626 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18628 prevMonth.setUTCDate(day);
18630 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18632 var nextMonth = new Date(prevMonth);
18634 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18636 nextMonth = nextMonth.valueOf();
18638 var fillMonths = false;
18640 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18642 while(prevMonth.valueOf() < nextMonth) {
18645 if (prevMonth.getUTCDay() === this.weekStart) {
18647 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18655 if(this.calendarWeeks){
18656 // ISO 8601: First week contains first thursday.
18657 // ISO also states week starts on Monday, but we can be more abstract here.
18659 // Start of current week: based on weekstart/current date
18660 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18661 // Thursday of this week
18662 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18663 // First Thursday of year, year from thursday
18664 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18665 // Calendar week: ms between thursdays, div ms per day, div 7 days
18666 calWeek = (th - yth) / 864e5 / 7 + 1;
18668 fillMonths.cn.push({
18676 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18678 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18681 if (this.todayHighlight &&
18682 prevMonth.getUTCFullYear() == today.getFullYear() &&
18683 prevMonth.getUTCMonth() == today.getMonth() &&
18684 prevMonth.getUTCDate() == today.getDate()) {
18685 clsName += ' today';
18688 if (currentDate && prevMonth.valueOf() === currentDate) {
18689 clsName += ' active';
18692 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18693 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18694 clsName += ' disabled';
18697 fillMonths.cn.push({
18699 cls: 'day ' + clsName,
18700 html: prevMonth.getDate()
18703 prevMonth.setDate(prevMonth.getDate()+1);
18706 var currentYear = this.date && this.date.getUTCFullYear();
18707 var currentMonth = this.date && this.date.getUTCMonth();
18709 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18711 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18712 v.removeClass('active');
18714 if(currentYear === year && k === currentMonth){
18715 v.addClass('active');
18718 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18719 v.addClass('disabled');
18725 year = parseInt(year/10, 10) * 10;
18727 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18729 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18732 for (var i = -1; i < 11; i++) {
18733 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18735 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18743 showMode: function(dir)
18746 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18749 Roo.each(this.picker().select('>div',true).elements, function(v){
18750 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18753 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18758 if(this.isInline) {
18762 this.picker().removeClass(['bottom', 'top']);
18764 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18766 * place to the top of element!
18770 this.picker().addClass('top');
18771 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18776 this.picker().addClass('bottom');
18778 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18781 parseDate : function(value)
18783 if(!value || value instanceof Date){
18786 var v = Date.parseDate(value, this.format);
18787 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18788 v = Date.parseDate(value, 'Y-m-d');
18790 if(!v && this.altFormats){
18791 if(!this.altFormatsArray){
18792 this.altFormatsArray = this.altFormats.split("|");
18794 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18795 v = Date.parseDate(value, this.altFormatsArray[i]);
18801 formatDate : function(date, fmt)
18803 return (!date || !(date instanceof Date)) ?
18804 date : date.dateFormat(fmt || this.format);
18807 onFocus : function()
18809 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18813 onBlur : function()
18815 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18817 var d = this.inputEl().getValue();
18826 this.picker().show();
18830 this.fireEvent('show', this, this.date);
18835 if(this.isInline) {
18838 this.picker().hide();
18839 this.viewMode = this.startViewMode;
18842 this.fireEvent('hide', this, this.date);
18846 onMousedown: function(e)
18848 e.stopPropagation();
18849 e.preventDefault();
18854 Roo.bootstrap.DateField.superclass.keyup.call(this);
18858 setValue: function(v)
18860 if(this.fireEvent('beforeselect', this, v) !== false){
18861 var d = new Date(this.parseDate(v) ).clearTime();
18863 if(isNaN(d.getTime())){
18864 this.date = this.viewDate = '';
18865 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18869 v = this.formatDate(d);
18871 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18873 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18877 this.fireEvent('select', this, this.date);
18881 getValue: function()
18883 return this.formatDate(this.date);
18886 fireKey: function(e)
18888 if (!this.picker().isVisible()){
18889 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18895 var dateChanged = false,
18897 newDate, newViewDate;
18902 e.preventDefault();
18906 if (!this.keyboardNavigation) {
18909 dir = e.keyCode == 37 ? -1 : 1;
18912 newDate = this.moveYear(this.date, dir);
18913 newViewDate = this.moveYear(this.viewDate, dir);
18914 } else if (e.shiftKey){
18915 newDate = this.moveMonth(this.date, dir);
18916 newViewDate = this.moveMonth(this.viewDate, dir);
18918 newDate = new Date(this.date);
18919 newDate.setUTCDate(this.date.getUTCDate() + dir);
18920 newViewDate = new Date(this.viewDate);
18921 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18923 if (this.dateWithinRange(newDate)){
18924 this.date = newDate;
18925 this.viewDate = newViewDate;
18926 this.setValue(this.formatDate(this.date));
18928 e.preventDefault();
18929 dateChanged = true;
18934 if (!this.keyboardNavigation) {
18937 dir = e.keyCode == 38 ? -1 : 1;
18939 newDate = this.moveYear(this.date, dir);
18940 newViewDate = this.moveYear(this.viewDate, dir);
18941 } else if (e.shiftKey){
18942 newDate = this.moveMonth(this.date, dir);
18943 newViewDate = this.moveMonth(this.viewDate, dir);
18945 newDate = new Date(this.date);
18946 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18947 newViewDate = new Date(this.viewDate);
18948 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18950 if (this.dateWithinRange(newDate)){
18951 this.date = newDate;
18952 this.viewDate = newViewDate;
18953 this.setValue(this.formatDate(this.date));
18955 e.preventDefault();
18956 dateChanged = true;
18960 this.setValue(this.formatDate(this.date));
18962 e.preventDefault();
18965 this.setValue(this.formatDate(this.date));
18979 onClick: function(e)
18981 e.stopPropagation();
18982 e.preventDefault();
18984 var target = e.getTarget();
18986 if(target.nodeName.toLowerCase() === 'i'){
18987 target = Roo.get(target).dom.parentNode;
18990 var nodeName = target.nodeName;
18991 var className = target.className;
18992 var html = target.innerHTML;
18993 //Roo.log(nodeName);
18995 switch(nodeName.toLowerCase()) {
18997 switch(className) {
19003 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19004 switch(this.viewMode){
19006 this.viewDate = this.moveMonth(this.viewDate, dir);
19010 this.viewDate = this.moveYear(this.viewDate, dir);
19016 var date = new Date();
19017 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19019 this.setValue(this.formatDate(this.date));
19026 if (className.indexOf('disabled') < 0) {
19027 this.viewDate.setUTCDate(1);
19028 if (className.indexOf('month') > -1) {
19029 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19031 var year = parseInt(html, 10) || 0;
19032 this.viewDate.setUTCFullYear(year);
19036 if(this.singleMode){
19037 this.setValue(this.formatDate(this.viewDate));
19048 //Roo.log(className);
19049 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19050 var day = parseInt(html, 10) || 1;
19051 var year = this.viewDate.getUTCFullYear(),
19052 month = this.viewDate.getUTCMonth();
19054 if (className.indexOf('old') > -1) {
19061 } else if (className.indexOf('new') > -1) {
19069 //Roo.log([year,month,day]);
19070 this.date = this.UTCDate(year, month, day,0,0,0,0);
19071 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19073 //Roo.log(this.formatDate(this.date));
19074 this.setValue(this.formatDate(this.date));
19081 setStartDate: function(startDate)
19083 this.startDate = startDate || -Infinity;
19084 if (this.startDate !== -Infinity) {
19085 this.startDate = this.parseDate(this.startDate);
19088 this.updateNavArrows();
19091 setEndDate: function(endDate)
19093 this.endDate = endDate || Infinity;
19094 if (this.endDate !== Infinity) {
19095 this.endDate = this.parseDate(this.endDate);
19098 this.updateNavArrows();
19101 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19103 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19104 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19105 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19107 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19108 return parseInt(d, 10);
19111 this.updateNavArrows();
19114 updateNavArrows: function()
19116 if(this.singleMode){
19120 var d = new Date(this.viewDate),
19121 year = d.getUTCFullYear(),
19122 month = d.getUTCMonth();
19124 Roo.each(this.picker().select('.prev', true).elements, function(v){
19126 switch (this.viewMode) {
19129 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19135 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19142 Roo.each(this.picker().select('.next', true).elements, function(v){
19144 switch (this.viewMode) {
19147 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19153 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19161 moveMonth: function(date, dir)
19166 var new_date = new Date(date.valueOf()),
19167 day = new_date.getUTCDate(),
19168 month = new_date.getUTCMonth(),
19169 mag = Math.abs(dir),
19171 dir = dir > 0 ? 1 : -1;
19174 // If going back one month, make sure month is not current month
19175 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19177 return new_date.getUTCMonth() == month;
19179 // If going forward one month, make sure month is as expected
19180 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19182 return new_date.getUTCMonth() != new_month;
19184 new_month = month + dir;
19185 new_date.setUTCMonth(new_month);
19186 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19187 if (new_month < 0 || new_month > 11) {
19188 new_month = (new_month + 12) % 12;
19191 // For magnitudes >1, move one month at a time...
19192 for (var i=0; i<mag; i++) {
19193 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19194 new_date = this.moveMonth(new_date, dir);
19196 // ...then reset the day, keeping it in the new month
19197 new_month = new_date.getUTCMonth();
19198 new_date.setUTCDate(day);
19200 return new_month != new_date.getUTCMonth();
19203 // Common date-resetting loop -- if date is beyond end of month, make it
19206 new_date.setUTCDate(--day);
19207 new_date.setUTCMonth(new_month);
19212 moveYear: function(date, dir)
19214 return this.moveMonth(date, dir*12);
19217 dateWithinRange: function(date)
19219 return date >= this.startDate && date <= this.endDate;
19225 this.picker().remove();
19228 validateValue : function(value)
19230 if(this.getVisibilityEl().hasClass('hidden')){
19234 if(value.length < 1) {
19235 if(this.allowBlank){
19241 if(value.length < this.minLength){
19244 if(value.length > this.maxLength){
19248 var vt = Roo.form.VTypes;
19249 if(!vt[this.vtype](value, this)){
19253 if(typeof this.validator == "function"){
19254 var msg = this.validator(value);
19260 if(this.regex && !this.regex.test(value)){
19264 if(typeof(this.parseDate(value)) == 'undefined'){
19268 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19272 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19280 setVisible : function(visible)
19286 this.getEl().removeClass('hidden');
19292 this.getEl().addClass('hidden');
19297 Roo.apply(Roo.bootstrap.DateField, {
19308 html: '<i class="fa fa-arrow-left"/>'
19318 html: '<i class="fa fa-arrow-right"/>'
19360 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19361 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19362 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19363 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19364 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19377 navFnc: 'FullYear',
19382 navFnc: 'FullYear',
19387 Roo.apply(Roo.bootstrap.DateField, {
19391 cls: 'datepicker dropdown-menu roo-dynamic',
19395 cls: 'datepicker-days',
19399 cls: 'table-condensed',
19401 Roo.bootstrap.DateField.head,
19405 Roo.bootstrap.DateField.footer
19412 cls: 'datepicker-months',
19416 cls: 'table-condensed',
19418 Roo.bootstrap.DateField.head,
19419 Roo.bootstrap.DateField.content,
19420 Roo.bootstrap.DateField.footer
19427 cls: 'datepicker-years',
19431 cls: 'table-condensed',
19433 Roo.bootstrap.DateField.head,
19434 Roo.bootstrap.DateField.content,
19435 Roo.bootstrap.DateField.footer
19454 * @class Roo.bootstrap.TimeField
19455 * @extends Roo.bootstrap.Input
19456 * Bootstrap DateField class
19460 * Create a new TimeField
19461 * @param {Object} config The config object
19464 Roo.bootstrap.TimeField = function(config){
19465 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19469 * Fires when this field show.
19470 * @param {Roo.bootstrap.DateField} thisthis
19471 * @param {Mixed} date The date value
19476 * Fires when this field hide.
19477 * @param {Roo.bootstrap.DateField} this
19478 * @param {Mixed} date The date value
19483 * Fires when select a date.
19484 * @param {Roo.bootstrap.DateField} this
19485 * @param {Mixed} date The date value
19491 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19494 * @cfg {String} format
19495 * The default time format string which can be overriden for localization support. The format must be
19496 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19500 onRender: function(ct, position)
19503 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19505 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19507 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19509 this.pop = this.picker().select('>.datepicker-time',true).first();
19510 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19512 this.picker().on('mousedown', this.onMousedown, this);
19513 this.picker().on('click', this.onClick, this);
19515 this.picker().addClass('datepicker-dropdown');
19520 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19521 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19522 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19523 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19524 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19525 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19529 fireKey: function(e){
19530 if (!this.picker().isVisible()){
19531 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19537 e.preventDefault();
19545 this.onTogglePeriod();
19548 this.onIncrementMinutes();
19551 this.onDecrementMinutes();
19560 onClick: function(e) {
19561 e.stopPropagation();
19562 e.preventDefault();
19565 picker : function()
19567 return this.el.select('.datepicker', true).first();
19570 fillTime: function()
19572 var time = this.pop.select('tbody', true).first();
19574 time.dom.innerHTML = '';
19589 cls: 'hours-up glyphicon glyphicon-chevron-up'
19609 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19630 cls: 'timepicker-hour',
19645 cls: 'timepicker-minute',
19660 cls: 'btn btn-primary period',
19682 cls: 'hours-down glyphicon glyphicon-chevron-down'
19702 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19720 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19727 var hours = this.time.getHours();
19728 var minutes = this.time.getMinutes();
19741 hours = hours - 12;
19745 hours = '0' + hours;
19749 minutes = '0' + minutes;
19752 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19753 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19754 this.pop.select('button', true).first().dom.innerHTML = period;
19760 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19762 var cls = ['bottom'];
19764 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19771 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19776 this.picker().addClass(cls.join('-'));
19780 Roo.each(cls, function(c){
19782 _this.picker().setTop(_this.inputEl().getHeight());
19786 _this.picker().setTop(0 - _this.picker().getHeight());
19791 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19795 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19802 onFocus : function()
19804 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19808 onBlur : function()
19810 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19816 this.picker().show();
19821 this.fireEvent('show', this, this.date);
19826 this.picker().hide();
19829 this.fireEvent('hide', this, this.date);
19832 setTime : function()
19835 this.setValue(this.time.format(this.format));
19837 this.fireEvent('select', this, this.date);
19842 onMousedown: function(e){
19843 e.stopPropagation();
19844 e.preventDefault();
19847 onIncrementHours: function()
19849 Roo.log('onIncrementHours');
19850 this.time = this.time.add(Date.HOUR, 1);
19855 onDecrementHours: function()
19857 Roo.log('onDecrementHours');
19858 this.time = this.time.add(Date.HOUR, -1);
19862 onIncrementMinutes: function()
19864 Roo.log('onIncrementMinutes');
19865 this.time = this.time.add(Date.MINUTE, 1);
19869 onDecrementMinutes: function()
19871 Roo.log('onDecrementMinutes');
19872 this.time = this.time.add(Date.MINUTE, -1);
19876 onTogglePeriod: function()
19878 Roo.log('onTogglePeriod');
19879 this.time = this.time.add(Date.HOUR, 12);
19886 Roo.apply(Roo.bootstrap.TimeField, {
19916 cls: 'btn btn-info ok',
19928 Roo.apply(Roo.bootstrap.TimeField, {
19932 cls: 'datepicker dropdown-menu',
19936 cls: 'datepicker-time',
19940 cls: 'table-condensed',
19942 Roo.bootstrap.TimeField.content,
19943 Roo.bootstrap.TimeField.footer
19962 * @class Roo.bootstrap.MonthField
19963 * @extends Roo.bootstrap.Input
19964 * Bootstrap MonthField class
19966 * @cfg {String} language default en
19969 * Create a new MonthField
19970 * @param {Object} config The config object
19973 Roo.bootstrap.MonthField = function(config){
19974 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19979 * Fires when this field show.
19980 * @param {Roo.bootstrap.MonthField} this
19981 * @param {Mixed} date The date value
19986 * Fires when this field hide.
19987 * @param {Roo.bootstrap.MonthField} this
19988 * @param {Mixed} date The date value
19993 * Fires when select a date.
19994 * @param {Roo.bootstrap.MonthField} this
19995 * @param {String} oldvalue The old value
19996 * @param {String} newvalue The new value
20002 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20004 onRender: function(ct, position)
20007 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20009 this.language = this.language || 'en';
20010 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20011 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20013 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20014 this.isInline = false;
20015 this.isInput = true;
20016 this.component = this.el.select('.add-on', true).first() || false;
20017 this.component = (this.component && this.component.length === 0) ? false : this.component;
20018 this.hasInput = this.component && this.inputEL().length;
20020 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20022 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20024 this.picker().on('mousedown', this.onMousedown, this);
20025 this.picker().on('click', this.onClick, this);
20027 this.picker().addClass('datepicker-dropdown');
20029 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20030 v.setStyle('width', '189px');
20037 if(this.isInline) {
20043 setValue: function(v, suppressEvent)
20045 var o = this.getValue();
20047 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20051 if(suppressEvent !== true){
20052 this.fireEvent('select', this, o, v);
20057 getValue: function()
20062 onClick: function(e)
20064 e.stopPropagation();
20065 e.preventDefault();
20067 var target = e.getTarget();
20069 if(target.nodeName.toLowerCase() === 'i'){
20070 target = Roo.get(target).dom.parentNode;
20073 var nodeName = target.nodeName;
20074 var className = target.className;
20075 var html = target.innerHTML;
20077 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20081 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20083 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20089 picker : function()
20091 return this.pickerEl;
20094 fillMonths: function()
20097 var months = this.picker().select('>.datepicker-months td', true).first();
20099 months.dom.innerHTML = '';
20105 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20108 months.createChild(month);
20117 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20118 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20121 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20122 e.removeClass('active');
20124 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20125 e.addClass('active');
20132 if(this.isInline) {
20136 this.picker().removeClass(['bottom', 'top']);
20138 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20140 * place to the top of element!
20144 this.picker().addClass('top');
20145 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20150 this.picker().addClass('bottom');
20152 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20155 onFocus : function()
20157 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20161 onBlur : function()
20163 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20165 var d = this.inputEl().getValue();
20174 this.picker().show();
20175 this.picker().select('>.datepicker-months', true).first().show();
20179 this.fireEvent('show', this, this.date);
20184 if(this.isInline) {
20187 this.picker().hide();
20188 this.fireEvent('hide', this, this.date);
20192 onMousedown: function(e)
20194 e.stopPropagation();
20195 e.preventDefault();
20200 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20204 fireKey: function(e)
20206 if (!this.picker().isVisible()){
20207 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20218 e.preventDefault();
20222 dir = e.keyCode == 37 ? -1 : 1;
20224 this.vIndex = this.vIndex + dir;
20226 if(this.vIndex < 0){
20230 if(this.vIndex > 11){
20234 if(isNaN(this.vIndex)){
20238 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20244 dir = e.keyCode == 38 ? -1 : 1;
20246 this.vIndex = this.vIndex + dir * 4;
20248 if(this.vIndex < 0){
20252 if(this.vIndex > 11){
20256 if(isNaN(this.vIndex)){
20260 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20265 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20266 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20270 e.preventDefault();
20273 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20274 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20290 this.picker().remove();
20295 Roo.apply(Roo.bootstrap.MonthField, {
20314 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20315 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20320 Roo.apply(Roo.bootstrap.MonthField, {
20324 cls: 'datepicker dropdown-menu roo-dynamic',
20328 cls: 'datepicker-months',
20332 cls: 'table-condensed',
20334 Roo.bootstrap.DateField.content
20354 * @class Roo.bootstrap.CheckBox
20355 * @extends Roo.bootstrap.Input
20356 * Bootstrap CheckBox class
20358 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20359 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20360 * @cfg {String} boxLabel The text that appears beside the checkbox
20361 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20362 * @cfg {Boolean} checked initnal the element
20363 * @cfg {Boolean} inline inline the element (default false)
20364 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20365 * @cfg {String} tooltip label tooltip
20368 * Create a new CheckBox
20369 * @param {Object} config The config object
20372 Roo.bootstrap.CheckBox = function(config){
20373 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20378 * Fires when the element is checked or unchecked.
20379 * @param {Roo.bootstrap.CheckBox} this This input
20380 * @param {Boolean} checked The new checked value
20385 * Fires when the element is click.
20386 * @param {Roo.bootstrap.CheckBox} this This input
20393 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20395 inputType: 'checkbox',
20404 getAutoCreate : function()
20406 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20412 cfg.cls = 'form-group ' + this.inputType; //input-group
20415 cfg.cls += ' ' + this.inputType + '-inline';
20421 type : this.inputType,
20422 value : this.inputValue,
20423 cls : 'roo-' + this.inputType, //'form-box',
20424 placeholder : this.placeholder || ''
20428 if(this.inputType != 'radio'){
20432 cls : 'roo-hidden-value',
20433 value : this.checked ? this.inputValue : this.valueOff
20438 if (this.weight) { // Validity check?
20439 cfg.cls += " " + this.inputType + "-" + this.weight;
20442 if (this.disabled) {
20443 input.disabled=true;
20447 input.checked = this.checked;
20452 input.name = this.name;
20454 if(this.inputType != 'radio'){
20455 hidden.name = this.name;
20456 input.name = '_hidden_' + this.name;
20461 input.cls += ' input-' + this.size;
20466 ['xs','sm','md','lg'].map(function(size){
20467 if (settings[size]) {
20468 cfg.cls += ' col-' + size + '-' + settings[size];
20472 var inputblock = input;
20474 if (this.before || this.after) {
20477 cls : 'input-group',
20482 inputblock.cn.push({
20484 cls : 'input-group-addon',
20489 inputblock.cn.push(input);
20491 if(this.inputType != 'radio'){
20492 inputblock.cn.push(hidden);
20496 inputblock.cn.push({
20498 cls : 'input-group-addon',
20505 if (align ==='left' && this.fieldLabel.length) {
20506 // Roo.log("left and has label");
20511 cls : 'control-label',
20512 html : this.fieldLabel
20522 if(this.labelWidth > 12){
20523 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20526 if(this.labelWidth < 13 && this.labelmd == 0){
20527 this.labelmd = this.labelWidth;
20530 if(this.labellg > 0){
20531 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20532 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20535 if(this.labelmd > 0){
20536 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20537 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20540 if(this.labelsm > 0){
20541 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20542 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20545 if(this.labelxs > 0){
20546 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20547 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20550 } else if ( this.fieldLabel.length) {
20551 // Roo.log(" label");
20555 tag: this.boxLabel ? 'span' : 'label',
20557 cls: 'control-label box-input-label',
20558 //cls : 'input-group-addon',
20559 html : this.fieldLabel
20568 // Roo.log(" no label && no align");
20569 cfg.cn = [ inputblock ] ;
20575 var boxLabelCfg = {
20577 //'for': id, // box label is handled by onclick - so no for...
20579 html: this.boxLabel
20583 boxLabelCfg.tooltip = this.tooltip;
20586 cfg.cn.push(boxLabelCfg);
20589 if(this.inputType != 'radio'){
20590 cfg.cn.push(hidden);
20598 * return the real input element.
20600 inputEl: function ()
20602 return this.el.select('input.roo-' + this.inputType,true).first();
20604 hiddenEl: function ()
20606 return this.el.select('input.roo-hidden-value',true).first();
20609 labelEl: function()
20611 return this.el.select('label.control-label',true).first();
20613 /* depricated... */
20617 return this.labelEl();
20620 boxLabelEl: function()
20622 return this.el.select('label.box-label',true).first();
20625 initEvents : function()
20627 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20629 this.inputEl().on('click', this.onClick, this);
20631 if (this.boxLabel) {
20632 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20635 this.startValue = this.getValue();
20638 Roo.bootstrap.CheckBox.register(this);
20642 onClick : function(e)
20644 if(this.fireEvent('click', this, e) !== false){
20645 this.setChecked(!this.checked);
20650 setChecked : function(state,suppressEvent)
20652 this.startValue = this.getValue();
20654 if(this.inputType == 'radio'){
20656 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20657 e.dom.checked = false;
20660 this.inputEl().dom.checked = true;
20662 this.inputEl().dom.value = this.inputValue;
20664 if(suppressEvent !== true){
20665 this.fireEvent('check', this, true);
20673 this.checked = state;
20675 this.inputEl().dom.checked = state;
20678 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20680 if(suppressEvent !== true){
20681 this.fireEvent('check', this, state);
20687 getValue : function()
20689 if(this.inputType == 'radio'){
20690 return this.getGroupValue();
20693 return this.hiddenEl().dom.value;
20697 getGroupValue : function()
20699 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20703 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20706 setValue : function(v,suppressEvent)
20708 if(this.inputType == 'radio'){
20709 this.setGroupValue(v, suppressEvent);
20713 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20718 setGroupValue : function(v, suppressEvent)
20720 this.startValue = this.getValue();
20722 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20723 e.dom.checked = false;
20725 if(e.dom.value == v){
20726 e.dom.checked = true;
20730 if(suppressEvent !== true){
20731 this.fireEvent('check', this, true);
20739 validate : function()
20741 if(this.getVisibilityEl().hasClass('hidden')){
20747 (this.inputType == 'radio' && this.validateRadio()) ||
20748 (this.inputType == 'checkbox' && this.validateCheckbox())
20754 this.markInvalid();
20758 validateRadio : function()
20760 if(this.getVisibilityEl().hasClass('hidden')){
20764 if(this.allowBlank){
20770 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20771 if(!e.dom.checked){
20783 validateCheckbox : function()
20786 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20787 //return (this.getValue() == this.inputValue) ? true : false;
20790 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20798 for(var i in group){
20799 if(group[i].el.isVisible(true)){
20807 for(var i in group){
20812 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20819 * Mark this field as valid
20821 markValid : function()
20825 this.fireEvent('valid', this);
20827 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20830 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20837 if(this.inputType == 'radio'){
20838 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20839 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20840 e.findParent('.form-group', false, true).addClass(_this.validClass);
20847 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20848 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20852 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20858 for(var i in group){
20859 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20860 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20865 * Mark this field as invalid
20866 * @param {String} msg The validation message
20868 markInvalid : function(msg)
20870 if(this.allowBlank){
20876 this.fireEvent('invalid', this, msg);
20878 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20881 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20885 label.markInvalid();
20888 if(this.inputType == 'radio'){
20889 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20890 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20891 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20898 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20899 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20903 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20909 for(var i in group){
20910 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20911 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20916 clearInvalid : function()
20918 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20920 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20922 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20924 if (label && label.iconEl) {
20925 label.iconEl.removeClass(label.validClass);
20926 label.iconEl.removeClass(label.invalidClass);
20930 disable : function()
20932 if(this.inputType != 'radio'){
20933 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20940 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20941 _this.getActionEl().addClass(this.disabledClass);
20942 e.dom.disabled = true;
20946 this.disabled = true;
20947 this.fireEvent("disable", this);
20951 enable : function()
20953 if(this.inputType != 'radio'){
20954 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20961 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20962 _this.getActionEl().removeClass(this.disabledClass);
20963 e.dom.disabled = false;
20967 this.disabled = false;
20968 this.fireEvent("enable", this);
20972 setBoxLabel : function(v)
20977 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20983 Roo.apply(Roo.bootstrap.CheckBox, {
20988 * register a CheckBox Group
20989 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20991 register : function(checkbox)
20993 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20994 this.groups[checkbox.groupId] = {};
20997 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21001 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21005 * fetch a CheckBox Group based on the group ID
21006 * @param {string} the group ID
21007 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21009 get: function(groupId) {
21010 if (typeof(this.groups[groupId]) == 'undefined') {
21014 return this.groups[groupId] ;
21027 * @class Roo.bootstrap.Radio
21028 * @extends Roo.bootstrap.Component
21029 * Bootstrap Radio class
21030 * @cfg {String} boxLabel - the label associated
21031 * @cfg {String} value - the value of radio
21034 * Create a new Radio
21035 * @param {Object} config The config object
21037 Roo.bootstrap.Radio = function(config){
21038 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21042 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21048 getAutoCreate : function()
21052 cls : 'form-group radio',
21057 html : this.boxLabel
21065 initEvents : function()
21067 this.parent().register(this);
21069 this.el.on('click', this.onClick, this);
21073 onClick : function(e)
21075 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21076 this.setChecked(true);
21080 setChecked : function(state, suppressEvent)
21082 this.parent().setValue(this.value, suppressEvent);
21086 setBoxLabel : function(v)
21091 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21106 * @class Roo.bootstrap.SecurePass
21107 * @extends Roo.bootstrap.Input
21108 * Bootstrap SecurePass class
21112 * Create a new SecurePass
21113 * @param {Object} config The config object
21116 Roo.bootstrap.SecurePass = function (config) {
21117 // these go here, so the translation tool can replace them..
21119 PwdEmpty: "Please type a password, and then retype it to confirm.",
21120 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21121 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21122 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21123 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21124 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21125 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21126 TooWeak: "Your password is Too Weak."
21128 this.meterLabel = "Password strength:";
21129 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21130 this.meterClass = [
21131 "roo-password-meter-tooweak",
21132 "roo-password-meter-weak",
21133 "roo-password-meter-medium",
21134 "roo-password-meter-strong",
21135 "roo-password-meter-grey"
21140 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21143 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21145 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21147 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21148 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21149 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21150 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21151 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21152 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21153 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21163 * @cfg {String/Object} Label for the strength meter (defaults to
21164 * 'Password strength:')
21169 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21170 * ['Weak', 'Medium', 'Strong'])
21173 pwdStrengths: false,
21186 initEvents: function ()
21188 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21190 if (this.el.is('input[type=password]') && Roo.isSafari) {
21191 this.el.on('keydown', this.SafariOnKeyDown, this);
21194 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21197 onRender: function (ct, position)
21199 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21200 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21201 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21203 this.trigger.createChild({
21208 cls: 'roo-password-meter-grey col-xs-12',
21211 //width: this.meterWidth + 'px'
21215 cls: 'roo-password-meter-text'
21221 if (this.hideTrigger) {
21222 this.trigger.setDisplayed(false);
21224 this.setSize(this.width || '', this.height || '');
21227 onDestroy: function ()
21229 if (this.trigger) {
21230 this.trigger.removeAllListeners();
21231 this.trigger.remove();
21234 this.wrap.remove();
21236 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21239 checkStrength: function ()
21241 var pwd = this.inputEl().getValue();
21242 if (pwd == this._lastPwd) {
21247 if (this.ClientSideStrongPassword(pwd)) {
21249 } else if (this.ClientSideMediumPassword(pwd)) {
21251 } else if (this.ClientSideWeakPassword(pwd)) {
21257 Roo.log('strength1: ' + strength);
21259 //var pm = this.trigger.child('div/div/div').dom;
21260 var pm = this.trigger.child('div/div');
21261 pm.removeClass(this.meterClass);
21262 pm.addClass(this.meterClass[strength]);
21265 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21267 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21269 this._lastPwd = pwd;
21273 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21275 this._lastPwd = '';
21277 var pm = this.trigger.child('div/div');
21278 pm.removeClass(this.meterClass);
21279 pm.addClass('roo-password-meter-grey');
21282 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21285 this.inputEl().dom.type='password';
21288 validateValue: function (value)
21291 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21294 if (value.length == 0) {
21295 if (this.allowBlank) {
21296 this.clearInvalid();
21300 this.markInvalid(this.errors.PwdEmpty);
21301 this.errorMsg = this.errors.PwdEmpty;
21309 if ('[\x21-\x7e]*'.match(value)) {
21310 this.markInvalid(this.errors.PwdBadChar);
21311 this.errorMsg = this.errors.PwdBadChar;
21314 if (value.length < 6) {
21315 this.markInvalid(this.errors.PwdShort);
21316 this.errorMsg = this.errors.PwdShort;
21319 if (value.length > 16) {
21320 this.markInvalid(this.errors.PwdLong);
21321 this.errorMsg = this.errors.PwdLong;
21325 if (this.ClientSideStrongPassword(value)) {
21327 } else if (this.ClientSideMediumPassword(value)) {
21329 } else if (this.ClientSideWeakPassword(value)) {
21336 if (strength < 2) {
21337 //this.markInvalid(this.errors.TooWeak);
21338 this.errorMsg = this.errors.TooWeak;
21343 console.log('strength2: ' + strength);
21345 //var pm = this.trigger.child('div/div/div').dom;
21347 var pm = this.trigger.child('div/div');
21348 pm.removeClass(this.meterClass);
21349 pm.addClass(this.meterClass[strength]);
21351 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21353 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21355 this.errorMsg = '';
21359 CharacterSetChecks: function (type)
21362 this.fResult = false;
21365 isctype: function (character, type)
21368 case this.kCapitalLetter:
21369 if (character >= 'A' && character <= 'Z') {
21374 case this.kSmallLetter:
21375 if (character >= 'a' && character <= 'z') {
21381 if (character >= '0' && character <= '9') {
21386 case this.kPunctuation:
21387 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21398 IsLongEnough: function (pwd, size)
21400 return !(pwd == null || isNaN(size) || pwd.length < size);
21403 SpansEnoughCharacterSets: function (word, nb)
21405 if (!this.IsLongEnough(word, nb))
21410 var characterSetChecks = new Array(
21411 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21412 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21415 for (var index = 0; index < word.length; ++index) {
21416 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21417 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21418 characterSetChecks[nCharSet].fResult = true;
21425 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21426 if (characterSetChecks[nCharSet].fResult) {
21431 if (nCharSets < nb) {
21437 ClientSideStrongPassword: function (pwd)
21439 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21442 ClientSideMediumPassword: function (pwd)
21444 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21447 ClientSideWeakPassword: function (pwd)
21449 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21452 })//<script type="text/javascript">
21455 * Based Ext JS Library 1.1.1
21456 * Copyright(c) 2006-2007, Ext JS, LLC.
21462 * @class Roo.HtmlEditorCore
21463 * @extends Roo.Component
21464 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21466 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21469 Roo.HtmlEditorCore = function(config){
21472 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21477 * @event initialize
21478 * Fires when the editor is fully initialized (including the iframe)
21479 * @param {Roo.HtmlEditorCore} this
21484 * Fires when the editor is first receives the focus. Any insertion must wait
21485 * until after this event.
21486 * @param {Roo.HtmlEditorCore} this
21490 * @event beforesync
21491 * Fires before the textarea is updated with content from the editor iframe. Return false
21492 * to cancel the sync.
21493 * @param {Roo.HtmlEditorCore} this
21494 * @param {String} html
21498 * @event beforepush
21499 * Fires before the iframe editor is updated with content from the textarea. Return false
21500 * to cancel the push.
21501 * @param {Roo.HtmlEditorCore} this
21502 * @param {String} html
21507 * Fires when the textarea is updated with content from the editor iframe.
21508 * @param {Roo.HtmlEditorCore} this
21509 * @param {String} html
21514 * Fires when the iframe editor is updated with content from the textarea.
21515 * @param {Roo.HtmlEditorCore} this
21516 * @param {String} html
21521 * @event editorevent
21522 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21523 * @param {Roo.HtmlEditorCore} this
21529 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21531 // defaults : white / black...
21532 this.applyBlacklists();
21539 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21543 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21549 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21554 * @cfg {Number} height (in pixels)
21558 * @cfg {Number} width (in pixels)
21563 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21566 stylesheets: false,
21571 // private properties
21572 validationEvent : false,
21574 initialized : false,
21576 sourceEditMode : false,
21577 onFocus : Roo.emptyFn,
21579 hideMode:'offsets',
21583 // blacklist + whitelisted elements..
21590 * Protected method that will not generally be called directly. It
21591 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21592 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21594 getDocMarkup : function(){
21598 // inherit styels from page...??
21599 if (this.stylesheets === false) {
21601 Roo.get(document.head).select('style').each(function(node) {
21602 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21605 Roo.get(document.head).select('link').each(function(node) {
21606 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21609 } else if (!this.stylesheets.length) {
21611 st = '<style type="text/css">' +
21612 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21615 st = '<style type="text/css">' +
21620 st += '<style type="text/css">' +
21621 'IMG { cursor: pointer } ' +
21624 var cls = 'roo-htmleditor-body';
21626 if(this.bodyCls.length){
21627 cls += ' ' + this.bodyCls;
21630 return '<html><head>' + st +
21631 //<style type="text/css">' +
21632 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21634 ' </head><body class="' + cls + '"></body></html>';
21638 onRender : function(ct, position)
21641 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21642 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21645 this.el.dom.style.border = '0 none';
21646 this.el.dom.setAttribute('tabIndex', -1);
21647 this.el.addClass('x-hidden hide');
21651 if(Roo.isIE){ // fix IE 1px bogus margin
21652 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21656 this.frameId = Roo.id();
21660 var iframe = this.owner.wrap.createChild({
21662 cls: 'form-control', // bootstrap..
21664 name: this.frameId,
21665 frameBorder : 'no',
21666 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21671 this.iframe = iframe.dom;
21673 this.assignDocWin();
21675 this.doc.designMode = 'on';
21678 this.doc.write(this.getDocMarkup());
21682 var task = { // must defer to wait for browser to be ready
21684 //console.log("run task?" + this.doc.readyState);
21685 this.assignDocWin();
21686 if(this.doc.body || this.doc.readyState == 'complete'){
21688 this.doc.designMode="on";
21692 Roo.TaskMgr.stop(task);
21693 this.initEditor.defer(10, this);
21700 Roo.TaskMgr.start(task);
21705 onResize : function(w, h)
21707 Roo.log('resize: ' +w + ',' + h );
21708 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21712 if(typeof w == 'number'){
21714 this.iframe.style.width = w + 'px';
21716 if(typeof h == 'number'){
21718 this.iframe.style.height = h + 'px';
21720 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21727 * Toggles the editor between standard and source edit mode.
21728 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21730 toggleSourceEdit : function(sourceEditMode){
21732 this.sourceEditMode = sourceEditMode === true;
21734 if(this.sourceEditMode){
21736 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21739 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21740 //this.iframe.className = '';
21743 //this.setSize(this.owner.wrap.getSize());
21744 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21751 * Protected method that will not generally be called directly. If you need/want
21752 * custom HTML cleanup, this is the method you should override.
21753 * @param {String} html The HTML to be cleaned
21754 * return {String} The cleaned HTML
21756 cleanHtml : function(html){
21757 html = String(html);
21758 if(html.length > 5){
21759 if(Roo.isSafari){ // strip safari nonsense
21760 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21763 if(html == ' '){
21770 * HTML Editor -> Textarea
21771 * Protected method that will not generally be called directly. Syncs the contents
21772 * of the editor iframe with the textarea.
21774 syncValue : function(){
21775 if(this.initialized){
21776 var bd = (this.doc.body || this.doc.documentElement);
21777 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21778 var html = bd.innerHTML;
21780 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21781 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21783 html = '<div style="'+m[0]+'">' + html + '</div>';
21786 html = this.cleanHtml(html);
21787 // fix up the special chars.. normaly like back quotes in word...
21788 // however we do not want to do this with chinese..
21789 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21790 var cc = b.charCodeAt();
21792 (cc >= 0x4E00 && cc < 0xA000 ) ||
21793 (cc >= 0x3400 && cc < 0x4E00 ) ||
21794 (cc >= 0xf900 && cc < 0xfb00 )
21800 if(this.owner.fireEvent('beforesync', this, html) !== false){
21801 this.el.dom.value = html;
21802 this.owner.fireEvent('sync', this, html);
21808 * Protected method that will not generally be called directly. Pushes the value of the textarea
21809 * into the iframe editor.
21811 pushValue : function(){
21812 if(this.initialized){
21813 var v = this.el.dom.value.trim();
21815 // if(v.length < 1){
21819 if(this.owner.fireEvent('beforepush', this, v) !== false){
21820 var d = (this.doc.body || this.doc.documentElement);
21822 this.cleanUpPaste();
21823 this.el.dom.value = d.innerHTML;
21824 this.owner.fireEvent('push', this, v);
21830 deferFocus : function(){
21831 this.focus.defer(10, this);
21835 focus : function(){
21836 if(this.win && !this.sourceEditMode){
21843 assignDocWin: function()
21845 var iframe = this.iframe;
21848 this.doc = iframe.contentWindow.document;
21849 this.win = iframe.contentWindow;
21851 // if (!Roo.get(this.frameId)) {
21854 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21855 // this.win = Roo.get(this.frameId).dom.contentWindow;
21857 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21861 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21862 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21867 initEditor : function(){
21868 //console.log("INIT EDITOR");
21869 this.assignDocWin();
21873 this.doc.designMode="on";
21875 this.doc.write(this.getDocMarkup());
21878 var dbody = (this.doc.body || this.doc.documentElement);
21879 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21880 // this copies styles from the containing element into thsi one..
21881 // not sure why we need all of this..
21882 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21884 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21885 //ss['background-attachment'] = 'fixed'; // w3c
21886 dbody.bgProperties = 'fixed'; // ie
21887 //Roo.DomHelper.applyStyles(dbody, ss);
21888 Roo.EventManager.on(this.doc, {
21889 //'mousedown': this.onEditorEvent,
21890 'mouseup': this.onEditorEvent,
21891 'dblclick': this.onEditorEvent,
21892 'click': this.onEditorEvent,
21893 'keyup': this.onEditorEvent,
21898 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21900 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21901 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21903 this.initialized = true;
21905 this.owner.fireEvent('initialize', this);
21910 onDestroy : function(){
21916 //for (var i =0; i < this.toolbars.length;i++) {
21917 // // fixme - ask toolbars for heights?
21918 // this.toolbars[i].onDestroy();
21921 //this.wrap.dom.innerHTML = '';
21922 //this.wrap.remove();
21927 onFirstFocus : function(){
21929 this.assignDocWin();
21932 this.activated = true;
21935 if(Roo.isGecko){ // prevent silly gecko errors
21937 var s = this.win.getSelection();
21938 if(!s.focusNode || s.focusNode.nodeType != 3){
21939 var r = s.getRangeAt(0);
21940 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21945 this.execCmd('useCSS', true);
21946 this.execCmd('styleWithCSS', false);
21949 this.owner.fireEvent('activate', this);
21953 adjustFont: function(btn){
21954 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21955 //if(Roo.isSafari){ // safari
21958 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21959 if(Roo.isSafari){ // safari
21960 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21961 v = (v < 10) ? 10 : v;
21962 v = (v > 48) ? 48 : v;
21963 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21968 v = Math.max(1, v+adjust);
21970 this.execCmd('FontSize', v );
21973 onEditorEvent : function(e)
21975 this.owner.fireEvent('editorevent', this, e);
21976 // this.updateToolbar();
21977 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21980 insertTag : function(tg)
21982 // could be a bit smarter... -> wrap the current selected tRoo..
21983 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21985 range = this.createRange(this.getSelection());
21986 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21987 wrappingNode.appendChild(range.extractContents());
21988 range.insertNode(wrappingNode);
21995 this.execCmd("formatblock", tg);
21999 insertText : function(txt)
22003 var range = this.createRange();
22004 range.deleteContents();
22005 //alert(Sender.getAttribute('label'));
22007 range.insertNode(this.doc.createTextNode(txt));
22013 * Executes a Midas editor command on the editor document and performs necessary focus and
22014 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22015 * @param {String} cmd The Midas command
22016 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22018 relayCmd : function(cmd, value){
22020 this.execCmd(cmd, value);
22021 this.owner.fireEvent('editorevent', this);
22022 //this.updateToolbar();
22023 this.owner.deferFocus();
22027 * Executes a Midas editor command directly on the editor document.
22028 * For visual commands, you should use {@link #relayCmd} instead.
22029 * <b>This should only be called after the editor is initialized.</b>
22030 * @param {String} cmd The Midas command
22031 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22033 execCmd : function(cmd, value){
22034 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22041 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22043 * @param {String} text | dom node..
22045 insertAtCursor : function(text)
22048 if(!this.activated){
22054 var r = this.doc.selection.createRange();
22065 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22069 // from jquery ui (MIT licenced)
22071 var win = this.win;
22073 if (win.getSelection && win.getSelection().getRangeAt) {
22074 range = win.getSelection().getRangeAt(0);
22075 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22076 range.insertNode(node);
22077 } else if (win.document.selection && win.document.selection.createRange) {
22078 // no firefox support
22079 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22080 win.document.selection.createRange().pasteHTML(txt);
22082 // no firefox support
22083 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22084 this.execCmd('InsertHTML', txt);
22093 mozKeyPress : function(e){
22095 var c = e.getCharCode(), cmd;
22098 c = String.fromCharCode(c).toLowerCase();
22112 this.cleanUpPaste.defer(100, this);
22120 e.preventDefault();
22128 fixKeys : function(){ // load time branching for fastest keydown performance
22130 return function(e){
22131 var k = e.getKey(), r;
22134 r = this.doc.selection.createRange();
22137 r.pasteHTML('    ');
22144 r = this.doc.selection.createRange();
22146 var target = r.parentElement();
22147 if(!target || target.tagName.toLowerCase() != 'li'){
22149 r.pasteHTML('<br />');
22155 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22156 this.cleanUpPaste.defer(100, this);
22162 }else if(Roo.isOpera){
22163 return function(e){
22164 var k = e.getKey();
22168 this.execCmd('InsertHTML','    ');
22171 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22172 this.cleanUpPaste.defer(100, this);
22177 }else if(Roo.isSafari){
22178 return function(e){
22179 var k = e.getKey();
22183 this.execCmd('InsertText','\t');
22187 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22188 this.cleanUpPaste.defer(100, this);
22196 getAllAncestors: function()
22198 var p = this.getSelectedNode();
22201 a.push(p); // push blank onto stack..
22202 p = this.getParentElement();
22206 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22210 a.push(this.doc.body);
22214 lastSelNode : false,
22217 getSelection : function()
22219 this.assignDocWin();
22220 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22223 getSelectedNode: function()
22225 // this may only work on Gecko!!!
22227 // should we cache this!!!!
22232 var range = this.createRange(this.getSelection()).cloneRange();
22235 var parent = range.parentElement();
22237 var testRange = range.duplicate();
22238 testRange.moveToElementText(parent);
22239 if (testRange.inRange(range)) {
22242 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22245 parent = parent.parentElement;
22250 // is ancestor a text element.
22251 var ac = range.commonAncestorContainer;
22252 if (ac.nodeType == 3) {
22253 ac = ac.parentNode;
22256 var ar = ac.childNodes;
22259 var other_nodes = [];
22260 var has_other_nodes = false;
22261 for (var i=0;i<ar.length;i++) {
22262 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22265 // fullly contained node.
22267 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22272 // probably selected..
22273 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22274 other_nodes.push(ar[i]);
22278 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22283 has_other_nodes = true;
22285 if (!nodes.length && other_nodes.length) {
22286 nodes= other_nodes;
22288 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22294 createRange: function(sel)
22296 // this has strange effects when using with
22297 // top toolbar - not sure if it's a great idea.
22298 //this.editor.contentWindow.focus();
22299 if (typeof sel != "undefined") {
22301 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22303 return this.doc.createRange();
22306 return this.doc.createRange();
22309 getParentElement: function()
22312 this.assignDocWin();
22313 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22315 var range = this.createRange(sel);
22318 var p = range.commonAncestorContainer;
22319 while (p.nodeType == 3) { // text node
22330 * Range intersection.. the hard stuff...
22334 * [ -- selected range --- ]
22338 * if end is before start or hits it. fail.
22339 * if start is after end or hits it fail.
22341 * if either hits (but other is outside. - then it's not
22347 // @see http://www.thismuchiknow.co.uk/?p=64.
22348 rangeIntersectsNode : function(range, node)
22350 var nodeRange = node.ownerDocument.createRange();
22352 nodeRange.selectNode(node);
22354 nodeRange.selectNodeContents(node);
22357 var rangeStartRange = range.cloneRange();
22358 rangeStartRange.collapse(true);
22360 var rangeEndRange = range.cloneRange();
22361 rangeEndRange.collapse(false);
22363 var nodeStartRange = nodeRange.cloneRange();
22364 nodeStartRange.collapse(true);
22366 var nodeEndRange = nodeRange.cloneRange();
22367 nodeEndRange.collapse(false);
22369 return rangeStartRange.compareBoundaryPoints(
22370 Range.START_TO_START, nodeEndRange) == -1 &&
22371 rangeEndRange.compareBoundaryPoints(
22372 Range.START_TO_START, nodeStartRange) == 1;
22376 rangeCompareNode : function(range, node)
22378 var nodeRange = node.ownerDocument.createRange();
22380 nodeRange.selectNode(node);
22382 nodeRange.selectNodeContents(node);
22386 range.collapse(true);
22388 nodeRange.collapse(true);
22390 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22391 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22393 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22395 var nodeIsBefore = ss == 1;
22396 var nodeIsAfter = ee == -1;
22398 if (nodeIsBefore && nodeIsAfter) {
22401 if (!nodeIsBefore && nodeIsAfter) {
22402 return 1; //right trailed.
22405 if (nodeIsBefore && !nodeIsAfter) {
22406 return 2; // left trailed.
22412 // private? - in a new class?
22413 cleanUpPaste : function()
22415 // cleans up the whole document..
22416 Roo.log('cleanuppaste');
22418 this.cleanUpChildren(this.doc.body);
22419 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22420 if (clean != this.doc.body.innerHTML) {
22421 this.doc.body.innerHTML = clean;
22426 cleanWordChars : function(input) {// change the chars to hex code
22427 var he = Roo.HtmlEditorCore;
22429 var output = input;
22430 Roo.each(he.swapCodes, function(sw) {
22431 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22433 output = output.replace(swapper, sw[1]);
22440 cleanUpChildren : function (n)
22442 if (!n.childNodes.length) {
22445 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22446 this.cleanUpChild(n.childNodes[i]);
22453 cleanUpChild : function (node)
22456 //console.log(node);
22457 if (node.nodeName == "#text") {
22458 // clean up silly Windows -- stuff?
22461 if (node.nodeName == "#comment") {
22462 node.parentNode.removeChild(node);
22463 // clean up silly Windows -- stuff?
22466 var lcname = node.tagName.toLowerCase();
22467 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22468 // whitelist of tags..
22470 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22472 node.parentNode.removeChild(node);
22477 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22479 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22480 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22482 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22483 // remove_keep_children = true;
22486 if (remove_keep_children) {
22487 this.cleanUpChildren(node);
22488 // inserts everything just before this node...
22489 while (node.childNodes.length) {
22490 var cn = node.childNodes[0];
22491 node.removeChild(cn);
22492 node.parentNode.insertBefore(cn, node);
22494 node.parentNode.removeChild(node);
22498 if (!node.attributes || !node.attributes.length) {
22499 this.cleanUpChildren(node);
22503 function cleanAttr(n,v)
22506 if (v.match(/^\./) || v.match(/^\//)) {
22509 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22512 if (v.match(/^#/)) {
22515 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22516 node.removeAttribute(n);
22520 var cwhite = this.cwhite;
22521 var cblack = this.cblack;
22523 function cleanStyle(n,v)
22525 if (v.match(/expression/)) { //XSS?? should we even bother..
22526 node.removeAttribute(n);
22530 var parts = v.split(/;/);
22533 Roo.each(parts, function(p) {
22534 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22538 var l = p.split(':').shift().replace(/\s+/g,'');
22539 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22541 if ( cwhite.length && cblack.indexOf(l) > -1) {
22542 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22543 //node.removeAttribute(n);
22547 // only allow 'c whitelisted system attributes'
22548 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22549 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22550 //node.removeAttribute(n);
22560 if (clean.length) {
22561 node.setAttribute(n, clean.join(';'));
22563 node.removeAttribute(n);
22569 for (var i = node.attributes.length-1; i > -1 ; i--) {
22570 var a = node.attributes[i];
22573 if (a.name.toLowerCase().substr(0,2)=='on') {
22574 node.removeAttribute(a.name);
22577 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22578 node.removeAttribute(a.name);
22581 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22582 cleanAttr(a.name,a.value); // fixme..
22585 if (a.name == 'style') {
22586 cleanStyle(a.name,a.value);
22589 /// clean up MS crap..
22590 // tecnically this should be a list of valid class'es..
22593 if (a.name == 'class') {
22594 if (a.value.match(/^Mso/)) {
22595 node.className = '';
22598 if (a.value.match(/^body$/)) {
22599 node.className = '';
22610 this.cleanUpChildren(node);
22616 * Clean up MS wordisms...
22618 cleanWord : function(node)
22623 this.cleanWord(this.doc.body);
22626 if (node.nodeName == "#text") {
22627 // clean up silly Windows -- stuff?
22630 if (node.nodeName == "#comment") {
22631 node.parentNode.removeChild(node);
22632 // clean up silly Windows -- stuff?
22636 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22637 node.parentNode.removeChild(node);
22641 // remove - but keep children..
22642 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22643 while (node.childNodes.length) {
22644 var cn = node.childNodes[0];
22645 node.removeChild(cn);
22646 node.parentNode.insertBefore(cn, node);
22648 node.parentNode.removeChild(node);
22649 this.iterateChildren(node, this.cleanWord);
22653 if (node.className.length) {
22655 var cn = node.className.split(/\W+/);
22657 Roo.each(cn, function(cls) {
22658 if (cls.match(/Mso[a-zA-Z]+/)) {
22663 node.className = cna.length ? cna.join(' ') : '';
22665 node.removeAttribute("class");
22669 if (node.hasAttribute("lang")) {
22670 node.removeAttribute("lang");
22673 if (node.hasAttribute("style")) {
22675 var styles = node.getAttribute("style").split(";");
22677 Roo.each(styles, function(s) {
22678 if (!s.match(/:/)) {
22681 var kv = s.split(":");
22682 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22685 // what ever is left... we allow.
22688 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22689 if (!nstyle.length) {
22690 node.removeAttribute('style');
22693 this.iterateChildren(node, this.cleanWord);
22699 * iterateChildren of a Node, calling fn each time, using this as the scole..
22700 * @param {DomNode} node node to iterate children of.
22701 * @param {Function} fn method of this class to call on each item.
22703 iterateChildren : function(node, fn)
22705 if (!node.childNodes.length) {
22708 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22709 fn.call(this, node.childNodes[i])
22715 * cleanTableWidths.
22717 * Quite often pasting from word etc.. results in tables with column and widths.
22718 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22721 cleanTableWidths : function(node)
22726 this.cleanTableWidths(this.doc.body);
22731 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22734 Roo.log(node.tagName);
22735 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22736 this.iterateChildren(node, this.cleanTableWidths);
22739 if (node.hasAttribute('width')) {
22740 node.removeAttribute('width');
22744 if (node.hasAttribute("style")) {
22747 var styles = node.getAttribute("style").split(";");
22749 Roo.each(styles, function(s) {
22750 if (!s.match(/:/)) {
22753 var kv = s.split(":");
22754 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22757 // what ever is left... we allow.
22760 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22761 if (!nstyle.length) {
22762 node.removeAttribute('style');
22766 this.iterateChildren(node, this.cleanTableWidths);
22774 domToHTML : function(currentElement, depth, nopadtext) {
22776 depth = depth || 0;
22777 nopadtext = nopadtext || false;
22779 if (!currentElement) {
22780 return this.domToHTML(this.doc.body);
22783 //Roo.log(currentElement);
22785 var allText = false;
22786 var nodeName = currentElement.nodeName;
22787 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22789 if (nodeName == '#text') {
22791 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22796 if (nodeName != 'BODY') {
22799 // Prints the node tagName, such as <A>, <IMG>, etc
22802 for(i = 0; i < currentElement.attributes.length;i++) {
22804 var aname = currentElement.attributes.item(i).name;
22805 if (!currentElement.attributes.item(i).value.length) {
22808 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22811 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22820 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22823 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22828 // Traverse the tree
22830 var currentElementChild = currentElement.childNodes.item(i);
22831 var allText = true;
22832 var innerHTML = '';
22834 while (currentElementChild) {
22835 // Formatting code (indent the tree so it looks nice on the screen)
22836 var nopad = nopadtext;
22837 if (lastnode == 'SPAN') {
22841 if (currentElementChild.nodeName == '#text') {
22842 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22843 toadd = nopadtext ? toadd : toadd.trim();
22844 if (!nopad && toadd.length > 80) {
22845 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22847 innerHTML += toadd;
22850 currentElementChild = currentElement.childNodes.item(i);
22856 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22858 // Recursively traverse the tree structure of the child node
22859 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22860 lastnode = currentElementChild.nodeName;
22862 currentElementChild=currentElement.childNodes.item(i);
22868 // The remaining code is mostly for formatting the tree
22869 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22874 ret+= "</"+tagName+">";
22880 applyBlacklists : function()
22882 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22883 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22887 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22888 if (b.indexOf(tag) > -1) {
22891 this.white.push(tag);
22895 Roo.each(w, function(tag) {
22896 if (b.indexOf(tag) > -1) {
22899 if (this.white.indexOf(tag) > -1) {
22902 this.white.push(tag);
22907 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22908 if (w.indexOf(tag) > -1) {
22911 this.black.push(tag);
22915 Roo.each(b, function(tag) {
22916 if (w.indexOf(tag) > -1) {
22919 if (this.black.indexOf(tag) > -1) {
22922 this.black.push(tag);
22927 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22928 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22932 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22933 if (b.indexOf(tag) > -1) {
22936 this.cwhite.push(tag);
22940 Roo.each(w, function(tag) {
22941 if (b.indexOf(tag) > -1) {
22944 if (this.cwhite.indexOf(tag) > -1) {
22947 this.cwhite.push(tag);
22952 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22953 if (w.indexOf(tag) > -1) {
22956 this.cblack.push(tag);
22960 Roo.each(b, function(tag) {
22961 if (w.indexOf(tag) > -1) {
22964 if (this.cblack.indexOf(tag) > -1) {
22967 this.cblack.push(tag);
22972 setStylesheets : function(stylesheets)
22974 if(typeof(stylesheets) == 'string'){
22975 Roo.get(this.iframe.contentDocument.head).createChild({
22977 rel : 'stylesheet',
22986 Roo.each(stylesheets, function(s) {
22991 Roo.get(_this.iframe.contentDocument.head).createChild({
22993 rel : 'stylesheet',
23002 removeStylesheets : function()
23006 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23011 setStyle : function(style)
23013 Roo.get(this.iframe.contentDocument.head).createChild({
23022 // hide stuff that is not compatible
23036 * @event specialkey
23040 * @cfg {String} fieldClass @hide
23043 * @cfg {String} focusClass @hide
23046 * @cfg {String} autoCreate @hide
23049 * @cfg {String} inputType @hide
23052 * @cfg {String} invalidClass @hide
23055 * @cfg {String} invalidText @hide
23058 * @cfg {String} msgFx @hide
23061 * @cfg {String} validateOnBlur @hide
23065 Roo.HtmlEditorCore.white = [
23066 'area', 'br', 'img', 'input', 'hr', 'wbr',
23068 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23069 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23070 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23071 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23072 'table', 'ul', 'xmp',
23074 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23077 'dir', 'menu', 'ol', 'ul', 'dl',
23083 Roo.HtmlEditorCore.black = [
23084 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23086 'base', 'basefont', 'bgsound', 'blink', 'body',
23087 'frame', 'frameset', 'head', 'html', 'ilayer',
23088 'iframe', 'layer', 'link', 'meta', 'object',
23089 'script', 'style' ,'title', 'xml' // clean later..
23091 Roo.HtmlEditorCore.clean = [
23092 'script', 'style', 'title', 'xml'
23094 Roo.HtmlEditorCore.remove = [
23099 Roo.HtmlEditorCore.ablack = [
23103 Roo.HtmlEditorCore.aclean = [
23104 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23108 Roo.HtmlEditorCore.pwhite= [
23109 'http', 'https', 'mailto'
23112 // white listed style attributes.
23113 Roo.HtmlEditorCore.cwhite= [
23114 // 'text-align', /// default is to allow most things..
23120 // black listed style attributes.
23121 Roo.HtmlEditorCore.cblack= [
23122 // 'font-size' -- this can be set by the project
23126 Roo.HtmlEditorCore.swapCodes =[
23145 * @class Roo.bootstrap.HtmlEditor
23146 * @extends Roo.bootstrap.TextArea
23147 * Bootstrap HtmlEditor class
23150 * Create a new HtmlEditor
23151 * @param {Object} config The config object
23154 Roo.bootstrap.HtmlEditor = function(config){
23155 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23156 if (!this.toolbars) {
23157 this.toolbars = [];
23160 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23163 * @event initialize
23164 * Fires when the editor is fully initialized (including the iframe)
23165 * @param {HtmlEditor} this
23170 * Fires when the editor is first receives the focus. Any insertion must wait
23171 * until after this event.
23172 * @param {HtmlEditor} this
23176 * @event beforesync
23177 * Fires before the textarea is updated with content from the editor iframe. Return false
23178 * to cancel the sync.
23179 * @param {HtmlEditor} this
23180 * @param {String} html
23184 * @event beforepush
23185 * Fires before the iframe editor is updated with content from the textarea. Return false
23186 * to cancel the push.
23187 * @param {HtmlEditor} this
23188 * @param {String} html
23193 * Fires when the textarea is updated with content from the editor iframe.
23194 * @param {HtmlEditor} this
23195 * @param {String} html
23200 * Fires when the iframe editor is updated with content from the textarea.
23201 * @param {HtmlEditor} this
23202 * @param {String} html
23206 * @event editmodechange
23207 * Fires when the editor switches edit modes
23208 * @param {HtmlEditor} this
23209 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23211 editmodechange: true,
23213 * @event editorevent
23214 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23215 * @param {HtmlEditor} this
23219 * @event firstfocus
23220 * Fires when on first focus - needed by toolbars..
23221 * @param {HtmlEditor} this
23226 * Auto save the htmlEditor value as a file into Events
23227 * @param {HtmlEditor} this
23231 * @event savedpreview
23232 * preview the saved version of htmlEditor
23233 * @param {HtmlEditor} this
23240 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23244 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23249 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23254 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23259 * @cfg {Number} height (in pixels)
23263 * @cfg {Number} width (in pixels)
23268 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23271 stylesheets: false,
23276 // private properties
23277 validationEvent : false,
23279 initialized : false,
23282 onFocus : Roo.emptyFn,
23284 hideMode:'offsets',
23286 tbContainer : false,
23290 toolbarContainer :function() {
23291 return this.wrap.select('.x-html-editor-tb',true).first();
23295 * Protected method that will not generally be called directly. It
23296 * is called when the editor creates its toolbar. Override this method if you need to
23297 * add custom toolbar buttons.
23298 * @param {HtmlEditor} editor
23300 createToolbar : function(){
23301 Roo.log('renewing');
23302 Roo.log("create toolbars");
23304 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23305 this.toolbars[0].render(this.toolbarContainer());
23309 // if (!editor.toolbars || !editor.toolbars.length) {
23310 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23313 // for (var i =0 ; i < editor.toolbars.length;i++) {
23314 // editor.toolbars[i] = Roo.factory(
23315 // typeof(editor.toolbars[i]) == 'string' ?
23316 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23317 // Roo.bootstrap.HtmlEditor);
23318 // editor.toolbars[i].init(editor);
23324 onRender : function(ct, position)
23326 // Roo.log("Call onRender: " + this.xtype);
23328 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23330 this.wrap = this.inputEl().wrap({
23331 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23334 this.editorcore.onRender(ct, position);
23336 if (this.resizable) {
23337 this.resizeEl = new Roo.Resizable(this.wrap, {
23341 minHeight : this.height,
23342 height: this.height,
23343 handles : this.resizable,
23346 resize : function(r, w, h) {
23347 _t.onResize(w,h); // -something
23353 this.createToolbar(this);
23356 if(!this.width && this.resizable){
23357 this.setSize(this.wrap.getSize());
23359 if (this.resizeEl) {
23360 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23361 // should trigger onReize..
23367 onResize : function(w, h)
23369 Roo.log('resize: ' +w + ',' + h );
23370 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23374 if(this.inputEl() ){
23375 if(typeof w == 'number'){
23376 var aw = w - this.wrap.getFrameWidth('lr');
23377 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23380 if(typeof h == 'number'){
23381 var tbh = -11; // fixme it needs to tool bar size!
23382 for (var i =0; i < this.toolbars.length;i++) {
23383 // fixme - ask toolbars for heights?
23384 tbh += this.toolbars[i].el.getHeight();
23385 //if (this.toolbars[i].footer) {
23386 // tbh += this.toolbars[i].footer.el.getHeight();
23394 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23395 ah -= 5; // knock a few pixes off for look..
23396 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23400 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23401 this.editorcore.onResize(ew,eh);
23406 * Toggles the editor between standard and source edit mode.
23407 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23409 toggleSourceEdit : function(sourceEditMode)
23411 this.editorcore.toggleSourceEdit(sourceEditMode);
23413 if(this.editorcore.sourceEditMode){
23414 Roo.log('editor - showing textarea');
23417 // Roo.log(this.syncValue());
23419 this.inputEl().removeClass(['hide', 'x-hidden']);
23420 this.inputEl().dom.removeAttribute('tabIndex');
23421 this.inputEl().focus();
23423 Roo.log('editor - hiding textarea');
23425 // Roo.log(this.pushValue());
23428 this.inputEl().addClass(['hide', 'x-hidden']);
23429 this.inputEl().dom.setAttribute('tabIndex', -1);
23430 //this.deferFocus();
23433 if(this.resizable){
23434 this.setSize(this.wrap.getSize());
23437 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23440 // private (for BoxComponent)
23441 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23443 // private (for BoxComponent)
23444 getResizeEl : function(){
23448 // private (for BoxComponent)
23449 getPositionEl : function(){
23454 initEvents : function(){
23455 this.originalValue = this.getValue();
23459 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23462 // markInvalid : Roo.emptyFn,
23464 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23467 // clearInvalid : Roo.emptyFn,
23469 setValue : function(v){
23470 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23471 this.editorcore.pushValue();
23476 deferFocus : function(){
23477 this.focus.defer(10, this);
23481 focus : function(){
23482 this.editorcore.focus();
23488 onDestroy : function(){
23494 for (var i =0; i < this.toolbars.length;i++) {
23495 // fixme - ask toolbars for heights?
23496 this.toolbars[i].onDestroy();
23499 this.wrap.dom.innerHTML = '';
23500 this.wrap.remove();
23505 onFirstFocus : function(){
23506 //Roo.log("onFirstFocus");
23507 this.editorcore.onFirstFocus();
23508 for (var i =0; i < this.toolbars.length;i++) {
23509 this.toolbars[i].onFirstFocus();
23515 syncValue : function()
23517 this.editorcore.syncValue();
23520 pushValue : function()
23522 this.editorcore.pushValue();
23526 // hide stuff that is not compatible
23540 * @event specialkey
23544 * @cfg {String} fieldClass @hide
23547 * @cfg {String} focusClass @hide
23550 * @cfg {String} autoCreate @hide
23553 * @cfg {String} inputType @hide
23556 * @cfg {String} invalidClass @hide
23559 * @cfg {String} invalidText @hide
23562 * @cfg {String} msgFx @hide
23565 * @cfg {String} validateOnBlur @hide
23574 Roo.namespace('Roo.bootstrap.htmleditor');
23576 * @class Roo.bootstrap.HtmlEditorToolbar1
23581 new Roo.bootstrap.HtmlEditor({
23584 new Roo.bootstrap.HtmlEditorToolbar1({
23585 disable : { fonts: 1 , format: 1, ..., ... , ...],
23591 * @cfg {Object} disable List of elements to disable..
23592 * @cfg {Array} btns List of additional buttons.
23596 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23599 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23602 Roo.apply(this, config);
23604 // default disabled, based on 'good practice'..
23605 this.disable = this.disable || {};
23606 Roo.applyIf(this.disable, {
23609 specialElements : true
23611 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23613 this.editor = config.editor;
23614 this.editorcore = config.editor.editorcore;
23616 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23618 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23619 // dont call parent... till later.
23621 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23626 editorcore : false,
23631 "h1","h2","h3","h4","h5","h6",
23633 "abbr", "acronym", "address", "cite", "samp", "var",
23637 onRender : function(ct, position)
23639 // Roo.log("Call onRender: " + this.xtype);
23641 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23643 this.el.dom.style.marginBottom = '0';
23645 var editorcore = this.editorcore;
23646 var editor= this.editor;
23649 var btn = function(id,cmd , toggle, handler, html){
23651 var event = toggle ? 'toggle' : 'click';
23656 xns: Roo.bootstrap,
23659 enableToggle:toggle !== false,
23661 pressed : toggle ? false : null,
23664 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23665 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23671 // var cb_box = function...
23676 xns: Roo.bootstrap,
23677 glyphicon : 'font',
23681 xns: Roo.bootstrap,
23685 Roo.each(this.formats, function(f) {
23686 style.menu.items.push({
23688 xns: Roo.bootstrap,
23689 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23694 editorcore.insertTag(this.tagname);
23701 children.push(style);
23703 btn('bold',false,true);
23704 btn('italic',false,true);
23705 btn('align-left', 'justifyleft',true);
23706 btn('align-center', 'justifycenter',true);
23707 btn('align-right' , 'justifyright',true);
23708 btn('link', false, false, function(btn) {
23709 //Roo.log("create link?");
23710 var url = prompt(this.createLinkText, this.defaultLinkValue);
23711 if(url && url != 'http:/'+'/'){
23712 this.editorcore.relayCmd('createlink', url);
23715 btn('list','insertunorderedlist',true);
23716 btn('pencil', false,true, function(btn){
23718 this.toggleSourceEdit(btn.pressed);
23721 if (this.editor.btns.length > 0) {
23722 for (var i = 0; i<this.editor.btns.length; i++) {
23723 children.push(this.editor.btns[i]);
23731 xns: Roo.bootstrap,
23736 xns: Roo.bootstrap,
23741 cog.menu.items.push({
23743 xns: Roo.bootstrap,
23744 html : Clean styles,
23749 editorcore.insertTag(this.tagname);
23758 this.xtype = 'NavSimplebar';
23760 for(var i=0;i< children.length;i++) {
23762 this.buttons.add(this.addxtypeChild(children[i]));
23766 editor.on('editorevent', this.updateToolbar, this);
23768 onBtnClick : function(id)
23770 this.editorcore.relayCmd(id);
23771 this.editorcore.focus();
23775 * Protected method that will not generally be called directly. It triggers
23776 * a toolbar update by reading the markup state of the current selection in the editor.
23778 updateToolbar: function(){
23780 if(!this.editorcore.activated){
23781 this.editor.onFirstFocus(); // is this neeed?
23785 var btns = this.buttons;
23786 var doc = this.editorcore.doc;
23787 btns.get('bold').setActive(doc.queryCommandState('bold'));
23788 btns.get('italic').setActive(doc.queryCommandState('italic'));
23789 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23791 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23792 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23793 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23795 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23796 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23799 var ans = this.editorcore.getAllAncestors();
23800 if (this.formatCombo) {
23803 var store = this.formatCombo.store;
23804 this.formatCombo.setValue("");
23805 for (var i =0; i < ans.length;i++) {
23806 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23808 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23816 // hides menus... - so this cant be on a menu...
23817 Roo.bootstrap.MenuMgr.hideAll();
23819 Roo.bootstrap.MenuMgr.hideAll();
23820 //this.editorsyncValue();
23822 onFirstFocus: function() {
23823 this.buttons.each(function(item){
23827 toggleSourceEdit : function(sourceEditMode){
23830 if(sourceEditMode){
23831 Roo.log("disabling buttons");
23832 this.buttons.each( function(item){
23833 if(item.cmd != 'pencil'){
23839 Roo.log("enabling buttons");
23840 if(this.editorcore.initialized){
23841 this.buttons.each( function(item){
23847 Roo.log("calling toggole on editor");
23848 // tell the editor that it's been pressed..
23849 this.editor.toggleSourceEdit(sourceEditMode);
23859 * @class Roo.bootstrap.Table.AbstractSelectionModel
23860 * @extends Roo.util.Observable
23861 * Abstract base class for grid SelectionModels. It provides the interface that should be
23862 * implemented by descendant classes. This class should not be directly instantiated.
23865 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23866 this.locked = false;
23867 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23871 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23872 /** @ignore Called by the grid automatically. Do not call directly. */
23873 init : function(grid){
23879 * Locks the selections.
23882 this.locked = true;
23886 * Unlocks the selections.
23888 unlock : function(){
23889 this.locked = false;
23893 * Returns true if the selections are locked.
23894 * @return {Boolean}
23896 isLocked : function(){
23897 return this.locked;
23901 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23902 * @class Roo.bootstrap.Table.RowSelectionModel
23903 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23904 * It supports multiple selections and keyboard selection/navigation.
23906 * @param {Object} config
23909 Roo.bootstrap.Table.RowSelectionModel = function(config){
23910 Roo.apply(this, config);
23911 this.selections = new Roo.util.MixedCollection(false, function(o){
23916 this.lastActive = false;
23920 * @event selectionchange
23921 * Fires when the selection changes
23922 * @param {SelectionModel} this
23924 "selectionchange" : true,
23926 * @event afterselectionchange
23927 * Fires after the selection changes (eg. by key press or clicking)
23928 * @param {SelectionModel} this
23930 "afterselectionchange" : true,
23932 * @event beforerowselect
23933 * Fires when a row is selected being selected, return false to cancel.
23934 * @param {SelectionModel} this
23935 * @param {Number} rowIndex The selected index
23936 * @param {Boolean} keepExisting False if other selections will be cleared
23938 "beforerowselect" : true,
23941 * Fires when a row is selected.
23942 * @param {SelectionModel} this
23943 * @param {Number} rowIndex The selected index
23944 * @param {Roo.data.Record} r The record
23946 "rowselect" : true,
23948 * @event rowdeselect
23949 * Fires when a row is deselected.
23950 * @param {SelectionModel} this
23951 * @param {Number} rowIndex The selected index
23953 "rowdeselect" : true
23955 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23956 this.locked = false;
23959 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23961 * @cfg {Boolean} singleSelect
23962 * True to allow selection of only one row at a time (defaults to false)
23964 singleSelect : false,
23967 initEvents : function()
23970 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23971 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23972 //}else{ // allow click to work like normal
23973 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23975 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23976 this.grid.on("rowclick", this.handleMouseDown, this);
23978 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23979 "up" : function(e){
23981 this.selectPrevious(e.shiftKey);
23982 }else if(this.last !== false && this.lastActive !== false){
23983 var last = this.last;
23984 this.selectRange(this.last, this.lastActive-1);
23985 this.grid.getView().focusRow(this.lastActive);
23986 if(last !== false){
23990 this.selectFirstRow();
23992 this.fireEvent("afterselectionchange", this);
23994 "down" : function(e){
23996 this.selectNext(e.shiftKey);
23997 }else if(this.last !== false && this.lastActive !== false){
23998 var last = this.last;
23999 this.selectRange(this.last, this.lastActive+1);
24000 this.grid.getView().focusRow(this.lastActive);
24001 if(last !== false){
24005 this.selectFirstRow();
24007 this.fireEvent("afterselectionchange", this);
24011 this.grid.store.on('load', function(){
24012 this.selections.clear();
24015 var view = this.grid.view;
24016 view.on("refresh", this.onRefresh, this);
24017 view.on("rowupdated", this.onRowUpdated, this);
24018 view.on("rowremoved", this.onRemove, this);
24023 onRefresh : function()
24025 var ds = this.grid.store, i, v = this.grid.view;
24026 var s = this.selections;
24027 s.each(function(r){
24028 if((i = ds.indexOfId(r.id)) != -1){
24037 onRemove : function(v, index, r){
24038 this.selections.remove(r);
24042 onRowUpdated : function(v, index, r){
24043 if(this.isSelected(r)){
24044 v.onRowSelect(index);
24050 * @param {Array} records The records to select
24051 * @param {Boolean} keepExisting (optional) True to keep existing selections
24053 selectRecords : function(records, keepExisting)
24056 this.clearSelections();
24058 var ds = this.grid.store;
24059 for(var i = 0, len = records.length; i < len; i++){
24060 this.selectRow(ds.indexOf(records[i]), true);
24065 * Gets the number of selected rows.
24068 getCount : function(){
24069 return this.selections.length;
24073 * Selects the first row in the grid.
24075 selectFirstRow : function(){
24080 * Select the last row.
24081 * @param {Boolean} keepExisting (optional) True to keep existing selections
24083 selectLastRow : function(keepExisting){
24084 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24085 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24089 * Selects the row immediately following the last selected row.
24090 * @param {Boolean} keepExisting (optional) True to keep existing selections
24092 selectNext : function(keepExisting)
24094 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24095 this.selectRow(this.last+1, keepExisting);
24096 this.grid.getView().focusRow(this.last);
24101 * Selects the row that precedes the last selected row.
24102 * @param {Boolean} keepExisting (optional) True to keep existing selections
24104 selectPrevious : function(keepExisting){
24106 this.selectRow(this.last-1, keepExisting);
24107 this.grid.getView().focusRow(this.last);
24112 * Returns the selected records
24113 * @return {Array} Array of selected records
24115 getSelections : function(){
24116 return [].concat(this.selections.items);
24120 * Returns the first selected record.
24123 getSelected : function(){
24124 return this.selections.itemAt(0);
24129 * Clears all selections.
24131 clearSelections : function(fast)
24137 var ds = this.grid.store;
24138 var s = this.selections;
24139 s.each(function(r){
24140 this.deselectRow(ds.indexOfId(r.id));
24144 this.selections.clear();
24151 * Selects all rows.
24153 selectAll : function(){
24157 this.selections.clear();
24158 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24159 this.selectRow(i, true);
24164 * Returns True if there is a selection.
24165 * @return {Boolean}
24167 hasSelection : function(){
24168 return this.selections.length > 0;
24172 * Returns True if the specified row is selected.
24173 * @param {Number/Record} record The record or index of the record to check
24174 * @return {Boolean}
24176 isSelected : function(index){
24177 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24178 return (r && this.selections.key(r.id) ? true : false);
24182 * Returns True if the specified record id is selected.
24183 * @param {String} id The id of record to check
24184 * @return {Boolean}
24186 isIdSelected : function(id){
24187 return (this.selections.key(id) ? true : false);
24192 handleMouseDBClick : function(e, t){
24196 handleMouseDown : function(e, t)
24198 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24199 if(this.isLocked() || rowIndex < 0 ){
24202 if(e.shiftKey && this.last !== false){
24203 var last = this.last;
24204 this.selectRange(last, rowIndex, e.ctrlKey);
24205 this.last = last; // reset the last
24209 var isSelected = this.isSelected(rowIndex);
24210 //Roo.log("select row:" + rowIndex);
24212 this.deselectRow(rowIndex);
24214 this.selectRow(rowIndex, true);
24218 if(e.button !== 0 && isSelected){
24219 alert('rowIndex 2: ' + rowIndex);
24220 view.focusRow(rowIndex);
24221 }else if(e.ctrlKey && isSelected){
24222 this.deselectRow(rowIndex);
24223 }else if(!isSelected){
24224 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24225 view.focusRow(rowIndex);
24229 this.fireEvent("afterselectionchange", this);
24232 handleDragableRowClick : function(grid, rowIndex, e)
24234 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24235 this.selectRow(rowIndex, false);
24236 grid.view.focusRow(rowIndex);
24237 this.fireEvent("afterselectionchange", this);
24242 * Selects multiple rows.
24243 * @param {Array} rows Array of the indexes of the row to select
24244 * @param {Boolean} keepExisting (optional) True to keep existing selections
24246 selectRows : function(rows, keepExisting){
24248 this.clearSelections();
24250 for(var i = 0, len = rows.length; i < len; i++){
24251 this.selectRow(rows[i], true);
24256 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24257 * @param {Number} startRow The index of the first row in the range
24258 * @param {Number} endRow The index of the last row in the range
24259 * @param {Boolean} keepExisting (optional) True to retain existing selections
24261 selectRange : function(startRow, endRow, keepExisting){
24266 this.clearSelections();
24268 if(startRow <= endRow){
24269 for(var i = startRow; i <= endRow; i++){
24270 this.selectRow(i, true);
24273 for(var i = startRow; i >= endRow; i--){
24274 this.selectRow(i, true);
24280 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24281 * @param {Number} startRow The index of the first row in the range
24282 * @param {Number} endRow The index of the last row in the range
24284 deselectRange : function(startRow, endRow, preventViewNotify){
24288 for(var i = startRow; i <= endRow; i++){
24289 this.deselectRow(i, preventViewNotify);
24295 * @param {Number} row The index of the row to select
24296 * @param {Boolean} keepExisting (optional) True to keep existing selections
24298 selectRow : function(index, keepExisting, preventViewNotify)
24300 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24303 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24304 if(!keepExisting || this.singleSelect){
24305 this.clearSelections();
24308 var r = this.grid.store.getAt(index);
24309 //console.log('selectRow - record id :' + r.id);
24311 this.selections.add(r);
24312 this.last = this.lastActive = index;
24313 if(!preventViewNotify){
24314 var proxy = new Roo.Element(
24315 this.grid.getRowDom(index)
24317 proxy.addClass('bg-info info');
24319 this.fireEvent("rowselect", this, index, r);
24320 this.fireEvent("selectionchange", this);
24326 * @param {Number} row The index of the row to deselect
24328 deselectRow : function(index, preventViewNotify)
24333 if(this.last == index){
24336 if(this.lastActive == index){
24337 this.lastActive = false;
24340 var r = this.grid.store.getAt(index);
24345 this.selections.remove(r);
24346 //.console.log('deselectRow - record id :' + r.id);
24347 if(!preventViewNotify){
24349 var proxy = new Roo.Element(
24350 this.grid.getRowDom(index)
24352 proxy.removeClass('bg-info info');
24354 this.fireEvent("rowdeselect", this, index);
24355 this.fireEvent("selectionchange", this);
24359 restoreLast : function(){
24361 this.last = this._last;
24366 acceptsNav : function(row, col, cm){
24367 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24371 onEditorKey : function(field, e){
24372 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24377 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24379 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24381 }else if(k == e.ENTER && !e.ctrlKey){
24385 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24387 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24389 }else if(k == e.ESC){
24393 g.startEditing(newCell[0], newCell[1]);
24399 * Ext JS Library 1.1.1
24400 * Copyright(c) 2006-2007, Ext JS, LLC.
24402 * Originally Released Under LGPL - original licence link has changed is not relivant.
24405 * <script type="text/javascript">
24409 * @class Roo.bootstrap.PagingToolbar
24410 * @extends Roo.bootstrap.NavSimplebar
24411 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24413 * Create a new PagingToolbar
24414 * @param {Object} config The config object
24415 * @param {Roo.data.Store} store
24417 Roo.bootstrap.PagingToolbar = function(config)
24419 // old args format still supported... - xtype is prefered..
24420 // created from xtype...
24422 this.ds = config.dataSource;
24424 if (config.store && !this.ds) {
24425 this.store= Roo.factory(config.store, Roo.data);
24426 this.ds = this.store;
24427 this.ds.xmodule = this.xmodule || false;
24430 this.toolbarItems = [];
24431 if (config.items) {
24432 this.toolbarItems = config.items;
24435 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24440 this.bind(this.ds);
24443 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24447 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24449 * @cfg {Roo.data.Store} dataSource
24450 * The underlying data store providing the paged data
24453 * @cfg {String/HTMLElement/Element} container
24454 * container The id or element that will contain the toolbar
24457 * @cfg {Boolean} displayInfo
24458 * True to display the displayMsg (defaults to false)
24461 * @cfg {Number} pageSize
24462 * The number of records to display per page (defaults to 20)
24466 * @cfg {String} displayMsg
24467 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24469 displayMsg : 'Displaying {0} - {1} of {2}',
24471 * @cfg {String} emptyMsg
24472 * The message to display when no records are found (defaults to "No data to display")
24474 emptyMsg : 'No data to display',
24476 * Customizable piece of the default paging text (defaults to "Page")
24479 beforePageText : "Page",
24481 * Customizable piece of the default paging text (defaults to "of %0")
24484 afterPageText : "of {0}",
24486 * Customizable piece of the default paging text (defaults to "First Page")
24489 firstText : "First Page",
24491 * Customizable piece of the default paging text (defaults to "Previous Page")
24494 prevText : "Previous Page",
24496 * Customizable piece of the default paging text (defaults to "Next Page")
24499 nextText : "Next Page",
24501 * Customizable piece of the default paging text (defaults to "Last Page")
24504 lastText : "Last Page",
24506 * Customizable piece of the default paging text (defaults to "Refresh")
24509 refreshText : "Refresh",
24513 onRender : function(ct, position)
24515 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24516 this.navgroup.parentId = this.id;
24517 this.navgroup.onRender(this.el, null);
24518 // add the buttons to the navgroup
24520 if(this.displayInfo){
24521 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24522 this.displayEl = this.el.select('.x-paging-info', true).first();
24523 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24524 // this.displayEl = navel.el.select('span',true).first();
24530 Roo.each(_this.buttons, function(e){ // this might need to use render????
24531 Roo.factory(e).render(_this.el);
24535 Roo.each(_this.toolbarItems, function(e) {
24536 _this.navgroup.addItem(e);
24540 this.first = this.navgroup.addItem({
24541 tooltip: this.firstText,
24543 icon : 'fa fa-backward',
24545 preventDefault: true,
24546 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24549 this.prev = this.navgroup.addItem({
24550 tooltip: this.prevText,
24552 icon : 'fa fa-step-backward',
24554 preventDefault: true,
24555 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24557 //this.addSeparator();
24560 var field = this.navgroup.addItem( {
24562 cls : 'x-paging-position',
24564 html : this.beforePageText +
24565 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24566 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24569 this.field = field.el.select('input', true).first();
24570 this.field.on("keydown", this.onPagingKeydown, this);
24571 this.field.on("focus", function(){this.dom.select();});
24574 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24575 //this.field.setHeight(18);
24576 //this.addSeparator();
24577 this.next = this.navgroup.addItem({
24578 tooltip: this.nextText,
24580 html : ' <i class="fa fa-step-forward">',
24582 preventDefault: true,
24583 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24585 this.last = this.navgroup.addItem({
24586 tooltip: this.lastText,
24587 icon : 'fa fa-forward',
24590 preventDefault: true,
24591 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24593 //this.addSeparator();
24594 this.loading = this.navgroup.addItem({
24595 tooltip: this.refreshText,
24596 icon: 'fa fa-refresh',
24597 preventDefault: true,
24598 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24604 updateInfo : function(){
24605 if(this.displayEl){
24606 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24607 var msg = count == 0 ?
24611 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24613 this.displayEl.update(msg);
24618 onLoad : function(ds, r, o)
24620 this.cursor = o.params.start ? o.params.start : 0;
24622 var d = this.getPageData(),
24627 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24628 this.field.dom.value = ap;
24629 this.first.setDisabled(ap == 1);
24630 this.prev.setDisabled(ap == 1);
24631 this.next.setDisabled(ap == ps);
24632 this.last.setDisabled(ap == ps);
24633 this.loading.enable();
24638 getPageData : function(){
24639 var total = this.ds.getTotalCount();
24642 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24643 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24648 onLoadError : function(){
24649 this.loading.enable();
24653 onPagingKeydown : function(e){
24654 var k = e.getKey();
24655 var d = this.getPageData();
24657 var v = this.field.dom.value, pageNum;
24658 if(!v || isNaN(pageNum = parseInt(v, 10))){
24659 this.field.dom.value = d.activePage;
24662 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24663 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24666 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))
24668 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24669 this.field.dom.value = pageNum;
24670 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24673 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24675 var v = this.field.dom.value, pageNum;
24676 var increment = (e.shiftKey) ? 10 : 1;
24677 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24680 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24681 this.field.dom.value = d.activePage;
24684 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24686 this.field.dom.value = parseInt(v, 10) + increment;
24687 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24688 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24695 beforeLoad : function(){
24697 this.loading.disable();
24702 onClick : function(which){
24711 ds.load({params:{start: 0, limit: this.pageSize}});
24714 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24717 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24720 var total = ds.getTotalCount();
24721 var extra = total % this.pageSize;
24722 var lastStart = extra ? (total - extra) : total-this.pageSize;
24723 ds.load({params:{start: lastStart, limit: this.pageSize}});
24726 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24732 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24733 * @param {Roo.data.Store} store The data store to unbind
24735 unbind : function(ds){
24736 ds.un("beforeload", this.beforeLoad, this);
24737 ds.un("load", this.onLoad, this);
24738 ds.un("loadexception", this.onLoadError, this);
24739 ds.un("remove", this.updateInfo, this);
24740 ds.un("add", this.updateInfo, this);
24741 this.ds = undefined;
24745 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24746 * @param {Roo.data.Store} store The data store to bind
24748 bind : function(ds){
24749 ds.on("beforeload", this.beforeLoad, this);
24750 ds.on("load", this.onLoad, this);
24751 ds.on("loadexception", this.onLoadError, this);
24752 ds.on("remove", this.updateInfo, this);
24753 ds.on("add", this.updateInfo, this);
24764 * @class Roo.bootstrap.MessageBar
24765 * @extends Roo.bootstrap.Component
24766 * Bootstrap MessageBar class
24767 * @cfg {String} html contents of the MessageBar
24768 * @cfg {String} weight (info | success | warning | danger) default info
24769 * @cfg {String} beforeClass insert the bar before the given class
24770 * @cfg {Boolean} closable (true | false) default false
24771 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24774 * Create a new Element
24775 * @param {Object} config The config object
24778 Roo.bootstrap.MessageBar = function(config){
24779 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24782 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24788 beforeClass: 'bootstrap-sticky-wrap',
24790 getAutoCreate : function(){
24794 cls: 'alert alert-dismissable alert-' + this.weight,
24799 html: this.html || ''
24805 cfg.cls += ' alert-messages-fixed';
24819 onRender : function(ct, position)
24821 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24824 var cfg = Roo.apply({}, this.getAutoCreate());
24828 cfg.cls += ' ' + this.cls;
24831 cfg.style = this.style;
24833 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24835 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24838 this.el.select('>button.close').on('click', this.hide, this);
24844 if (!this.rendered) {
24850 this.fireEvent('show', this);
24856 if (!this.rendered) {
24862 this.fireEvent('hide', this);
24865 update : function()
24867 // var e = this.el.dom.firstChild;
24869 // if(this.closable){
24870 // e = e.nextSibling;
24873 // e.data = this.html || '';
24875 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24891 * @class Roo.bootstrap.Graph
24892 * @extends Roo.bootstrap.Component
24893 * Bootstrap Graph class
24897 @cfg {String} graphtype bar | vbar | pie
24898 @cfg {number} g_x coodinator | centre x (pie)
24899 @cfg {number} g_y coodinator | centre y (pie)
24900 @cfg {number} g_r radius (pie)
24901 @cfg {number} g_height height of the chart (respected by all elements in the set)
24902 @cfg {number} g_width width of the chart (respected by all elements in the set)
24903 @cfg {Object} title The title of the chart
24906 -opts (object) options for the chart
24908 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24909 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24911 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.
24912 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24914 o stretch (boolean)
24916 -opts (object) options for the pie
24919 o startAngle (number)
24920 o endAngle (number)
24924 * Create a new Input
24925 * @param {Object} config The config object
24928 Roo.bootstrap.Graph = function(config){
24929 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24935 * The img click event for the img.
24936 * @param {Roo.EventObject} e
24942 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24953 //g_colors: this.colors,
24960 getAutoCreate : function(){
24971 onRender : function(ct,position){
24974 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24976 if (typeof(Raphael) == 'undefined') {
24977 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24981 this.raphael = Raphael(this.el.dom);
24983 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24984 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24985 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24986 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24988 r.text(160, 10, "Single Series Chart").attr(txtattr);
24989 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24990 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24991 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24993 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24994 r.barchart(330, 10, 300, 220, data1);
24995 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24996 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24999 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25000 // r.barchart(30, 30, 560, 250, xdata, {
25001 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25002 // axis : "0 0 1 1",
25003 // axisxlabels : xdata
25004 // //yvalues : cols,
25007 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25009 // this.load(null,xdata,{
25010 // axis : "0 0 1 1",
25011 // axisxlabels : xdata
25016 load : function(graphtype,xdata,opts)
25018 this.raphael.clear();
25020 graphtype = this.graphtype;
25025 var r = this.raphael,
25026 fin = function () {
25027 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25029 fout = function () {
25030 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25032 pfin = function() {
25033 this.sector.stop();
25034 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25037 this.label[0].stop();
25038 this.label[0].attr({ r: 7.5 });
25039 this.label[1].attr({ "font-weight": 800 });
25042 pfout = function() {
25043 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25046 this.label[0].animate({ r: 5 }, 500, "bounce");
25047 this.label[1].attr({ "font-weight": 400 });
25053 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25056 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25059 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25060 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25062 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25069 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25074 setTitle: function(o)
25079 initEvents: function() {
25082 this.el.on('click', this.onClick, this);
25086 onClick : function(e)
25088 Roo.log('img onclick');
25089 this.fireEvent('click', this, e);
25101 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25104 * @class Roo.bootstrap.dash.NumberBox
25105 * @extends Roo.bootstrap.Component
25106 * Bootstrap NumberBox class
25107 * @cfg {String} headline Box headline
25108 * @cfg {String} content Box content
25109 * @cfg {String} icon Box icon
25110 * @cfg {String} footer Footer text
25111 * @cfg {String} fhref Footer href
25114 * Create a new NumberBox
25115 * @param {Object} config The config object
25119 Roo.bootstrap.dash.NumberBox = function(config){
25120 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25124 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25133 getAutoCreate : function(){
25137 cls : 'small-box ',
25145 cls : 'roo-headline',
25146 html : this.headline
25150 cls : 'roo-content',
25151 html : this.content
25165 cls : 'ion ' + this.icon
25174 cls : 'small-box-footer',
25175 href : this.fhref || '#',
25179 cfg.cn.push(footer);
25186 onRender : function(ct,position){
25187 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25194 setHeadline: function (value)
25196 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25199 setFooter: function (value, href)
25201 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25204 this.el.select('a.small-box-footer',true).first().attr('href', href);
25209 setContent: function (value)
25211 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25214 initEvents: function()
25228 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25231 * @class Roo.bootstrap.dash.TabBox
25232 * @extends Roo.bootstrap.Component
25233 * Bootstrap TabBox class
25234 * @cfg {String} title Title of the TabBox
25235 * @cfg {String} icon Icon of the TabBox
25236 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25237 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25240 * Create a new TabBox
25241 * @param {Object} config The config object
25245 Roo.bootstrap.dash.TabBox = function(config){
25246 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25251 * When a pane is added
25252 * @param {Roo.bootstrap.dash.TabPane} pane
25256 * @event activatepane
25257 * When a pane is activated
25258 * @param {Roo.bootstrap.dash.TabPane} pane
25260 "activatepane" : true
25268 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25273 tabScrollable : false,
25275 getChildContainer : function()
25277 return this.el.select('.tab-content', true).first();
25280 getAutoCreate : function(){
25284 cls: 'pull-left header',
25292 cls: 'fa ' + this.icon
25298 cls: 'nav nav-tabs pull-right',
25304 if(this.tabScrollable){
25311 cls: 'nav nav-tabs pull-right',
25322 cls: 'nav-tabs-custom',
25327 cls: 'tab-content no-padding',
25335 initEvents : function()
25337 //Roo.log('add add pane handler');
25338 this.on('addpane', this.onAddPane, this);
25341 * Updates the box title
25342 * @param {String} html to set the title to.
25344 setTitle : function(value)
25346 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25348 onAddPane : function(pane)
25350 this.panes.push(pane);
25351 //Roo.log('addpane');
25353 // tabs are rendere left to right..
25354 if(!this.showtabs){
25358 var ctr = this.el.select('.nav-tabs', true).first();
25361 var existing = ctr.select('.nav-tab',true);
25362 var qty = existing.getCount();;
25365 var tab = ctr.createChild({
25367 cls : 'nav-tab' + (qty ? '' : ' active'),
25375 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25378 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25380 pane.el.addClass('active');
25385 onTabClick : function(ev,un,ob,pane)
25387 //Roo.log('tab - prev default');
25388 ev.preventDefault();
25391 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25392 pane.tab.addClass('active');
25393 //Roo.log(pane.title);
25394 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25395 // technically we should have a deactivate event.. but maybe add later.
25396 // and it should not de-activate the selected tab...
25397 this.fireEvent('activatepane', pane);
25398 pane.el.addClass('active');
25399 pane.fireEvent('activate');
25404 getActivePane : function()
25407 Roo.each(this.panes, function(p) {
25408 if(p.el.hasClass('active')){
25429 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25431 * @class Roo.bootstrap.TabPane
25432 * @extends Roo.bootstrap.Component
25433 * Bootstrap TabPane class
25434 * @cfg {Boolean} active (false | true) Default false
25435 * @cfg {String} title title of panel
25439 * Create a new TabPane
25440 * @param {Object} config The config object
25443 Roo.bootstrap.dash.TabPane = function(config){
25444 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25450 * When a pane is activated
25451 * @param {Roo.bootstrap.dash.TabPane} pane
25458 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25463 // the tabBox that this is attached to.
25466 getAutoCreate : function()
25474 cfg.cls += ' active';
25479 initEvents : function()
25481 //Roo.log('trigger add pane handler');
25482 this.parent().fireEvent('addpane', this)
25486 * Updates the tab title
25487 * @param {String} html to set the title to.
25489 setTitle: function(str)
25495 this.tab.select('a', true).first().dom.innerHTML = str;
25512 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25515 * @class Roo.bootstrap.menu.Menu
25516 * @extends Roo.bootstrap.Component
25517 * Bootstrap Menu class - container for Menu
25518 * @cfg {String} html Text of the menu
25519 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25520 * @cfg {String} icon Font awesome icon
25521 * @cfg {String} pos Menu align to (top | bottom) default bottom
25525 * Create a new Menu
25526 * @param {Object} config The config object
25530 Roo.bootstrap.menu.Menu = function(config){
25531 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25535 * @event beforeshow
25536 * Fires before this menu is displayed
25537 * @param {Roo.bootstrap.menu.Menu} this
25541 * @event beforehide
25542 * Fires before this menu is hidden
25543 * @param {Roo.bootstrap.menu.Menu} this
25548 * Fires after this menu is displayed
25549 * @param {Roo.bootstrap.menu.Menu} this
25554 * Fires after this menu is hidden
25555 * @param {Roo.bootstrap.menu.Menu} this
25560 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25561 * @param {Roo.bootstrap.menu.Menu} this
25562 * @param {Roo.EventObject} e
25569 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25573 weight : 'default',
25578 getChildContainer : function() {
25579 if(this.isSubMenu){
25583 return this.el.select('ul.dropdown-menu', true).first();
25586 getAutoCreate : function()
25591 cls : 'roo-menu-text',
25599 cls : 'fa ' + this.icon
25610 cls : 'dropdown-button btn btn-' + this.weight,
25615 cls : 'dropdown-toggle btn btn-' + this.weight,
25625 cls : 'dropdown-menu'
25631 if(this.pos == 'top'){
25632 cfg.cls += ' dropup';
25635 if(this.isSubMenu){
25638 cls : 'dropdown-menu'
25645 onRender : function(ct, position)
25647 this.isSubMenu = ct.hasClass('dropdown-submenu');
25649 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25652 initEvents : function()
25654 if(this.isSubMenu){
25658 this.hidden = true;
25660 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25661 this.triggerEl.on('click', this.onTriggerPress, this);
25663 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25664 this.buttonEl.on('click', this.onClick, this);
25670 if(this.isSubMenu){
25674 return this.el.select('ul.dropdown-menu', true).first();
25677 onClick : function(e)
25679 this.fireEvent("click", this, e);
25682 onTriggerPress : function(e)
25684 if (this.isVisible()) {
25691 isVisible : function(){
25692 return !this.hidden;
25697 this.fireEvent("beforeshow", this);
25699 this.hidden = false;
25700 this.el.addClass('open');
25702 Roo.get(document).on("mouseup", this.onMouseUp, this);
25704 this.fireEvent("show", this);
25711 this.fireEvent("beforehide", this);
25713 this.hidden = true;
25714 this.el.removeClass('open');
25716 Roo.get(document).un("mouseup", this.onMouseUp);
25718 this.fireEvent("hide", this);
25721 onMouseUp : function()
25735 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25738 * @class Roo.bootstrap.menu.Item
25739 * @extends Roo.bootstrap.Component
25740 * Bootstrap MenuItem class
25741 * @cfg {Boolean} submenu (true | false) default false
25742 * @cfg {String} html text of the item
25743 * @cfg {String} href the link
25744 * @cfg {Boolean} disable (true | false) default false
25745 * @cfg {Boolean} preventDefault (true | false) default true
25746 * @cfg {String} icon Font awesome icon
25747 * @cfg {String} pos Submenu align to (left | right) default right
25751 * Create a new Item
25752 * @param {Object} config The config object
25756 Roo.bootstrap.menu.Item = function(config){
25757 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25761 * Fires when the mouse is hovering over this menu
25762 * @param {Roo.bootstrap.menu.Item} this
25763 * @param {Roo.EventObject} e
25768 * Fires when the mouse exits this menu
25769 * @param {Roo.bootstrap.menu.Item} this
25770 * @param {Roo.EventObject} e
25776 * The raw click event for the entire grid.
25777 * @param {Roo.EventObject} e
25783 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25788 preventDefault: true,
25793 getAutoCreate : function()
25798 cls : 'roo-menu-item-text',
25806 cls : 'fa ' + this.icon
25815 href : this.href || '#',
25822 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25826 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25828 if(this.pos == 'left'){
25829 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25836 initEvents : function()
25838 this.el.on('mouseover', this.onMouseOver, this);
25839 this.el.on('mouseout', this.onMouseOut, this);
25841 this.el.select('a', true).first().on('click', this.onClick, this);
25845 onClick : function(e)
25847 if(this.preventDefault){
25848 e.preventDefault();
25851 this.fireEvent("click", this, e);
25854 onMouseOver : function(e)
25856 if(this.submenu && this.pos == 'left'){
25857 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25860 this.fireEvent("mouseover", this, e);
25863 onMouseOut : function(e)
25865 this.fireEvent("mouseout", this, e);
25877 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25880 * @class Roo.bootstrap.menu.Separator
25881 * @extends Roo.bootstrap.Component
25882 * Bootstrap Separator class
25885 * Create a new Separator
25886 * @param {Object} config The config object
25890 Roo.bootstrap.menu.Separator = function(config){
25891 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25894 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25896 getAutoCreate : function(){
25917 * @class Roo.bootstrap.Tooltip
25918 * Bootstrap Tooltip class
25919 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25920 * to determine which dom element triggers the tooltip.
25922 * It needs to add support for additional attributes like tooltip-position
25925 * Create a new Toolti
25926 * @param {Object} config The config object
25929 Roo.bootstrap.Tooltip = function(config){
25930 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25932 this.alignment = Roo.bootstrap.Tooltip.alignment;
25934 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25935 this.alignment = config.alignment;
25940 Roo.apply(Roo.bootstrap.Tooltip, {
25942 * @function init initialize tooltip monitoring.
25946 currentTip : false,
25947 currentRegion : false,
25953 Roo.get(document).on('mouseover', this.enter ,this);
25954 Roo.get(document).on('mouseout', this.leave, this);
25957 this.currentTip = new Roo.bootstrap.Tooltip();
25960 enter : function(ev)
25962 var dom = ev.getTarget();
25964 //Roo.log(['enter',dom]);
25965 var el = Roo.fly(dom);
25966 if (this.currentEl) {
25968 //Roo.log(this.currentEl);
25969 //Roo.log(this.currentEl.contains(dom));
25970 if (this.currentEl == el) {
25973 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25979 if (this.currentTip.el) {
25980 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25984 if(!el || el.dom == document){
25990 // you can not look for children, as if el is the body.. then everythign is the child..
25991 if (!el.attr('tooltip')) { //
25992 if (!el.select("[tooltip]").elements.length) {
25995 // is the mouse over this child...?
25996 bindEl = el.select("[tooltip]").first();
25997 var xy = ev.getXY();
25998 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25999 //Roo.log("not in region.");
26002 //Roo.log("child element over..");
26005 this.currentEl = bindEl;
26006 this.currentTip.bind(bindEl);
26007 this.currentRegion = Roo.lib.Region.getRegion(dom);
26008 this.currentTip.enter();
26011 leave : function(ev)
26013 var dom = ev.getTarget();
26014 //Roo.log(['leave',dom]);
26015 if (!this.currentEl) {
26020 if (dom != this.currentEl.dom) {
26023 var xy = ev.getXY();
26024 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26027 // only activate leave if mouse cursor is outside... bounding box..
26032 if (this.currentTip) {
26033 this.currentTip.leave();
26035 //Roo.log('clear currentEl');
26036 this.currentEl = false;
26041 'left' : ['r-l', [-2,0], 'right'],
26042 'right' : ['l-r', [2,0], 'left'],
26043 'bottom' : ['t-b', [0,2], 'top'],
26044 'top' : [ 'b-t', [0,-2], 'bottom']
26050 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26055 delay : null, // can be { show : 300 , hide: 500}
26059 hoverState : null, //???
26061 placement : 'bottom',
26065 getAutoCreate : function(){
26072 cls : 'tooltip-arrow'
26075 cls : 'tooltip-inner'
26082 bind : function(el)
26088 enter : function () {
26090 if (this.timeout != null) {
26091 clearTimeout(this.timeout);
26094 this.hoverState = 'in';
26095 //Roo.log("enter - show");
26096 if (!this.delay || !this.delay.show) {
26101 this.timeout = setTimeout(function () {
26102 if (_t.hoverState == 'in') {
26105 }, this.delay.show);
26109 clearTimeout(this.timeout);
26111 this.hoverState = 'out';
26112 if (!this.delay || !this.delay.hide) {
26118 this.timeout = setTimeout(function () {
26119 //Roo.log("leave - timeout");
26121 if (_t.hoverState == 'out') {
26123 Roo.bootstrap.Tooltip.currentEl = false;
26128 show : function (msg)
26131 this.render(document.body);
26134 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26136 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26138 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26140 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26142 var placement = typeof this.placement == 'function' ?
26143 this.placement.call(this, this.el, on_el) :
26146 var autoToken = /\s?auto?\s?/i;
26147 var autoPlace = autoToken.test(placement);
26149 placement = placement.replace(autoToken, '') || 'top';
26153 //this.el.setXY([0,0]);
26155 //this.el.dom.style.display='block';
26157 //this.el.appendTo(on_el);
26159 var p = this.getPosition();
26160 var box = this.el.getBox();
26166 var align = this.alignment[placement];
26168 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26170 if(placement == 'top' || placement == 'bottom'){
26172 placement = 'right';
26175 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26176 placement = 'left';
26179 var scroll = Roo.select('body', true).first().getScroll();
26181 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26187 this.el.alignTo(this.bindEl, align[0],align[1]);
26188 //var arrow = this.el.select('.arrow',true).first();
26189 //arrow.set(align[2],
26191 this.el.addClass(placement);
26193 this.el.addClass('in fade');
26195 this.hoverState = null;
26197 if (this.el.hasClass('fade')) {
26208 //this.el.setXY([0,0]);
26209 this.el.removeClass('in');
26225 * @class Roo.bootstrap.LocationPicker
26226 * @extends Roo.bootstrap.Component
26227 * Bootstrap LocationPicker class
26228 * @cfg {Number} latitude Position when init default 0
26229 * @cfg {Number} longitude Position when init default 0
26230 * @cfg {Number} zoom default 15
26231 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26232 * @cfg {Boolean} mapTypeControl default false
26233 * @cfg {Boolean} disableDoubleClickZoom default false
26234 * @cfg {Boolean} scrollwheel default true
26235 * @cfg {Boolean} streetViewControl default false
26236 * @cfg {Number} radius default 0
26237 * @cfg {String} locationName
26238 * @cfg {Boolean} draggable default true
26239 * @cfg {Boolean} enableAutocomplete default false
26240 * @cfg {Boolean} enableReverseGeocode default true
26241 * @cfg {String} markerTitle
26244 * Create a new LocationPicker
26245 * @param {Object} config The config object
26249 Roo.bootstrap.LocationPicker = function(config){
26251 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26256 * Fires when the picker initialized.
26257 * @param {Roo.bootstrap.LocationPicker} this
26258 * @param {Google Location} location
26262 * @event positionchanged
26263 * Fires when the picker position changed.
26264 * @param {Roo.bootstrap.LocationPicker} this
26265 * @param {Google Location} location
26267 positionchanged : true,
26270 * Fires when the map resize.
26271 * @param {Roo.bootstrap.LocationPicker} this
26276 * Fires when the map show.
26277 * @param {Roo.bootstrap.LocationPicker} this
26282 * Fires when the map hide.
26283 * @param {Roo.bootstrap.LocationPicker} this
26288 * Fires when click the map.
26289 * @param {Roo.bootstrap.LocationPicker} this
26290 * @param {Map event} e
26294 * @event mapRightClick
26295 * Fires when right click the map.
26296 * @param {Roo.bootstrap.LocationPicker} this
26297 * @param {Map event} e
26299 mapRightClick : true,
26301 * @event markerClick
26302 * Fires when click the marker.
26303 * @param {Roo.bootstrap.LocationPicker} this
26304 * @param {Map event} e
26306 markerClick : true,
26308 * @event markerRightClick
26309 * Fires when right click the marker.
26310 * @param {Roo.bootstrap.LocationPicker} this
26311 * @param {Map event} e
26313 markerRightClick : true,
26315 * @event OverlayViewDraw
26316 * Fires when OverlayView Draw
26317 * @param {Roo.bootstrap.LocationPicker} this
26319 OverlayViewDraw : true,
26321 * @event OverlayViewOnAdd
26322 * Fires when OverlayView Draw
26323 * @param {Roo.bootstrap.LocationPicker} this
26325 OverlayViewOnAdd : true,
26327 * @event OverlayViewOnRemove
26328 * Fires when OverlayView Draw
26329 * @param {Roo.bootstrap.LocationPicker} this
26331 OverlayViewOnRemove : true,
26333 * @event OverlayViewShow
26334 * Fires when OverlayView Draw
26335 * @param {Roo.bootstrap.LocationPicker} this
26336 * @param {Pixel} cpx
26338 OverlayViewShow : true,
26340 * @event OverlayViewHide
26341 * Fires when OverlayView Draw
26342 * @param {Roo.bootstrap.LocationPicker} this
26344 OverlayViewHide : true,
26346 * @event loadexception
26347 * Fires when load google lib failed.
26348 * @param {Roo.bootstrap.LocationPicker} this
26350 loadexception : true
26355 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26357 gMapContext: false,
26363 mapTypeControl: false,
26364 disableDoubleClickZoom: false,
26366 streetViewControl: false,
26370 enableAutocomplete: false,
26371 enableReverseGeocode: true,
26374 getAutoCreate: function()
26379 cls: 'roo-location-picker'
26385 initEvents: function(ct, position)
26387 if(!this.el.getWidth() || this.isApplied()){
26391 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26396 initial: function()
26398 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26399 this.fireEvent('loadexception', this);
26403 if(!this.mapTypeId){
26404 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26407 this.gMapContext = this.GMapContext();
26409 this.initOverlayView();
26411 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26415 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26416 _this.setPosition(_this.gMapContext.marker.position);
26419 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26420 _this.fireEvent('mapClick', this, event);
26424 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26425 _this.fireEvent('mapRightClick', this, event);
26429 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26430 _this.fireEvent('markerClick', this, event);
26434 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26435 _this.fireEvent('markerRightClick', this, event);
26439 this.setPosition(this.gMapContext.location);
26441 this.fireEvent('initial', this, this.gMapContext.location);
26444 initOverlayView: function()
26448 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26452 _this.fireEvent('OverlayViewDraw', _this);
26457 _this.fireEvent('OverlayViewOnAdd', _this);
26460 onRemove: function()
26462 _this.fireEvent('OverlayViewOnRemove', _this);
26465 show: function(cpx)
26467 _this.fireEvent('OverlayViewShow', _this, cpx);
26472 _this.fireEvent('OverlayViewHide', _this);
26478 fromLatLngToContainerPixel: function(event)
26480 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26483 isApplied: function()
26485 return this.getGmapContext() == false ? false : true;
26488 getGmapContext: function()
26490 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26493 GMapContext: function()
26495 var position = new google.maps.LatLng(this.latitude, this.longitude);
26497 var _map = new google.maps.Map(this.el.dom, {
26500 mapTypeId: this.mapTypeId,
26501 mapTypeControl: this.mapTypeControl,
26502 disableDoubleClickZoom: this.disableDoubleClickZoom,
26503 scrollwheel: this.scrollwheel,
26504 streetViewControl: this.streetViewControl,
26505 locationName: this.locationName,
26506 draggable: this.draggable,
26507 enableAutocomplete: this.enableAutocomplete,
26508 enableReverseGeocode: this.enableReverseGeocode
26511 var _marker = new google.maps.Marker({
26512 position: position,
26514 title: this.markerTitle,
26515 draggable: this.draggable
26522 location: position,
26523 radius: this.radius,
26524 locationName: this.locationName,
26525 addressComponents: {
26526 formatted_address: null,
26527 addressLine1: null,
26528 addressLine2: null,
26530 streetNumber: null,
26534 stateOrProvince: null
26537 domContainer: this.el.dom,
26538 geodecoder: new google.maps.Geocoder()
26542 drawCircle: function(center, radius, options)
26544 if (this.gMapContext.circle != null) {
26545 this.gMapContext.circle.setMap(null);
26549 options = Roo.apply({}, options, {
26550 strokeColor: "#0000FF",
26551 strokeOpacity: .35,
26553 fillColor: "#0000FF",
26557 options.map = this.gMapContext.map;
26558 options.radius = radius;
26559 options.center = center;
26560 this.gMapContext.circle = new google.maps.Circle(options);
26561 return this.gMapContext.circle;
26567 setPosition: function(location)
26569 this.gMapContext.location = location;
26570 this.gMapContext.marker.setPosition(location);
26571 this.gMapContext.map.panTo(location);
26572 this.drawCircle(location, this.gMapContext.radius, {});
26576 if (this.gMapContext.settings.enableReverseGeocode) {
26577 this.gMapContext.geodecoder.geocode({
26578 latLng: this.gMapContext.location
26579 }, function(results, status) {
26581 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26582 _this.gMapContext.locationName = results[0].formatted_address;
26583 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26585 _this.fireEvent('positionchanged', this, location);
26592 this.fireEvent('positionchanged', this, location);
26597 google.maps.event.trigger(this.gMapContext.map, "resize");
26599 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26601 this.fireEvent('resize', this);
26604 setPositionByLatLng: function(latitude, longitude)
26606 this.setPosition(new google.maps.LatLng(latitude, longitude));
26609 getCurrentPosition: function()
26612 latitude: this.gMapContext.location.lat(),
26613 longitude: this.gMapContext.location.lng()
26617 getAddressName: function()
26619 return this.gMapContext.locationName;
26622 getAddressComponents: function()
26624 return this.gMapContext.addressComponents;
26627 address_component_from_google_geocode: function(address_components)
26631 for (var i = 0; i < address_components.length; i++) {
26632 var component = address_components[i];
26633 if (component.types.indexOf("postal_code") >= 0) {
26634 result.postalCode = component.short_name;
26635 } else if (component.types.indexOf("street_number") >= 0) {
26636 result.streetNumber = component.short_name;
26637 } else if (component.types.indexOf("route") >= 0) {
26638 result.streetName = component.short_name;
26639 } else if (component.types.indexOf("neighborhood") >= 0) {
26640 result.city = component.short_name;
26641 } else if (component.types.indexOf("locality") >= 0) {
26642 result.city = component.short_name;
26643 } else if (component.types.indexOf("sublocality") >= 0) {
26644 result.district = component.short_name;
26645 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26646 result.stateOrProvince = component.short_name;
26647 } else if (component.types.indexOf("country") >= 0) {
26648 result.country = component.short_name;
26652 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26653 result.addressLine2 = "";
26657 setZoomLevel: function(zoom)
26659 this.gMapContext.map.setZoom(zoom);
26672 this.fireEvent('show', this);
26683 this.fireEvent('hide', this);
26688 Roo.apply(Roo.bootstrap.LocationPicker, {
26690 OverlayView : function(map, options)
26692 options = options || {};
26706 * @class Roo.bootstrap.Alert
26707 * @extends Roo.bootstrap.Component
26708 * Bootstrap Alert class
26709 * @cfg {String} title The title of alert
26710 * @cfg {String} html The content of alert
26711 * @cfg {String} weight ( success | info | warning | danger )
26712 * @cfg {String} faicon font-awesomeicon
26715 * Create a new alert
26716 * @param {Object} config The config object
26720 Roo.bootstrap.Alert = function(config){
26721 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26725 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26732 getAutoCreate : function()
26741 cls : 'roo-alert-icon'
26746 cls : 'roo-alert-title',
26751 cls : 'roo-alert-text',
26758 cfg.cn[0].cls += ' fa ' + this.faicon;
26762 cfg.cls += ' alert-' + this.weight;
26768 initEvents: function()
26770 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26773 setTitle : function(str)
26775 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26778 setText : function(str)
26780 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26783 setWeight : function(weight)
26786 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26789 this.weight = weight;
26791 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26794 setIcon : function(icon)
26797 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26800 this.faicon = icon;
26802 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26823 * @class Roo.bootstrap.UploadCropbox
26824 * @extends Roo.bootstrap.Component
26825 * Bootstrap UploadCropbox class
26826 * @cfg {String} emptyText show when image has been loaded
26827 * @cfg {String} rotateNotify show when image too small to rotate
26828 * @cfg {Number} errorTimeout default 3000
26829 * @cfg {Number} minWidth default 300
26830 * @cfg {Number} minHeight default 300
26831 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26832 * @cfg {Boolean} isDocument (true|false) default false
26833 * @cfg {String} url action url
26834 * @cfg {String} paramName default 'imageUpload'
26835 * @cfg {String} method default POST
26836 * @cfg {Boolean} loadMask (true|false) default true
26837 * @cfg {Boolean} loadingText default 'Loading...'
26840 * Create a new UploadCropbox
26841 * @param {Object} config The config object
26844 Roo.bootstrap.UploadCropbox = function(config){
26845 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26849 * @event beforeselectfile
26850 * Fire before select file
26851 * @param {Roo.bootstrap.UploadCropbox} this
26853 "beforeselectfile" : true,
26856 * Fire after initEvent
26857 * @param {Roo.bootstrap.UploadCropbox} this
26862 * Fire after initEvent
26863 * @param {Roo.bootstrap.UploadCropbox} this
26864 * @param {String} data
26869 * Fire when preparing the file data
26870 * @param {Roo.bootstrap.UploadCropbox} this
26871 * @param {Object} file
26876 * Fire when get exception
26877 * @param {Roo.bootstrap.UploadCropbox} this
26878 * @param {XMLHttpRequest} xhr
26880 "exception" : true,
26882 * @event beforeloadcanvas
26883 * Fire before load the canvas
26884 * @param {Roo.bootstrap.UploadCropbox} this
26885 * @param {String} src
26887 "beforeloadcanvas" : true,
26890 * Fire when trash image
26891 * @param {Roo.bootstrap.UploadCropbox} this
26896 * Fire when download the image
26897 * @param {Roo.bootstrap.UploadCropbox} this
26901 * @event footerbuttonclick
26902 * Fire when footerbuttonclick
26903 * @param {Roo.bootstrap.UploadCropbox} this
26904 * @param {String} type
26906 "footerbuttonclick" : true,
26910 * @param {Roo.bootstrap.UploadCropbox} this
26915 * Fire when rotate the image
26916 * @param {Roo.bootstrap.UploadCropbox} this
26917 * @param {String} pos
26922 * Fire when inspect the file
26923 * @param {Roo.bootstrap.UploadCropbox} this
26924 * @param {Object} file
26929 * Fire when xhr upload the file
26930 * @param {Roo.bootstrap.UploadCropbox} this
26931 * @param {Object} data
26936 * Fire when arrange the file data
26937 * @param {Roo.bootstrap.UploadCropbox} this
26938 * @param {Object} formData
26943 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26946 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26948 emptyText : 'Click to upload image',
26949 rotateNotify : 'Image is too small to rotate',
26950 errorTimeout : 3000,
26964 cropType : 'image/jpeg',
26966 canvasLoaded : false,
26967 isDocument : false,
26969 paramName : 'imageUpload',
26971 loadingText : 'Loading...',
26974 getAutoCreate : function()
26978 cls : 'roo-upload-cropbox',
26982 cls : 'roo-upload-cropbox-selector',
26987 cls : 'roo-upload-cropbox-body',
26988 style : 'cursor:pointer',
26992 cls : 'roo-upload-cropbox-preview'
26996 cls : 'roo-upload-cropbox-thumb'
27000 cls : 'roo-upload-cropbox-empty-notify',
27001 html : this.emptyText
27005 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27006 html : this.rotateNotify
27012 cls : 'roo-upload-cropbox-footer',
27015 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27025 onRender : function(ct, position)
27027 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27029 if (this.buttons.length) {
27031 Roo.each(this.buttons, function(bb) {
27033 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27035 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27041 this.maskEl = this.el;
27045 initEvents : function()
27047 this.urlAPI = (window.createObjectURL && window) ||
27048 (window.URL && URL.revokeObjectURL && URL) ||
27049 (window.webkitURL && webkitURL);
27051 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27052 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27054 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27055 this.selectorEl.hide();
27057 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27058 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27060 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27061 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27062 this.thumbEl.hide();
27064 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27065 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27067 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27068 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27069 this.errorEl.hide();
27071 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27072 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27073 this.footerEl.hide();
27075 this.setThumbBoxSize();
27081 this.fireEvent('initial', this);
27088 window.addEventListener("resize", function() { _this.resize(); } );
27090 this.bodyEl.on('click', this.beforeSelectFile, this);
27093 this.bodyEl.on('touchstart', this.onTouchStart, this);
27094 this.bodyEl.on('touchmove', this.onTouchMove, this);
27095 this.bodyEl.on('touchend', this.onTouchEnd, this);
27099 this.bodyEl.on('mousedown', this.onMouseDown, this);
27100 this.bodyEl.on('mousemove', this.onMouseMove, this);
27101 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27102 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27103 Roo.get(document).on('mouseup', this.onMouseUp, this);
27106 this.selectorEl.on('change', this.onFileSelected, this);
27112 this.baseScale = 1;
27114 this.baseRotate = 1;
27115 this.dragable = false;
27116 this.pinching = false;
27119 this.cropData = false;
27120 this.notifyEl.dom.innerHTML = this.emptyText;
27122 this.selectorEl.dom.value = '';
27126 resize : function()
27128 if(this.fireEvent('resize', this) != false){
27129 this.setThumbBoxPosition();
27130 this.setCanvasPosition();
27134 onFooterButtonClick : function(e, el, o, type)
27137 case 'rotate-left' :
27138 this.onRotateLeft(e);
27140 case 'rotate-right' :
27141 this.onRotateRight(e);
27144 this.beforeSelectFile(e);
27159 this.fireEvent('footerbuttonclick', this, type);
27162 beforeSelectFile : function(e)
27164 e.preventDefault();
27166 if(this.fireEvent('beforeselectfile', this) != false){
27167 this.selectorEl.dom.click();
27171 onFileSelected : function(e)
27173 e.preventDefault();
27175 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27179 var file = this.selectorEl.dom.files[0];
27181 if(this.fireEvent('inspect', this, file) != false){
27182 this.prepare(file);
27187 trash : function(e)
27189 this.fireEvent('trash', this);
27192 download : function(e)
27194 this.fireEvent('download', this);
27197 loadCanvas : function(src)
27199 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27203 this.imageEl = document.createElement('img');
27207 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27209 this.imageEl.src = src;
27213 onLoadCanvas : function()
27215 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27216 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27218 this.bodyEl.un('click', this.beforeSelectFile, this);
27220 this.notifyEl.hide();
27221 this.thumbEl.show();
27222 this.footerEl.show();
27224 this.baseRotateLevel();
27226 if(this.isDocument){
27227 this.setThumbBoxSize();
27230 this.setThumbBoxPosition();
27232 this.baseScaleLevel();
27238 this.canvasLoaded = true;
27241 this.maskEl.unmask();
27246 setCanvasPosition : function()
27248 if(!this.canvasEl){
27252 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27253 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27255 this.previewEl.setLeft(pw);
27256 this.previewEl.setTop(ph);
27260 onMouseDown : function(e)
27264 this.dragable = true;
27265 this.pinching = false;
27267 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27268 this.dragable = false;
27272 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27273 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27277 onMouseMove : function(e)
27281 if(!this.canvasLoaded){
27285 if (!this.dragable){
27289 var minX = Math.ceil(this.thumbEl.getLeft(true));
27290 var minY = Math.ceil(this.thumbEl.getTop(true));
27292 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27293 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27295 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27296 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27298 x = x - this.mouseX;
27299 y = y - this.mouseY;
27301 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27302 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27304 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27305 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27307 this.previewEl.setLeft(bgX);
27308 this.previewEl.setTop(bgY);
27310 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27311 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27314 onMouseUp : function(e)
27318 this.dragable = false;
27321 onMouseWheel : function(e)
27325 this.startScale = this.scale;
27327 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27329 if(!this.zoomable()){
27330 this.scale = this.startScale;
27339 zoomable : function()
27341 var minScale = this.thumbEl.getWidth() / this.minWidth;
27343 if(this.minWidth < this.minHeight){
27344 minScale = this.thumbEl.getHeight() / this.minHeight;
27347 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27348 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27352 (this.rotate == 0 || this.rotate == 180) &&
27354 width > this.imageEl.OriginWidth ||
27355 height > this.imageEl.OriginHeight ||
27356 (width < this.minWidth && height < this.minHeight)
27364 (this.rotate == 90 || this.rotate == 270) &&
27366 width > this.imageEl.OriginWidth ||
27367 height > this.imageEl.OriginHeight ||
27368 (width < this.minHeight && height < this.minWidth)
27375 !this.isDocument &&
27376 (this.rotate == 0 || this.rotate == 180) &&
27378 width < this.minWidth ||
27379 width > this.imageEl.OriginWidth ||
27380 height < this.minHeight ||
27381 height > this.imageEl.OriginHeight
27388 !this.isDocument &&
27389 (this.rotate == 90 || this.rotate == 270) &&
27391 width < this.minHeight ||
27392 width > this.imageEl.OriginWidth ||
27393 height < this.minWidth ||
27394 height > this.imageEl.OriginHeight
27404 onRotateLeft : function(e)
27406 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27408 var minScale = this.thumbEl.getWidth() / this.minWidth;
27410 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27411 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27413 this.startScale = this.scale;
27415 while (this.getScaleLevel() < minScale){
27417 this.scale = this.scale + 1;
27419 if(!this.zoomable()){
27424 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27425 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27430 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27437 this.scale = this.startScale;
27439 this.onRotateFail();
27444 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27446 if(this.isDocument){
27447 this.setThumbBoxSize();
27448 this.setThumbBoxPosition();
27449 this.setCanvasPosition();
27454 this.fireEvent('rotate', this, 'left');
27458 onRotateRight : function(e)
27460 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27462 var minScale = this.thumbEl.getWidth() / this.minWidth;
27464 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27465 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27467 this.startScale = this.scale;
27469 while (this.getScaleLevel() < minScale){
27471 this.scale = this.scale + 1;
27473 if(!this.zoomable()){
27478 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27479 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27484 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27491 this.scale = this.startScale;
27493 this.onRotateFail();
27498 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27500 if(this.isDocument){
27501 this.setThumbBoxSize();
27502 this.setThumbBoxPosition();
27503 this.setCanvasPosition();
27508 this.fireEvent('rotate', this, 'right');
27511 onRotateFail : function()
27513 this.errorEl.show(true);
27517 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27522 this.previewEl.dom.innerHTML = '';
27524 var canvasEl = document.createElement("canvas");
27526 var contextEl = canvasEl.getContext("2d");
27528 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27529 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27530 var center = this.imageEl.OriginWidth / 2;
27532 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27533 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27534 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27535 center = this.imageEl.OriginHeight / 2;
27538 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27540 contextEl.translate(center, center);
27541 contextEl.rotate(this.rotate * Math.PI / 180);
27543 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27545 this.canvasEl = document.createElement("canvas");
27547 this.contextEl = this.canvasEl.getContext("2d");
27549 switch (this.rotate) {
27552 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27553 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27555 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27560 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27561 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27563 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27564 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);
27568 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27573 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27574 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27576 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27577 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);
27581 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);
27586 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27587 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27589 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27590 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27594 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);
27601 this.previewEl.appendChild(this.canvasEl);
27603 this.setCanvasPosition();
27608 if(!this.canvasLoaded){
27612 var imageCanvas = document.createElement("canvas");
27614 var imageContext = imageCanvas.getContext("2d");
27616 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27617 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27619 var center = imageCanvas.width / 2;
27621 imageContext.translate(center, center);
27623 imageContext.rotate(this.rotate * Math.PI / 180);
27625 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27627 var canvas = document.createElement("canvas");
27629 var context = canvas.getContext("2d");
27631 canvas.width = this.minWidth;
27632 canvas.height = this.minHeight;
27634 switch (this.rotate) {
27637 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27638 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27640 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27641 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27643 var targetWidth = this.minWidth - 2 * x;
27644 var targetHeight = this.minHeight - 2 * y;
27648 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27649 scale = targetWidth / width;
27652 if(x > 0 && y == 0){
27653 scale = targetHeight / height;
27656 if(x > 0 && y > 0){
27657 scale = targetWidth / width;
27659 if(width < height){
27660 scale = targetHeight / height;
27664 context.scale(scale, scale);
27666 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27667 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27669 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27670 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27672 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27677 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27678 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27680 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27681 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27683 var targetWidth = this.minWidth - 2 * x;
27684 var targetHeight = this.minHeight - 2 * y;
27688 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27689 scale = targetWidth / width;
27692 if(x > 0 && y == 0){
27693 scale = targetHeight / height;
27696 if(x > 0 && y > 0){
27697 scale = targetWidth / width;
27699 if(width < height){
27700 scale = targetHeight / height;
27704 context.scale(scale, scale);
27706 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27707 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27709 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27710 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27712 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27714 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27719 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27720 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27722 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27723 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27725 var targetWidth = this.minWidth - 2 * x;
27726 var targetHeight = this.minHeight - 2 * y;
27730 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27731 scale = targetWidth / width;
27734 if(x > 0 && y == 0){
27735 scale = targetHeight / height;
27738 if(x > 0 && y > 0){
27739 scale = targetWidth / width;
27741 if(width < height){
27742 scale = targetHeight / height;
27746 context.scale(scale, scale);
27748 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27749 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27751 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27752 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27754 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27755 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27757 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27762 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27763 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27765 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27766 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27768 var targetWidth = this.minWidth - 2 * x;
27769 var targetHeight = this.minHeight - 2 * y;
27773 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27774 scale = targetWidth / width;
27777 if(x > 0 && y == 0){
27778 scale = targetHeight / height;
27781 if(x > 0 && y > 0){
27782 scale = targetWidth / width;
27784 if(width < height){
27785 scale = targetHeight / height;
27789 context.scale(scale, scale);
27791 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27792 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27794 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27795 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27797 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27799 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27806 this.cropData = canvas.toDataURL(this.cropType);
27808 if(this.fireEvent('crop', this, this.cropData) !== false){
27809 this.process(this.file, this.cropData);
27816 setThumbBoxSize : function()
27820 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27821 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27822 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27824 this.minWidth = width;
27825 this.minHeight = height;
27827 if(this.rotate == 90 || this.rotate == 270){
27828 this.minWidth = height;
27829 this.minHeight = width;
27834 width = Math.ceil(this.minWidth * height / this.minHeight);
27836 if(this.minWidth > this.minHeight){
27838 height = Math.ceil(this.minHeight * width / this.minWidth);
27841 this.thumbEl.setStyle({
27842 width : width + 'px',
27843 height : height + 'px'
27850 setThumbBoxPosition : function()
27852 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27853 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27855 this.thumbEl.setLeft(x);
27856 this.thumbEl.setTop(y);
27860 baseRotateLevel : function()
27862 this.baseRotate = 1;
27865 typeof(this.exif) != 'undefined' &&
27866 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27867 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27869 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27872 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27876 baseScaleLevel : function()
27880 if(this.isDocument){
27882 if(this.baseRotate == 6 || this.baseRotate == 8){
27884 height = this.thumbEl.getHeight();
27885 this.baseScale = height / this.imageEl.OriginWidth;
27887 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27888 width = this.thumbEl.getWidth();
27889 this.baseScale = width / this.imageEl.OriginHeight;
27895 height = this.thumbEl.getHeight();
27896 this.baseScale = height / this.imageEl.OriginHeight;
27898 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27899 width = this.thumbEl.getWidth();
27900 this.baseScale = width / this.imageEl.OriginWidth;
27906 if(this.baseRotate == 6 || this.baseRotate == 8){
27908 width = this.thumbEl.getHeight();
27909 this.baseScale = width / this.imageEl.OriginHeight;
27911 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27912 height = this.thumbEl.getWidth();
27913 this.baseScale = height / this.imageEl.OriginHeight;
27916 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27917 height = this.thumbEl.getWidth();
27918 this.baseScale = height / this.imageEl.OriginHeight;
27920 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27921 width = this.thumbEl.getHeight();
27922 this.baseScale = width / this.imageEl.OriginWidth;
27929 width = this.thumbEl.getWidth();
27930 this.baseScale = width / this.imageEl.OriginWidth;
27932 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27933 height = this.thumbEl.getHeight();
27934 this.baseScale = height / this.imageEl.OriginHeight;
27937 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27939 height = this.thumbEl.getHeight();
27940 this.baseScale = height / this.imageEl.OriginHeight;
27942 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27943 width = this.thumbEl.getWidth();
27944 this.baseScale = width / this.imageEl.OriginWidth;
27952 getScaleLevel : function()
27954 return this.baseScale * Math.pow(1.1, this.scale);
27957 onTouchStart : function(e)
27959 if(!this.canvasLoaded){
27960 this.beforeSelectFile(e);
27964 var touches = e.browserEvent.touches;
27970 if(touches.length == 1){
27971 this.onMouseDown(e);
27975 if(touches.length != 2){
27981 for(var i = 0, finger; finger = touches[i]; i++){
27982 coords.push(finger.pageX, finger.pageY);
27985 var x = Math.pow(coords[0] - coords[2], 2);
27986 var y = Math.pow(coords[1] - coords[3], 2);
27988 this.startDistance = Math.sqrt(x + y);
27990 this.startScale = this.scale;
27992 this.pinching = true;
27993 this.dragable = false;
27997 onTouchMove : function(e)
27999 if(!this.pinching && !this.dragable){
28003 var touches = e.browserEvent.touches;
28010 this.onMouseMove(e);
28016 for(var i = 0, finger; finger = touches[i]; i++){
28017 coords.push(finger.pageX, finger.pageY);
28020 var x = Math.pow(coords[0] - coords[2], 2);
28021 var y = Math.pow(coords[1] - coords[3], 2);
28023 this.endDistance = Math.sqrt(x + y);
28025 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28027 if(!this.zoomable()){
28028 this.scale = this.startScale;
28036 onTouchEnd : function(e)
28038 this.pinching = false;
28039 this.dragable = false;
28043 process : function(file, crop)
28046 this.maskEl.mask(this.loadingText);
28049 this.xhr = new XMLHttpRequest();
28051 file.xhr = this.xhr;
28053 this.xhr.open(this.method, this.url, true);
28056 "Accept": "application/json",
28057 "Cache-Control": "no-cache",
28058 "X-Requested-With": "XMLHttpRequest"
28061 for (var headerName in headers) {
28062 var headerValue = headers[headerName];
28064 this.xhr.setRequestHeader(headerName, headerValue);
28070 this.xhr.onload = function()
28072 _this.xhrOnLoad(_this.xhr);
28075 this.xhr.onerror = function()
28077 _this.xhrOnError(_this.xhr);
28080 var formData = new FormData();
28082 formData.append('returnHTML', 'NO');
28085 formData.append('crop', crop);
28088 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28089 formData.append(this.paramName, file, file.name);
28092 if(typeof(file.filename) != 'undefined'){
28093 formData.append('filename', file.filename);
28096 if(typeof(file.mimetype) != 'undefined'){
28097 formData.append('mimetype', file.mimetype);
28100 if(this.fireEvent('arrange', this, formData) != false){
28101 this.xhr.send(formData);
28105 xhrOnLoad : function(xhr)
28108 this.maskEl.unmask();
28111 if (xhr.readyState !== 4) {
28112 this.fireEvent('exception', this, xhr);
28116 var response = Roo.decode(xhr.responseText);
28118 if(!response.success){
28119 this.fireEvent('exception', this, xhr);
28123 var response = Roo.decode(xhr.responseText);
28125 this.fireEvent('upload', this, response);
28129 xhrOnError : function()
28132 this.maskEl.unmask();
28135 Roo.log('xhr on error');
28137 var response = Roo.decode(xhr.responseText);
28143 prepare : function(file)
28146 this.maskEl.mask(this.loadingText);
28152 if(typeof(file) === 'string'){
28153 this.loadCanvas(file);
28157 if(!file || !this.urlAPI){
28162 this.cropType = file.type;
28166 if(this.fireEvent('prepare', this, this.file) != false){
28168 var reader = new FileReader();
28170 reader.onload = function (e) {
28171 if (e.target.error) {
28172 Roo.log(e.target.error);
28176 var buffer = e.target.result,
28177 dataView = new DataView(buffer),
28179 maxOffset = dataView.byteLength - 4,
28183 if (dataView.getUint16(0) === 0xffd8) {
28184 while (offset < maxOffset) {
28185 markerBytes = dataView.getUint16(offset);
28187 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28188 markerLength = dataView.getUint16(offset + 2) + 2;
28189 if (offset + markerLength > dataView.byteLength) {
28190 Roo.log('Invalid meta data: Invalid segment size.');
28194 if(markerBytes == 0xffe1){
28195 _this.parseExifData(
28202 offset += markerLength;
28212 var url = _this.urlAPI.createObjectURL(_this.file);
28214 _this.loadCanvas(url);
28219 reader.readAsArrayBuffer(this.file);
28225 parseExifData : function(dataView, offset, length)
28227 var tiffOffset = offset + 10,
28231 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28232 // No Exif data, might be XMP data instead
28236 // Check for the ASCII code for "Exif" (0x45786966):
28237 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28238 // No Exif data, might be XMP data instead
28241 if (tiffOffset + 8 > dataView.byteLength) {
28242 Roo.log('Invalid Exif data: Invalid segment size.');
28245 // Check for the two null bytes:
28246 if (dataView.getUint16(offset + 8) !== 0x0000) {
28247 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28250 // Check the byte alignment:
28251 switch (dataView.getUint16(tiffOffset)) {
28253 littleEndian = true;
28256 littleEndian = false;
28259 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28262 // Check for the TIFF tag marker (0x002A):
28263 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28264 Roo.log('Invalid Exif data: Missing TIFF marker.');
28267 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28268 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28270 this.parseExifTags(
28273 tiffOffset + dirOffset,
28278 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28283 if (dirOffset + 6 > dataView.byteLength) {
28284 Roo.log('Invalid Exif data: Invalid directory offset.');
28287 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28288 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28289 if (dirEndOffset + 4 > dataView.byteLength) {
28290 Roo.log('Invalid Exif data: Invalid directory size.');
28293 for (i = 0; i < tagsNumber; i += 1) {
28297 dirOffset + 2 + 12 * i, // tag offset
28301 // Return the offset to the next directory:
28302 return dataView.getUint32(dirEndOffset, littleEndian);
28305 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28307 var tag = dataView.getUint16(offset, littleEndian);
28309 this.exif[tag] = this.getExifValue(
28313 dataView.getUint16(offset + 2, littleEndian), // tag type
28314 dataView.getUint32(offset + 4, littleEndian), // tag length
28319 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28321 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28330 Roo.log('Invalid Exif data: Invalid tag type.');
28334 tagSize = tagType.size * length;
28335 // Determine if the value is contained in the dataOffset bytes,
28336 // or if the value at the dataOffset is a pointer to the actual data:
28337 dataOffset = tagSize > 4 ?
28338 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28339 if (dataOffset + tagSize > dataView.byteLength) {
28340 Roo.log('Invalid Exif data: Invalid data offset.');
28343 if (length === 1) {
28344 return tagType.getValue(dataView, dataOffset, littleEndian);
28347 for (i = 0; i < length; i += 1) {
28348 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28351 if (tagType.ascii) {
28353 // Concatenate the chars:
28354 for (i = 0; i < values.length; i += 1) {
28356 // Ignore the terminating NULL byte(s):
28357 if (c === '\u0000') {
28369 Roo.apply(Roo.bootstrap.UploadCropbox, {
28371 'Orientation': 0x0112
28375 1: 0, //'top-left',
28377 3: 180, //'bottom-right',
28378 // 4: 'bottom-left',
28380 6: 90, //'right-top',
28381 // 7: 'right-bottom',
28382 8: 270 //'left-bottom'
28386 // byte, 8-bit unsigned int:
28388 getValue: function (dataView, dataOffset) {
28389 return dataView.getUint8(dataOffset);
28393 // ascii, 8-bit byte:
28395 getValue: function (dataView, dataOffset) {
28396 return String.fromCharCode(dataView.getUint8(dataOffset));
28401 // short, 16 bit int:
28403 getValue: function (dataView, dataOffset, littleEndian) {
28404 return dataView.getUint16(dataOffset, littleEndian);
28408 // long, 32 bit int:
28410 getValue: function (dataView, dataOffset, littleEndian) {
28411 return dataView.getUint32(dataOffset, littleEndian);
28415 // rational = two long values, first is numerator, second is denominator:
28417 getValue: function (dataView, dataOffset, littleEndian) {
28418 return dataView.getUint32(dataOffset, littleEndian) /
28419 dataView.getUint32(dataOffset + 4, littleEndian);
28423 // slong, 32 bit signed int:
28425 getValue: function (dataView, dataOffset, littleEndian) {
28426 return dataView.getInt32(dataOffset, littleEndian);
28430 // srational, two slongs, first is numerator, second is denominator:
28432 getValue: function (dataView, dataOffset, littleEndian) {
28433 return dataView.getInt32(dataOffset, littleEndian) /
28434 dataView.getInt32(dataOffset + 4, littleEndian);
28444 cls : 'btn-group roo-upload-cropbox-rotate-left',
28445 action : 'rotate-left',
28449 cls : 'btn btn-default',
28450 html : '<i class="fa fa-undo"></i>'
28456 cls : 'btn-group roo-upload-cropbox-picture',
28457 action : 'picture',
28461 cls : 'btn btn-default',
28462 html : '<i class="fa fa-picture-o"></i>'
28468 cls : 'btn-group roo-upload-cropbox-rotate-right',
28469 action : 'rotate-right',
28473 cls : 'btn btn-default',
28474 html : '<i class="fa fa-repeat"></i>'
28482 cls : 'btn-group roo-upload-cropbox-rotate-left',
28483 action : 'rotate-left',
28487 cls : 'btn btn-default',
28488 html : '<i class="fa fa-undo"></i>'
28494 cls : 'btn-group roo-upload-cropbox-download',
28495 action : 'download',
28499 cls : 'btn btn-default',
28500 html : '<i class="fa fa-download"></i>'
28506 cls : 'btn-group roo-upload-cropbox-crop',
28511 cls : 'btn btn-default',
28512 html : '<i class="fa fa-crop"></i>'
28518 cls : 'btn-group roo-upload-cropbox-trash',
28523 cls : 'btn btn-default',
28524 html : '<i class="fa fa-trash"></i>'
28530 cls : 'btn-group roo-upload-cropbox-rotate-right',
28531 action : 'rotate-right',
28535 cls : 'btn btn-default',
28536 html : '<i class="fa fa-repeat"></i>'
28544 cls : 'btn-group roo-upload-cropbox-rotate-left',
28545 action : 'rotate-left',
28549 cls : 'btn btn-default',
28550 html : '<i class="fa fa-undo"></i>'
28556 cls : 'btn-group roo-upload-cropbox-rotate-right',
28557 action : 'rotate-right',
28561 cls : 'btn btn-default',
28562 html : '<i class="fa fa-repeat"></i>'
28575 * @class Roo.bootstrap.DocumentManager
28576 * @extends Roo.bootstrap.Component
28577 * Bootstrap DocumentManager class
28578 * @cfg {String} paramName default 'imageUpload'
28579 * @cfg {String} toolTipName default 'filename'
28580 * @cfg {String} method default POST
28581 * @cfg {String} url action url
28582 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28583 * @cfg {Boolean} multiple multiple upload default true
28584 * @cfg {Number} thumbSize default 300
28585 * @cfg {String} fieldLabel
28586 * @cfg {Number} labelWidth default 4
28587 * @cfg {String} labelAlign (left|top) default left
28588 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28589 * @cfg {Number} labellg set the width of label (1-12)
28590 * @cfg {Number} labelmd set the width of label (1-12)
28591 * @cfg {Number} labelsm set the width of label (1-12)
28592 * @cfg {Number} labelxs set the width of label (1-12)
28595 * Create a new DocumentManager
28596 * @param {Object} config The config object
28599 Roo.bootstrap.DocumentManager = function(config){
28600 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28603 this.delegates = [];
28608 * Fire when initial the DocumentManager
28609 * @param {Roo.bootstrap.DocumentManager} this
28614 * inspect selected file
28615 * @param {Roo.bootstrap.DocumentManager} this
28616 * @param {File} file
28621 * Fire when xhr load exception
28622 * @param {Roo.bootstrap.DocumentManager} this
28623 * @param {XMLHttpRequest} xhr
28625 "exception" : true,
28627 * @event afterupload
28628 * Fire when xhr load exception
28629 * @param {Roo.bootstrap.DocumentManager} this
28630 * @param {XMLHttpRequest} xhr
28632 "afterupload" : true,
28635 * prepare the form data
28636 * @param {Roo.bootstrap.DocumentManager} this
28637 * @param {Object} formData
28642 * Fire when remove the file
28643 * @param {Roo.bootstrap.DocumentManager} this
28644 * @param {Object} file
28649 * Fire after refresh the file
28650 * @param {Roo.bootstrap.DocumentManager} this
28655 * Fire after click the image
28656 * @param {Roo.bootstrap.DocumentManager} this
28657 * @param {Object} file
28662 * Fire when upload a image and editable set to true
28663 * @param {Roo.bootstrap.DocumentManager} this
28664 * @param {Object} file
28668 * @event beforeselectfile
28669 * Fire before select file
28670 * @param {Roo.bootstrap.DocumentManager} this
28672 "beforeselectfile" : true,
28675 * Fire before process file
28676 * @param {Roo.bootstrap.DocumentManager} this
28677 * @param {Object} file
28681 * @event previewrendered
28682 * Fire when preview rendered
28683 * @param {Roo.bootstrap.DocumentManager} this
28684 * @param {Object} file
28686 "previewrendered" : true
28691 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28700 paramName : 'imageUpload',
28701 toolTipName : 'filename',
28704 labelAlign : 'left',
28714 getAutoCreate : function()
28716 var managerWidget = {
28718 cls : 'roo-document-manager',
28722 cls : 'roo-document-manager-selector',
28727 cls : 'roo-document-manager-uploader',
28731 cls : 'roo-document-manager-upload-btn',
28732 html : '<i class="fa fa-plus"></i>'
28743 cls : 'column col-md-12',
28748 if(this.fieldLabel.length){
28753 cls : 'column col-md-12',
28754 html : this.fieldLabel
28758 cls : 'column col-md-12',
28763 if(this.labelAlign == 'left'){
28768 html : this.fieldLabel
28777 if(this.labelWidth > 12){
28778 content[0].style = "width: " + this.labelWidth + 'px';
28781 if(this.labelWidth < 13 && this.labelmd == 0){
28782 this.labelmd = this.labelWidth;
28785 if(this.labellg > 0){
28786 content[0].cls += ' col-lg-' + this.labellg;
28787 content[1].cls += ' col-lg-' + (12 - this.labellg);
28790 if(this.labelmd > 0){
28791 content[0].cls += ' col-md-' + this.labelmd;
28792 content[1].cls += ' col-md-' + (12 - this.labelmd);
28795 if(this.labelsm > 0){
28796 content[0].cls += ' col-sm-' + this.labelsm;
28797 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28800 if(this.labelxs > 0){
28801 content[0].cls += ' col-xs-' + this.labelxs;
28802 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28810 cls : 'row clearfix',
28818 initEvents : function()
28820 this.managerEl = this.el.select('.roo-document-manager', true).first();
28821 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28823 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28824 this.selectorEl.hide();
28827 this.selectorEl.attr('multiple', 'multiple');
28830 this.selectorEl.on('change', this.onFileSelected, this);
28832 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28833 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28835 this.uploader.on('click', this.onUploaderClick, this);
28837 this.renderProgressDialog();
28841 window.addEventListener("resize", function() { _this.refresh(); } );
28843 this.fireEvent('initial', this);
28846 renderProgressDialog : function()
28850 this.progressDialog = new Roo.bootstrap.Modal({
28851 cls : 'roo-document-manager-progress-dialog',
28852 allow_close : false,
28862 btnclick : function() {
28863 _this.uploadCancel();
28869 this.progressDialog.render(Roo.get(document.body));
28871 this.progress = new Roo.bootstrap.Progress({
28872 cls : 'roo-document-manager-progress',
28877 this.progress.render(this.progressDialog.getChildContainer());
28879 this.progressBar = new Roo.bootstrap.ProgressBar({
28880 cls : 'roo-document-manager-progress-bar',
28883 aria_valuemax : 12,
28887 this.progressBar.render(this.progress.getChildContainer());
28890 onUploaderClick : function(e)
28892 e.preventDefault();
28894 if(this.fireEvent('beforeselectfile', this) != false){
28895 this.selectorEl.dom.click();
28900 onFileSelected : function(e)
28902 e.preventDefault();
28904 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28908 Roo.each(this.selectorEl.dom.files, function(file){
28909 if(this.fireEvent('inspect', this, file) != false){
28910 this.files.push(file);
28920 this.selectorEl.dom.value = '';
28922 if(!this.files || !this.files.length){
28926 if(this.boxes > 0 && this.files.length > this.boxes){
28927 this.files = this.files.slice(0, this.boxes);
28930 this.uploader.show();
28932 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28933 this.uploader.hide();
28942 Roo.each(this.files, function(file){
28944 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28945 var f = this.renderPreview(file);
28950 if(file.type.indexOf('image') != -1){
28951 this.delegates.push(
28953 _this.process(file);
28954 }).createDelegate(this)
28962 _this.process(file);
28963 }).createDelegate(this)
28968 this.files = files;
28970 this.delegates = this.delegates.concat(docs);
28972 if(!this.delegates.length){
28977 this.progressBar.aria_valuemax = this.delegates.length;
28984 arrange : function()
28986 if(!this.delegates.length){
28987 this.progressDialog.hide();
28992 var delegate = this.delegates.shift();
28994 this.progressDialog.show();
28996 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28998 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29003 refresh : function()
29005 this.uploader.show();
29007 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29008 this.uploader.hide();
29011 Roo.isTouch ? this.closable(false) : this.closable(true);
29013 this.fireEvent('refresh', this);
29016 onRemove : function(e, el, o)
29018 e.preventDefault();
29020 this.fireEvent('remove', this, o);
29024 remove : function(o)
29028 Roo.each(this.files, function(file){
29029 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29038 this.files = files;
29045 Roo.each(this.files, function(file){
29050 file.target.remove();
29059 onClick : function(e, el, o)
29061 e.preventDefault();
29063 this.fireEvent('click', this, o);
29067 closable : function(closable)
29069 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29071 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29083 xhrOnLoad : function(xhr)
29085 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29089 if (xhr.readyState !== 4) {
29091 this.fireEvent('exception', this, xhr);
29095 var response = Roo.decode(xhr.responseText);
29097 if(!response.success){
29099 this.fireEvent('exception', this, xhr);
29103 var file = this.renderPreview(response.data);
29105 this.files.push(file);
29109 this.fireEvent('afterupload', this, xhr);
29113 xhrOnError : function(xhr)
29115 Roo.log('xhr on error');
29117 var response = Roo.decode(xhr.responseText);
29124 process : function(file)
29126 if(this.fireEvent('process', this, file) !== false){
29127 if(this.editable && file.type.indexOf('image') != -1){
29128 this.fireEvent('edit', this, file);
29132 this.uploadStart(file, false);
29139 uploadStart : function(file, crop)
29141 this.xhr = new XMLHttpRequest();
29143 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29148 file.xhr = this.xhr;
29150 this.managerEl.createChild({
29152 cls : 'roo-document-manager-loading',
29156 tooltip : file.name,
29157 cls : 'roo-document-manager-thumb',
29158 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29164 this.xhr.open(this.method, this.url, true);
29167 "Accept": "application/json",
29168 "Cache-Control": "no-cache",
29169 "X-Requested-With": "XMLHttpRequest"
29172 for (var headerName in headers) {
29173 var headerValue = headers[headerName];
29175 this.xhr.setRequestHeader(headerName, headerValue);
29181 this.xhr.onload = function()
29183 _this.xhrOnLoad(_this.xhr);
29186 this.xhr.onerror = function()
29188 _this.xhrOnError(_this.xhr);
29191 var formData = new FormData();
29193 formData.append('returnHTML', 'NO');
29196 formData.append('crop', crop);
29199 formData.append(this.paramName, file, file.name);
29206 if(this.fireEvent('prepare', this, formData, options) != false){
29208 if(options.manually){
29212 this.xhr.send(formData);
29216 this.uploadCancel();
29219 uploadCancel : function()
29225 this.delegates = [];
29227 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29234 renderPreview : function(file)
29236 if(typeof(file.target) != 'undefined' && file.target){
29240 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29242 var previewEl = this.managerEl.createChild({
29244 cls : 'roo-document-manager-preview',
29248 tooltip : file[this.toolTipName],
29249 cls : 'roo-document-manager-thumb',
29250 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29255 html : '<i class="fa fa-times-circle"></i>'
29260 var close = previewEl.select('button.close', true).first();
29262 close.on('click', this.onRemove, this, file);
29264 file.target = previewEl;
29266 var image = previewEl.select('img', true).first();
29270 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29272 image.on('click', this.onClick, this, file);
29274 this.fireEvent('previewrendered', this, file);
29280 onPreviewLoad : function(file, image)
29282 if(typeof(file.target) == 'undefined' || !file.target){
29286 var width = image.dom.naturalWidth || image.dom.width;
29287 var height = image.dom.naturalHeight || image.dom.height;
29289 if(width > height){
29290 file.target.addClass('wide');
29294 file.target.addClass('tall');
29299 uploadFromSource : function(file, crop)
29301 this.xhr = new XMLHttpRequest();
29303 this.managerEl.createChild({
29305 cls : 'roo-document-manager-loading',
29309 tooltip : file.name,
29310 cls : 'roo-document-manager-thumb',
29311 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29317 this.xhr.open(this.method, this.url, true);
29320 "Accept": "application/json",
29321 "Cache-Control": "no-cache",
29322 "X-Requested-With": "XMLHttpRequest"
29325 for (var headerName in headers) {
29326 var headerValue = headers[headerName];
29328 this.xhr.setRequestHeader(headerName, headerValue);
29334 this.xhr.onload = function()
29336 _this.xhrOnLoad(_this.xhr);
29339 this.xhr.onerror = function()
29341 _this.xhrOnError(_this.xhr);
29344 var formData = new FormData();
29346 formData.append('returnHTML', 'NO');
29348 formData.append('crop', crop);
29350 if(typeof(file.filename) != 'undefined'){
29351 formData.append('filename', file.filename);
29354 if(typeof(file.mimetype) != 'undefined'){
29355 formData.append('mimetype', file.mimetype);
29360 if(this.fireEvent('prepare', this, formData) != false){
29361 this.xhr.send(formData);
29371 * @class Roo.bootstrap.DocumentViewer
29372 * @extends Roo.bootstrap.Component
29373 * Bootstrap DocumentViewer class
29374 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29375 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29378 * Create a new DocumentViewer
29379 * @param {Object} config The config object
29382 Roo.bootstrap.DocumentViewer = function(config){
29383 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29388 * Fire after initEvent
29389 * @param {Roo.bootstrap.DocumentViewer} this
29395 * @param {Roo.bootstrap.DocumentViewer} this
29400 * Fire after download button
29401 * @param {Roo.bootstrap.DocumentViewer} this
29406 * Fire after trash button
29407 * @param {Roo.bootstrap.DocumentViewer} this
29414 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29416 showDownload : true,
29420 getAutoCreate : function()
29424 cls : 'roo-document-viewer',
29428 cls : 'roo-document-viewer-body',
29432 cls : 'roo-document-viewer-thumb',
29436 cls : 'roo-document-viewer-image'
29444 cls : 'roo-document-viewer-footer',
29447 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29451 cls : 'btn-group roo-document-viewer-download',
29455 cls : 'btn btn-default',
29456 html : '<i class="fa fa-download"></i>'
29462 cls : 'btn-group roo-document-viewer-trash',
29466 cls : 'btn btn-default',
29467 html : '<i class="fa fa-trash"></i>'
29480 initEvents : function()
29482 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29483 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29485 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29486 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29488 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29489 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29491 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29492 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29494 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29495 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29497 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29498 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29500 this.bodyEl.on('click', this.onClick, this);
29501 this.downloadBtn.on('click', this.onDownload, this);
29502 this.trashBtn.on('click', this.onTrash, this);
29504 this.downloadBtn.hide();
29505 this.trashBtn.hide();
29507 if(this.showDownload){
29508 this.downloadBtn.show();
29511 if(this.showTrash){
29512 this.trashBtn.show();
29515 if(!this.showDownload && !this.showTrash) {
29516 this.footerEl.hide();
29521 initial : function()
29523 this.fireEvent('initial', this);
29527 onClick : function(e)
29529 e.preventDefault();
29531 this.fireEvent('click', this);
29534 onDownload : function(e)
29536 e.preventDefault();
29538 this.fireEvent('download', this);
29541 onTrash : function(e)
29543 e.preventDefault();
29545 this.fireEvent('trash', this);
29557 * @class Roo.bootstrap.NavProgressBar
29558 * @extends Roo.bootstrap.Component
29559 * Bootstrap NavProgressBar class
29562 * Create a new nav progress bar
29563 * @param {Object} config The config object
29566 Roo.bootstrap.NavProgressBar = function(config){
29567 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29569 this.bullets = this.bullets || [];
29571 // Roo.bootstrap.NavProgressBar.register(this);
29575 * Fires when the active item changes
29576 * @param {Roo.bootstrap.NavProgressBar} this
29577 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29578 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29585 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29590 getAutoCreate : function()
29592 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29596 cls : 'roo-navigation-bar-group',
29600 cls : 'roo-navigation-top-bar'
29604 cls : 'roo-navigation-bullets-bar',
29608 cls : 'roo-navigation-bar'
29615 cls : 'roo-navigation-bottom-bar'
29625 initEvents: function()
29630 onRender : function(ct, position)
29632 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29634 if(this.bullets.length){
29635 Roo.each(this.bullets, function(b){
29644 addItem : function(cfg)
29646 var item = new Roo.bootstrap.NavProgressItem(cfg);
29648 item.parentId = this.id;
29649 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29652 var top = new Roo.bootstrap.Element({
29654 cls : 'roo-navigation-bar-text'
29657 var bottom = new Roo.bootstrap.Element({
29659 cls : 'roo-navigation-bar-text'
29662 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29663 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29665 var topText = new Roo.bootstrap.Element({
29667 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29670 var bottomText = new Roo.bootstrap.Element({
29672 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29675 topText.onRender(top.el, null);
29676 bottomText.onRender(bottom.el, null);
29679 item.bottomEl = bottom;
29682 this.barItems.push(item);
29687 getActive : function()
29689 var active = false;
29691 Roo.each(this.barItems, function(v){
29693 if (!v.isActive()) {
29705 setActiveItem : function(item)
29709 Roo.each(this.barItems, function(v){
29710 if (v.rid == item.rid) {
29714 if (v.isActive()) {
29715 v.setActive(false);
29720 item.setActive(true);
29722 this.fireEvent('changed', this, item, prev);
29725 getBarItem: function(rid)
29729 Roo.each(this.barItems, function(e) {
29730 if (e.rid != rid) {
29741 indexOfItem : function(item)
29745 Roo.each(this.barItems, function(v, i){
29747 if (v.rid != item.rid) {
29758 setActiveNext : function()
29760 var i = this.indexOfItem(this.getActive());
29762 if (i > this.barItems.length) {
29766 this.setActiveItem(this.barItems[i+1]);
29769 setActivePrev : function()
29771 var i = this.indexOfItem(this.getActive());
29777 this.setActiveItem(this.barItems[i-1]);
29780 format : function()
29782 if(!this.barItems.length){
29786 var width = 100 / this.barItems.length;
29788 Roo.each(this.barItems, function(i){
29789 i.el.setStyle('width', width + '%');
29790 i.topEl.el.setStyle('width', width + '%');
29791 i.bottomEl.el.setStyle('width', width + '%');
29800 * Nav Progress Item
29805 * @class Roo.bootstrap.NavProgressItem
29806 * @extends Roo.bootstrap.Component
29807 * Bootstrap NavProgressItem class
29808 * @cfg {String} rid the reference id
29809 * @cfg {Boolean} active (true|false) Is item active default false
29810 * @cfg {Boolean} disabled (true|false) Is item active default false
29811 * @cfg {String} html
29812 * @cfg {String} position (top|bottom) text position default bottom
29813 * @cfg {String} icon show icon instead of number
29816 * Create a new NavProgressItem
29817 * @param {Object} config The config object
29819 Roo.bootstrap.NavProgressItem = function(config){
29820 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29825 * The raw click event for the entire grid.
29826 * @param {Roo.bootstrap.NavProgressItem} this
29827 * @param {Roo.EventObject} e
29834 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29840 position : 'bottom',
29843 getAutoCreate : function()
29845 var iconCls = 'roo-navigation-bar-item-icon';
29847 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29851 cls: 'roo-navigation-bar-item',
29861 cfg.cls += ' active';
29864 cfg.cls += ' disabled';
29870 disable : function()
29872 this.setDisabled(true);
29875 enable : function()
29877 this.setDisabled(false);
29880 initEvents: function()
29882 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29884 this.iconEl.on('click', this.onClick, this);
29887 onClick : function(e)
29889 e.preventDefault();
29895 if(this.fireEvent('click', this, e) === false){
29899 this.parent().setActiveItem(this);
29902 isActive: function ()
29904 return this.active;
29907 setActive : function(state)
29909 if(this.active == state){
29913 this.active = state;
29916 this.el.addClass('active');
29920 this.el.removeClass('active');
29925 setDisabled : function(state)
29927 if(this.disabled == state){
29931 this.disabled = state;
29934 this.el.addClass('disabled');
29938 this.el.removeClass('disabled');
29941 tooltipEl : function()
29943 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29956 * @class Roo.bootstrap.FieldLabel
29957 * @extends Roo.bootstrap.Component
29958 * Bootstrap FieldLabel class
29959 * @cfg {String} html contents of the element
29960 * @cfg {String} tag tag of the element default label
29961 * @cfg {String} cls class of the element
29962 * @cfg {String} target label target
29963 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29964 * @cfg {String} invalidClass default "text-warning"
29965 * @cfg {String} validClass default "text-success"
29966 * @cfg {String} iconTooltip default "This field is required"
29967 * @cfg {String} indicatorpos (left|right) default left
29970 * Create a new FieldLabel
29971 * @param {Object} config The config object
29974 Roo.bootstrap.FieldLabel = function(config){
29975 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29980 * Fires after the field has been marked as invalid.
29981 * @param {Roo.form.FieldLabel} this
29982 * @param {String} msg The validation message
29987 * Fires after the field has been validated with no errors.
29988 * @param {Roo.form.FieldLabel} this
29994 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30001 invalidClass : 'has-warning',
30002 validClass : 'has-success',
30003 iconTooltip : 'This field is required',
30004 indicatorpos : 'left',
30006 getAutoCreate : function(){
30010 cls : 'roo-bootstrap-field-label ' + this.cls,
30015 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30016 tooltip : this.iconTooltip
30025 if(this.indicatorpos == 'right'){
30028 cls : 'roo-bootstrap-field-label ' + this.cls,
30037 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30038 tooltip : this.iconTooltip
30047 initEvents: function()
30049 Roo.bootstrap.Element.superclass.initEvents.call(this);
30051 this.indicator = this.indicatorEl();
30053 if(this.indicator){
30054 this.indicator.removeClass('visible');
30055 this.indicator.addClass('invisible');
30058 Roo.bootstrap.FieldLabel.register(this);
30061 indicatorEl : function()
30063 var indicator = this.el.select('i.roo-required-indicator',true).first();
30074 * Mark this field as valid
30076 markValid : function()
30078 if(this.indicator){
30079 this.indicator.removeClass('visible');
30080 this.indicator.addClass('invisible');
30083 this.el.removeClass(this.invalidClass);
30085 this.el.addClass(this.validClass);
30087 this.fireEvent('valid', this);
30091 * Mark this field as invalid
30092 * @param {String} msg The validation message
30094 markInvalid : function(msg)
30096 if(this.indicator){
30097 this.indicator.removeClass('invisible');
30098 this.indicator.addClass('visible');
30101 this.el.removeClass(this.validClass);
30103 this.el.addClass(this.invalidClass);
30105 this.fireEvent('invalid', this, msg);
30111 Roo.apply(Roo.bootstrap.FieldLabel, {
30116 * register a FieldLabel Group
30117 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30119 register : function(label)
30121 if(this.groups.hasOwnProperty(label.target)){
30125 this.groups[label.target] = label;
30129 * fetch a FieldLabel Group based on the target
30130 * @param {string} target
30131 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30133 get: function(target) {
30134 if (typeof(this.groups[target]) == 'undefined') {
30138 return this.groups[target] ;
30147 * page DateSplitField.
30153 * @class Roo.bootstrap.DateSplitField
30154 * @extends Roo.bootstrap.Component
30155 * Bootstrap DateSplitField class
30156 * @cfg {string} fieldLabel - the label associated
30157 * @cfg {Number} labelWidth set the width of label (0-12)
30158 * @cfg {String} labelAlign (top|left)
30159 * @cfg {Boolean} dayAllowBlank (true|false) default false
30160 * @cfg {Boolean} monthAllowBlank (true|false) default false
30161 * @cfg {Boolean} yearAllowBlank (true|false) default false
30162 * @cfg {string} dayPlaceholder
30163 * @cfg {string} monthPlaceholder
30164 * @cfg {string} yearPlaceholder
30165 * @cfg {string} dayFormat default 'd'
30166 * @cfg {string} monthFormat default 'm'
30167 * @cfg {string} yearFormat default 'Y'
30168 * @cfg {Number} labellg set the width of label (1-12)
30169 * @cfg {Number} labelmd set the width of label (1-12)
30170 * @cfg {Number} labelsm set the width of label (1-12)
30171 * @cfg {Number} labelxs set the width of label (1-12)
30175 * Create a new DateSplitField
30176 * @param {Object} config The config object
30179 Roo.bootstrap.DateSplitField = function(config){
30180 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30186 * getting the data of years
30187 * @param {Roo.bootstrap.DateSplitField} this
30188 * @param {Object} years
30193 * getting the data of days
30194 * @param {Roo.bootstrap.DateSplitField} this
30195 * @param {Object} days
30200 * Fires after the field has been marked as invalid.
30201 * @param {Roo.form.Field} this
30202 * @param {String} msg The validation message
30207 * Fires after the field has been validated with no errors.
30208 * @param {Roo.form.Field} this
30214 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30217 labelAlign : 'top',
30219 dayAllowBlank : false,
30220 monthAllowBlank : false,
30221 yearAllowBlank : false,
30222 dayPlaceholder : '',
30223 monthPlaceholder : '',
30224 yearPlaceholder : '',
30228 isFormField : true,
30234 getAutoCreate : function()
30238 cls : 'row roo-date-split-field-group',
30243 cls : 'form-hidden-field roo-date-split-field-group-value',
30249 var labelCls = 'col-md-12';
30250 var contentCls = 'col-md-4';
30252 if(this.fieldLabel){
30256 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30260 html : this.fieldLabel
30265 if(this.labelAlign == 'left'){
30267 if(this.labelWidth > 12){
30268 label.style = "width: " + this.labelWidth + 'px';
30271 if(this.labelWidth < 13 && this.labelmd == 0){
30272 this.labelmd = this.labelWidth;
30275 if(this.labellg > 0){
30276 labelCls = ' col-lg-' + this.labellg;
30277 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30280 if(this.labelmd > 0){
30281 labelCls = ' col-md-' + this.labelmd;
30282 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30285 if(this.labelsm > 0){
30286 labelCls = ' col-sm-' + this.labelsm;
30287 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30290 if(this.labelxs > 0){
30291 labelCls = ' col-xs-' + this.labelxs;
30292 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30296 label.cls += ' ' + labelCls;
30298 cfg.cn.push(label);
30301 Roo.each(['day', 'month', 'year'], function(t){
30304 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30311 inputEl: function ()
30313 return this.el.select('.roo-date-split-field-group-value', true).first();
30316 onRender : function(ct, position)
30320 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30322 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30324 this.dayField = new Roo.bootstrap.ComboBox({
30325 allowBlank : this.dayAllowBlank,
30326 alwaysQuery : true,
30327 displayField : 'value',
30330 forceSelection : true,
30332 placeholder : this.dayPlaceholder,
30333 selectOnFocus : true,
30334 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30335 triggerAction : 'all',
30337 valueField : 'value',
30338 store : new Roo.data.SimpleStore({
30339 data : (function() {
30341 _this.fireEvent('days', _this, days);
30344 fields : [ 'value' ]
30347 select : function (_self, record, index)
30349 _this.setValue(_this.getValue());
30354 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30356 this.monthField = new Roo.bootstrap.MonthField({
30357 after : '<i class=\"fa fa-calendar\"></i>',
30358 allowBlank : this.monthAllowBlank,
30359 placeholder : this.monthPlaceholder,
30362 render : function (_self)
30364 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30365 e.preventDefault();
30369 select : function (_self, oldvalue, newvalue)
30371 _this.setValue(_this.getValue());
30376 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30378 this.yearField = new Roo.bootstrap.ComboBox({
30379 allowBlank : this.yearAllowBlank,
30380 alwaysQuery : true,
30381 displayField : 'value',
30384 forceSelection : true,
30386 placeholder : this.yearPlaceholder,
30387 selectOnFocus : true,
30388 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30389 triggerAction : 'all',
30391 valueField : 'value',
30392 store : new Roo.data.SimpleStore({
30393 data : (function() {
30395 _this.fireEvent('years', _this, years);
30398 fields : [ 'value' ]
30401 select : function (_self, record, index)
30403 _this.setValue(_this.getValue());
30408 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30411 setValue : function(v, format)
30413 this.inputEl.dom.value = v;
30415 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30417 var d = Date.parseDate(v, f);
30424 this.setDay(d.format(this.dayFormat));
30425 this.setMonth(d.format(this.monthFormat));
30426 this.setYear(d.format(this.yearFormat));
30433 setDay : function(v)
30435 this.dayField.setValue(v);
30436 this.inputEl.dom.value = this.getValue();
30441 setMonth : function(v)
30443 this.monthField.setValue(v, true);
30444 this.inputEl.dom.value = this.getValue();
30449 setYear : function(v)
30451 this.yearField.setValue(v);
30452 this.inputEl.dom.value = this.getValue();
30457 getDay : function()
30459 return this.dayField.getValue();
30462 getMonth : function()
30464 return this.monthField.getValue();
30467 getYear : function()
30469 return this.yearField.getValue();
30472 getValue : function()
30474 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30476 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30486 this.inputEl.dom.value = '';
30491 validate : function()
30493 var d = this.dayField.validate();
30494 var m = this.monthField.validate();
30495 var y = this.yearField.validate();
30500 (!this.dayAllowBlank && !d) ||
30501 (!this.monthAllowBlank && !m) ||
30502 (!this.yearAllowBlank && !y)
30507 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30516 this.markInvalid();
30521 markValid : function()
30524 var label = this.el.select('label', true).first();
30525 var icon = this.el.select('i.fa-star', true).first();
30531 this.fireEvent('valid', this);
30535 * Mark this field as invalid
30536 * @param {String} msg The validation message
30538 markInvalid : function(msg)
30541 var label = this.el.select('label', true).first();
30542 var icon = this.el.select('i.fa-star', true).first();
30544 if(label && !icon){
30545 this.el.select('.roo-date-split-field-label', true).createChild({
30547 cls : 'text-danger fa fa-lg fa-star',
30548 tooltip : 'This field is required',
30549 style : 'margin-right:5px;'
30553 this.fireEvent('invalid', this, msg);
30556 clearInvalid : function()
30558 var label = this.el.select('label', true).first();
30559 var icon = this.el.select('i.fa-star', true).first();
30565 this.fireEvent('valid', this);
30568 getName: function()
30578 * http://masonry.desandro.com
30580 * The idea is to render all the bricks based on vertical width...
30582 * The original code extends 'outlayer' - we might need to use that....
30588 * @class Roo.bootstrap.LayoutMasonry
30589 * @extends Roo.bootstrap.Component
30590 * Bootstrap Layout Masonry class
30593 * Create a new Element
30594 * @param {Object} config The config object
30597 Roo.bootstrap.LayoutMasonry = function(config){
30599 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30603 Roo.bootstrap.LayoutMasonry.register(this);
30609 * Fire after layout the items
30610 * @param {Roo.bootstrap.LayoutMasonry} this
30611 * @param {Roo.EventObject} e
30618 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30621 * @cfg {Boolean} isLayoutInstant = no animation?
30623 isLayoutInstant : false, // needed?
30626 * @cfg {Number} boxWidth width of the columns
30631 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30636 * @cfg {Number} padWidth padding below box..
30641 * @cfg {Number} gutter gutter width..
30646 * @cfg {Number} maxCols maximum number of columns
30652 * @cfg {Boolean} isAutoInitial defalut true
30654 isAutoInitial : true,
30659 * @cfg {Boolean} isHorizontal defalut false
30661 isHorizontal : false,
30663 currentSize : null,
30669 bricks: null, //CompositeElement
30673 _isLayoutInited : false,
30675 // isAlternative : false, // only use for vertical layout...
30678 * @cfg {Number} alternativePadWidth padding below box..
30680 alternativePadWidth : 50,
30682 selectedBrick : [],
30684 getAutoCreate : function(){
30686 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30690 cls: 'blog-masonary-wrapper ' + this.cls,
30692 cls : 'mas-boxes masonary'
30699 getChildContainer: function( )
30701 if (this.boxesEl) {
30702 return this.boxesEl;
30705 this.boxesEl = this.el.select('.mas-boxes').first();
30707 return this.boxesEl;
30711 initEvents : function()
30715 if(this.isAutoInitial){
30716 Roo.log('hook children rendered');
30717 this.on('childrenrendered', function() {
30718 Roo.log('children rendered');
30724 initial : function()
30726 this.selectedBrick = [];
30728 this.currentSize = this.el.getBox(true);
30730 Roo.EventManager.onWindowResize(this.resize, this);
30732 if(!this.isAutoInitial){
30740 //this.layout.defer(500,this);
30744 resize : function()
30746 var cs = this.el.getBox(true);
30749 this.currentSize.width == cs.width &&
30750 this.currentSize.x == cs.x &&
30751 this.currentSize.height == cs.height &&
30752 this.currentSize.y == cs.y
30754 Roo.log("no change in with or X or Y");
30758 this.currentSize = cs;
30764 layout : function()
30766 this._resetLayout();
30768 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30770 this.layoutItems( isInstant );
30772 this._isLayoutInited = true;
30774 this.fireEvent('layout', this);
30778 _resetLayout : function()
30780 if(this.isHorizontal){
30781 this.horizontalMeasureColumns();
30785 this.verticalMeasureColumns();
30789 verticalMeasureColumns : function()
30791 this.getContainerWidth();
30793 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30794 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30798 var boxWidth = this.boxWidth + this.padWidth;
30800 if(this.containerWidth < this.boxWidth){
30801 boxWidth = this.containerWidth
30804 var containerWidth = this.containerWidth;
30806 var cols = Math.floor(containerWidth / boxWidth);
30808 this.cols = Math.max( cols, 1 );
30810 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30812 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30814 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30816 this.colWidth = boxWidth + avail - this.padWidth;
30818 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30819 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30822 horizontalMeasureColumns : function()
30824 this.getContainerWidth();
30826 var boxWidth = this.boxWidth;
30828 if(this.containerWidth < boxWidth){
30829 boxWidth = this.containerWidth;
30832 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30834 this.el.setHeight(boxWidth);
30838 getContainerWidth : function()
30840 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30843 layoutItems : function( isInstant )
30845 Roo.log(this.bricks);
30847 var items = Roo.apply([], this.bricks);
30849 if(this.isHorizontal){
30850 this._horizontalLayoutItems( items , isInstant );
30854 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30855 // this._verticalAlternativeLayoutItems( items , isInstant );
30859 this._verticalLayoutItems( items , isInstant );
30863 _verticalLayoutItems : function ( items , isInstant)
30865 if ( !items || !items.length ) {
30870 ['xs', 'xs', 'xs', 'tall'],
30871 ['xs', 'xs', 'tall'],
30872 ['xs', 'xs', 'sm'],
30873 ['xs', 'xs', 'xs'],
30879 ['sm', 'xs', 'xs'],
30883 ['tall', 'xs', 'xs', 'xs'],
30884 ['tall', 'xs', 'xs'],
30896 Roo.each(items, function(item, k){
30898 switch (item.size) {
30899 // these layouts take up a full box,
30910 boxes.push([item]);
30933 var filterPattern = function(box, length)
30941 var pattern = box.slice(0, length);
30945 Roo.each(pattern, function(i){
30946 format.push(i.size);
30949 Roo.each(standard, function(s){
30951 if(String(s) != String(format)){
30960 if(!match && length == 1){
30965 filterPattern(box, length - 1);
30969 queue.push(pattern);
30971 box = box.slice(length, box.length);
30973 filterPattern(box, 4);
30979 Roo.each(boxes, function(box, k){
30985 if(box.length == 1){
30990 filterPattern(box, 4);
30994 this._processVerticalLayoutQueue( queue, isInstant );
30998 // _verticalAlternativeLayoutItems : function( items , isInstant )
31000 // if ( !items || !items.length ) {
31004 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31008 _horizontalLayoutItems : function ( items , isInstant)
31010 if ( !items || !items.length || items.length < 3) {
31016 var eItems = items.slice(0, 3);
31018 items = items.slice(3, items.length);
31021 ['xs', 'xs', 'xs', 'wide'],
31022 ['xs', 'xs', 'wide'],
31023 ['xs', 'xs', 'sm'],
31024 ['xs', 'xs', 'xs'],
31030 ['sm', 'xs', 'xs'],
31034 ['wide', 'xs', 'xs', 'xs'],
31035 ['wide', 'xs', 'xs'],
31048 Roo.each(items, function(item, k){
31050 switch (item.size) {
31061 boxes.push([item]);
31085 var filterPattern = function(box, length)
31093 var pattern = box.slice(0, length);
31097 Roo.each(pattern, function(i){
31098 format.push(i.size);
31101 Roo.each(standard, function(s){
31103 if(String(s) != String(format)){
31112 if(!match && length == 1){
31117 filterPattern(box, length - 1);
31121 queue.push(pattern);
31123 box = box.slice(length, box.length);
31125 filterPattern(box, 4);
31131 Roo.each(boxes, function(box, k){
31137 if(box.length == 1){
31142 filterPattern(box, 4);
31149 var pos = this.el.getBox(true);
31153 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31155 var hit_end = false;
31157 Roo.each(queue, function(box){
31161 Roo.each(box, function(b){
31163 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31173 Roo.each(box, function(b){
31175 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31178 mx = Math.max(mx, b.x);
31182 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31186 Roo.each(box, function(b){
31188 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31202 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31205 /** Sets position of item in DOM
31206 * @param {Element} item
31207 * @param {Number} x - horizontal position
31208 * @param {Number} y - vertical position
31209 * @param {Boolean} isInstant - disables transitions
31211 _processVerticalLayoutQueue : function( queue, isInstant )
31213 var pos = this.el.getBox(true);
31218 for (var i = 0; i < this.cols; i++){
31222 Roo.each(queue, function(box, k){
31224 var col = k % this.cols;
31226 Roo.each(box, function(b,kk){
31228 b.el.position('absolute');
31230 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31231 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31233 if(b.size == 'md-left' || b.size == 'md-right'){
31234 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31235 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31238 b.el.setWidth(width);
31239 b.el.setHeight(height);
31241 b.el.select('iframe',true).setSize(width,height);
31245 for (var i = 0; i < this.cols; i++){
31247 if(maxY[i] < maxY[col]){
31252 col = Math.min(col, i);
31256 x = pos.x + col * (this.colWidth + this.padWidth);
31260 var positions = [];
31262 switch (box.length){
31264 positions = this.getVerticalOneBoxColPositions(x, y, box);
31267 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31270 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31273 positions = this.getVerticalFourBoxColPositions(x, y, box);
31279 Roo.each(box, function(b,kk){
31281 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31283 var sz = b.el.getSize();
31285 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31293 for (var i = 0; i < this.cols; i++){
31294 mY = Math.max(mY, maxY[i]);
31297 this.el.setHeight(mY - pos.y);
31301 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31303 // var pos = this.el.getBox(true);
31306 // var maxX = pos.right;
31308 // var maxHeight = 0;
31310 // Roo.each(items, function(item, k){
31314 // item.el.position('absolute');
31316 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31318 // item.el.setWidth(width);
31320 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31322 // item.el.setHeight(height);
31325 // item.el.setXY([x, y], isInstant ? false : true);
31327 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31330 // y = y + height + this.alternativePadWidth;
31332 // maxHeight = maxHeight + height + this.alternativePadWidth;
31336 // this.el.setHeight(maxHeight);
31340 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31342 var pos = this.el.getBox(true);
31347 var maxX = pos.right;
31349 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31351 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31353 Roo.each(queue, function(box, k){
31355 Roo.each(box, function(b, kk){
31357 b.el.position('absolute');
31359 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31360 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31362 if(b.size == 'md-left' || b.size == 'md-right'){
31363 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31364 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31367 b.el.setWidth(width);
31368 b.el.setHeight(height);
31376 var positions = [];
31378 switch (box.length){
31380 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31383 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31386 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31389 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31395 Roo.each(box, function(b,kk){
31397 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31399 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31407 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31409 Roo.each(eItems, function(b,k){
31411 b.size = (k == 0) ? 'sm' : 'xs';
31412 b.x = (k == 0) ? 2 : 1;
31413 b.y = (k == 0) ? 2 : 1;
31415 b.el.position('absolute');
31417 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31419 b.el.setWidth(width);
31421 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31423 b.el.setHeight(height);
31427 var positions = [];
31430 x : maxX - this.unitWidth * 2 - this.gutter,
31435 x : maxX - this.unitWidth,
31436 y : minY + (this.unitWidth + this.gutter) * 2
31440 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31444 Roo.each(eItems, function(b,k){
31446 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31452 getVerticalOneBoxColPositions : function(x, y, box)
31456 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31458 if(box[0].size == 'md-left'){
31462 if(box[0].size == 'md-right'){
31467 x : x + (this.unitWidth + this.gutter) * rand,
31474 getVerticalTwoBoxColPositions : function(x, y, box)
31478 if(box[0].size == 'xs'){
31482 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31486 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31500 x : x + (this.unitWidth + this.gutter) * 2,
31501 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31508 getVerticalThreeBoxColPositions : function(x, y, box)
31512 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31520 x : x + (this.unitWidth + this.gutter) * 1,
31525 x : x + (this.unitWidth + this.gutter) * 2,
31533 if(box[0].size == 'xs' && box[1].size == 'xs'){
31542 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31546 x : x + (this.unitWidth + this.gutter) * 1,
31560 x : x + (this.unitWidth + this.gutter) * 2,
31565 x : x + (this.unitWidth + this.gutter) * 2,
31566 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31573 getVerticalFourBoxColPositions : function(x, y, box)
31577 if(box[0].size == 'xs'){
31586 y : y + (this.unitHeight + this.gutter) * 1
31591 y : y + (this.unitHeight + this.gutter) * 2
31595 x : x + (this.unitWidth + this.gutter) * 1,
31609 x : x + (this.unitWidth + this.gutter) * 2,
31614 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31615 y : y + (this.unitHeight + this.gutter) * 1
31619 x : x + (this.unitWidth + this.gutter) * 2,
31620 y : y + (this.unitWidth + this.gutter) * 2
31627 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31631 if(box[0].size == 'md-left'){
31633 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31640 if(box[0].size == 'md-right'){
31642 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31643 y : minY + (this.unitWidth + this.gutter) * 1
31649 var rand = Math.floor(Math.random() * (4 - box[0].y));
31652 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31653 y : minY + (this.unitWidth + this.gutter) * rand
31660 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31664 if(box[0].size == 'xs'){
31667 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31672 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31673 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31681 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31686 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31687 y : minY + (this.unitWidth + this.gutter) * 2
31694 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31698 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31701 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31706 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31707 y : minY + (this.unitWidth + this.gutter) * 1
31711 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31712 y : minY + (this.unitWidth + this.gutter) * 2
31719 if(box[0].size == 'xs' && box[1].size == 'xs'){
31722 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31727 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31732 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31733 y : minY + (this.unitWidth + this.gutter) * 1
31741 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31746 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31747 y : minY + (this.unitWidth + this.gutter) * 2
31751 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31752 y : minY + (this.unitWidth + this.gutter) * 2
31759 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31763 if(box[0].size == 'xs'){
31766 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31771 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31776 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31781 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31782 y : minY + (this.unitWidth + this.gutter) * 1
31790 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31795 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31796 y : minY + (this.unitWidth + this.gutter) * 2
31800 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31801 y : minY + (this.unitWidth + this.gutter) * 2
31805 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31806 y : minY + (this.unitWidth + this.gutter) * 2
31814 * remove a Masonry Brick
31815 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31817 removeBrick : function(brick_id)
31823 for (var i = 0; i<this.bricks.length; i++) {
31824 if (this.bricks[i].id == brick_id) {
31825 this.bricks.splice(i,1);
31826 this.el.dom.removeChild(Roo.get(brick_id).dom);
31833 * adds a Masonry Brick
31834 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31836 addBrick : function(cfg)
31838 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31839 //this.register(cn);
31840 cn.parentId = this.id;
31841 cn.onRender(this.el, null);
31846 * register a Masonry Brick
31847 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31850 register : function(brick)
31852 this.bricks.push(brick);
31853 brick.masonryId = this.id;
31857 * clear all the Masonry Brick
31859 clearAll : function()
31862 //this.getChildContainer().dom.innerHTML = "";
31863 this.el.dom.innerHTML = '';
31866 getSelected : function()
31868 if (!this.selectedBrick) {
31872 return this.selectedBrick;
31876 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31880 * register a Masonry Layout
31881 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31884 register : function(layout)
31886 this.groups[layout.id] = layout;
31889 * fetch a Masonry Layout based on the masonry layout ID
31890 * @param {string} the masonry layout to add
31891 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31894 get: function(layout_id) {
31895 if (typeof(this.groups[layout_id]) == 'undefined') {
31898 return this.groups[layout_id] ;
31910 * http://masonry.desandro.com
31912 * The idea is to render all the bricks based on vertical width...
31914 * The original code extends 'outlayer' - we might need to use that....
31920 * @class Roo.bootstrap.LayoutMasonryAuto
31921 * @extends Roo.bootstrap.Component
31922 * Bootstrap Layout Masonry class
31925 * Create a new Element
31926 * @param {Object} config The config object
31929 Roo.bootstrap.LayoutMasonryAuto = function(config){
31930 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31933 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31936 * @cfg {Boolean} isFitWidth - resize the width..
31938 isFitWidth : false, // options..
31940 * @cfg {Boolean} isOriginLeft = left align?
31942 isOriginLeft : true,
31944 * @cfg {Boolean} isOriginTop = top align?
31946 isOriginTop : false,
31948 * @cfg {Boolean} isLayoutInstant = no animation?
31950 isLayoutInstant : false, // needed?
31952 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31954 isResizingContainer : true,
31956 * @cfg {Number} columnWidth width of the columns
31962 * @cfg {Number} maxCols maximum number of columns
31967 * @cfg {Number} padHeight padding below box..
31973 * @cfg {Boolean} isAutoInitial defalut true
31976 isAutoInitial : true,
31982 initialColumnWidth : 0,
31983 currentSize : null,
31985 colYs : null, // array.
31992 bricks: null, //CompositeElement
31993 cols : 0, // array?
31994 // element : null, // wrapped now this.el
31995 _isLayoutInited : null,
31998 getAutoCreate : function(){
32002 cls: 'blog-masonary-wrapper ' + this.cls,
32004 cls : 'mas-boxes masonary'
32011 getChildContainer: function( )
32013 if (this.boxesEl) {
32014 return this.boxesEl;
32017 this.boxesEl = this.el.select('.mas-boxes').first();
32019 return this.boxesEl;
32023 initEvents : function()
32027 if(this.isAutoInitial){
32028 Roo.log('hook children rendered');
32029 this.on('childrenrendered', function() {
32030 Roo.log('children rendered');
32037 initial : function()
32039 this.reloadItems();
32041 this.currentSize = this.el.getBox(true);
32043 /// was window resize... - let's see if this works..
32044 Roo.EventManager.onWindowResize(this.resize, this);
32046 if(!this.isAutoInitial){
32051 this.layout.defer(500,this);
32054 reloadItems: function()
32056 this.bricks = this.el.select('.masonry-brick', true);
32058 this.bricks.each(function(b) {
32059 //Roo.log(b.getSize());
32060 if (!b.attr('originalwidth')) {
32061 b.attr('originalwidth', b.getSize().width);
32066 Roo.log(this.bricks.elements.length);
32069 resize : function()
32072 var cs = this.el.getBox(true);
32074 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32075 Roo.log("no change in with or X");
32078 this.currentSize = cs;
32082 layout : function()
32085 this._resetLayout();
32086 //this._manageStamps();
32088 // don't animate first layout
32089 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32090 this.layoutItems( isInstant );
32092 // flag for initalized
32093 this._isLayoutInited = true;
32096 layoutItems : function( isInstant )
32098 //var items = this._getItemsForLayout( this.items );
32099 // original code supports filtering layout items.. we just ignore it..
32101 this._layoutItems( this.bricks , isInstant );
32103 this._postLayout();
32105 _layoutItems : function ( items , isInstant)
32107 //this.fireEvent( 'layout', this, items );
32110 if ( !items || !items.elements.length ) {
32111 // no items, emit event with empty array
32116 items.each(function(item) {
32117 Roo.log("layout item");
32119 // get x/y object from method
32120 var position = this._getItemLayoutPosition( item );
32122 position.item = item;
32123 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32124 queue.push( position );
32127 this._processLayoutQueue( queue );
32129 /** Sets position of item in DOM
32130 * @param {Element} item
32131 * @param {Number} x - horizontal position
32132 * @param {Number} y - vertical position
32133 * @param {Boolean} isInstant - disables transitions
32135 _processLayoutQueue : function( queue )
32137 for ( var i=0, len = queue.length; i < len; i++ ) {
32138 var obj = queue[i];
32139 obj.item.position('absolute');
32140 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32146 * Any logic you want to do after each layout,
32147 * i.e. size the container
32149 _postLayout : function()
32151 this.resizeContainer();
32154 resizeContainer : function()
32156 if ( !this.isResizingContainer ) {
32159 var size = this._getContainerSize();
32161 this.el.setSize(size.width,size.height);
32162 this.boxesEl.setSize(size.width,size.height);
32168 _resetLayout : function()
32170 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32171 this.colWidth = this.el.getWidth();
32172 //this.gutter = this.el.getWidth();
32174 this.measureColumns();
32180 this.colYs.push( 0 );
32186 measureColumns : function()
32188 this.getContainerWidth();
32189 // if columnWidth is 0, default to outerWidth of first item
32190 if ( !this.columnWidth ) {
32191 var firstItem = this.bricks.first();
32192 Roo.log(firstItem);
32193 this.columnWidth = this.containerWidth;
32194 if (firstItem && firstItem.attr('originalwidth') ) {
32195 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32197 // columnWidth fall back to item of first element
32198 Roo.log("set column width?");
32199 this.initialColumnWidth = this.columnWidth ;
32201 // if first elem has no width, default to size of container
32206 if (this.initialColumnWidth) {
32207 this.columnWidth = this.initialColumnWidth;
32212 // column width is fixed at the top - however if container width get's smaller we should
32215 // this bit calcs how man columns..
32217 var columnWidth = this.columnWidth += this.gutter;
32219 // calculate columns
32220 var containerWidth = this.containerWidth + this.gutter;
32222 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32223 // fix rounding errors, typically with gutters
32224 var excess = columnWidth - containerWidth % columnWidth;
32227 // if overshoot is less than a pixel, round up, otherwise floor it
32228 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32229 cols = Math[ mathMethod ]( cols );
32230 this.cols = Math.max( cols, 1 );
32231 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32233 // padding positioning..
32234 var totalColWidth = this.cols * this.columnWidth;
32235 var padavail = this.containerWidth - totalColWidth;
32236 // so for 2 columns - we need 3 'pads'
32238 var padNeeded = (1+this.cols) * this.padWidth;
32240 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32242 this.columnWidth += padExtra
32243 //this.padWidth = Math.floor(padavail / ( this.cols));
32245 // adjust colum width so that padding is fixed??
32247 // we have 3 columns ... total = width * 3
32248 // we have X left over... that should be used by
32250 //if (this.expandC) {
32258 getContainerWidth : function()
32260 /* // container is parent if fit width
32261 var container = this.isFitWidth ? this.element.parentNode : this.element;
32262 // check that this.size and size are there
32263 // IE8 triggers resize on body size change, so they might not be
32265 var size = getSize( container ); //FIXME
32266 this.containerWidth = size && size.innerWidth; //FIXME
32269 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32273 _getItemLayoutPosition : function( item ) // what is item?
32275 // we resize the item to our columnWidth..
32277 item.setWidth(this.columnWidth);
32278 item.autoBoxAdjust = false;
32280 var sz = item.getSize();
32282 // how many columns does this brick span
32283 var remainder = this.containerWidth % this.columnWidth;
32285 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32286 // round if off by 1 pixel, otherwise use ceil
32287 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32288 colSpan = Math.min( colSpan, this.cols );
32290 // normally this should be '1' as we dont' currently allow multi width columns..
32292 var colGroup = this._getColGroup( colSpan );
32293 // get the minimum Y value from the columns
32294 var minimumY = Math.min.apply( Math, colGroup );
32295 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32297 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32299 // position the brick
32301 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32302 y: this.currentSize.y + minimumY + this.padHeight
32306 // apply setHeight to necessary columns
32307 var setHeight = minimumY + sz.height + this.padHeight;
32308 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32310 var setSpan = this.cols + 1 - colGroup.length;
32311 for ( var i = 0; i < setSpan; i++ ) {
32312 this.colYs[ shortColIndex + i ] = setHeight ;
32319 * @param {Number} colSpan - number of columns the element spans
32320 * @returns {Array} colGroup
32322 _getColGroup : function( colSpan )
32324 if ( colSpan < 2 ) {
32325 // if brick spans only one column, use all the column Ys
32330 // how many different places could this brick fit horizontally
32331 var groupCount = this.cols + 1 - colSpan;
32332 // for each group potential horizontal position
32333 for ( var i = 0; i < groupCount; i++ ) {
32334 // make an array of colY values for that one group
32335 var groupColYs = this.colYs.slice( i, i + colSpan );
32336 // and get the max value of the array
32337 colGroup[i] = Math.max.apply( Math, groupColYs );
32342 _manageStamp : function( stamp )
32344 var stampSize = stamp.getSize();
32345 var offset = stamp.getBox();
32346 // get the columns that this stamp affects
32347 var firstX = this.isOriginLeft ? offset.x : offset.right;
32348 var lastX = firstX + stampSize.width;
32349 var firstCol = Math.floor( firstX / this.columnWidth );
32350 firstCol = Math.max( 0, firstCol );
32352 var lastCol = Math.floor( lastX / this.columnWidth );
32353 // lastCol should not go over if multiple of columnWidth #425
32354 lastCol -= lastX % this.columnWidth ? 0 : 1;
32355 lastCol = Math.min( this.cols - 1, lastCol );
32357 // set colYs to bottom of the stamp
32358 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32361 for ( var i = firstCol; i <= lastCol; i++ ) {
32362 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32367 _getContainerSize : function()
32369 this.maxY = Math.max.apply( Math, this.colYs );
32374 if ( this.isFitWidth ) {
32375 size.width = this._getContainerFitWidth();
32381 _getContainerFitWidth : function()
32383 var unusedCols = 0;
32384 // count unused columns
32387 if ( this.colYs[i] !== 0 ) {
32392 // fit container to columns that have been used
32393 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32396 needsResizeLayout : function()
32398 var previousWidth = this.containerWidth;
32399 this.getContainerWidth();
32400 return previousWidth !== this.containerWidth;
32415 * @class Roo.bootstrap.MasonryBrick
32416 * @extends Roo.bootstrap.Component
32417 * Bootstrap MasonryBrick class
32420 * Create a new MasonryBrick
32421 * @param {Object} config The config object
32424 Roo.bootstrap.MasonryBrick = function(config){
32426 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32428 Roo.bootstrap.MasonryBrick.register(this);
32434 * When a MasonryBrick is clcik
32435 * @param {Roo.bootstrap.MasonryBrick} this
32436 * @param {Roo.EventObject} e
32442 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32445 * @cfg {String} title
32449 * @cfg {String} html
32453 * @cfg {String} bgimage
32457 * @cfg {String} videourl
32461 * @cfg {String} cls
32465 * @cfg {String} href
32469 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32474 * @cfg {String} placetitle (center|bottom)
32479 * @cfg {Boolean} isFitContainer defalut true
32481 isFitContainer : true,
32484 * @cfg {Boolean} preventDefault defalut false
32486 preventDefault : false,
32489 * @cfg {Boolean} inverse defalut false
32491 maskInverse : false,
32493 getAutoCreate : function()
32495 if(!this.isFitContainer){
32496 return this.getSplitAutoCreate();
32499 var cls = 'masonry-brick masonry-brick-full';
32501 if(this.href.length){
32502 cls += ' masonry-brick-link';
32505 if(this.bgimage.length){
32506 cls += ' masonry-brick-image';
32509 if(this.maskInverse){
32510 cls += ' mask-inverse';
32513 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32514 cls += ' enable-mask';
32518 cls += ' masonry-' + this.size + '-brick';
32521 if(this.placetitle.length){
32523 switch (this.placetitle) {
32525 cls += ' masonry-center-title';
32528 cls += ' masonry-bottom-title';
32535 if(!this.html.length && !this.bgimage.length){
32536 cls += ' masonry-center-title';
32539 if(!this.html.length && this.bgimage.length){
32540 cls += ' masonry-bottom-title';
32545 cls += ' ' + this.cls;
32549 tag: (this.href.length) ? 'a' : 'div',
32554 cls: 'masonry-brick-mask'
32558 cls: 'masonry-brick-paragraph',
32564 if(this.href.length){
32565 cfg.href = this.href;
32568 var cn = cfg.cn[1].cn;
32570 if(this.title.length){
32573 cls: 'masonry-brick-title',
32578 if(this.html.length){
32581 cls: 'masonry-brick-text',
32586 if (!this.title.length && !this.html.length) {
32587 cfg.cn[1].cls += ' hide';
32590 if(this.bgimage.length){
32593 cls: 'masonry-brick-image-view',
32598 if(this.videourl.length){
32599 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32600 // youtube support only?
32603 cls: 'masonry-brick-image-view',
32606 allowfullscreen : true
32614 getSplitAutoCreate : function()
32616 var cls = 'masonry-brick masonry-brick-split';
32618 if(this.href.length){
32619 cls += ' masonry-brick-link';
32622 if(this.bgimage.length){
32623 cls += ' masonry-brick-image';
32627 cls += ' masonry-' + this.size + '-brick';
32630 switch (this.placetitle) {
32632 cls += ' masonry-center-title';
32635 cls += ' masonry-bottom-title';
32638 if(!this.bgimage.length){
32639 cls += ' masonry-center-title';
32642 if(this.bgimage.length){
32643 cls += ' masonry-bottom-title';
32649 cls += ' ' + this.cls;
32653 tag: (this.href.length) ? 'a' : 'div',
32658 cls: 'masonry-brick-split-head',
32662 cls: 'masonry-brick-paragraph',
32669 cls: 'masonry-brick-split-body',
32675 if(this.href.length){
32676 cfg.href = this.href;
32679 if(this.title.length){
32680 cfg.cn[0].cn[0].cn.push({
32682 cls: 'masonry-brick-title',
32687 if(this.html.length){
32688 cfg.cn[1].cn.push({
32690 cls: 'masonry-brick-text',
32695 if(this.bgimage.length){
32696 cfg.cn[0].cn.push({
32698 cls: 'masonry-brick-image-view',
32703 if(this.videourl.length){
32704 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32705 // youtube support only?
32706 cfg.cn[0].cn.cn.push({
32708 cls: 'masonry-brick-image-view',
32711 allowfullscreen : true
32718 initEvents: function()
32720 switch (this.size) {
32753 this.el.on('touchstart', this.onTouchStart, this);
32754 this.el.on('touchmove', this.onTouchMove, this);
32755 this.el.on('touchend', this.onTouchEnd, this);
32756 this.el.on('contextmenu', this.onContextMenu, this);
32758 this.el.on('mouseenter' ,this.enter, this);
32759 this.el.on('mouseleave', this.leave, this);
32760 this.el.on('click', this.onClick, this);
32763 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32764 this.parent().bricks.push(this);
32769 onClick: function(e, el)
32771 var time = this.endTimer - this.startTimer;
32772 // Roo.log(e.preventDefault());
32775 e.preventDefault();
32780 if(!this.preventDefault){
32784 e.preventDefault();
32786 if (this.activeClass != '') {
32787 this.selectBrick();
32790 this.fireEvent('click', this, e);
32793 enter: function(e, el)
32795 e.preventDefault();
32797 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32801 if(this.bgimage.length && this.html.length){
32802 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32806 leave: function(e, el)
32808 e.preventDefault();
32810 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32814 if(this.bgimage.length && this.html.length){
32815 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32819 onTouchStart: function(e, el)
32821 // e.preventDefault();
32823 this.touchmoved = false;
32825 if(!this.isFitContainer){
32829 if(!this.bgimage.length || !this.html.length){
32833 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32835 this.timer = new Date().getTime();
32839 onTouchMove: function(e, el)
32841 this.touchmoved = true;
32844 onContextMenu : function(e,el)
32846 e.preventDefault();
32847 e.stopPropagation();
32851 onTouchEnd: function(e, el)
32853 // e.preventDefault();
32855 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32862 if(!this.bgimage.length || !this.html.length){
32864 if(this.href.length){
32865 window.location.href = this.href;
32871 if(!this.isFitContainer){
32875 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32877 window.location.href = this.href;
32880 //selection on single brick only
32881 selectBrick : function() {
32883 if (!this.parentId) {
32887 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32888 var index = m.selectedBrick.indexOf(this.id);
32891 m.selectedBrick.splice(index,1);
32892 this.el.removeClass(this.activeClass);
32896 for(var i = 0; i < m.selectedBrick.length; i++) {
32897 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32898 b.el.removeClass(b.activeClass);
32901 m.selectedBrick = [];
32903 m.selectedBrick.push(this.id);
32904 this.el.addClass(this.activeClass);
32908 isSelected : function(){
32909 return this.el.hasClass(this.activeClass);
32914 Roo.apply(Roo.bootstrap.MasonryBrick, {
32917 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32919 * register a Masonry Brick
32920 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32923 register : function(brick)
32925 //this.groups[brick.id] = brick;
32926 this.groups.add(brick.id, brick);
32929 * fetch a masonry brick based on the masonry brick ID
32930 * @param {string} the masonry brick to add
32931 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32934 get: function(brick_id)
32936 // if (typeof(this.groups[brick_id]) == 'undefined') {
32939 // return this.groups[brick_id] ;
32941 if(this.groups.key(brick_id)) {
32942 return this.groups.key(brick_id);
32960 * @class Roo.bootstrap.Brick
32961 * @extends Roo.bootstrap.Component
32962 * Bootstrap Brick class
32965 * Create a new Brick
32966 * @param {Object} config The config object
32969 Roo.bootstrap.Brick = function(config){
32970 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32976 * When a Brick is click
32977 * @param {Roo.bootstrap.Brick} this
32978 * @param {Roo.EventObject} e
32984 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32987 * @cfg {String} title
32991 * @cfg {String} html
32995 * @cfg {String} bgimage
32999 * @cfg {String} cls
33003 * @cfg {String} href
33007 * @cfg {String} video
33011 * @cfg {Boolean} square
33015 getAutoCreate : function()
33017 var cls = 'roo-brick';
33019 if(this.href.length){
33020 cls += ' roo-brick-link';
33023 if(this.bgimage.length){
33024 cls += ' roo-brick-image';
33027 if(!this.html.length && !this.bgimage.length){
33028 cls += ' roo-brick-center-title';
33031 if(!this.html.length && this.bgimage.length){
33032 cls += ' roo-brick-bottom-title';
33036 cls += ' ' + this.cls;
33040 tag: (this.href.length) ? 'a' : 'div',
33045 cls: 'roo-brick-paragraph',
33051 if(this.href.length){
33052 cfg.href = this.href;
33055 var cn = cfg.cn[0].cn;
33057 if(this.title.length){
33060 cls: 'roo-brick-title',
33065 if(this.html.length){
33068 cls: 'roo-brick-text',
33075 if(this.bgimage.length){
33078 cls: 'roo-brick-image-view',
33086 initEvents: function()
33088 if(this.title.length || this.html.length){
33089 this.el.on('mouseenter' ,this.enter, this);
33090 this.el.on('mouseleave', this.leave, this);
33093 Roo.EventManager.onWindowResize(this.resize, this);
33095 if(this.bgimage.length){
33096 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33097 this.imageEl.on('load', this.onImageLoad, this);
33104 onImageLoad : function()
33109 resize : function()
33111 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33113 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33115 if(this.bgimage.length){
33116 var image = this.el.select('.roo-brick-image-view', true).first();
33118 image.setWidth(paragraph.getWidth());
33121 image.setHeight(paragraph.getWidth());
33124 this.el.setHeight(image.getHeight());
33125 paragraph.setHeight(image.getHeight());
33131 enter: function(e, el)
33133 e.preventDefault();
33135 if(this.bgimage.length){
33136 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33137 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33141 leave: function(e, el)
33143 e.preventDefault();
33145 if(this.bgimage.length){
33146 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33147 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33162 * @class Roo.bootstrap.NumberField
33163 * @extends Roo.bootstrap.Input
33164 * Bootstrap NumberField class
33170 * Create a new NumberField
33171 * @param {Object} config The config object
33174 Roo.bootstrap.NumberField = function(config){
33175 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33178 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33181 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33183 allowDecimals : true,
33185 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33187 decimalSeparator : ".",
33189 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33191 decimalPrecision : 2,
33193 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33195 allowNegative : true,
33198 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33202 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33204 minValue : Number.NEGATIVE_INFINITY,
33206 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33208 maxValue : Number.MAX_VALUE,
33210 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33212 minText : "The minimum value for this field is {0}",
33214 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33216 maxText : "The maximum value for this field is {0}",
33218 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33219 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33221 nanText : "{0} is not a valid number",
33223 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33227 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33229 thousandsDelimiter : false,
33231 * @cfg {String} valueAlign alignment of value
33233 valueAlign : "left",
33235 getAutoCreate : function()
33237 var hiddenInput = {
33241 cls: 'hidden-number-input'
33245 hiddenInput.name = this.name;
33250 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33252 this.name = hiddenInput.name;
33254 if(cfg.cn.length > 0) {
33255 cfg.cn.push(hiddenInput);
33262 initEvents : function()
33264 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33266 var allowed = "0123456789";
33268 if(this.allowDecimals){
33269 allowed += this.decimalSeparator;
33272 if(this.allowNegative){
33276 if(this.thousandsDelimiter) {
33280 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33282 var keyPress = function(e){
33284 var k = e.getKey();
33286 var c = e.getCharCode();
33289 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33290 allowed.indexOf(String.fromCharCode(c)) === -1
33296 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33300 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33305 this.el.on("keypress", keyPress, this);
33308 validateValue : function(value)
33311 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33315 var num = this.parseValue(value);
33318 this.markInvalid(String.format(this.nanText, value));
33322 if(num < this.minValue){
33323 this.markInvalid(String.format(this.minText, this.minValue));
33327 if(num > this.maxValue){
33328 this.markInvalid(String.format(this.maxText, this.maxValue));
33335 getValue : function()
33337 var v = this.hiddenEl().getValue();
33339 return this.fixPrecision(this.parseValue(v));
33342 parseValue : function(value)
33344 if(this.thousandsDelimiter) {
33346 r = new RegExp(",", "g");
33347 value = value.replace(r, "");
33350 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33351 return isNaN(value) ? '' : value;
33354 fixPrecision : function(value)
33356 if(this.thousandsDelimiter) {
33358 r = new RegExp(",", "g");
33359 value = value.replace(r, "");
33362 var nan = isNaN(value);
33364 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33365 return nan ? '' : value;
33367 return parseFloat(value).toFixed(this.decimalPrecision);
33370 setValue : function(v)
33372 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33378 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33380 this.inputEl().dom.value = (v == '') ? '' :
33381 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33383 if(!this.allowZero && v === '0') {
33384 this.hiddenEl().dom.value = '';
33385 this.inputEl().dom.value = '';
33392 decimalPrecisionFcn : function(v)
33394 return Math.floor(v);
33397 beforeBlur : function()
33403 var v = this.parseValue(this.getRawValue());
33410 hiddenEl : function()
33412 return this.el.select('input.hidden-number-input',true).first();
33424 * @class Roo.bootstrap.DocumentSlider
33425 * @extends Roo.bootstrap.Component
33426 * Bootstrap DocumentSlider class
33429 * Create a new DocumentViewer
33430 * @param {Object} config The config object
33433 Roo.bootstrap.DocumentSlider = function(config){
33434 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33441 * Fire after initEvent
33442 * @param {Roo.bootstrap.DocumentSlider} this
33447 * Fire after update
33448 * @param {Roo.bootstrap.DocumentSlider} this
33454 * @param {Roo.bootstrap.DocumentSlider} this
33460 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33466 getAutoCreate : function()
33470 cls : 'roo-document-slider',
33474 cls : 'roo-document-slider-header',
33478 cls : 'roo-document-slider-header-title'
33484 cls : 'roo-document-slider-body',
33488 cls : 'roo-document-slider-prev',
33492 cls : 'fa fa-chevron-left'
33498 cls : 'roo-document-slider-thumb',
33502 cls : 'roo-document-slider-image'
33508 cls : 'roo-document-slider-next',
33512 cls : 'fa fa-chevron-right'
33524 initEvents : function()
33526 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33527 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33529 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33530 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33532 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33533 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33535 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33536 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33538 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33539 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33541 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33542 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33544 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33545 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33547 this.thumbEl.on('click', this.onClick, this);
33549 this.prevIndicator.on('click', this.prev, this);
33551 this.nextIndicator.on('click', this.next, this);
33555 initial : function()
33557 if(this.files.length){
33558 this.indicator = 1;
33562 this.fireEvent('initial', this);
33565 update : function()
33567 this.imageEl.attr('src', this.files[this.indicator - 1]);
33569 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33571 this.prevIndicator.show();
33573 if(this.indicator == 1){
33574 this.prevIndicator.hide();
33577 this.nextIndicator.show();
33579 if(this.indicator == this.files.length){
33580 this.nextIndicator.hide();
33583 this.thumbEl.scrollTo('top');
33585 this.fireEvent('update', this);
33588 onClick : function(e)
33590 e.preventDefault();
33592 this.fireEvent('click', this);
33597 e.preventDefault();
33599 this.indicator = Math.max(1, this.indicator - 1);
33606 e.preventDefault();
33608 this.indicator = Math.min(this.files.length, this.indicator + 1);
33622 * @class Roo.bootstrap.RadioSet
33623 * @extends Roo.bootstrap.Input
33624 * Bootstrap RadioSet class
33625 * @cfg {String} indicatorpos (left|right) default left
33626 * @cfg {Boolean} inline (true|false) inline the element (default true)
33627 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33629 * Create a new RadioSet
33630 * @param {Object} config The config object
33633 Roo.bootstrap.RadioSet = function(config){
33635 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33639 Roo.bootstrap.RadioSet.register(this);
33644 * Fires when the element is checked or unchecked.
33645 * @param {Roo.bootstrap.RadioSet} this This radio
33646 * @param {Roo.bootstrap.Radio} item The checked item
33651 * Fires when the element is click.
33652 * @param {Roo.bootstrap.RadioSet} this This radio set
33653 * @param {Roo.bootstrap.Radio} item The checked item
33654 * @param {Roo.EventObject} e The event object
33661 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33669 indicatorpos : 'left',
33671 getAutoCreate : function()
33675 cls : 'roo-radio-set-label',
33679 html : this.fieldLabel
33684 if(this.indicatorpos == 'left'){
33687 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33688 tooltip : 'This field is required'
33693 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33694 tooltip : 'This field is required'
33700 cls : 'roo-radio-set-items'
33703 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33705 if (align === 'left' && this.fieldLabel.length) {
33708 cls : "roo-radio-set-right",
33714 if(this.labelWidth > 12){
33715 label.style = "width: " + this.labelWidth + 'px';
33718 if(this.labelWidth < 13 && this.labelmd == 0){
33719 this.labelmd = this.labelWidth;
33722 if(this.labellg > 0){
33723 label.cls += ' col-lg-' + this.labellg;
33724 items.cls += ' col-lg-' + (12 - this.labellg);
33727 if(this.labelmd > 0){
33728 label.cls += ' col-md-' + this.labelmd;
33729 items.cls += ' col-md-' + (12 - this.labelmd);
33732 if(this.labelsm > 0){
33733 label.cls += ' col-sm-' + this.labelsm;
33734 items.cls += ' col-sm-' + (12 - this.labelsm);
33737 if(this.labelxs > 0){
33738 label.cls += ' col-xs-' + this.labelxs;
33739 items.cls += ' col-xs-' + (12 - this.labelxs);
33745 cls : 'roo-radio-set',
33749 cls : 'roo-radio-set-input',
33752 value : this.value ? this.value : ''
33759 if(this.weight.length){
33760 cfg.cls += ' roo-radio-' + this.weight;
33764 cfg.cls += ' roo-radio-set-inline';
33768 ['xs','sm','md','lg'].map(function(size){
33769 if (settings[size]) {
33770 cfg.cls += ' col-' + size + '-' + settings[size];
33778 initEvents : function()
33780 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33781 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33783 if(!this.fieldLabel.length){
33784 this.labelEl.hide();
33787 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33788 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33790 this.indicator = this.indicatorEl();
33792 if(this.indicator){
33793 this.indicator.addClass('invisible');
33796 this.originalValue = this.getValue();
33800 inputEl: function ()
33802 return this.el.select('.roo-radio-set-input', true).first();
33805 getChildContainer : function()
33807 return this.itemsEl;
33810 register : function(item)
33812 this.radioes.push(item);
33816 validate : function()
33818 if(this.getVisibilityEl().hasClass('hidden')){
33824 Roo.each(this.radioes, function(i){
33833 if(this.allowBlank) {
33837 if(this.disabled || valid){
33842 this.markInvalid();
33847 markValid : function()
33849 if(this.labelEl.isVisible(true)){
33850 this.indicatorEl().removeClass('visible');
33851 this.indicatorEl().addClass('invisible');
33854 this.el.removeClass([this.invalidClass, this.validClass]);
33855 this.el.addClass(this.validClass);
33857 this.fireEvent('valid', this);
33860 markInvalid : function(msg)
33862 if(this.allowBlank || this.disabled){
33866 if(this.labelEl.isVisible(true)){
33867 this.indicatorEl().removeClass('invisible');
33868 this.indicatorEl().addClass('visible');
33871 this.el.removeClass([this.invalidClass, this.validClass]);
33872 this.el.addClass(this.invalidClass);
33874 this.fireEvent('invalid', this, msg);
33878 setValue : function(v, suppressEvent)
33880 if(this.value === v){
33887 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33890 Roo.each(this.radioes, function(i){
33892 i.el.removeClass('checked');
33895 Roo.each(this.radioes, function(i){
33897 if(i.value === v || i.value.toString() === v.toString()){
33899 i.el.addClass('checked');
33901 if(suppressEvent !== true){
33902 this.fireEvent('check', this, i);
33913 clearInvalid : function(){
33915 if(!this.el || this.preventMark){
33919 this.el.removeClass([this.invalidClass]);
33921 this.fireEvent('valid', this);
33926 Roo.apply(Roo.bootstrap.RadioSet, {
33930 register : function(set)
33932 this.groups[set.name] = set;
33935 get: function(name)
33937 if (typeof(this.groups[name]) == 'undefined') {
33941 return this.groups[name] ;
33947 * Ext JS Library 1.1.1
33948 * Copyright(c) 2006-2007, Ext JS, LLC.
33950 * Originally Released Under LGPL - original licence link has changed is not relivant.
33953 * <script type="text/javascript">
33958 * @class Roo.bootstrap.SplitBar
33959 * @extends Roo.util.Observable
33960 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33964 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33965 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33966 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33967 split.minSize = 100;
33968 split.maxSize = 600;
33969 split.animate = true;
33970 split.on('moved', splitterMoved);
33973 * Create a new SplitBar
33974 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33975 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33976 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33977 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33978 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33979 position of the SplitBar).
33981 Roo.bootstrap.SplitBar = function(cfg){
33986 // dragElement : elm
33987 // resizingElement: el,
33989 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33990 // placement : Roo.bootstrap.SplitBar.LEFT ,
33991 // existingProxy ???
33994 this.el = Roo.get(cfg.dragElement, true);
33995 this.el.dom.unselectable = "on";
33997 this.resizingEl = Roo.get(cfg.resizingElement, true);
34001 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34002 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34005 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34008 * The minimum size of the resizing element. (Defaults to 0)
34014 * The maximum size of the resizing element. (Defaults to 2000)
34017 this.maxSize = 2000;
34020 * Whether to animate the transition to the new size
34023 this.animate = false;
34026 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34029 this.useShim = false;
34034 if(!cfg.existingProxy){
34036 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34038 this.proxy = Roo.get(cfg.existingProxy).dom;
34041 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34044 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34047 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34050 this.dragSpecs = {};
34053 * @private The adapter to use to positon and resize elements
34055 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34056 this.adapter.init(this);
34058 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34060 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34061 this.el.addClass("roo-splitbar-h");
34064 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34065 this.el.addClass("roo-splitbar-v");
34071 * Fires when the splitter is moved (alias for {@link #event-moved})
34072 * @param {Roo.bootstrap.SplitBar} this
34073 * @param {Number} newSize the new width or height
34078 * Fires when the splitter is moved
34079 * @param {Roo.bootstrap.SplitBar} this
34080 * @param {Number} newSize the new width or height
34084 * @event beforeresize
34085 * Fires before the splitter is dragged
34086 * @param {Roo.bootstrap.SplitBar} this
34088 "beforeresize" : true,
34090 "beforeapply" : true
34093 Roo.util.Observable.call(this);
34096 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34097 onStartProxyDrag : function(x, y){
34098 this.fireEvent("beforeresize", this);
34100 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34102 o.enableDisplayMode("block");
34103 // all splitbars share the same overlay
34104 Roo.bootstrap.SplitBar.prototype.overlay = o;
34106 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34107 this.overlay.show();
34108 Roo.get(this.proxy).setDisplayed("block");
34109 var size = this.adapter.getElementSize(this);
34110 this.activeMinSize = this.getMinimumSize();;
34111 this.activeMaxSize = this.getMaximumSize();;
34112 var c1 = size - this.activeMinSize;
34113 var c2 = Math.max(this.activeMaxSize - size, 0);
34114 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34115 this.dd.resetConstraints();
34116 this.dd.setXConstraint(
34117 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34118 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34120 this.dd.setYConstraint(0, 0);
34122 this.dd.resetConstraints();
34123 this.dd.setXConstraint(0, 0);
34124 this.dd.setYConstraint(
34125 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34126 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34129 this.dragSpecs.startSize = size;
34130 this.dragSpecs.startPoint = [x, y];
34131 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34135 * @private Called after the drag operation by the DDProxy
34137 onEndProxyDrag : function(e){
34138 Roo.get(this.proxy).setDisplayed(false);
34139 var endPoint = Roo.lib.Event.getXY(e);
34141 this.overlay.hide();
34144 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34145 newSize = this.dragSpecs.startSize +
34146 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34147 endPoint[0] - this.dragSpecs.startPoint[0] :
34148 this.dragSpecs.startPoint[0] - endPoint[0]
34151 newSize = this.dragSpecs.startSize +
34152 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34153 endPoint[1] - this.dragSpecs.startPoint[1] :
34154 this.dragSpecs.startPoint[1] - endPoint[1]
34157 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34158 if(newSize != this.dragSpecs.startSize){
34159 if(this.fireEvent('beforeapply', this, newSize) !== false){
34160 this.adapter.setElementSize(this, newSize);
34161 this.fireEvent("moved", this, newSize);
34162 this.fireEvent("resize", this, newSize);
34168 * Get the adapter this SplitBar uses
34169 * @return The adapter object
34171 getAdapter : function(){
34172 return this.adapter;
34176 * Set the adapter this SplitBar uses
34177 * @param {Object} adapter A SplitBar adapter object
34179 setAdapter : function(adapter){
34180 this.adapter = adapter;
34181 this.adapter.init(this);
34185 * Gets the minimum size for the resizing element
34186 * @return {Number} The minimum size
34188 getMinimumSize : function(){
34189 return this.minSize;
34193 * Sets the minimum size for the resizing element
34194 * @param {Number} minSize The minimum size
34196 setMinimumSize : function(minSize){
34197 this.minSize = minSize;
34201 * Gets the maximum size for the resizing element
34202 * @return {Number} The maximum size
34204 getMaximumSize : function(){
34205 return this.maxSize;
34209 * Sets the maximum size for the resizing element
34210 * @param {Number} maxSize The maximum size
34212 setMaximumSize : function(maxSize){
34213 this.maxSize = maxSize;
34217 * Sets the initialize size for the resizing element
34218 * @param {Number} size The initial size
34220 setCurrentSize : function(size){
34221 var oldAnimate = this.animate;
34222 this.animate = false;
34223 this.adapter.setElementSize(this, size);
34224 this.animate = oldAnimate;
34228 * Destroy this splitbar.
34229 * @param {Boolean} removeEl True to remove the element
34231 destroy : function(removeEl){
34233 this.shim.remove();
34236 this.proxy.parentNode.removeChild(this.proxy);
34244 * @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.
34246 Roo.bootstrap.SplitBar.createProxy = function(dir){
34247 var proxy = new Roo.Element(document.createElement("div"));
34248 proxy.unselectable();
34249 var cls = 'roo-splitbar-proxy';
34250 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34251 document.body.appendChild(proxy.dom);
34256 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34257 * Default Adapter. It assumes the splitter and resizing element are not positioned
34258 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34260 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34263 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34264 // do nothing for now
34265 init : function(s){
34269 * Called before drag operations to get the current size of the resizing element.
34270 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34272 getElementSize : function(s){
34273 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34274 return s.resizingEl.getWidth();
34276 return s.resizingEl.getHeight();
34281 * Called after drag operations to set the size of the resizing element.
34282 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34283 * @param {Number} newSize The new size to set
34284 * @param {Function} onComplete A function to be invoked when resizing is complete
34286 setElementSize : function(s, newSize, onComplete){
34287 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34289 s.resizingEl.setWidth(newSize);
34291 onComplete(s, newSize);
34294 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34299 s.resizingEl.setHeight(newSize);
34301 onComplete(s, newSize);
34304 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34311 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34312 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34313 * Adapter that moves the splitter element to align with the resized sizing element.
34314 * Used with an absolute positioned SplitBar.
34315 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34316 * document.body, make sure you assign an id to the body element.
34318 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34319 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34320 this.container = Roo.get(container);
34323 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34324 init : function(s){
34325 this.basic.init(s);
34328 getElementSize : function(s){
34329 return this.basic.getElementSize(s);
34332 setElementSize : function(s, newSize, onComplete){
34333 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34336 moveSplitter : function(s){
34337 var yes = Roo.bootstrap.SplitBar;
34338 switch(s.placement){
34340 s.el.setX(s.resizingEl.getRight());
34343 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34346 s.el.setY(s.resizingEl.getBottom());
34349 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34356 * Orientation constant - Create a vertical SplitBar
34360 Roo.bootstrap.SplitBar.VERTICAL = 1;
34363 * Orientation constant - Create a horizontal SplitBar
34367 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34370 * Placement constant - The resizing element is to the left of the splitter element
34374 Roo.bootstrap.SplitBar.LEFT = 1;
34377 * Placement constant - The resizing element is to the right of the splitter element
34381 Roo.bootstrap.SplitBar.RIGHT = 2;
34384 * Placement constant - The resizing element is positioned above the splitter element
34388 Roo.bootstrap.SplitBar.TOP = 3;
34391 * Placement constant - The resizing element is positioned under splitter element
34395 Roo.bootstrap.SplitBar.BOTTOM = 4;
34396 Roo.namespace("Roo.bootstrap.layout");/*
34398 * Ext JS Library 1.1.1
34399 * Copyright(c) 2006-2007, Ext JS, LLC.
34401 * Originally Released Under LGPL - original licence link has changed is not relivant.
34404 * <script type="text/javascript">
34408 * @class Roo.bootstrap.layout.Manager
34409 * @extends Roo.bootstrap.Component
34410 * Base class for layout managers.
34412 Roo.bootstrap.layout.Manager = function(config)
34414 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34420 /** false to disable window resize monitoring @type Boolean */
34421 this.monitorWindowResize = true;
34426 * Fires when a layout is performed.
34427 * @param {Roo.LayoutManager} this
34431 * @event regionresized
34432 * Fires when the user resizes a region.
34433 * @param {Roo.LayoutRegion} region The resized region
34434 * @param {Number} newSize The new size (width for east/west, height for north/south)
34436 "regionresized" : true,
34438 * @event regioncollapsed
34439 * Fires when a region is collapsed.
34440 * @param {Roo.LayoutRegion} region The collapsed region
34442 "regioncollapsed" : true,
34444 * @event regionexpanded
34445 * Fires when a region is expanded.
34446 * @param {Roo.LayoutRegion} region The expanded region
34448 "regionexpanded" : true
34450 this.updating = false;
34453 this.el = Roo.get(config.el);
34459 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34464 monitorWindowResize : true,
34470 onRender : function(ct, position)
34473 this.el = Roo.get(ct);
34476 //this.fireEvent('render',this);
34480 initEvents: function()
34484 // ie scrollbar fix
34485 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34486 document.body.scroll = "no";
34487 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34488 this.el.position('relative');
34490 this.id = this.el.id;
34491 this.el.addClass("roo-layout-container");
34492 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34493 if(this.el.dom != document.body ) {
34494 this.el.on('resize', this.layout,this);
34495 this.el.on('show', this.layout,this);
34501 * Returns true if this layout is currently being updated
34502 * @return {Boolean}
34504 isUpdating : function(){
34505 return this.updating;
34509 * Suspend the LayoutManager from doing auto-layouts while
34510 * making multiple add or remove calls
34512 beginUpdate : function(){
34513 this.updating = true;
34517 * Restore auto-layouts and optionally disable the manager from performing a layout
34518 * @param {Boolean} noLayout true to disable a layout update
34520 endUpdate : function(noLayout){
34521 this.updating = false;
34527 layout: function(){
34531 onRegionResized : function(region, newSize){
34532 this.fireEvent("regionresized", region, newSize);
34536 onRegionCollapsed : function(region){
34537 this.fireEvent("regioncollapsed", region);
34540 onRegionExpanded : function(region){
34541 this.fireEvent("regionexpanded", region);
34545 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34546 * performs box-model adjustments.
34547 * @return {Object} The size as an object {width: (the width), height: (the height)}
34549 getViewSize : function()
34552 if(this.el.dom != document.body){
34553 size = this.el.getSize();
34555 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34557 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34558 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34563 * Returns the Element this layout is bound to.
34564 * @return {Roo.Element}
34566 getEl : function(){
34571 * Returns the specified region.
34572 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34573 * @return {Roo.LayoutRegion}
34575 getRegion : function(target){
34576 return this.regions[target.toLowerCase()];
34579 onWindowResize : function(){
34580 if(this.monitorWindowResize){
34587 * Ext JS Library 1.1.1
34588 * Copyright(c) 2006-2007, Ext JS, LLC.
34590 * Originally Released Under LGPL - original licence link has changed is not relivant.
34593 * <script type="text/javascript">
34596 * @class Roo.bootstrap.layout.Border
34597 * @extends Roo.bootstrap.layout.Manager
34598 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34599 * please see: examples/bootstrap/nested.html<br><br>
34601 <b>The container the layout is rendered into can be either the body element or any other element.
34602 If it is not the body element, the container needs to either be an absolute positioned element,
34603 or you will need to add "position:relative" to the css of the container. You will also need to specify
34604 the container size if it is not the body element.</b>
34607 * Create a new Border
34608 * @param {Object} config Configuration options
34610 Roo.bootstrap.layout.Border = function(config){
34611 config = config || {};
34612 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34616 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34617 if(config[region]){
34618 config[region].region = region;
34619 this.addRegion(config[region]);
34625 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34627 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34629 * Creates and adds a new region if it doesn't already exist.
34630 * @param {String} target The target region key (north, south, east, west or center).
34631 * @param {Object} config The regions config object
34632 * @return {BorderLayoutRegion} The new region
34634 addRegion : function(config)
34636 if(!this.regions[config.region]){
34637 var r = this.factory(config);
34638 this.bindRegion(r);
34640 return this.regions[config.region];
34644 bindRegion : function(r){
34645 this.regions[r.config.region] = r;
34647 r.on("visibilitychange", this.layout, this);
34648 r.on("paneladded", this.layout, this);
34649 r.on("panelremoved", this.layout, this);
34650 r.on("invalidated", this.layout, this);
34651 r.on("resized", this.onRegionResized, this);
34652 r.on("collapsed", this.onRegionCollapsed, this);
34653 r.on("expanded", this.onRegionExpanded, this);
34657 * Performs a layout update.
34659 layout : function()
34661 if(this.updating) {
34665 // render all the rebions if they have not been done alreayd?
34666 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34667 if(this.regions[region] && !this.regions[region].bodyEl){
34668 this.regions[region].onRender(this.el)
34672 var size = this.getViewSize();
34673 var w = size.width;
34674 var h = size.height;
34679 //var x = 0, y = 0;
34681 var rs = this.regions;
34682 var north = rs["north"];
34683 var south = rs["south"];
34684 var west = rs["west"];
34685 var east = rs["east"];
34686 var center = rs["center"];
34687 //if(this.hideOnLayout){ // not supported anymore
34688 //c.el.setStyle("display", "none");
34690 if(north && north.isVisible()){
34691 var b = north.getBox();
34692 var m = north.getMargins();
34693 b.width = w - (m.left+m.right);
34696 centerY = b.height + b.y + m.bottom;
34697 centerH -= centerY;
34698 north.updateBox(this.safeBox(b));
34700 if(south && south.isVisible()){
34701 var b = south.getBox();
34702 var m = south.getMargins();
34703 b.width = w - (m.left+m.right);
34705 var totalHeight = (b.height + m.top + m.bottom);
34706 b.y = h - totalHeight + m.top;
34707 centerH -= totalHeight;
34708 south.updateBox(this.safeBox(b));
34710 if(west && west.isVisible()){
34711 var b = west.getBox();
34712 var m = west.getMargins();
34713 b.height = centerH - (m.top+m.bottom);
34715 b.y = centerY + m.top;
34716 var totalWidth = (b.width + m.left + m.right);
34717 centerX += totalWidth;
34718 centerW -= totalWidth;
34719 west.updateBox(this.safeBox(b));
34721 if(east && east.isVisible()){
34722 var b = east.getBox();
34723 var m = east.getMargins();
34724 b.height = centerH - (m.top+m.bottom);
34725 var totalWidth = (b.width + m.left + m.right);
34726 b.x = w - totalWidth + m.left;
34727 b.y = centerY + m.top;
34728 centerW -= totalWidth;
34729 east.updateBox(this.safeBox(b));
34732 var m = center.getMargins();
34734 x: centerX + m.left,
34735 y: centerY + m.top,
34736 width: centerW - (m.left+m.right),
34737 height: centerH - (m.top+m.bottom)
34739 //if(this.hideOnLayout){
34740 //center.el.setStyle("display", "block");
34742 center.updateBox(this.safeBox(centerBox));
34745 this.fireEvent("layout", this);
34749 safeBox : function(box){
34750 box.width = Math.max(0, box.width);
34751 box.height = Math.max(0, box.height);
34756 * Adds a ContentPanel (or subclass) to this layout.
34757 * @param {String} target The target region key (north, south, east, west or center).
34758 * @param {Roo.ContentPanel} panel The panel to add
34759 * @return {Roo.ContentPanel} The added panel
34761 add : function(target, panel){
34763 target = target.toLowerCase();
34764 return this.regions[target].add(panel);
34768 * Remove a ContentPanel (or subclass) to this layout.
34769 * @param {String} target The target region key (north, south, east, west or center).
34770 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34771 * @return {Roo.ContentPanel} The removed panel
34773 remove : function(target, panel){
34774 target = target.toLowerCase();
34775 return this.regions[target].remove(panel);
34779 * Searches all regions for a panel with the specified id
34780 * @param {String} panelId
34781 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34783 findPanel : function(panelId){
34784 var rs = this.regions;
34785 for(var target in rs){
34786 if(typeof rs[target] != "function"){
34787 var p = rs[target].getPanel(panelId);
34797 * Searches all regions for a panel with the specified id and activates (shows) it.
34798 * @param {String/ContentPanel} panelId The panels id or the panel itself
34799 * @return {Roo.ContentPanel} The shown panel or null
34801 showPanel : function(panelId) {
34802 var rs = this.regions;
34803 for(var target in rs){
34804 var r = rs[target];
34805 if(typeof r != "function"){
34806 if(r.hasPanel(panelId)){
34807 return r.showPanel(panelId);
34815 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34816 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34819 restoreState : function(provider){
34821 provider = Roo.state.Manager;
34823 var sm = new Roo.LayoutStateManager();
34824 sm.init(this, provider);
34830 * Adds a xtype elements to the layout.
34834 xtype : 'ContentPanel',
34841 xtype : 'NestedLayoutPanel',
34847 items : [ ... list of content panels or nested layout panels.. ]
34851 * @param {Object} cfg Xtype definition of item to add.
34853 addxtype : function(cfg)
34855 // basically accepts a pannel...
34856 // can accept a layout region..!?!?
34857 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34860 // theory? children can only be panels??
34862 //if (!cfg.xtype.match(/Panel$/)) {
34867 if (typeof(cfg.region) == 'undefined') {
34868 Roo.log("Failed to add Panel, region was not set");
34872 var region = cfg.region;
34878 xitems = cfg.items;
34885 case 'Content': // ContentPanel (el, cfg)
34886 case 'Scroll': // ContentPanel (el, cfg)
34888 cfg.autoCreate = true;
34889 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34891 // var el = this.el.createChild();
34892 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34895 this.add(region, ret);
34899 case 'TreePanel': // our new panel!
34900 cfg.el = this.el.createChild();
34901 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34902 this.add(region, ret);
34907 // create a new Layout (which is a Border Layout...
34909 var clayout = cfg.layout;
34910 clayout.el = this.el.createChild();
34911 clayout.items = clayout.items || [];
34915 // replace this exitems with the clayout ones..
34916 xitems = clayout.items;
34918 // force background off if it's in center...
34919 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34920 cfg.background = false;
34922 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34925 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34926 //console.log('adding nested layout panel ' + cfg.toSource());
34927 this.add(region, ret);
34928 nb = {}; /// find first...
34933 // needs grid and region
34935 //var el = this.getRegion(region).el.createChild();
34937 *var el = this.el.createChild();
34938 // create the grid first...
34939 cfg.grid.container = el;
34940 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34943 if (region == 'center' && this.active ) {
34944 cfg.background = false;
34947 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34949 this.add(region, ret);
34951 if (cfg.background) {
34952 // render grid on panel activation (if panel background)
34953 ret.on('activate', function(gp) {
34954 if (!gp.grid.rendered) {
34955 // gp.grid.render(el);
34959 // cfg.grid.render(el);
34965 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34966 // it was the old xcomponent building that caused this before.
34967 // espeically if border is the top element in the tree.
34977 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34979 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34980 this.add(region, ret);
34984 throw "Can not add '" + cfg.xtype + "' to Border";
34990 this.beginUpdate();
34994 Roo.each(xitems, function(i) {
34995 region = nb && i.region ? i.region : false;
34997 var add = ret.addxtype(i);
35000 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35001 if (!i.background) {
35002 abn[region] = nb[region] ;
35009 // make the last non-background panel active..
35010 //if (nb) { Roo.log(abn); }
35013 for(var r in abn) {
35014 region = this.getRegion(r);
35016 // tried using nb[r], but it does not work..
35018 region.showPanel(abn[r]);
35029 factory : function(cfg)
35032 var validRegions = Roo.bootstrap.layout.Border.regions;
35034 var target = cfg.region;
35037 var r = Roo.bootstrap.layout;
35041 return new r.North(cfg);
35043 return new r.South(cfg);
35045 return new r.East(cfg);
35047 return new r.West(cfg);
35049 return new r.Center(cfg);
35051 throw 'Layout region "'+target+'" not supported.';
35058 * Ext JS Library 1.1.1
35059 * Copyright(c) 2006-2007, Ext JS, LLC.
35061 * Originally Released Under LGPL - original licence link has changed is not relivant.
35064 * <script type="text/javascript">
35068 * @class Roo.bootstrap.layout.Basic
35069 * @extends Roo.util.Observable
35070 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35071 * and does not have a titlebar, tabs or any other features. All it does is size and position
35072 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35073 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35074 * @cfg {string} region the region that it inhabits..
35075 * @cfg {bool} skipConfig skip config?
35079 Roo.bootstrap.layout.Basic = function(config){
35081 this.mgr = config.mgr;
35083 this.position = config.region;
35085 var skipConfig = config.skipConfig;
35089 * @scope Roo.BasicLayoutRegion
35093 * @event beforeremove
35094 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35095 * @param {Roo.LayoutRegion} this
35096 * @param {Roo.ContentPanel} panel The panel
35097 * @param {Object} e The cancel event object
35099 "beforeremove" : true,
35101 * @event invalidated
35102 * Fires when the layout for this region is changed.
35103 * @param {Roo.LayoutRegion} this
35105 "invalidated" : true,
35107 * @event visibilitychange
35108 * Fires when this region is shown or hidden
35109 * @param {Roo.LayoutRegion} this
35110 * @param {Boolean} visibility true or false
35112 "visibilitychange" : true,
35114 * @event paneladded
35115 * Fires when a panel is added.
35116 * @param {Roo.LayoutRegion} this
35117 * @param {Roo.ContentPanel} panel The panel
35119 "paneladded" : true,
35121 * @event panelremoved
35122 * Fires when a panel is removed.
35123 * @param {Roo.LayoutRegion} this
35124 * @param {Roo.ContentPanel} panel The panel
35126 "panelremoved" : true,
35128 * @event beforecollapse
35129 * Fires when this region before collapse.
35130 * @param {Roo.LayoutRegion} this
35132 "beforecollapse" : true,
35135 * Fires when this region is collapsed.
35136 * @param {Roo.LayoutRegion} this
35138 "collapsed" : true,
35141 * Fires when this region is expanded.
35142 * @param {Roo.LayoutRegion} this
35147 * Fires when this region is slid into view.
35148 * @param {Roo.LayoutRegion} this
35150 "slideshow" : true,
35153 * Fires when this region slides out of view.
35154 * @param {Roo.LayoutRegion} this
35156 "slidehide" : true,
35158 * @event panelactivated
35159 * Fires when a panel is activated.
35160 * @param {Roo.LayoutRegion} this
35161 * @param {Roo.ContentPanel} panel The activated panel
35163 "panelactivated" : true,
35166 * Fires when the user resizes this region.
35167 * @param {Roo.LayoutRegion} this
35168 * @param {Number} newSize The new size (width for east/west, height for north/south)
35172 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35173 this.panels = new Roo.util.MixedCollection();
35174 this.panels.getKey = this.getPanelId.createDelegate(this);
35176 this.activePanel = null;
35177 // ensure listeners are added...
35179 if (config.listeners || config.events) {
35180 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35181 listeners : config.listeners || {},
35182 events : config.events || {}
35186 if(skipConfig !== true){
35187 this.applyConfig(config);
35191 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35193 getPanelId : function(p){
35197 applyConfig : function(config){
35198 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35199 this.config = config;
35204 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35205 * the width, for horizontal (north, south) the height.
35206 * @param {Number} newSize The new width or height
35208 resizeTo : function(newSize){
35209 var el = this.el ? this.el :
35210 (this.activePanel ? this.activePanel.getEl() : null);
35212 switch(this.position){
35215 el.setWidth(newSize);
35216 this.fireEvent("resized", this, newSize);
35220 el.setHeight(newSize);
35221 this.fireEvent("resized", this, newSize);
35227 getBox : function(){
35228 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35231 getMargins : function(){
35232 return this.margins;
35235 updateBox : function(box){
35237 var el = this.activePanel.getEl();
35238 el.dom.style.left = box.x + "px";
35239 el.dom.style.top = box.y + "px";
35240 this.activePanel.setSize(box.width, box.height);
35244 * Returns the container element for this region.
35245 * @return {Roo.Element}
35247 getEl : function(){
35248 return this.activePanel;
35252 * Returns true if this region is currently visible.
35253 * @return {Boolean}
35255 isVisible : function(){
35256 return this.activePanel ? true : false;
35259 setActivePanel : function(panel){
35260 panel = this.getPanel(panel);
35261 if(this.activePanel && this.activePanel != panel){
35262 this.activePanel.setActiveState(false);
35263 this.activePanel.getEl().setLeftTop(-10000,-10000);
35265 this.activePanel = panel;
35266 panel.setActiveState(true);
35268 panel.setSize(this.box.width, this.box.height);
35270 this.fireEvent("panelactivated", this, panel);
35271 this.fireEvent("invalidated");
35275 * Show the specified panel.
35276 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35277 * @return {Roo.ContentPanel} The shown panel or null
35279 showPanel : function(panel){
35280 panel = this.getPanel(panel);
35282 this.setActivePanel(panel);
35288 * Get the active panel for this region.
35289 * @return {Roo.ContentPanel} The active panel or null
35291 getActivePanel : function(){
35292 return this.activePanel;
35296 * Add the passed ContentPanel(s)
35297 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35298 * @return {Roo.ContentPanel} The panel added (if only one was added)
35300 add : function(panel){
35301 if(arguments.length > 1){
35302 for(var i = 0, len = arguments.length; i < len; i++) {
35303 this.add(arguments[i]);
35307 if(this.hasPanel(panel)){
35308 this.showPanel(panel);
35311 var el = panel.getEl();
35312 if(el.dom.parentNode != this.mgr.el.dom){
35313 this.mgr.el.dom.appendChild(el.dom);
35315 if(panel.setRegion){
35316 panel.setRegion(this);
35318 this.panels.add(panel);
35319 el.setStyle("position", "absolute");
35320 if(!panel.background){
35321 this.setActivePanel(panel);
35322 if(this.config.initialSize && this.panels.getCount()==1){
35323 this.resizeTo(this.config.initialSize);
35326 this.fireEvent("paneladded", this, panel);
35331 * Returns true if the panel is in this region.
35332 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35333 * @return {Boolean}
35335 hasPanel : function(panel){
35336 if(typeof panel == "object"){ // must be panel obj
35337 panel = panel.getId();
35339 return this.getPanel(panel) ? true : false;
35343 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35344 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35345 * @param {Boolean} preservePanel Overrides the config preservePanel option
35346 * @return {Roo.ContentPanel} The panel that was removed
35348 remove : function(panel, preservePanel){
35349 panel = this.getPanel(panel);
35354 this.fireEvent("beforeremove", this, panel, e);
35355 if(e.cancel === true){
35358 var panelId = panel.getId();
35359 this.panels.removeKey(panelId);
35364 * Returns the panel specified or null if it's not in this region.
35365 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35366 * @return {Roo.ContentPanel}
35368 getPanel : function(id){
35369 if(typeof id == "object"){ // must be panel obj
35372 return this.panels.get(id);
35376 * Returns this regions position (north/south/east/west/center).
35379 getPosition: function(){
35380 return this.position;
35384 * Ext JS Library 1.1.1
35385 * Copyright(c) 2006-2007, Ext JS, LLC.
35387 * Originally Released Under LGPL - original licence link has changed is not relivant.
35390 * <script type="text/javascript">
35394 * @class Roo.bootstrap.layout.Region
35395 * @extends Roo.bootstrap.layout.Basic
35396 * This class represents a region in a layout manager.
35398 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35399 * @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})
35400 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35401 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35402 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35403 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35404 * @cfg {String} title The title for the region (overrides panel titles)
35405 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35406 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35407 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35408 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35409 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35410 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35411 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35412 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35413 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35414 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35416 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35417 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35418 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35419 * @cfg {Number} width For East/West panels
35420 * @cfg {Number} height For North/South panels
35421 * @cfg {Boolean} split To show the splitter
35422 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35424 * @cfg {string} cls Extra CSS classes to add to region
35426 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35427 * @cfg {string} region the region that it inhabits..
35430 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35431 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35433 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35434 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35435 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35437 Roo.bootstrap.layout.Region = function(config)
35439 this.applyConfig(config);
35441 var mgr = config.mgr;
35442 var pos = config.region;
35443 config.skipConfig = true;
35444 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35447 this.onRender(mgr.el);
35450 this.visible = true;
35451 this.collapsed = false;
35452 this.unrendered_panels = [];
35455 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35457 position: '', // set by wrapper (eg. north/south etc..)
35458 unrendered_panels : null, // unrendered panels.
35459 createBody : function(){
35460 /** This region's body element
35461 * @type Roo.Element */
35462 this.bodyEl = this.el.createChild({
35464 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35468 onRender: function(ctr, pos)
35470 var dh = Roo.DomHelper;
35471 /** This region's container element
35472 * @type Roo.Element */
35473 this.el = dh.append(ctr.dom, {
35475 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35477 /** This region's title element
35478 * @type Roo.Element */
35480 this.titleEl = dh.append(this.el.dom,
35483 unselectable: "on",
35484 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35486 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35487 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35490 this.titleEl.enableDisplayMode();
35491 /** This region's title text element
35492 * @type HTMLElement */
35493 this.titleTextEl = this.titleEl.dom.firstChild;
35494 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35496 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35497 this.closeBtn.enableDisplayMode();
35498 this.closeBtn.on("click", this.closeClicked, this);
35499 this.closeBtn.hide();
35501 this.createBody(this.config);
35502 if(this.config.hideWhenEmpty){
35504 this.on("paneladded", this.validateVisibility, this);
35505 this.on("panelremoved", this.validateVisibility, this);
35507 if(this.autoScroll){
35508 this.bodyEl.setStyle("overflow", "auto");
35510 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35512 //if(c.titlebar !== false){
35513 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35514 this.titleEl.hide();
35516 this.titleEl.show();
35517 if(this.config.title){
35518 this.titleTextEl.innerHTML = this.config.title;
35522 if(this.config.collapsed){
35523 this.collapse(true);
35525 if(this.config.hidden){
35529 if (this.unrendered_panels && this.unrendered_panels.length) {
35530 for (var i =0;i< this.unrendered_panels.length; i++) {
35531 this.add(this.unrendered_panels[i]);
35533 this.unrendered_panels = null;
35539 applyConfig : function(c)
35542 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35543 var dh = Roo.DomHelper;
35544 if(c.titlebar !== false){
35545 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35546 this.collapseBtn.on("click", this.collapse, this);
35547 this.collapseBtn.enableDisplayMode();
35549 if(c.showPin === true || this.showPin){
35550 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35551 this.stickBtn.enableDisplayMode();
35552 this.stickBtn.on("click", this.expand, this);
35553 this.stickBtn.hide();
35558 /** This region's collapsed element
35559 * @type Roo.Element */
35562 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35563 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35566 if(c.floatable !== false){
35567 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35568 this.collapsedEl.on("click", this.collapseClick, this);
35571 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35572 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35573 id: "message", unselectable: "on", style:{"float":"left"}});
35574 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35576 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35577 this.expandBtn.on("click", this.expand, this);
35581 if(this.collapseBtn){
35582 this.collapseBtn.setVisible(c.collapsible == true);
35585 this.cmargins = c.cmargins || this.cmargins ||
35586 (this.position == "west" || this.position == "east" ?
35587 {top: 0, left: 2, right:2, bottom: 0} :
35588 {top: 2, left: 0, right:0, bottom: 2});
35590 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35593 this.bottomTabs = c.tabPosition != "top";
35595 this.autoScroll = c.autoScroll || false;
35600 this.duration = c.duration || .30;
35601 this.slideDuration = c.slideDuration || .45;
35606 * Returns true if this region is currently visible.
35607 * @return {Boolean}
35609 isVisible : function(){
35610 return this.visible;
35614 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35615 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35617 //setCollapsedTitle : function(title){
35618 // title = title || " ";
35619 // if(this.collapsedTitleTextEl){
35620 // this.collapsedTitleTextEl.innerHTML = title;
35624 getBox : function(){
35626 // if(!this.collapsed){
35627 b = this.el.getBox(false, true);
35629 // b = this.collapsedEl.getBox(false, true);
35634 getMargins : function(){
35635 return this.margins;
35636 //return this.collapsed ? this.cmargins : this.margins;
35639 highlight : function(){
35640 this.el.addClass("x-layout-panel-dragover");
35643 unhighlight : function(){
35644 this.el.removeClass("x-layout-panel-dragover");
35647 updateBox : function(box)
35649 if (!this.bodyEl) {
35650 return; // not rendered yet..
35654 if(!this.collapsed){
35655 this.el.dom.style.left = box.x + "px";
35656 this.el.dom.style.top = box.y + "px";
35657 this.updateBody(box.width, box.height);
35659 this.collapsedEl.dom.style.left = box.x + "px";
35660 this.collapsedEl.dom.style.top = box.y + "px";
35661 this.collapsedEl.setSize(box.width, box.height);
35664 this.tabs.autoSizeTabs();
35668 updateBody : function(w, h)
35671 this.el.setWidth(w);
35672 w -= this.el.getBorderWidth("rl");
35673 if(this.config.adjustments){
35674 w += this.config.adjustments[0];
35677 if(h !== null && h > 0){
35678 this.el.setHeight(h);
35679 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35680 h -= this.el.getBorderWidth("tb");
35681 if(this.config.adjustments){
35682 h += this.config.adjustments[1];
35684 this.bodyEl.setHeight(h);
35686 h = this.tabs.syncHeight(h);
35689 if(this.panelSize){
35690 w = w !== null ? w : this.panelSize.width;
35691 h = h !== null ? h : this.panelSize.height;
35693 if(this.activePanel){
35694 var el = this.activePanel.getEl();
35695 w = w !== null ? w : el.getWidth();
35696 h = h !== null ? h : el.getHeight();
35697 this.panelSize = {width: w, height: h};
35698 this.activePanel.setSize(w, h);
35700 if(Roo.isIE && this.tabs){
35701 this.tabs.el.repaint();
35706 * Returns the container element for this region.
35707 * @return {Roo.Element}
35709 getEl : function(){
35714 * Hides this region.
35717 //if(!this.collapsed){
35718 this.el.dom.style.left = "-2000px";
35721 // this.collapsedEl.dom.style.left = "-2000px";
35722 // this.collapsedEl.hide();
35724 this.visible = false;
35725 this.fireEvent("visibilitychange", this, false);
35729 * Shows this region if it was previously hidden.
35732 //if(!this.collapsed){
35735 // this.collapsedEl.show();
35737 this.visible = true;
35738 this.fireEvent("visibilitychange", this, true);
35741 closeClicked : function(){
35742 if(this.activePanel){
35743 this.remove(this.activePanel);
35747 collapseClick : function(e){
35749 e.stopPropagation();
35752 e.stopPropagation();
35758 * Collapses this region.
35759 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35762 collapse : function(skipAnim, skipCheck = false){
35763 if(this.collapsed) {
35767 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35769 this.collapsed = true;
35771 this.split.el.hide();
35773 if(this.config.animate && skipAnim !== true){
35774 this.fireEvent("invalidated", this);
35775 this.animateCollapse();
35777 this.el.setLocation(-20000,-20000);
35779 this.collapsedEl.show();
35780 this.fireEvent("collapsed", this);
35781 this.fireEvent("invalidated", this);
35787 animateCollapse : function(){
35792 * Expands this region if it was previously collapsed.
35793 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35794 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35797 expand : function(e, skipAnim){
35799 e.stopPropagation();
35801 if(!this.collapsed || this.el.hasActiveFx()) {
35805 this.afterSlideIn();
35808 this.collapsed = false;
35809 if(this.config.animate && skipAnim !== true){
35810 this.animateExpand();
35814 this.split.el.show();
35816 this.collapsedEl.setLocation(-2000,-2000);
35817 this.collapsedEl.hide();
35818 this.fireEvent("invalidated", this);
35819 this.fireEvent("expanded", this);
35823 animateExpand : function(){
35827 initTabs : function()
35829 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35831 var ts = new Roo.bootstrap.panel.Tabs({
35832 el: this.bodyEl.dom,
35833 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35834 disableTooltips: this.config.disableTabTips,
35835 toolbar : this.config.toolbar
35838 if(this.config.hideTabs){
35839 ts.stripWrap.setDisplayed(false);
35842 ts.resizeTabs = this.config.resizeTabs === true;
35843 ts.minTabWidth = this.config.minTabWidth || 40;
35844 ts.maxTabWidth = this.config.maxTabWidth || 250;
35845 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35846 ts.monitorResize = false;
35847 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35848 ts.bodyEl.addClass('roo-layout-tabs-body');
35849 this.panels.each(this.initPanelAsTab, this);
35852 initPanelAsTab : function(panel){
35853 var ti = this.tabs.addTab(
35857 this.config.closeOnTab && panel.isClosable(),
35860 if(panel.tabTip !== undefined){
35861 ti.setTooltip(panel.tabTip);
35863 ti.on("activate", function(){
35864 this.setActivePanel(panel);
35867 if(this.config.closeOnTab){
35868 ti.on("beforeclose", function(t, e){
35870 this.remove(panel);
35874 panel.tabItem = ti;
35879 updatePanelTitle : function(panel, title)
35881 if(this.activePanel == panel){
35882 this.updateTitle(title);
35885 var ti = this.tabs.getTab(panel.getEl().id);
35887 if(panel.tabTip !== undefined){
35888 ti.setTooltip(panel.tabTip);
35893 updateTitle : function(title){
35894 if(this.titleTextEl && !this.config.title){
35895 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35899 setActivePanel : function(panel)
35901 panel = this.getPanel(panel);
35902 if(this.activePanel && this.activePanel != panel){
35903 if(this.activePanel.setActiveState(false) === false){
35907 this.activePanel = panel;
35908 panel.setActiveState(true);
35909 if(this.panelSize){
35910 panel.setSize(this.panelSize.width, this.panelSize.height);
35913 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35915 this.updateTitle(panel.getTitle());
35917 this.fireEvent("invalidated", this);
35919 this.fireEvent("panelactivated", this, panel);
35923 * Shows the specified panel.
35924 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35925 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35927 showPanel : function(panel)
35929 panel = this.getPanel(panel);
35932 var tab = this.tabs.getTab(panel.getEl().id);
35933 if(tab.isHidden()){
35934 this.tabs.unhideTab(tab.id);
35938 this.setActivePanel(panel);
35945 * Get the active panel for this region.
35946 * @return {Roo.ContentPanel} The active panel or null
35948 getActivePanel : function(){
35949 return this.activePanel;
35952 validateVisibility : function(){
35953 if(this.panels.getCount() < 1){
35954 this.updateTitle(" ");
35955 this.closeBtn.hide();
35958 if(!this.isVisible()){
35965 * Adds the passed ContentPanel(s) to this region.
35966 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35967 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35969 add : function(panel)
35971 if(arguments.length > 1){
35972 for(var i = 0, len = arguments.length; i < len; i++) {
35973 this.add(arguments[i]);
35978 // if we have not been rendered yet, then we can not really do much of this..
35979 if (!this.bodyEl) {
35980 this.unrendered_panels.push(panel);
35987 if(this.hasPanel(panel)){
35988 this.showPanel(panel);
35991 panel.setRegion(this);
35992 this.panels.add(panel);
35993 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35994 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35995 // and hide them... ???
35996 this.bodyEl.dom.appendChild(panel.getEl().dom);
35997 if(panel.background !== true){
35998 this.setActivePanel(panel);
36000 this.fireEvent("paneladded", this, panel);
36007 this.initPanelAsTab(panel);
36011 if(panel.background !== true){
36012 this.tabs.activate(panel.getEl().id);
36014 this.fireEvent("paneladded", this, panel);
36019 * Hides the tab for the specified panel.
36020 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36022 hidePanel : function(panel){
36023 if(this.tabs && (panel = this.getPanel(panel))){
36024 this.tabs.hideTab(panel.getEl().id);
36029 * Unhides the tab for a previously hidden panel.
36030 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36032 unhidePanel : function(panel){
36033 if(this.tabs && (panel = this.getPanel(panel))){
36034 this.tabs.unhideTab(panel.getEl().id);
36038 clearPanels : function(){
36039 while(this.panels.getCount() > 0){
36040 this.remove(this.panels.first());
36045 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36046 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36047 * @param {Boolean} preservePanel Overrides the config preservePanel option
36048 * @return {Roo.ContentPanel} The panel that was removed
36050 remove : function(panel, preservePanel)
36052 panel = this.getPanel(panel);
36057 this.fireEvent("beforeremove", this, panel, e);
36058 if(e.cancel === true){
36061 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36062 var panelId = panel.getId();
36063 this.panels.removeKey(panelId);
36065 document.body.appendChild(panel.getEl().dom);
36068 this.tabs.removeTab(panel.getEl().id);
36069 }else if (!preservePanel){
36070 this.bodyEl.dom.removeChild(panel.getEl().dom);
36072 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36073 var p = this.panels.first();
36074 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36075 tempEl.appendChild(p.getEl().dom);
36076 this.bodyEl.update("");
36077 this.bodyEl.dom.appendChild(p.getEl().dom);
36079 this.updateTitle(p.getTitle());
36081 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36082 this.setActivePanel(p);
36084 panel.setRegion(null);
36085 if(this.activePanel == panel){
36086 this.activePanel = null;
36088 if(this.config.autoDestroy !== false && preservePanel !== true){
36089 try{panel.destroy();}catch(e){}
36091 this.fireEvent("panelremoved", this, panel);
36096 * Returns the TabPanel component used by this region
36097 * @return {Roo.TabPanel}
36099 getTabs : function(){
36103 createTool : function(parentEl, className){
36104 var btn = Roo.DomHelper.append(parentEl, {
36106 cls: "x-layout-tools-button",
36109 cls: "roo-layout-tools-button-inner " + className,
36113 btn.addClassOnOver("roo-layout-tools-button-over");
36118 * Ext JS Library 1.1.1
36119 * Copyright(c) 2006-2007, Ext JS, LLC.
36121 * Originally Released Under LGPL - original licence link has changed is not relivant.
36124 * <script type="text/javascript">
36130 * @class Roo.SplitLayoutRegion
36131 * @extends Roo.LayoutRegion
36132 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36134 Roo.bootstrap.layout.Split = function(config){
36135 this.cursor = config.cursor;
36136 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36139 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36141 splitTip : "Drag to resize.",
36142 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36143 useSplitTips : false,
36145 applyConfig : function(config){
36146 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36149 onRender : function(ctr,pos) {
36151 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36152 if(!this.config.split){
36157 var splitEl = Roo.DomHelper.append(ctr.dom, {
36159 id: this.el.id + "-split",
36160 cls: "roo-layout-split roo-layout-split-"+this.position,
36163 /** The SplitBar for this region
36164 * @type Roo.SplitBar */
36165 // does not exist yet...
36166 Roo.log([this.position, this.orientation]);
36168 this.split = new Roo.bootstrap.SplitBar({
36169 dragElement : splitEl,
36170 resizingElement: this.el,
36171 orientation : this.orientation
36174 this.split.on("moved", this.onSplitMove, this);
36175 this.split.useShim = this.config.useShim === true;
36176 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36177 if(this.useSplitTips){
36178 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36180 //if(config.collapsible){
36181 // this.split.el.on("dblclick", this.collapse, this);
36184 if(typeof this.config.minSize != "undefined"){
36185 this.split.minSize = this.config.minSize;
36187 if(typeof this.config.maxSize != "undefined"){
36188 this.split.maxSize = this.config.maxSize;
36190 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36191 this.hideSplitter();
36196 getHMaxSize : function(){
36197 var cmax = this.config.maxSize || 10000;
36198 var center = this.mgr.getRegion("center");
36199 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36202 getVMaxSize : function(){
36203 var cmax = this.config.maxSize || 10000;
36204 var center = this.mgr.getRegion("center");
36205 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36208 onSplitMove : function(split, newSize){
36209 this.fireEvent("resized", this, newSize);
36213 * Returns the {@link Roo.SplitBar} for this region.
36214 * @return {Roo.SplitBar}
36216 getSplitBar : function(){
36221 this.hideSplitter();
36222 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36225 hideSplitter : function(){
36227 this.split.el.setLocation(-2000,-2000);
36228 this.split.el.hide();
36234 this.split.el.show();
36236 Roo.bootstrap.layout.Split.superclass.show.call(this);
36239 beforeSlide: function(){
36240 if(Roo.isGecko){// firefox overflow auto bug workaround
36241 this.bodyEl.clip();
36243 this.tabs.bodyEl.clip();
36245 if(this.activePanel){
36246 this.activePanel.getEl().clip();
36248 if(this.activePanel.beforeSlide){
36249 this.activePanel.beforeSlide();
36255 afterSlide : function(){
36256 if(Roo.isGecko){// firefox overflow auto bug workaround
36257 this.bodyEl.unclip();
36259 this.tabs.bodyEl.unclip();
36261 if(this.activePanel){
36262 this.activePanel.getEl().unclip();
36263 if(this.activePanel.afterSlide){
36264 this.activePanel.afterSlide();
36270 initAutoHide : function(){
36271 if(this.autoHide !== false){
36272 if(!this.autoHideHd){
36273 var st = new Roo.util.DelayedTask(this.slideIn, this);
36274 this.autoHideHd = {
36275 "mouseout": function(e){
36276 if(!e.within(this.el, true)){
36280 "mouseover" : function(e){
36286 this.el.on(this.autoHideHd);
36290 clearAutoHide : function(){
36291 if(this.autoHide !== false){
36292 this.el.un("mouseout", this.autoHideHd.mouseout);
36293 this.el.un("mouseover", this.autoHideHd.mouseover);
36297 clearMonitor : function(){
36298 Roo.get(document).un("click", this.slideInIf, this);
36301 // these names are backwards but not changed for compat
36302 slideOut : function(){
36303 if(this.isSlid || this.el.hasActiveFx()){
36306 this.isSlid = true;
36307 if(this.collapseBtn){
36308 this.collapseBtn.hide();
36310 this.closeBtnState = this.closeBtn.getStyle('display');
36311 this.closeBtn.hide();
36313 this.stickBtn.show();
36316 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36317 this.beforeSlide();
36318 this.el.setStyle("z-index", 10001);
36319 this.el.slideIn(this.getSlideAnchor(), {
36320 callback: function(){
36322 this.initAutoHide();
36323 Roo.get(document).on("click", this.slideInIf, this);
36324 this.fireEvent("slideshow", this);
36331 afterSlideIn : function(){
36332 this.clearAutoHide();
36333 this.isSlid = false;
36334 this.clearMonitor();
36335 this.el.setStyle("z-index", "");
36336 if(this.collapseBtn){
36337 this.collapseBtn.show();
36339 this.closeBtn.setStyle('display', this.closeBtnState);
36341 this.stickBtn.hide();
36343 this.fireEvent("slidehide", this);
36346 slideIn : function(cb){
36347 if(!this.isSlid || this.el.hasActiveFx()){
36351 this.isSlid = false;
36352 this.beforeSlide();
36353 this.el.slideOut(this.getSlideAnchor(), {
36354 callback: function(){
36355 this.el.setLeftTop(-10000, -10000);
36357 this.afterSlideIn();
36365 slideInIf : function(e){
36366 if(!e.within(this.el)){
36371 animateCollapse : function(){
36372 this.beforeSlide();
36373 this.el.setStyle("z-index", 20000);
36374 var anchor = this.getSlideAnchor();
36375 this.el.slideOut(anchor, {
36376 callback : function(){
36377 this.el.setStyle("z-index", "");
36378 this.collapsedEl.slideIn(anchor, {duration:.3});
36380 this.el.setLocation(-10000,-10000);
36382 this.fireEvent("collapsed", this);
36389 animateExpand : function(){
36390 this.beforeSlide();
36391 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36392 this.el.setStyle("z-index", 20000);
36393 this.collapsedEl.hide({
36396 this.el.slideIn(this.getSlideAnchor(), {
36397 callback : function(){
36398 this.el.setStyle("z-index", "");
36401 this.split.el.show();
36403 this.fireEvent("invalidated", this);
36404 this.fireEvent("expanded", this);
36432 getAnchor : function(){
36433 return this.anchors[this.position];
36436 getCollapseAnchor : function(){
36437 return this.canchors[this.position];
36440 getSlideAnchor : function(){
36441 return this.sanchors[this.position];
36444 getAlignAdj : function(){
36445 var cm = this.cmargins;
36446 switch(this.position){
36462 getExpandAdj : function(){
36463 var c = this.collapsedEl, cm = this.cmargins;
36464 switch(this.position){
36466 return [-(cm.right+c.getWidth()+cm.left), 0];
36469 return [cm.right+c.getWidth()+cm.left, 0];
36472 return [0, -(cm.top+cm.bottom+c.getHeight())];
36475 return [0, cm.top+cm.bottom+c.getHeight()];
36481 * Ext JS Library 1.1.1
36482 * Copyright(c) 2006-2007, Ext JS, LLC.
36484 * Originally Released Under LGPL - original licence link has changed is not relivant.
36487 * <script type="text/javascript">
36490 * These classes are private internal classes
36492 Roo.bootstrap.layout.Center = function(config){
36493 config.region = "center";
36494 Roo.bootstrap.layout.Region.call(this, config);
36495 this.visible = true;
36496 this.minWidth = config.minWidth || 20;
36497 this.minHeight = config.minHeight || 20;
36500 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36502 // center panel can't be hidden
36506 // center panel can't be hidden
36509 getMinWidth: function(){
36510 return this.minWidth;
36513 getMinHeight: function(){
36514 return this.minHeight;
36527 Roo.bootstrap.layout.North = function(config)
36529 config.region = 'north';
36530 config.cursor = 'n-resize';
36532 Roo.bootstrap.layout.Split.call(this, config);
36536 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36537 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36538 this.split.el.addClass("roo-layout-split-v");
36540 var size = config.initialSize || config.height;
36541 if(typeof size != "undefined"){
36542 this.el.setHeight(size);
36545 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36547 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36551 getBox : function(){
36552 if(this.collapsed){
36553 return this.collapsedEl.getBox();
36555 var box = this.el.getBox();
36557 box.height += this.split.el.getHeight();
36562 updateBox : function(box){
36563 if(this.split && !this.collapsed){
36564 box.height -= this.split.el.getHeight();
36565 this.split.el.setLeft(box.x);
36566 this.split.el.setTop(box.y+box.height);
36567 this.split.el.setWidth(box.width);
36569 if(this.collapsed){
36570 this.updateBody(box.width, null);
36572 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36580 Roo.bootstrap.layout.South = function(config){
36581 config.region = 'south';
36582 config.cursor = 's-resize';
36583 Roo.bootstrap.layout.Split.call(this, config);
36585 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36586 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36587 this.split.el.addClass("roo-layout-split-v");
36589 var size = config.initialSize || config.height;
36590 if(typeof size != "undefined"){
36591 this.el.setHeight(size);
36595 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36596 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36597 getBox : function(){
36598 if(this.collapsed){
36599 return this.collapsedEl.getBox();
36601 var box = this.el.getBox();
36603 var sh = this.split.el.getHeight();
36610 updateBox : function(box){
36611 if(this.split && !this.collapsed){
36612 var sh = this.split.el.getHeight();
36615 this.split.el.setLeft(box.x);
36616 this.split.el.setTop(box.y-sh);
36617 this.split.el.setWidth(box.width);
36619 if(this.collapsed){
36620 this.updateBody(box.width, null);
36622 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36626 Roo.bootstrap.layout.East = function(config){
36627 config.region = "east";
36628 config.cursor = "e-resize";
36629 Roo.bootstrap.layout.Split.call(this, config);
36631 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36632 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36633 this.split.el.addClass("roo-layout-split-h");
36635 var size = config.initialSize || config.width;
36636 if(typeof size != "undefined"){
36637 this.el.setWidth(size);
36640 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36641 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36642 getBox : function(){
36643 if(this.collapsed){
36644 return this.collapsedEl.getBox();
36646 var box = this.el.getBox();
36648 var sw = this.split.el.getWidth();
36655 updateBox : function(box){
36656 if(this.split && !this.collapsed){
36657 var sw = this.split.el.getWidth();
36659 this.split.el.setLeft(box.x);
36660 this.split.el.setTop(box.y);
36661 this.split.el.setHeight(box.height);
36664 if(this.collapsed){
36665 this.updateBody(null, box.height);
36667 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36671 Roo.bootstrap.layout.West = function(config){
36672 config.region = "west";
36673 config.cursor = "w-resize";
36675 Roo.bootstrap.layout.Split.call(this, config);
36677 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36678 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36679 this.split.el.addClass("roo-layout-split-h");
36683 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36684 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36686 onRender: function(ctr, pos)
36688 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36689 var size = this.config.initialSize || this.config.width;
36690 if(typeof size != "undefined"){
36691 this.el.setWidth(size);
36695 getBox : function(){
36696 if(this.collapsed){
36697 return this.collapsedEl.getBox();
36699 var box = this.el.getBox();
36701 box.width += this.split.el.getWidth();
36706 updateBox : function(box){
36707 if(this.split && !this.collapsed){
36708 var sw = this.split.el.getWidth();
36710 this.split.el.setLeft(box.x+box.width);
36711 this.split.el.setTop(box.y);
36712 this.split.el.setHeight(box.height);
36714 if(this.collapsed){
36715 this.updateBody(null, box.height);
36717 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36720 Roo.namespace("Roo.bootstrap.panel");/*
36722 * Ext JS Library 1.1.1
36723 * Copyright(c) 2006-2007, Ext JS, LLC.
36725 * Originally Released Under LGPL - original licence link has changed is not relivant.
36728 * <script type="text/javascript">
36731 * @class Roo.ContentPanel
36732 * @extends Roo.util.Observable
36733 * A basic ContentPanel element.
36734 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36735 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36736 * @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
36737 * @cfg {Boolean} closable True if the panel can be closed/removed
36738 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36739 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36740 * @cfg {Toolbar} toolbar A toolbar for this panel
36741 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36742 * @cfg {String} title The title for this panel
36743 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36744 * @cfg {String} url Calls {@link #setUrl} with this value
36745 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36746 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36747 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36748 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36749 * @cfg {Boolean} badges render the badges
36752 * Create a new ContentPanel.
36753 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36754 * @param {String/Object} config A string to set only the title or a config object
36755 * @param {String} content (optional) Set the HTML content for this panel
36756 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36758 Roo.bootstrap.panel.Content = function( config){
36760 this.tpl = config.tpl || false;
36762 var el = config.el;
36763 var content = config.content;
36765 if(config.autoCreate){ // xtype is available if this is called from factory
36768 this.el = Roo.get(el);
36769 if(!this.el && config && config.autoCreate){
36770 if(typeof config.autoCreate == "object"){
36771 if(!config.autoCreate.id){
36772 config.autoCreate.id = config.id||el;
36774 this.el = Roo.DomHelper.append(document.body,
36775 config.autoCreate, true);
36777 var elcfg = { tag: "div",
36778 cls: "roo-layout-inactive-content",
36782 elcfg.html = config.html;
36786 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36789 this.closable = false;
36790 this.loaded = false;
36791 this.active = false;
36794 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36796 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36798 this.wrapEl = this.el; //this.el.wrap();
36800 if (config.toolbar.items) {
36801 ti = config.toolbar.items ;
36802 delete config.toolbar.items ;
36806 this.toolbar.render(this.wrapEl, 'before');
36807 for(var i =0;i < ti.length;i++) {
36808 // Roo.log(['add child', items[i]]);
36809 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36811 this.toolbar.items = nitems;
36812 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36813 delete config.toolbar;
36817 // xtype created footer. - not sure if will work as we normally have to render first..
36818 if (this.footer && !this.footer.el && this.footer.xtype) {
36819 if (!this.wrapEl) {
36820 this.wrapEl = this.el.wrap();
36823 this.footer.container = this.wrapEl.createChild();
36825 this.footer = Roo.factory(this.footer, Roo);
36830 if(typeof config == "string"){
36831 this.title = config;
36833 Roo.apply(this, config);
36837 this.resizeEl = Roo.get(this.resizeEl, true);
36839 this.resizeEl = this.el;
36841 // handle view.xtype
36849 * Fires when this panel is activated.
36850 * @param {Roo.ContentPanel} this
36854 * @event deactivate
36855 * Fires when this panel is activated.
36856 * @param {Roo.ContentPanel} this
36858 "deactivate" : true,
36862 * Fires when this panel is resized if fitToFrame is true.
36863 * @param {Roo.ContentPanel} this
36864 * @param {Number} width The width after any component adjustments
36865 * @param {Number} height The height after any component adjustments
36871 * Fires when this tab is created
36872 * @param {Roo.ContentPanel} this
36883 if(this.autoScroll){
36884 this.resizeEl.setStyle("overflow", "auto");
36886 // fix randome scrolling
36887 //this.el.on('scroll', function() {
36888 // Roo.log('fix random scolling');
36889 // this.scrollTo('top',0);
36892 content = content || this.content;
36894 this.setContent(content);
36896 if(config && config.url){
36897 this.setUrl(this.url, this.params, this.loadOnce);
36902 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36904 if (this.view && typeof(this.view.xtype) != 'undefined') {
36905 this.view.el = this.el.appendChild(document.createElement("div"));
36906 this.view = Roo.factory(this.view);
36907 this.view.render && this.view.render(false, '');
36911 this.fireEvent('render', this);
36914 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36918 setRegion : function(region){
36919 this.region = region;
36920 this.setActiveClass(region && !this.background);
36924 setActiveClass: function(state)
36927 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36928 this.el.setStyle('position','relative');
36930 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36931 this.el.setStyle('position', 'absolute');
36936 * Returns the toolbar for this Panel if one was configured.
36937 * @return {Roo.Toolbar}
36939 getToolbar : function(){
36940 return this.toolbar;
36943 setActiveState : function(active)
36945 this.active = active;
36946 this.setActiveClass(active);
36948 if(this.fireEvent("deactivate", this) === false){
36953 this.fireEvent("activate", this);
36957 * Updates this panel's element
36958 * @param {String} content The new content
36959 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36961 setContent : function(content, loadScripts){
36962 this.el.update(content, loadScripts);
36965 ignoreResize : function(w, h){
36966 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36969 this.lastSize = {width: w, height: h};
36974 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36975 * @return {Roo.UpdateManager} The UpdateManager
36977 getUpdateManager : function(){
36978 return this.el.getUpdateManager();
36981 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36982 * @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:
36985 url: "your-url.php",
36986 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36987 callback: yourFunction,
36988 scope: yourObject, //(optional scope)
36991 text: "Loading...",
36996 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36997 * 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.
36998 * @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}
36999 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37000 * @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.
37001 * @return {Roo.ContentPanel} this
37004 var um = this.el.getUpdateManager();
37005 um.update.apply(um, arguments);
37011 * 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.
37012 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37013 * @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)
37014 * @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)
37015 * @return {Roo.UpdateManager} The UpdateManager
37017 setUrl : function(url, params, loadOnce){
37018 if(this.refreshDelegate){
37019 this.removeListener("activate", this.refreshDelegate);
37021 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37022 this.on("activate", this.refreshDelegate);
37023 return this.el.getUpdateManager();
37026 _handleRefresh : function(url, params, loadOnce){
37027 if(!loadOnce || !this.loaded){
37028 var updater = this.el.getUpdateManager();
37029 updater.update(url, params, this._setLoaded.createDelegate(this));
37033 _setLoaded : function(){
37034 this.loaded = true;
37038 * Returns this panel's id
37041 getId : function(){
37046 * Returns this panel's element - used by regiosn to add.
37047 * @return {Roo.Element}
37049 getEl : function(){
37050 return this.wrapEl || this.el;
37055 adjustForComponents : function(width, height)
37057 //Roo.log('adjustForComponents ');
37058 if(this.resizeEl != this.el){
37059 width -= this.el.getFrameWidth('lr');
37060 height -= this.el.getFrameWidth('tb');
37063 var te = this.toolbar.getEl();
37064 te.setWidth(width);
37065 height -= te.getHeight();
37068 var te = this.footer.getEl();
37069 te.setWidth(width);
37070 height -= te.getHeight();
37074 if(this.adjustments){
37075 width += this.adjustments[0];
37076 height += this.adjustments[1];
37078 return {"width": width, "height": height};
37081 setSize : function(width, height){
37082 if(this.fitToFrame && !this.ignoreResize(width, height)){
37083 if(this.fitContainer && this.resizeEl != this.el){
37084 this.el.setSize(width, height);
37086 var size = this.adjustForComponents(width, height);
37087 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37088 this.fireEvent('resize', this, size.width, size.height);
37093 * Returns this panel's title
37096 getTitle : function(){
37098 if (typeof(this.title) != 'object') {
37103 for (var k in this.title) {
37104 if (!this.title.hasOwnProperty(k)) {
37108 if (k.indexOf('-') >= 0) {
37109 var s = k.split('-');
37110 for (var i = 0; i<s.length; i++) {
37111 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37114 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37121 * Set this panel's title
37122 * @param {String} title
37124 setTitle : function(title){
37125 this.title = title;
37127 this.region.updatePanelTitle(this, title);
37132 * Returns true is this panel was configured to be closable
37133 * @return {Boolean}
37135 isClosable : function(){
37136 return this.closable;
37139 beforeSlide : function(){
37141 this.resizeEl.clip();
37144 afterSlide : function(){
37146 this.resizeEl.unclip();
37150 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37151 * Will fail silently if the {@link #setUrl} method has not been called.
37152 * This does not activate the panel, just updates its content.
37154 refresh : function(){
37155 if(this.refreshDelegate){
37156 this.loaded = false;
37157 this.refreshDelegate();
37162 * Destroys this panel
37164 destroy : function(){
37165 this.el.removeAllListeners();
37166 var tempEl = document.createElement("span");
37167 tempEl.appendChild(this.el.dom);
37168 tempEl.innerHTML = "";
37174 * form - if the content panel contains a form - this is a reference to it.
37175 * @type {Roo.form.Form}
37179 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37180 * This contains a reference to it.
37186 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37196 * @param {Object} cfg Xtype definition of item to add.
37200 getChildContainer: function () {
37201 return this.getEl();
37206 var ret = new Roo.factory(cfg);
37211 if (cfg.xtype.match(/^Form$/)) {
37214 //if (this.footer) {
37215 // el = this.footer.container.insertSibling(false, 'before');
37217 el = this.el.createChild();
37220 this.form = new Roo.form.Form(cfg);
37223 if ( this.form.allItems.length) {
37224 this.form.render(el.dom);
37228 // should only have one of theses..
37229 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37230 // views.. should not be just added - used named prop 'view''
37232 cfg.el = this.el.appendChild(document.createElement("div"));
37235 var ret = new Roo.factory(cfg);
37237 ret.render && ret.render(false, ''); // render blank..
37247 * @class Roo.bootstrap.panel.Grid
37248 * @extends Roo.bootstrap.panel.Content
37250 * Create a new GridPanel.
37251 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37252 * @param {Object} config A the config object
37258 Roo.bootstrap.panel.Grid = function(config)
37262 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37263 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37265 config.el = this.wrapper;
37266 //this.el = this.wrapper;
37268 if (config.container) {
37269 // ctor'ed from a Border/panel.grid
37272 this.wrapper.setStyle("overflow", "hidden");
37273 this.wrapper.addClass('roo-grid-container');
37278 if(config.toolbar){
37279 var tool_el = this.wrapper.createChild();
37280 this.toolbar = Roo.factory(config.toolbar);
37282 if (config.toolbar.items) {
37283 ti = config.toolbar.items ;
37284 delete config.toolbar.items ;
37288 this.toolbar.render(tool_el);
37289 for(var i =0;i < ti.length;i++) {
37290 // Roo.log(['add child', items[i]]);
37291 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37293 this.toolbar.items = nitems;
37295 delete config.toolbar;
37298 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37299 config.grid.scrollBody = true;;
37300 config.grid.monitorWindowResize = false; // turn off autosizing
37301 config.grid.autoHeight = false;
37302 config.grid.autoWidth = false;
37304 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37306 if (config.background) {
37307 // render grid on panel activation (if panel background)
37308 this.on('activate', function(gp) {
37309 if (!gp.grid.rendered) {
37310 gp.grid.render(this.wrapper);
37311 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37316 this.grid.render(this.wrapper);
37317 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37320 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37321 // ??? needed ??? config.el = this.wrapper;
37326 // xtype created footer. - not sure if will work as we normally have to render first..
37327 if (this.footer && !this.footer.el && this.footer.xtype) {
37329 var ctr = this.grid.getView().getFooterPanel(true);
37330 this.footer.dataSource = this.grid.dataSource;
37331 this.footer = Roo.factory(this.footer, Roo);
37332 this.footer.render(ctr);
37342 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37343 getId : function(){
37344 return this.grid.id;
37348 * Returns the grid for this panel
37349 * @return {Roo.bootstrap.Table}
37351 getGrid : function(){
37355 setSize : function(width, height){
37356 if(!this.ignoreResize(width, height)){
37357 var grid = this.grid;
37358 var size = this.adjustForComponents(width, height);
37359 var gridel = grid.getGridEl();
37360 gridel.setSize(size.width, size.height);
37362 var thd = grid.getGridEl().select('thead',true).first();
37363 var tbd = grid.getGridEl().select('tbody', true).first();
37365 tbd.setSize(width, height - thd.getHeight());
37374 beforeSlide : function(){
37375 this.grid.getView().scroller.clip();
37378 afterSlide : function(){
37379 this.grid.getView().scroller.unclip();
37382 destroy : function(){
37383 this.grid.destroy();
37385 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37390 * @class Roo.bootstrap.panel.Nest
37391 * @extends Roo.bootstrap.panel.Content
37393 * Create a new Panel, that can contain a layout.Border.
37396 * @param {Roo.BorderLayout} layout The layout for this panel
37397 * @param {String/Object} config A string to set only the title or a config object
37399 Roo.bootstrap.panel.Nest = function(config)
37401 // construct with only one argument..
37402 /* FIXME - implement nicer consturctors
37403 if (layout.layout) {
37405 layout = config.layout;
37406 delete config.layout;
37408 if (layout.xtype && !layout.getEl) {
37409 // then layout needs constructing..
37410 layout = Roo.factory(layout, Roo);
37414 config.el = config.layout.getEl();
37416 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37418 config.layout.monitorWindowResize = false; // turn off autosizing
37419 this.layout = config.layout;
37420 this.layout.getEl().addClass("roo-layout-nested-layout");
37427 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37429 setSize : function(width, height){
37430 if(!this.ignoreResize(width, height)){
37431 var size = this.adjustForComponents(width, height);
37432 var el = this.layout.getEl();
37433 if (size.height < 1) {
37434 el.setWidth(size.width);
37436 el.setSize(size.width, size.height);
37438 var touch = el.dom.offsetWidth;
37439 this.layout.layout();
37440 // ie requires a double layout on the first pass
37441 if(Roo.isIE && !this.initialized){
37442 this.initialized = true;
37443 this.layout.layout();
37448 // activate all subpanels if not currently active..
37450 setActiveState : function(active){
37451 this.active = active;
37452 this.setActiveClass(active);
37455 this.fireEvent("deactivate", this);
37459 this.fireEvent("activate", this);
37460 // not sure if this should happen before or after..
37461 if (!this.layout) {
37462 return; // should not happen..
37465 for (var r in this.layout.regions) {
37466 reg = this.layout.getRegion(r);
37467 if (reg.getActivePanel()) {
37468 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37469 reg.setActivePanel(reg.getActivePanel());
37472 if (!reg.panels.length) {
37475 reg.showPanel(reg.getPanel(0));
37484 * Returns the nested BorderLayout for this panel
37485 * @return {Roo.BorderLayout}
37487 getLayout : function(){
37488 return this.layout;
37492 * Adds a xtype elements to the layout of the nested panel
37496 xtype : 'ContentPanel',
37503 xtype : 'NestedLayoutPanel',
37509 items : [ ... list of content panels or nested layout panels.. ]
37513 * @param {Object} cfg Xtype definition of item to add.
37515 addxtype : function(cfg) {
37516 return this.layout.addxtype(cfg);
37521 * Ext JS Library 1.1.1
37522 * Copyright(c) 2006-2007, Ext JS, LLC.
37524 * Originally Released Under LGPL - original licence link has changed is not relivant.
37527 * <script type="text/javascript">
37530 * @class Roo.TabPanel
37531 * @extends Roo.util.Observable
37532 * A lightweight tab container.
37536 // basic tabs 1, built from existing content
37537 var tabs = new Roo.TabPanel("tabs1");
37538 tabs.addTab("script", "View Script");
37539 tabs.addTab("markup", "View Markup");
37540 tabs.activate("script");
37542 // more advanced tabs, built from javascript
37543 var jtabs = new Roo.TabPanel("jtabs");
37544 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37546 // set up the UpdateManager
37547 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37548 var updater = tab2.getUpdateManager();
37549 updater.setDefaultUrl("ajax1.htm");
37550 tab2.on('activate', updater.refresh, updater, true);
37552 // Use setUrl for Ajax loading
37553 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37554 tab3.setUrl("ajax2.htm", null, true);
37557 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37560 jtabs.activate("jtabs-1");
37563 * Create a new TabPanel.
37564 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37565 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37567 Roo.bootstrap.panel.Tabs = function(config){
37569 * The container element for this TabPanel.
37570 * @type Roo.Element
37572 this.el = Roo.get(config.el);
37575 if(typeof config == "boolean"){
37576 this.tabPosition = config ? "bottom" : "top";
37578 Roo.apply(this, config);
37582 if(this.tabPosition == "bottom"){
37583 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37584 this.el.addClass("roo-tabs-bottom");
37586 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37587 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37588 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37590 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37592 if(this.tabPosition != "bottom"){
37593 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37594 * @type Roo.Element
37596 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37597 this.el.addClass("roo-tabs-top");
37601 this.bodyEl.setStyle("position", "relative");
37603 this.active = null;
37604 this.activateDelegate = this.activate.createDelegate(this);
37609 * Fires when the active tab changes
37610 * @param {Roo.TabPanel} this
37611 * @param {Roo.TabPanelItem} activePanel The new active tab
37615 * @event beforetabchange
37616 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37617 * @param {Roo.TabPanel} this
37618 * @param {Object} e Set cancel to true on this object to cancel the tab change
37619 * @param {Roo.TabPanelItem} tab The tab being changed to
37621 "beforetabchange" : true
37624 Roo.EventManager.onWindowResize(this.onResize, this);
37625 this.cpad = this.el.getPadding("lr");
37626 this.hiddenCount = 0;
37629 // toolbar on the tabbar support...
37630 if (this.toolbar) {
37631 alert("no toolbar support yet");
37632 this.toolbar = false;
37634 var tcfg = this.toolbar;
37635 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37636 this.toolbar = new Roo.Toolbar(tcfg);
37637 if (Roo.isSafari) {
37638 var tbl = tcfg.container.child('table', true);
37639 tbl.setAttribute('width', '100%');
37647 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37650 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37652 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37654 tabPosition : "top",
37656 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37658 currentTabWidth : 0,
37660 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37664 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37668 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37670 preferredTabWidth : 175,
37672 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37674 resizeTabs : false,
37676 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37678 monitorResize : true,
37680 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37685 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37686 * @param {String} id The id of the div to use <b>or create</b>
37687 * @param {String} text The text for the tab
37688 * @param {String} content (optional) Content to put in the TabPanelItem body
37689 * @param {Boolean} closable (optional) True to create a close icon on the tab
37690 * @return {Roo.TabPanelItem} The created TabPanelItem
37692 addTab : function(id, text, content, closable, tpl)
37694 var item = new Roo.bootstrap.panel.TabItem({
37698 closable : closable,
37701 this.addTabItem(item);
37703 item.setContent(content);
37709 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37710 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37711 * @return {Roo.TabPanelItem}
37713 getTab : function(id){
37714 return this.items[id];
37718 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37719 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37721 hideTab : function(id){
37722 var t = this.items[id];
37725 this.hiddenCount++;
37726 this.autoSizeTabs();
37731 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37732 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37734 unhideTab : function(id){
37735 var t = this.items[id];
37737 t.setHidden(false);
37738 this.hiddenCount--;
37739 this.autoSizeTabs();
37744 * Adds an existing {@link Roo.TabPanelItem}.
37745 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37747 addTabItem : function(item){
37748 this.items[item.id] = item;
37749 this.items.push(item);
37750 // if(this.resizeTabs){
37751 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37752 // this.autoSizeTabs();
37754 // item.autoSize();
37759 * Removes a {@link Roo.TabPanelItem}.
37760 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37762 removeTab : function(id){
37763 var items = this.items;
37764 var tab = items[id];
37765 if(!tab) { return; }
37766 var index = items.indexOf(tab);
37767 if(this.active == tab && items.length > 1){
37768 var newTab = this.getNextAvailable(index);
37773 this.stripEl.dom.removeChild(tab.pnode.dom);
37774 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37775 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37777 items.splice(index, 1);
37778 delete this.items[tab.id];
37779 tab.fireEvent("close", tab);
37780 tab.purgeListeners();
37781 this.autoSizeTabs();
37784 getNextAvailable : function(start){
37785 var items = this.items;
37787 // look for a next tab that will slide over to
37788 // replace the one being removed
37789 while(index < items.length){
37790 var item = items[++index];
37791 if(item && !item.isHidden()){
37795 // if one isn't found select the previous tab (on the left)
37798 var item = items[--index];
37799 if(item && !item.isHidden()){
37807 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37808 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37810 disableTab : function(id){
37811 var tab = this.items[id];
37812 if(tab && this.active != tab){
37818 * Enables a {@link Roo.TabPanelItem} that is disabled.
37819 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37821 enableTab : function(id){
37822 var tab = this.items[id];
37827 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37828 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37829 * @return {Roo.TabPanelItem} The TabPanelItem.
37831 activate : function(id){
37832 var tab = this.items[id];
37836 if(tab == this.active || tab.disabled){
37840 this.fireEvent("beforetabchange", this, e, tab);
37841 if(e.cancel !== true && !tab.disabled){
37843 this.active.hide();
37845 this.active = this.items[id];
37846 this.active.show();
37847 this.fireEvent("tabchange", this, this.active);
37853 * Gets the active {@link Roo.TabPanelItem}.
37854 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37856 getActiveTab : function(){
37857 return this.active;
37861 * Updates the tab body element to fit the height of the container element
37862 * for overflow scrolling
37863 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37865 syncHeight : function(targetHeight){
37866 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37867 var bm = this.bodyEl.getMargins();
37868 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37869 this.bodyEl.setHeight(newHeight);
37873 onResize : function(){
37874 if(this.monitorResize){
37875 this.autoSizeTabs();
37880 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37882 beginUpdate : function(){
37883 this.updating = true;
37887 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37889 endUpdate : function(){
37890 this.updating = false;
37891 this.autoSizeTabs();
37895 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37897 autoSizeTabs : function(){
37898 var count = this.items.length;
37899 var vcount = count - this.hiddenCount;
37900 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37903 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37904 var availWidth = Math.floor(w / vcount);
37905 var b = this.stripBody;
37906 if(b.getWidth() > w){
37907 var tabs = this.items;
37908 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37909 if(availWidth < this.minTabWidth){
37910 /*if(!this.sleft){ // incomplete scrolling code
37911 this.createScrollButtons();
37914 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37917 if(this.currentTabWidth < this.preferredTabWidth){
37918 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37924 * Returns the number of tabs in this TabPanel.
37927 getCount : function(){
37928 return this.items.length;
37932 * Resizes all the tabs to the passed width
37933 * @param {Number} The new width
37935 setTabWidth : function(width){
37936 this.currentTabWidth = width;
37937 for(var i = 0, len = this.items.length; i < len; i++) {
37938 if(!this.items[i].isHidden()) {
37939 this.items[i].setWidth(width);
37945 * Destroys this TabPanel
37946 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37948 destroy : function(removeEl){
37949 Roo.EventManager.removeResizeListener(this.onResize, this);
37950 for(var i = 0, len = this.items.length; i < len; i++){
37951 this.items[i].purgeListeners();
37953 if(removeEl === true){
37954 this.el.update("");
37959 createStrip : function(container)
37961 var strip = document.createElement("nav");
37962 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37963 container.appendChild(strip);
37967 createStripList : function(strip)
37969 // div wrapper for retard IE
37970 // returns the "tr" element.
37971 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37972 //'<div class="x-tabs-strip-wrap">'+
37973 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37974 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37975 return strip.firstChild; //.firstChild.firstChild.firstChild;
37977 createBody : function(container)
37979 var body = document.createElement("div");
37980 Roo.id(body, "tab-body");
37981 //Roo.fly(body).addClass("x-tabs-body");
37982 Roo.fly(body).addClass("tab-content");
37983 container.appendChild(body);
37986 createItemBody :function(bodyEl, id){
37987 var body = Roo.getDom(id);
37989 body = document.createElement("div");
37992 //Roo.fly(body).addClass("x-tabs-item-body");
37993 Roo.fly(body).addClass("tab-pane");
37994 bodyEl.insertBefore(body, bodyEl.firstChild);
37998 createStripElements : function(stripEl, text, closable, tpl)
38000 var td = document.createElement("li"); // was td..
38003 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38006 stripEl.appendChild(td);
38008 td.className = "x-tabs-closable";
38009 if(!this.closeTpl){
38010 this.closeTpl = new Roo.Template(
38011 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38012 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38013 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38016 var el = this.closeTpl.overwrite(td, {"text": text});
38017 var close = el.getElementsByTagName("div")[0];
38018 var inner = el.getElementsByTagName("em")[0];
38019 return {"el": el, "close": close, "inner": inner};
38022 // not sure what this is..
38023 // if(!this.tabTpl){
38024 //this.tabTpl = new Roo.Template(
38025 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38026 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38028 // this.tabTpl = new Roo.Template(
38029 // '<a href="#">' +
38030 // '<span unselectable="on"' +
38031 // (this.disableTooltips ? '' : ' title="{text}"') +
38032 // ' >{text}</span></a>'
38038 var template = tpl || this.tabTpl || false;
38042 template = new Roo.Template(
38044 '<span unselectable="on"' +
38045 (this.disableTooltips ? '' : ' title="{text}"') +
38046 ' >{text}</span></a>'
38050 switch (typeof(template)) {
38054 template = new Roo.Template(template);
38060 var el = template.overwrite(td, {"text": text});
38062 var inner = el.getElementsByTagName("span")[0];
38064 return {"el": el, "inner": inner};
38072 * @class Roo.TabPanelItem
38073 * @extends Roo.util.Observable
38074 * Represents an individual item (tab plus body) in a TabPanel.
38075 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38076 * @param {String} id The id of this TabPanelItem
38077 * @param {String} text The text for the tab of this TabPanelItem
38078 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38080 Roo.bootstrap.panel.TabItem = function(config){
38082 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38083 * @type Roo.TabPanel
38085 this.tabPanel = config.panel;
38087 * The id for this TabPanelItem
38090 this.id = config.id;
38092 this.disabled = false;
38094 this.text = config.text;
38096 this.loaded = false;
38097 this.closable = config.closable;
38100 * The body element for this TabPanelItem.
38101 * @type Roo.Element
38103 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38104 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38105 this.bodyEl.setStyle("display", "block");
38106 this.bodyEl.setStyle("zoom", "1");
38107 //this.hideAction();
38109 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38111 this.el = Roo.get(els.el);
38112 this.inner = Roo.get(els.inner, true);
38113 this.textEl = Roo.get(this.el.dom.firstChild, true);
38114 this.pnode = Roo.get(els.el.parentNode, true);
38115 // this.el.on("mousedown", this.onTabMouseDown, this);
38116 this.el.on("click", this.onTabClick, this);
38118 if(config.closable){
38119 var c = Roo.get(els.close, true);
38120 c.dom.title = this.closeText;
38121 c.addClassOnOver("close-over");
38122 c.on("click", this.closeClick, this);
38128 * Fires when this tab becomes the active tab.
38129 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38130 * @param {Roo.TabPanelItem} this
38134 * @event beforeclose
38135 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38136 * @param {Roo.TabPanelItem} this
38137 * @param {Object} e Set cancel to true on this object to cancel the close.
38139 "beforeclose": true,
38142 * Fires when this tab is closed.
38143 * @param {Roo.TabPanelItem} this
38147 * @event deactivate
38148 * Fires when this tab is no longer the active tab.
38149 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38150 * @param {Roo.TabPanelItem} this
38152 "deactivate" : true
38154 this.hidden = false;
38156 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38159 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38161 purgeListeners : function(){
38162 Roo.util.Observable.prototype.purgeListeners.call(this);
38163 this.el.removeAllListeners();
38166 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38169 this.pnode.addClass("active");
38172 this.tabPanel.stripWrap.repaint();
38174 this.fireEvent("activate", this.tabPanel, this);
38178 * Returns true if this tab is the active tab.
38179 * @return {Boolean}
38181 isActive : function(){
38182 return this.tabPanel.getActiveTab() == this;
38186 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38189 this.pnode.removeClass("active");
38191 this.fireEvent("deactivate", this.tabPanel, this);
38194 hideAction : function(){
38195 this.bodyEl.hide();
38196 this.bodyEl.setStyle("position", "absolute");
38197 this.bodyEl.setLeft("-20000px");
38198 this.bodyEl.setTop("-20000px");
38201 showAction : function(){
38202 this.bodyEl.setStyle("position", "relative");
38203 this.bodyEl.setTop("");
38204 this.bodyEl.setLeft("");
38205 this.bodyEl.show();
38209 * Set the tooltip for the tab.
38210 * @param {String} tooltip The tab's tooltip
38212 setTooltip : function(text){
38213 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38214 this.textEl.dom.qtip = text;
38215 this.textEl.dom.removeAttribute('title');
38217 this.textEl.dom.title = text;
38221 onTabClick : function(e){
38222 e.preventDefault();
38223 this.tabPanel.activate(this.id);
38226 onTabMouseDown : function(e){
38227 e.preventDefault();
38228 this.tabPanel.activate(this.id);
38231 getWidth : function(){
38232 return this.inner.getWidth();
38235 setWidth : function(width){
38236 var iwidth = width - this.pnode.getPadding("lr");
38237 this.inner.setWidth(iwidth);
38238 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38239 this.pnode.setWidth(width);
38243 * Show or hide the tab
38244 * @param {Boolean} hidden True to hide or false to show.
38246 setHidden : function(hidden){
38247 this.hidden = hidden;
38248 this.pnode.setStyle("display", hidden ? "none" : "");
38252 * Returns true if this tab is "hidden"
38253 * @return {Boolean}
38255 isHidden : function(){
38256 return this.hidden;
38260 * Returns the text for this tab
38263 getText : function(){
38267 autoSize : function(){
38268 //this.el.beginMeasure();
38269 this.textEl.setWidth(1);
38271 * #2804 [new] Tabs in Roojs
38272 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38274 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38275 //this.el.endMeasure();
38279 * Sets the text for the tab (Note: this also sets the tooltip text)
38280 * @param {String} text The tab's text and tooltip
38282 setText : function(text){
38284 this.textEl.update(text);
38285 this.setTooltip(text);
38286 //if(!this.tabPanel.resizeTabs){
38287 // this.autoSize();
38291 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38293 activate : function(){
38294 this.tabPanel.activate(this.id);
38298 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38300 disable : function(){
38301 if(this.tabPanel.active != this){
38302 this.disabled = true;
38303 this.pnode.addClass("disabled");
38308 * Enables this TabPanelItem if it was previously disabled.
38310 enable : function(){
38311 this.disabled = false;
38312 this.pnode.removeClass("disabled");
38316 * Sets the content for this TabPanelItem.
38317 * @param {String} content The content
38318 * @param {Boolean} loadScripts true to look for and load scripts
38320 setContent : function(content, loadScripts){
38321 this.bodyEl.update(content, loadScripts);
38325 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38326 * @return {Roo.UpdateManager} The UpdateManager
38328 getUpdateManager : function(){
38329 return this.bodyEl.getUpdateManager();
38333 * Set a URL to be used to load the content for this TabPanelItem.
38334 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38335 * @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)
38336 * @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)
38337 * @return {Roo.UpdateManager} The UpdateManager
38339 setUrl : function(url, params, loadOnce){
38340 if(this.refreshDelegate){
38341 this.un('activate', this.refreshDelegate);
38343 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38344 this.on("activate", this.refreshDelegate);
38345 return this.bodyEl.getUpdateManager();
38349 _handleRefresh : function(url, params, loadOnce){
38350 if(!loadOnce || !this.loaded){
38351 var updater = this.bodyEl.getUpdateManager();
38352 updater.update(url, params, this._setLoaded.createDelegate(this));
38357 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38358 * Will fail silently if the setUrl method has not been called.
38359 * This does not activate the panel, just updates its content.
38361 refresh : function(){
38362 if(this.refreshDelegate){
38363 this.loaded = false;
38364 this.refreshDelegate();
38369 _setLoaded : function(){
38370 this.loaded = true;
38374 closeClick : function(e){
38377 this.fireEvent("beforeclose", this, o);
38378 if(o.cancel !== true){
38379 this.tabPanel.removeTab(this.id);
38383 * The text displayed in the tooltip for the close icon.
38386 closeText : "Close this tab"
38389 * This script refer to:
38390 * Title: International Telephone Input
38391 * Author: Jack O'Connor
38392 * Code version: v12.1.12
38393 * Availability: https://github.com/jackocnr/intl-tel-input.git
38396 Roo.bootstrap.PhoneInputData = function() {
38399 "Afghanistan (افغانستان)",
38404 "Albania (Shqipëri)",
38409 "Algeria (الجزائر)",
38434 "Antigua and Barbuda",
38444 "Armenia (Հայաստան)",
38460 "Austria (Österreich)",
38465 "Azerbaijan (Azərbaycan)",
38475 "Bahrain (البحرين)",
38480 "Bangladesh (বাংলাদেশ)",
38490 "Belarus (Беларусь)",
38495 "Belgium (België)",
38525 "Bosnia and Herzegovina (Босна и Херцеговина)",
38540 "British Indian Ocean Territory",
38545 "British Virgin Islands",
38555 "Bulgaria (България)",
38565 "Burundi (Uburundi)",
38570 "Cambodia (កម្ពុជា)",
38575 "Cameroon (Cameroun)",
38584 ["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"]
38587 "Cape Verde (Kabu Verdi)",
38592 "Caribbean Netherlands",
38603 "Central African Republic (République centrafricaine)",
38623 "Christmas Island",
38629 "Cocos (Keeling) Islands",
38640 "Comoros (جزر القمر)",
38645 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38650 "Congo (Republic) (Congo-Brazzaville)",
38670 "Croatia (Hrvatska)",
38691 "Czech Republic (Česká republika)",
38696 "Denmark (Danmark)",
38711 "Dominican Republic (República Dominicana)",
38715 ["809", "829", "849"]
38733 "Equatorial Guinea (Guinea Ecuatorial)",
38753 "Falkland Islands (Islas Malvinas)",
38758 "Faroe Islands (Føroyar)",
38779 "French Guiana (Guyane française)",
38784 "French Polynesia (Polynésie française)",
38799 "Georgia (საქართველო)",
38804 "Germany (Deutschland)",
38824 "Greenland (Kalaallit Nunaat)",
38861 "Guinea-Bissau (Guiné Bissau)",
38886 "Hungary (Magyarország)",
38891 "Iceland (Ísland)",
38911 "Iraq (العراق)",
38927 "Israel (ישראל)",
38954 "Jordan (الأردن)",
38959 "Kazakhstan (Казахстан)",
38980 "Kuwait (الكويت)",
38985 "Kyrgyzstan (Кыргызстан)",
38995 "Latvia (Latvija)",
39000 "Lebanon (لبنان)",
39015 "Libya (ليبيا)",
39025 "Lithuania (Lietuva)",
39040 "Macedonia (FYROM) (Македонија)",
39045 "Madagascar (Madagasikara)",
39075 "Marshall Islands",
39085 "Mauritania (موريتانيا)",
39090 "Mauritius (Moris)",
39111 "Moldova (Republica Moldova)",
39121 "Mongolia (Монгол)",
39126 "Montenegro (Crna Gora)",
39136 "Morocco (المغرب)",
39142 "Mozambique (Moçambique)",
39147 "Myanmar (Burma) (မြန်မာ)",
39152 "Namibia (Namibië)",
39167 "Netherlands (Nederland)",
39172 "New Caledonia (Nouvelle-Calédonie)",
39207 "North Korea (조선 민주주의 인민 공화국)",
39212 "Northern Mariana Islands",
39228 "Pakistan (پاکستان)",
39238 "Palestine (فلسطين)",
39248 "Papua New Guinea",
39290 "Réunion (La Réunion)",
39296 "Romania (România)",
39312 "Saint Barthélemy",
39323 "Saint Kitts and Nevis",
39333 "Saint Martin (Saint-Martin (partie française))",
39339 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39344 "Saint Vincent and the Grenadines",
39359 "São Tomé and Príncipe (São Tomé e Príncipe)",
39364 "Saudi Arabia (المملكة العربية السعودية)",
39369 "Senegal (Sénégal)",
39399 "Slovakia (Slovensko)",
39404 "Slovenia (Slovenija)",
39414 "Somalia (Soomaaliya)",
39424 "South Korea (대한민국)",
39429 "South Sudan (جنوب السودان)",
39439 "Sri Lanka (ශ්රී ලංකාව)",
39444 "Sudan (السودان)",
39454 "Svalbard and Jan Mayen",
39465 "Sweden (Sverige)",
39470 "Switzerland (Schweiz)",
39475 "Syria (سوريا)",
39520 "Trinidad and Tobago",
39525 "Tunisia (تونس)",
39530 "Turkey (Türkiye)",
39540 "Turks and Caicos Islands",
39550 "U.S. Virgin Islands",
39560 "Ukraine (Україна)",
39565 "United Arab Emirates (الإمارات العربية المتحدة)",
39587 "Uzbekistan (Oʻzbekiston)",
39597 "Vatican City (Città del Vaticano)",
39608 "Vietnam (Việt Nam)",
39613 "Wallis and Futuna (Wallis-et-Futuna)",
39618 "Western Sahara (الصحراء الغربية)",
39624 "Yemen (اليمن)",
39648 * This script refer to:
39649 * Title: International Telephone Input
39650 * Author: Jack O'Connor
39651 * Code version: v12.1.12
39652 * Availability: https://github.com/jackocnr/intl-tel-input.git
39656 * @class Roo.bootstrap.PhoneInput
39657 * @extends Roo.bootstrap.TriggerField
39658 * An input with International dial-code selection
39660 * @cfg {String} defaultDialCode default '+852'
39661 * @cfg {Array} preferedCountries default []
39664 * Create a new PhoneInput.
39665 * @param {Object} config Configuration options
39668 Roo.bootstrap.PhoneInput = function(config) {
39669 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39672 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39674 listWidth: undefined,
39676 selectedClass: 'active',
39678 invalidClass : "has-warning",
39680 validClass: 'has-success',
39682 allowed: '0123456789',
39685 * @cfg {String} defaultDialCode The default dial code when initializing the input
39687 defaultDialCode: '+852',
39690 * @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
39692 preferedCountries: false,
39694 getAutoCreate : function()
39696 var data = Roo.bootstrap.PhoneInputData();
39697 var align = this.labelAlign || this.parentLabelAlign();
39700 this.allCountries = [];
39701 this.dialCodeMapping = [];
39703 for (var i = 0; i < data.length; i++) {
39705 this.allCountries[i] = {
39709 priority: c[3] || 0,
39710 areaCodes: c[4] || null
39712 this.dialCodeMapping[c[2]] = {
39715 priority: c[3] || 0,
39716 areaCodes: c[4] || null
39728 cls : 'form-control tel-input',
39729 autocomplete: 'new-password'
39732 var hiddenInput = {
39735 cls: 'hidden-tel-input'
39739 hiddenInput.name = this.name;
39742 if (this.disabled) {
39743 input.disabled = true;
39746 var flag_container = {
39763 cls: this.hasFeedback ? 'has-feedback' : '',
39769 cls: 'dial-code-holder',
39776 cls: 'roo-select2-container input-group',
39783 if (this.fieldLabel.length) {
39786 tooltip: 'This field is required'
39792 cls: 'control-label',
39798 html: this.fieldLabel
39801 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39807 if(this.indicatorpos == 'right') {
39808 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39815 if(align == 'left') {
39823 if(this.labelWidth > 12){
39824 label.style = "width: " + this.labelWidth + 'px';
39826 if(this.labelWidth < 13 && this.labelmd == 0){
39827 this.labelmd = this.labelWidth;
39829 if(this.labellg > 0){
39830 label.cls += ' col-lg-' + this.labellg;
39831 input.cls += ' col-lg-' + (12 - this.labellg);
39833 if(this.labelmd > 0){
39834 label.cls += ' col-md-' + this.labelmd;
39835 container.cls += ' col-md-' + (12 - this.labelmd);
39837 if(this.labelsm > 0){
39838 label.cls += ' col-sm-' + this.labelsm;
39839 container.cls += ' col-sm-' + (12 - this.labelsm);
39841 if(this.labelxs > 0){
39842 label.cls += ' col-xs-' + this.labelxs;
39843 container.cls += ' col-xs-' + (12 - this.labelxs);
39853 var settings = this;
39855 ['xs','sm','md','lg'].map(function(size){
39856 if (settings[size]) {
39857 cfg.cls += ' col-' + size + '-' + settings[size];
39861 this.store = new Roo.data.Store({
39862 proxy : new Roo.data.MemoryProxy({}),
39863 reader : new Roo.data.JsonReader({
39874 'name' : 'dialCode',
39878 'name' : 'priority',
39882 'name' : 'areaCodes',
39889 if(!this.preferedCountries) {
39890 this.preferedCountries = [
39897 var p = this.preferedCountries.reverse();
39900 for (var i = 0; i < p.length; i++) {
39901 for (var j = 0; j < this.allCountries.length; j++) {
39902 if(this.allCountries[j].iso2 == p[i]) {
39903 var t = this.allCountries[j];
39904 this.allCountries.splice(j,1);
39905 this.allCountries.unshift(t);
39911 this.store.proxy.data = {
39913 data: this.allCountries
39919 initEvents : function()
39922 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39924 this.indicator = this.indicatorEl();
39925 this.flag = this.flagEl();
39926 this.dialCodeHolder = this.dialCodeHolderEl();
39928 this.trigger = this.el.select('div.flag-box',true).first();
39929 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39934 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39935 _this.list.setWidth(lw);
39938 this.list.on('mouseover', this.onViewOver, this);
39939 this.list.on('mousemove', this.onViewMove, this);
39940 this.inputEl().on("keyup", this.onKeyUp, this);
39942 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39944 this.view = new Roo.View(this.list, this.tpl, {
39945 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39948 this.view.on('click', this.onViewClick, this);
39949 this.setValue(this.defaultDialCode);
39952 onTriggerClick : function(e)
39954 Roo.log('trigger click');
39959 if(this.isExpanded()){
39961 this.hasFocus = false;
39963 this.store.load({});
39964 this.hasFocus = true;
39969 isExpanded : function()
39971 return this.list.isVisible();
39974 collapse : function()
39976 if(!this.isExpanded()){
39980 Roo.get(document).un('mousedown', this.collapseIf, this);
39981 Roo.get(document).un('mousewheel', this.collapseIf, this);
39982 this.fireEvent('collapse', this);
39986 expand : function()
39990 if(this.isExpanded() || !this.hasFocus){
39994 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39995 this.list.setWidth(lw);
39998 this.restrictHeight();
40000 Roo.get(document).on('mousedown', this.collapseIf, this);
40001 Roo.get(document).on('mousewheel', this.collapseIf, this);
40003 this.fireEvent('expand', this);
40006 restrictHeight : function()
40008 this.list.alignTo(this.inputEl(), this.listAlign);
40009 this.list.alignTo(this.inputEl(), this.listAlign);
40012 onViewOver : function(e, t)
40014 if(this.inKeyMode){
40017 var item = this.view.findItemFromChild(t);
40020 var index = this.view.indexOf(item);
40021 this.select(index, false);
40026 onViewClick : function(view, doFocus, el, e)
40028 var index = this.view.getSelectedIndexes()[0];
40030 var r = this.store.getAt(index);
40033 this.onSelect(r, index);
40035 if(doFocus !== false && !this.blockFocus){
40036 this.inputEl().focus();
40040 onViewMove : function(e, t)
40042 this.inKeyMode = false;
40045 select : function(index, scrollIntoView)
40047 this.selectedIndex = index;
40048 this.view.select(index);
40049 if(scrollIntoView !== false){
40050 var el = this.view.getNode(index);
40052 this.list.scrollChildIntoView(el, false);
40057 createList : function()
40059 this.list = Roo.get(document.body).createChild({
40061 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40062 style: 'display:none'
40065 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40068 collapseIf : function(e)
40070 var in_combo = e.within(this.el);
40071 var in_list = e.within(this.list);
40072 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40074 if (in_combo || in_list || is_list) {
40080 onSelect : function(record, index)
40082 if(this.fireEvent('beforeselect', this, record, index) !== false){
40084 this.setFlagClass(record.data.iso2);
40085 this.setDialCode(record.data.dialCode);
40086 this.hasFocus = false;
40088 this.fireEvent('select', this, record, index);
40092 flagEl : function()
40094 var flag = this.el.select('div.flag',true).first();
40101 dialCodeHolderEl : function()
40103 var d = this.el.select('input.dial-code-holder',true).first();
40110 setDialCode : function(v)
40112 this.dialCodeHolder.dom.value = '+'+v;
40115 setFlagClass : function(n)
40117 this.flag.dom.className = 'flag '+n;
40120 getValue : function()
40122 var v = this.inputEl().getValue();
40123 if(this.dialCodeHolder) {
40124 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40129 setValue : function(v)
40131 var d = this.getDialCode(v);
40133 //invalid dial code
40134 if(v.length == 0 || !d || d.length == 0) {
40136 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40137 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40143 this.setFlagClass(this.dialCodeMapping[d].iso2);
40144 this.setDialCode(d);
40145 this.inputEl().dom.value = v.replace('+'+d,'');
40146 this.hiddenEl().dom.value = this.getValue();
40151 getDialCode : function(v)
40155 if (v.length == 0) {
40156 return this.dialCodeHolder.dom.value;
40160 if (v.charAt(0) != "+") {
40163 var numericChars = "";
40164 for (var i = 1; i < v.length; i++) {
40165 var c = v.charAt(i);
40168 if (this.dialCodeMapping[numericChars]) {
40169 dialCode = v.substr(1, i);
40171 if (numericChars.length == 4) {
40181 this.setValue(this.defaultDialCode);
40185 hiddenEl : function()
40187 return this.el.select('input.hidden-tel-input',true).first();
40190 onKeyUp : function(e){
40192 var k = e.getKey();
40193 var c = e.getCharCode();
40196 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40197 this.allowed.indexOf(String.fromCharCode(c)) === -1
40202 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40205 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40209 this.setValue(this.getValue());
40214 * @class Roo.bootstrap.MoneyField
40215 * @extends Roo.bootstrap.ComboBox
40216 * Bootstrap MoneyField class
40219 * Create a new MoneyField.
40220 * @param {Object} config Configuration options
40223 Roo.bootstrap.MoneyField = function(config) {
40225 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40229 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40232 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40234 allowDecimals : true,
40236 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40238 decimalSeparator : ".",
40240 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40242 decimalPrecision : 0,
40244 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40246 allowNegative : true,
40248 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40252 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40254 minValue : Number.NEGATIVE_INFINITY,
40256 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40258 maxValue : Number.MAX_VALUE,
40260 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40262 minText : "The minimum value for this field is {0}",
40264 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40266 maxText : "The maximum value for this field is {0}",
40268 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40269 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40271 nanText : "{0} is not a valid number",
40273 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40277 * @cfg {String} defaults currency of the MoneyField
40278 * value should be in lkey
40280 defaultCurrency : false,
40282 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40284 thousandsDelimiter : false,
40294 getAutoCreate : function()
40296 var align = this.labelAlign || this.parentLabelAlign();
40308 cls : 'form-control roo-money-amount-input',
40309 autocomplete: 'new-password'
40312 var hiddenInput = {
40316 cls: 'hidden-number-input'
40320 hiddenInput.name = this.name;
40323 if (this.disabled) {
40324 input.disabled = true;
40327 var clg = 12 - this.inputlg;
40328 var cmd = 12 - this.inputmd;
40329 var csm = 12 - this.inputsm;
40330 var cxs = 12 - this.inputxs;
40334 cls : 'row roo-money-field',
40338 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40342 cls: 'roo-select2-container input-group',
40346 cls : 'form-control roo-money-currency-input',
40347 autocomplete: 'new-password',
40349 name : this.currencyName
40353 cls : 'input-group-addon',
40367 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40371 cls: this.hasFeedback ? 'has-feedback' : '',
40382 if (this.fieldLabel.length) {
40385 tooltip: 'This field is required'
40391 cls: 'control-label',
40397 html: this.fieldLabel
40400 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40406 if(this.indicatorpos == 'right') {
40407 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40414 if(align == 'left') {
40422 if(this.labelWidth > 12){
40423 label.style = "width: " + this.labelWidth + 'px';
40425 if(this.labelWidth < 13 && this.labelmd == 0){
40426 this.labelmd = this.labelWidth;
40428 if(this.labellg > 0){
40429 label.cls += ' col-lg-' + this.labellg;
40430 input.cls += ' col-lg-' + (12 - this.labellg);
40432 if(this.labelmd > 0){
40433 label.cls += ' col-md-' + this.labelmd;
40434 container.cls += ' col-md-' + (12 - this.labelmd);
40436 if(this.labelsm > 0){
40437 label.cls += ' col-sm-' + this.labelsm;
40438 container.cls += ' col-sm-' + (12 - this.labelsm);
40440 if(this.labelxs > 0){
40441 label.cls += ' col-xs-' + this.labelxs;
40442 container.cls += ' col-xs-' + (12 - this.labelxs);
40453 var settings = this;
40455 ['xs','sm','md','lg'].map(function(size){
40456 if (settings[size]) {
40457 cfg.cls += ' col-' + size + '-' + settings[size];
40464 initEvents : function()
40466 this.indicator = this.indicatorEl();
40468 this.initCurrencyEvent();
40470 this.initNumberEvent();
40473 initCurrencyEvent : function()
40476 throw "can not find store for combo";
40479 this.store = Roo.factory(this.store, Roo.data);
40480 this.store.parent = this;
40484 this.triggerEl = this.el.select('.input-group-addon', true).first();
40486 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40491 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40492 _this.list.setWidth(lw);
40495 this.list.on('mouseover', this.onViewOver, this);
40496 this.list.on('mousemove', this.onViewMove, this);
40497 this.list.on('scroll', this.onViewScroll, this);
40500 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40503 this.view = new Roo.View(this.list, this.tpl, {
40504 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40507 this.view.on('click', this.onViewClick, this);
40509 this.store.on('beforeload', this.onBeforeLoad, this);
40510 this.store.on('load', this.onLoad, this);
40511 this.store.on('loadexception', this.onLoadException, this);
40513 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40514 "up" : function(e){
40515 this.inKeyMode = true;
40519 "down" : function(e){
40520 if(!this.isExpanded()){
40521 this.onTriggerClick();
40523 this.inKeyMode = true;
40528 "enter" : function(e){
40531 if(this.fireEvent("specialkey", this, e)){
40532 this.onViewClick(false);
40538 "esc" : function(e){
40542 "tab" : function(e){
40545 if(this.fireEvent("specialkey", this, e)){
40546 this.onViewClick(false);
40554 doRelay : function(foo, bar, hname){
40555 if(hname == 'down' || this.scope.isExpanded()){
40556 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40564 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40568 initNumberEvent : function(e)
40570 this.inputEl().on("keydown" , this.fireKey, this);
40571 this.inputEl().on("focus", this.onFocus, this);
40572 this.inputEl().on("blur", this.onBlur, this);
40574 this.inputEl().relayEvent('keyup', this);
40576 if(this.indicator){
40577 this.indicator.addClass('invisible');
40580 this.originalValue = this.getValue();
40582 if(this.validationEvent == 'keyup'){
40583 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40584 this.inputEl().on('keyup', this.filterValidation, this);
40586 else if(this.validationEvent !== false){
40587 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40590 if(this.selectOnFocus){
40591 this.on("focus", this.preFocus, this);
40594 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40595 this.inputEl().on("keypress", this.filterKeys, this);
40597 this.inputEl().relayEvent('keypress', this);
40600 var allowed = "0123456789";
40602 if(this.allowDecimals){
40603 allowed += this.decimalSeparator;
40606 if(this.allowNegative){
40610 if(this.thousandsDelimiter) {
40614 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40616 var keyPress = function(e){
40618 var k = e.getKey();
40620 var c = e.getCharCode();
40623 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40624 allowed.indexOf(String.fromCharCode(c)) === -1
40630 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40634 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40639 this.inputEl().on("keypress", keyPress, this);
40643 onTriggerClick : function(e)
40650 this.loadNext = false;
40652 if(this.isExpanded()){
40657 this.hasFocus = true;
40659 if(this.triggerAction == 'all') {
40660 this.doQuery(this.allQuery, true);
40664 this.doQuery(this.getRawValue());
40667 getCurrency : function()
40669 var v = this.currencyEl().getValue();
40674 restrictHeight : function()
40676 this.list.alignTo(this.currencyEl(), this.listAlign);
40677 this.list.alignTo(this.currencyEl(), this.listAlign);
40680 onViewClick : function(view, doFocus, el, e)
40682 var index = this.view.getSelectedIndexes()[0];
40684 var r = this.store.getAt(index);
40687 this.onSelect(r, index);
40691 onSelect : function(record, index){
40693 if(this.fireEvent('beforeselect', this, record, index) !== false){
40695 this.setFromCurrencyData(index > -1 ? record.data : false);
40699 this.fireEvent('select', this, record, index);
40703 setFromCurrencyData : function(o)
40707 this.lastCurrency = o;
40709 if (this.currencyField) {
40710 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40712 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40715 this.lastSelectionText = currency;
40717 //setting default currency
40718 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40719 this.setCurrency(this.defaultCurrency);
40723 this.setCurrency(currency);
40726 setFromData : function(o)
40730 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40732 this.setFromCurrencyData(c);
40737 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40739 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40742 this.setValue(value);
40746 setCurrency : function(v)
40748 this.currencyValue = v;
40751 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40756 setValue : function(v)
40758 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40764 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40766 this.inputEl().dom.value = (v == '') ? '' :
40767 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40769 if(!this.allowZero && v === '0') {
40770 this.hiddenEl().dom.value = '';
40771 this.inputEl().dom.value = '';
40778 getRawValue : function()
40780 var v = this.inputEl().getValue();
40785 getValue : function()
40787 return this.fixPrecision(this.parseValue(this.getRawValue()));
40790 parseValue : function(value)
40792 if(this.thousandsDelimiter) {
40794 r = new RegExp(",", "g");
40795 value = value.replace(r, "");
40798 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40799 return isNaN(value) ? '' : value;
40803 fixPrecision : function(value)
40805 if(this.thousandsDelimiter) {
40807 r = new RegExp(",", "g");
40808 value = value.replace(r, "");
40811 var nan = isNaN(value);
40813 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40814 return nan ? '' : value;
40816 return parseFloat(value).toFixed(this.decimalPrecision);
40819 decimalPrecisionFcn : function(v)
40821 return Math.floor(v);
40824 validateValue : function(value)
40826 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40830 var num = this.parseValue(value);
40833 this.markInvalid(String.format(this.nanText, value));
40837 if(num < this.minValue){
40838 this.markInvalid(String.format(this.minText, this.minValue));
40842 if(num > this.maxValue){
40843 this.markInvalid(String.format(this.maxText, this.maxValue));
40850 validate : function()
40852 if(this.disabled || this.allowBlank){
40857 var currency = this.getCurrency();
40859 if(this.validateValue(this.getRawValue()) && currency.length){
40864 this.markInvalid();
40868 getName: function()
40873 beforeBlur : function()
40879 var v = this.parseValue(this.getRawValue());
40886 onBlur : function()
40890 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40891 //this.el.removeClass(this.focusClass);
40894 this.hasFocus = false;
40896 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40900 var v = this.getValue();
40902 if(String(v) !== String(this.startValue)){
40903 this.fireEvent('change', this, v, this.startValue);
40906 this.fireEvent("blur", this);
40909 inputEl : function()
40911 return this.el.select('.roo-money-amount-input', true).first();
40914 currencyEl : function()
40916 return this.el.select('.roo-money-currency-input', true).first();
40919 hiddenEl : function()
40921 return this.el.select('input.hidden-number-input',true).first();