4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
51 allowDomMove : false, // to stop relocations in parent onRender...
61 * Initialize Events for the element
63 initEvents : function() { },
69 can_build_overlaid : true,
71 container_method : false,
78 // returns the parent component..
79 return Roo.ComponentMgr.get(this.parentId)
85 onRender : function(ct, position)
87 // Roo.log("Call onRender: " + this.xtype);
89 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92 if (this.el.attr('xtype')) {
93 this.el.attr('xtypex', this.el.attr('xtype'));
94 this.el.dom.removeAttribute('xtype');
104 var cfg = Roo.apply({}, this.getAutoCreate());
106 cfg.id = this.id || Roo.id();
108 // fill in the extra attributes
109 if (this.xattr && typeof(this.xattr) =='object') {
110 for (var i in this.xattr) {
111 cfg[i] = this.xattr[i];
116 cfg.dataId = this.dataId;
120 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
123 if (this.style) { // fixme needs to support more complex style data.
124 cfg.style = this.style;
128 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
166 //Roo.log(['addxtype', cn]);
168 cn.parentType = this.xtype; //??
169 cn.parentId = this.id;
171 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 if (typeof(cn.container_method) == 'string') {
173 cntr = cn.container_method;
177 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
179 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
181 var build_from_html = Roo.XComponent.build_from_html;
183 var is_body = (tree.xtype == 'Body') ;
185 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
187 var self_cntr_el = Roo.get(this[cntr](false));
189 // do not try and build conditional elements
190 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
194 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196 return this.addxtypeChild(tree,cntr, is_body);
199 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
202 return this.addxtypeChild(Roo.apply({}, tree),cntr);
205 Roo.log('skipping render');
211 if (!build_from_html) {
215 // this i think handles overlaying multiple children of the same type
216 // with the sam eelement.. - which might be buggy..
218 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
224 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
228 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
235 addxtypeChild : function (tree, cntr, is_body)
237 Roo.debug && Roo.log('addxtypeChild:' + cntr);
239 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243 (typeof(tree['flexy:foreach']) != 'undefined');
247 skip_children = false;
248 // render the element if it's not BODY.
251 // if parent was disabled, then do not try and create the children..
252 if(!this[cntr](true)){
257 cn = Roo.factory(tree);
259 cn.parentType = this.xtype; //??
260 cn.parentId = this.id;
262 var build_from_html = Roo.XComponent.build_from_html;
265 // does the container contain child eleemnts with 'xtype' attributes.
266 // that match this xtype..
267 // note - when we render we create these as well..
268 // so we should check to see if body has xtype set.
269 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
271 var self_cntr_el = Roo.get(this[cntr](false));
272 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
274 //Roo.log(Roo.XComponent.build_from_html);
275 //Roo.log("got echild:");
278 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279 // and are not displayed -this causes this to use up the wrong element when matching.
280 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
283 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
290 //echild.dom.removeAttribute('xtype');
292 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293 Roo.debug && Roo.log(self_cntr_el);
294 Roo.debug && Roo.log(echild);
295 Roo.debug && Roo.log(cn);
301 // if object has flexy:if - then it may or may not be rendered.
302 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
303 // skip a flexy if element.
304 Roo.debug && Roo.log('skipping render');
305 Roo.debug && Roo.log(tree);
307 Roo.debug && Roo.log('skipping all children');
308 skip_children = true;
313 // actually if flexy:foreach is found, we really want to create
314 // multiple copies here...
316 //Roo.log(this[cntr]());
317 // some elements do not have render methods.. like the layouts...
319 if(this[cntr](true) === false){
324 cn.render && cn.render(this[cntr](true));
327 // then add the element..
334 if (typeof (tree.menu) != 'undefined') {
335 tree.menu.parentType = cn.xtype;
336 tree.menu.triggerEl = cn.el;
337 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
341 if (!tree.items || !tree.items.length) {
343 //Roo.log(["no children", this]);
348 var items = tree.items;
351 //Roo.log(items.length);
353 if (!skip_children) {
354 for(var i =0;i < items.length;i++) {
355 // Roo.log(['add child', items[i]]);
356 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
362 //Roo.log("fire childrenrendered");
364 cn.fireEvent('childrenrendered', this);
370 * Set the element that will be used to show or hide
372 setVisibilityEl : function(el)
374 this.visibilityEl = el;
378 * Get the element that will be used to show or hide
380 getVisibilityEl : function()
382 if (typeof(this.visibilityEl) == 'object') {
383 return this.visibilityEl;
386 if (typeof(this.visibilityEl) == 'string') {
387 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
394 * Show a component - removes 'hidden' class
398 if(!this.getVisibilityEl()){
402 this.getVisibilityEl().removeClass('hidden');
407 * Hide a component - adds 'hidden' class
411 if(!this.getVisibilityEl()){
415 this.getVisibilityEl().addClass('hidden');
428 * @class Roo.bootstrap.Body
429 * @extends Roo.bootstrap.Component
430 * Bootstrap Body class
434 * @param {Object} config The config object
437 Roo.bootstrap.Body = function(config){
439 config = config || {};
441 Roo.bootstrap.Body.superclass.constructor.call(this, config);
442 this.el = Roo.get(config.el ? config.el : document.body );
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
450 is_body : true,// just to make sure it's constructed?
455 onRender : function(ct, position)
457 /* Roo.log("Roo.bootstrap.Body - onRender");
458 if (this.cls && this.cls.length) {
459 Roo.get(document.body).addClass(this.cls);
478 * @class Roo.bootstrap.ButtonGroup
479 * @extends Roo.bootstrap.Component
480 * Bootstrap ButtonGroup class
481 * @cfg {String} size lg | sm | xs (default empty normal)
482 * @cfg {String} align vertical | justified (default none)
483 * @cfg {String} direction up | down (default down)
484 * @cfg {Boolean} toolbar false | true
485 * @cfg {Boolean} btn true | false
490 * @param {Object} config The config object
493 Roo.bootstrap.ButtonGroup = function(config){
494 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
505 getAutoCreate : function(){
511 cfg.html = this.html || cfg.html;
522 if (['vertical','justified'].indexOf(this.align)!==-1) {
523 cfg.cls = 'btn-group-' + this.align;
525 if (this.align == 'justified') {
526 console.log(this.items);
530 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531 cfg.cls += ' btn-group-' + this.size;
534 if (this.direction == 'up') {
535 cfg.cls += ' dropup' ;
551 * @class Roo.bootstrap.Button
552 * @extends Roo.bootstrap.Component
553 * Bootstrap Button class
554 * @cfg {String} html The button content
555 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
556 * @cfg {String} size ( lg | sm | xs)
557 * @cfg {String} tag ( a | input | submit)
558 * @cfg {String} href empty or href
559 * @cfg {Boolean} disabled default false;
560 * @cfg {Boolean} isClose default false;
561 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
562 * @cfg {String} badge text for badge
563 * @cfg {String} theme (default|glow)
564 * @cfg {Boolean} inverse dark themed version
565 * @cfg {Boolean} toggle is it a slidy toggle button
566 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567 * @cfg {String} ontext text for on slidy toggle state
568 * @cfg {String} offtext text for off slidy toggle state
569 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
570 * @cfg {Boolean} removeClass remove the standard class..
571 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
574 * Create a new button
575 * @param {Object} config The config object
579 Roo.bootstrap.Button = function(config){
580 Roo.bootstrap.Button.superclass.constructor.call(this, config);
581 this.weightClass = ["btn-default",
593 * When a butotn is pressed
594 * @param {Roo.bootstrap.Button} btn
595 * @param {Roo.EventObject} e
600 * After the button has been toggles
601 * @param {Roo.bootstrap.Button} btn
602 * @param {Roo.EventObject} e
603 * @param {boolean} pressed (also available as button.pressed)
609 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
627 preventDefault: true,
635 getAutoCreate : function(){
643 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
644 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
651 if (this.toggle == true) {
654 cls: 'slider-frame roo-button',
659 'data-off-text':'OFF',
660 cls: 'slider-button',
666 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667 cfg.cls += ' '+this.weight;
676 cfg["aria-hidden"] = true;
678 cfg.html = "×";
684 if (this.theme==='default') {
685 cfg.cls = 'btn roo-button';
687 //if (this.parentType != 'Navbar') {
688 this.weight = this.weight.length ? this.weight : 'default';
690 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
692 cfg.cls += ' btn-' + this.weight;
694 } else if (this.theme==='glow') {
697 cfg.cls = 'btn-glow roo-button';
699 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
701 cfg.cls += ' ' + this.weight;
707 this.cls += ' inverse';
711 if (this.active || this.pressed === true) {
712 cfg.cls += ' active';
716 cfg.disabled = 'disabled';
720 Roo.log('changing to ul' );
722 this.glyphicon = 'caret';
725 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
727 //gsRoo.log(this.parentType);
728 if (this.parentType === 'Navbar' && !this.parent().bar) {
729 Roo.log('changing to li?');
738 href : this.href || '#'
741 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
742 cfg.cls += ' dropdown';
749 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
751 if (this.glyphicon) {
752 cfg.html = ' ' + cfg.html;
757 cls: 'glyphicon glyphicon-' + this.glyphicon
767 // cfg.cls='btn roo-button';
771 var value = cfg.html;
776 cls: 'glyphicon glyphicon-' + this.glyphicon,
795 cfg.cls += ' dropdown';
796 cfg.html = typeof(cfg.html) != 'undefined' ?
797 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
800 if (cfg.tag !== 'a' && this.href !== '') {
801 throw "Tag must be a to set href.";
802 } else if (this.href.length > 0) {
803 cfg.href = this.href;
806 if(this.removeClass){
811 cfg.target = this.target;
816 initEvents: function() {
817 // Roo.log('init events?');
818 // Roo.log(this.el.dom);
821 if (typeof (this.menu) != 'undefined') {
822 this.menu.parentType = this.xtype;
823 this.menu.triggerEl = this.el;
824 this.addxtype(Roo.apply({}, this.menu));
828 if (this.el.hasClass('roo-button')) {
829 this.el.on('click', this.onClick, this);
831 this.el.select('.roo-button').on('click', this.onClick, this);
834 if(this.removeClass){
835 this.el.on('click', this.onClick, this);
838 this.el.enableDisplayMode();
841 onClick : function(e)
847 Roo.log('button on click ');
848 if(this.preventDefault){
852 if (this.pressed === true || this.pressed === false) {
853 this.toggleActive(e);
857 this.fireEvent('click', this, e);
861 * Enables this button
865 this.disabled = false;
866 this.el.removeClass('disabled');
870 * Disable this button
874 this.disabled = true;
875 this.el.addClass('disabled');
878 * sets the active state on/off,
879 * @param {Boolean} state (optional) Force a particular state
881 setActive : function(v) {
883 this.el[v ? 'addClass' : 'removeClass']('active');
887 * toggles the current active state
889 toggleActive : function(e)
891 this.setActive(!this.pressed);
892 this.fireEvent('toggle', this, e, !this.pressed);
895 * get the current active state
896 * @return {boolean} true if it's active
898 isActive : function()
900 return this.el.hasClass('active');
903 * set the text of the first selected button
905 setText : function(str)
907 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
910 * get the text of the first selected button
914 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
925 setWeight : function(str)
927 this.el.removeClass(this.weightClass);
928 this.el.addClass('btn-' + str);
942 * @class Roo.bootstrap.Column
943 * @extends Roo.bootstrap.Component
944 * Bootstrap Column class
945 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
946 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
947 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
948 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
949 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
950 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
951 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
952 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
955 * @cfg {Boolean} hidden (true|false) hide the element
956 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
957 * @cfg {String} fa (ban|check|...) font awesome icon
958 * @cfg {Number} fasize (1|2|....) font awsome size
960 * @cfg {String} icon (info-sign|check|...) glyphicon name
962 * @cfg {String} html content of column.
965 * Create a new Column
966 * @param {Object} config The config object
969 Roo.bootstrap.Column = function(config){
970 Roo.bootstrap.Column.superclass.constructor.call(this, config);
973 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
991 getAutoCreate : function(){
992 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1000 ['xs','sm','md','lg'].map(function(size){
1001 //Roo.log( size + ':' + settings[size]);
1003 if (settings[size+'off'] !== false) {
1004 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1007 if (settings[size] === false) {
1011 if (!settings[size]) { // 0 = hidden
1012 cfg.cls += ' hidden-' + size;
1015 cfg.cls += ' col-' + size + '-' + settings[size];
1020 cfg.cls += ' hidden';
1023 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1024 cfg.cls +=' alert alert-' + this.alert;
1028 if (this.html.length) {
1029 cfg.html = this.html;
1033 if (this.fasize > 1) {
1034 fasize = ' fa-' + this.fasize + 'x';
1036 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1041 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1060 * @class Roo.bootstrap.Container
1061 * @extends Roo.bootstrap.Component
1062 * Bootstrap Container class
1063 * @cfg {Boolean} jumbotron is it a jumbotron element
1064 * @cfg {String} html content of element
1065 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1066 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1067 * @cfg {String} header content of header (for panel)
1068 * @cfg {String} footer content of footer (for panel)
1069 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1070 * @cfg {String} tag (header|aside|section) type of HTML tag.
1071 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1072 * @cfg {String} fa font awesome icon
1073 * @cfg {String} icon (info-sign|check|...) glyphicon name
1074 * @cfg {Boolean} hidden (true|false) hide the element
1075 * @cfg {Boolean} expandable (true|false) default false
1076 * @cfg {Boolean} expanded (true|false) default true
1077 * @cfg {String} rheader contet on the right of header
1078 * @cfg {Boolean} clickable (true|false) default false
1082 * Create a new Container
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Container = function(config){
1087 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1093 * After the panel has been expand
1095 * @param {Roo.bootstrap.Container} this
1100 * After the panel has been collapsed
1102 * @param {Roo.bootstrap.Container} this
1107 * When a element is chick
1108 * @param {Roo.bootstrap.Container} this
1109 * @param {Roo.EventObject} e
1115 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1133 getChildContainer : function() {
1139 if (this.panel.length) {
1140 return this.el.select('.panel-body',true).first();
1147 getAutoCreate : function(){
1150 tag : this.tag || 'div',
1154 if (this.jumbotron) {
1155 cfg.cls = 'jumbotron';
1160 // - this is applied by the parent..
1162 // cfg.cls = this.cls + '';
1165 if (this.sticky.length) {
1167 var bd = Roo.get(document.body);
1168 if (!bd.hasClass('bootstrap-sticky')) {
1169 bd.addClass('bootstrap-sticky');
1170 Roo.select('html',true).setStyle('height', '100%');
1173 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1177 if (this.well.length) {
1178 switch (this.well) {
1181 cfg.cls +=' well well-' +this.well;
1190 cfg.cls += ' hidden';
1194 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1195 cfg.cls +=' alert alert-' + this.alert;
1200 if (this.panel.length) {
1201 cfg.cls += ' panel panel-' + this.panel;
1203 if (this.header.length) {
1207 if(this.expandable){
1209 cfg.cls = cfg.cls + ' expandable';
1213 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1221 cls : 'panel-title',
1222 html : (this.expandable ? ' ' : '') + this.header
1226 cls: 'panel-header-right',
1232 cls : 'panel-heading',
1233 style : this.expandable ? 'cursor: pointer' : '',
1241 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1246 if (this.footer.length) {
1248 cls : 'panel-footer',
1257 body.html = this.html || cfg.html;
1258 // prefix with the icons..
1260 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1263 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1268 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1269 cfg.cls = 'container';
1275 initEvents: function()
1277 if(this.expandable){
1278 var headerEl = this.headerEl();
1281 headerEl.on('click', this.onToggleClick, this);
1286 this.el.on('click', this.onClick, this);
1291 onToggleClick : function()
1293 var headerEl = this.headerEl();
1309 if(this.fireEvent('expand', this)) {
1311 this.expanded = true;
1313 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1315 this.el.select('.panel-body',true).first().removeClass('hide');
1317 var toggleEl = this.toggleEl();
1323 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1328 collapse : function()
1330 if(this.fireEvent('collapse', this)) {
1332 this.expanded = false;
1334 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1335 this.el.select('.panel-body',true).first().addClass('hide');
1337 var toggleEl = this.toggleEl();
1343 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1347 toggleEl : function()
1349 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1353 return this.el.select('.panel-heading .fa',true).first();
1356 headerEl : function()
1358 if(!this.el || !this.panel.length || !this.header.length){
1362 return this.el.select('.panel-heading',true).first()
1367 if(!this.el || !this.panel.length){
1371 return this.el.select('.panel-body',true).first()
1374 titleEl : function()
1376 if(!this.el || !this.panel.length || !this.header.length){
1380 return this.el.select('.panel-title',true).first();
1383 setTitle : function(v)
1385 var titleEl = this.titleEl();
1391 titleEl.dom.innerHTML = v;
1394 getTitle : function()
1397 var titleEl = this.titleEl();
1403 return titleEl.dom.innerHTML;
1406 setRightTitle : function(v)
1408 var t = this.el.select('.panel-header-right',true).first();
1414 t.dom.innerHTML = v;
1417 onClick : function(e)
1421 this.fireEvent('click', this, e);
1434 * @class Roo.bootstrap.Img
1435 * @extends Roo.bootstrap.Component
1436 * Bootstrap Img class
1437 * @cfg {Boolean} imgResponsive false | true
1438 * @cfg {String} border rounded | circle | thumbnail
1439 * @cfg {String} src image source
1440 * @cfg {String} alt image alternative text
1441 * @cfg {String} href a tag href
1442 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1443 * @cfg {String} xsUrl xs image source
1444 * @cfg {String} smUrl sm image source
1445 * @cfg {String} mdUrl md image source
1446 * @cfg {String} lgUrl lg image source
1449 * Create a new Input
1450 * @param {Object} config The config object
1453 Roo.bootstrap.Img = function(config){
1454 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1460 * The img click event for the img.
1461 * @param {Roo.EventObject} e
1467 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1469 imgResponsive: true,
1479 getAutoCreate : function()
1481 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1482 return this.createSingleImg();
1487 cls: 'roo-image-responsive-group',
1492 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1494 if(!_this[size + 'Url']){
1500 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1501 html: _this.html || cfg.html,
1502 src: _this[size + 'Url']
1505 img.cls += ' roo-image-responsive-' + size;
1507 var s = ['xs', 'sm', 'md', 'lg'];
1509 s.splice(s.indexOf(size), 1);
1511 Roo.each(s, function(ss){
1512 img.cls += ' hidden-' + ss;
1515 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1516 cfg.cls += ' img-' + _this.border;
1520 cfg.alt = _this.alt;
1533 a.target = _this.target;
1537 cfg.cn.push((_this.href) ? a : img);
1544 createSingleImg : function()
1548 cls: (this.imgResponsive) ? 'img-responsive' : '',
1550 src : 'about:blank' // just incase src get's set to undefined?!?
1553 cfg.html = this.html || cfg.html;
1555 cfg.src = this.src || cfg.src;
1557 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1558 cfg.cls += ' img-' + this.border;
1575 a.target = this.target;
1580 return (this.href) ? a : cfg;
1583 initEvents: function()
1586 this.el.on('click', this.onClick, this);
1591 onClick : function(e)
1593 Roo.log('img onclick');
1594 this.fireEvent('click', this, e);
1597 * Sets the url of the image - used to update it
1598 * @param {String} url the url of the image
1601 setSrc : function(url)
1605 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1606 this.el.dom.src = url;
1610 this.el.select('img', true).first().dom.src = url;
1626 * @class Roo.bootstrap.Link
1627 * @extends Roo.bootstrap.Component
1628 * Bootstrap Link Class
1629 * @cfg {String} alt image alternative text
1630 * @cfg {String} href a tag href
1631 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1632 * @cfg {String} html the content of the link.
1633 * @cfg {String} anchor name for the anchor link
1634 * @cfg {String} fa - favicon
1636 * @cfg {Boolean} preventDefault (true | false) default false
1640 * Create a new Input
1641 * @param {Object} config The config object
1644 Roo.bootstrap.Link = function(config){
1645 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1651 * The img click event for the img.
1652 * @param {Roo.EventObject} e
1658 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1662 preventDefault: false,
1668 getAutoCreate : function()
1670 var html = this.html || '';
1672 if (this.fa !== false) {
1673 html = '<i class="fa fa-' + this.fa + '"></i>';
1678 // anchor's do not require html/href...
1679 if (this.anchor === false) {
1681 cfg.href = this.href || '#';
1683 cfg.name = this.anchor;
1684 if (this.html !== false || this.fa !== false) {
1687 if (this.href !== false) {
1688 cfg.href = this.href;
1692 if(this.alt !== false){
1697 if(this.target !== false) {
1698 cfg.target = this.target;
1704 initEvents: function() {
1706 if(!this.href || this.preventDefault){
1707 this.el.on('click', this.onClick, this);
1711 onClick : function(e)
1713 if(this.preventDefault){
1716 //Roo.log('img onclick');
1717 this.fireEvent('click', this, e);
1730 * @class Roo.bootstrap.Header
1731 * @extends Roo.bootstrap.Component
1732 * Bootstrap Header class
1733 * @cfg {String} html content of header
1734 * @cfg {Number} level (1|2|3|4|5|6) default 1
1737 * Create a new Header
1738 * @param {Object} config The config object
1742 Roo.bootstrap.Header = function(config){
1743 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1746 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1754 getAutoCreate : function(){
1759 tag: 'h' + (1 *this.level),
1760 html: this.html || ''
1772 * Ext JS Library 1.1.1
1773 * Copyright(c) 2006-2007, Ext JS, LLC.
1775 * Originally Released Under LGPL - original licence link has changed is not relivant.
1778 * <script type="text/javascript">
1782 * @class Roo.bootstrap.MenuMgr
1783 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1786 Roo.bootstrap.MenuMgr = function(){
1787 var menus, active, groups = {}, attached = false, lastShow = new Date();
1789 // private - called when first menu is created
1792 active = new Roo.util.MixedCollection();
1793 Roo.get(document).addKeyListener(27, function(){
1794 if(active.length > 0){
1802 if(active && active.length > 0){
1803 var c = active.clone();
1813 if(active.length < 1){
1814 Roo.get(document).un("mouseup", onMouseDown);
1822 var last = active.last();
1823 lastShow = new Date();
1826 Roo.get(document).on("mouseup", onMouseDown);
1831 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1832 m.parentMenu.activeChild = m;
1833 }else if(last && last.isVisible()){
1834 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1839 function onBeforeHide(m){
1841 m.activeChild.hide();
1843 if(m.autoHideTimer){
1844 clearTimeout(m.autoHideTimer);
1845 delete m.autoHideTimer;
1850 function onBeforeShow(m){
1851 var pm = m.parentMenu;
1852 if(!pm && !m.allowOtherMenus){
1854 }else if(pm && pm.activeChild && active != m){
1855 pm.activeChild.hide();
1859 // private this should really trigger on mouseup..
1860 function onMouseDown(e){
1861 Roo.log("on Mouse Up");
1863 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1864 Roo.log("MenuManager hideAll");
1873 function onBeforeCheck(mi, state){
1875 var g = groups[mi.group];
1876 for(var i = 0, l = g.length; i < l; i++){
1878 g[i].setChecked(false);
1887 * Hides all menus that are currently visible
1889 hideAll : function(){
1894 register : function(menu){
1898 menus[menu.id] = menu;
1899 menu.on("beforehide", onBeforeHide);
1900 menu.on("hide", onHide);
1901 menu.on("beforeshow", onBeforeShow);
1902 menu.on("show", onShow);
1904 if(g && menu.events["checkchange"]){
1908 groups[g].push(menu);
1909 menu.on("checkchange", onCheck);
1914 * Returns a {@link Roo.menu.Menu} object
1915 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1916 * be used to generate and return a new Menu instance.
1918 get : function(menu){
1919 if(typeof menu == "string"){ // menu id
1921 }else if(menu.events){ // menu instance
1924 /*else if(typeof menu.length == 'number'){ // array of menu items?
1925 return new Roo.bootstrap.Menu({items:menu});
1926 }else{ // otherwise, must be a config
1927 return new Roo.bootstrap.Menu(menu);
1934 unregister : function(menu){
1935 delete menus[menu.id];
1936 menu.un("beforehide", onBeforeHide);
1937 menu.un("hide", onHide);
1938 menu.un("beforeshow", onBeforeShow);
1939 menu.un("show", onShow);
1941 if(g && menu.events["checkchange"]){
1942 groups[g].remove(menu);
1943 menu.un("checkchange", onCheck);
1948 registerCheckable : function(menuItem){
1949 var g = menuItem.group;
1954 groups[g].push(menuItem);
1955 menuItem.on("beforecheckchange", onBeforeCheck);
1960 unregisterCheckable : function(menuItem){
1961 var g = menuItem.group;
1963 groups[g].remove(menuItem);
1964 menuItem.un("beforecheckchange", onBeforeCheck);
1976 * @class Roo.bootstrap.Menu
1977 * @extends Roo.bootstrap.Component
1978 * Bootstrap Menu class - container for MenuItems
1979 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1980 * @cfg {bool} hidden if the menu should be hidden when rendered.
1981 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1982 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1986 * @param {Object} config The config object
1990 Roo.bootstrap.Menu = function(config){
1991 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1992 if (this.registerMenu && this.type != 'treeview') {
1993 Roo.bootstrap.MenuMgr.register(this);
1998 * Fires before this menu is displayed
1999 * @param {Roo.menu.Menu} this
2004 * Fires before this menu is hidden
2005 * @param {Roo.menu.Menu} this
2010 * Fires after this menu is displayed
2011 * @param {Roo.menu.Menu} this
2016 * Fires after this menu is hidden
2017 * @param {Roo.menu.Menu} this
2022 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2023 * @param {Roo.menu.Menu} this
2024 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2025 * @param {Roo.EventObject} e
2030 * Fires when the mouse is hovering over this menu
2031 * @param {Roo.menu.Menu} this
2032 * @param {Roo.EventObject} e
2033 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2038 * Fires when the mouse exits this menu
2039 * @param {Roo.menu.Menu} this
2040 * @param {Roo.EventObject} e
2041 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2046 * Fires when a menu item contained in this menu is clicked
2047 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2048 * @param {Roo.EventObject} e
2052 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2055 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2059 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2062 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2064 registerMenu : true,
2066 menuItems :false, // stores the menu items..
2076 getChildContainer : function() {
2080 getAutoCreate : function(){
2082 //if (['right'].indexOf(this.align)!==-1) {
2083 // cfg.cn[1].cls += ' pull-right'
2089 cls : 'dropdown-menu' ,
2090 style : 'z-index:1000'
2094 if (this.type === 'submenu') {
2095 cfg.cls = 'submenu active';
2097 if (this.type === 'treeview') {
2098 cfg.cls = 'treeview-menu';
2103 initEvents : function() {
2105 // Roo.log("ADD event");
2106 // Roo.log(this.triggerEl.dom);
2108 this.triggerEl.on('click', this.onTriggerClick, this);
2110 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2112 this.triggerEl.addClass('dropdown-toggle');
2115 this.el.on('touchstart' , this.onTouch, this);
2117 this.el.on('click' , this.onClick, this);
2119 this.el.on("mouseover", this.onMouseOver, this);
2120 this.el.on("mouseout", this.onMouseOut, this);
2124 findTargetItem : function(e)
2126 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2130 //Roo.log(t); Roo.log(t.id);
2132 //Roo.log(this.menuitems);
2133 return this.menuitems.get(t.id);
2135 //return this.items.get(t.menuItemId);
2141 onTouch : function(e)
2143 Roo.log("menu.onTouch");
2144 //e.stopEvent(); this make the user popdown broken
2148 onClick : function(e)
2150 Roo.log("menu.onClick");
2152 var t = this.findTargetItem(e);
2153 if(!t || t.isContainer){
2158 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2159 if(t == this.activeItem && t.shouldDeactivate(e)){
2160 this.activeItem.deactivate();
2161 delete this.activeItem;
2165 this.setActiveItem(t, true);
2173 Roo.log('pass click event');
2177 this.fireEvent("click", this, t, e);
2181 if(!t.href.length || t.href == '#'){
2182 (function() { _this.hide(); }).defer(100);
2187 onMouseOver : function(e){
2188 var t = this.findTargetItem(e);
2191 // if(t.canActivate && !t.disabled){
2192 // this.setActiveItem(t, true);
2196 this.fireEvent("mouseover", this, e, t);
2198 isVisible : function(){
2199 return !this.hidden;
2201 onMouseOut : function(e){
2202 var t = this.findTargetItem(e);
2205 // if(t == this.activeItem && t.shouldDeactivate(e)){
2206 // this.activeItem.deactivate();
2207 // delete this.activeItem;
2210 this.fireEvent("mouseout", this, e, t);
2215 * Displays this menu relative to another element
2216 * @param {String/HTMLElement/Roo.Element} element The element to align to
2217 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2218 * the element (defaults to this.defaultAlign)
2219 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2221 show : function(el, pos, parentMenu){
2222 this.parentMenu = parentMenu;
2226 this.fireEvent("beforeshow", this);
2228 Roo.log(this.el.getAlignToXY(el, pos || this.defaultAlign));
2230 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2233 * Displays this menu at a specific xy position
2234 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2235 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2237 showAt : function(xy, parentMenu, /* private: */_e){
2238 this.parentMenu = parentMenu;
2243 this.fireEvent("beforeshow", this);
2244 // xy = this.el.adjustForConstraints(xy);
2247 Roo.log(this.el.getAlignToXY(this.triggerEl, '?'));
2250 this.hideMenuItems();
2251 this.hidden = false;
2252 this.triggerEl.addClass('open');
2254 Roo.log(this.el.getAlignToXY(this.triggerEl, '?'));
2256 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2257 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2260 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2265 this.fireEvent("show", this);
2271 this.doFocus.defer(50, this);
2275 doFocus : function(){
2277 this.focusEl.focus();
2282 * Hides this menu and optionally all parent menus
2283 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2285 hide : function(deep)
2288 this.hideMenuItems();
2289 if(this.el && this.isVisible()){
2290 this.fireEvent("beforehide", this);
2291 if(this.activeItem){
2292 this.activeItem.deactivate();
2293 this.activeItem = null;
2295 this.triggerEl.removeClass('open');;
2297 this.fireEvent("hide", this);
2299 if(deep === true && this.parentMenu){
2300 this.parentMenu.hide(true);
2304 onTriggerClick : function(e)
2306 Roo.log('trigger click');
2308 var target = e.getTarget();
2310 Roo.log(target.nodeName.toLowerCase());
2312 if(target.nodeName.toLowerCase() === 'i'){
2318 onTriggerPress : function(e)
2320 Roo.log('trigger press');
2321 //Roo.log(e.getTarget());
2322 // Roo.log(this.triggerEl.dom);
2324 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2325 var pel = Roo.get(e.getTarget());
2326 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2327 Roo.log('is treeview or dropdown?');
2331 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2335 if (this.isVisible()) {
2340 this.show(this.triggerEl, false, false);
2343 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2350 hideMenuItems : function()
2352 Roo.log("hide Menu Items");
2356 //$(backdrop).remove()
2357 this.el.select('.open',true).each(function(aa) {
2359 aa.removeClass('open');
2360 //var parent = getParent($(this))
2361 //var relatedTarget = { relatedTarget: this }
2363 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2364 //if (e.isDefaultPrevented()) return
2365 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2368 addxtypeChild : function (tree, cntr) {
2369 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2371 this.menuitems.add(comp);
2383 this.getEl().dom.innerHTML = '';
2384 this.menuitems.clear();
2398 * @class Roo.bootstrap.MenuItem
2399 * @extends Roo.bootstrap.Component
2400 * Bootstrap MenuItem class
2401 * @cfg {String} html the menu label
2402 * @cfg {String} href the link
2403 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2404 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2405 * @cfg {Boolean} active used on sidebars to highlight active itesm
2406 * @cfg {String} fa favicon to show on left of menu item.
2407 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2411 * Create a new MenuItem
2412 * @param {Object} config The config object
2416 Roo.bootstrap.MenuItem = function(config){
2417 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2422 * The raw click event for the entire grid.
2423 * @param {Roo.bootstrap.MenuItem} this
2424 * @param {Roo.EventObject} e
2430 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2434 preventDefault: false,
2435 isContainer : false,
2439 getAutoCreate : function(){
2441 if(this.isContainer){
2444 cls: 'dropdown-menu-item'
2458 if (this.fa !== false) {
2461 cls : 'fa fa-' + this.fa
2470 cls: 'dropdown-menu-item',
2473 if (this.parent().type == 'treeview') {
2474 cfg.cls = 'treeview-menu';
2477 cfg.cls += ' active';
2482 anc.href = this.href || cfg.cn[0].href ;
2483 ctag.html = this.html || cfg.cn[0].html ;
2487 initEvents: function()
2489 if (this.parent().type == 'treeview') {
2490 this.el.select('a').on('click', this.onClick, this);
2494 this.menu.parentType = this.xtype;
2495 this.menu.triggerEl = this.el;
2496 this.menu = this.addxtype(Roo.apply({}, this.menu));
2500 onClick : function(e)
2502 Roo.log('item on click ');
2504 if(this.preventDefault){
2507 //this.parent().hideMenuItems();
2509 this.fireEvent('click', this, e);
2528 * @class Roo.bootstrap.MenuSeparator
2529 * @extends Roo.bootstrap.Component
2530 * Bootstrap MenuSeparator class
2533 * Create a new MenuItem
2534 * @param {Object} config The config object
2538 Roo.bootstrap.MenuSeparator = function(config){
2539 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2542 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2544 getAutoCreate : function(){
2563 * @class Roo.bootstrap.Modal
2564 * @extends Roo.bootstrap.Component
2565 * Bootstrap Modal class
2566 * @cfg {String} title Title of dialog
2567 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2568 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2569 * @cfg {Boolean} specificTitle default false
2570 * @cfg {Array} buttons Array of buttons or standard button set..
2571 * @cfg {String} buttonPosition (left|right|center) default right
2572 * @cfg {Boolean} animate default true
2573 * @cfg {Boolean} allow_close default true
2574 * @cfg {Boolean} fitwindow default false
2575 * @cfg {String} size (sm|lg) default empty
2579 * Create a new Modal Dialog
2580 * @param {Object} config The config object
2583 Roo.bootstrap.Modal = function(config){
2584 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2589 * The raw btnclick event for the button
2590 * @param {Roo.EventObject} e
2595 * Fire when dialog resize
2596 * @param {Roo.bootstrap.Modal} this
2597 * @param {Roo.EventObject} e
2601 this.buttons = this.buttons || [];
2604 this.tmpl = Roo.factory(this.tmpl);
2609 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2611 title : 'test dialog',
2621 specificTitle: false,
2623 buttonPosition: 'right',
2642 onRender : function(ct, position)
2644 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2647 var cfg = Roo.apply({}, this.getAutoCreate());
2650 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2652 //if (!cfg.name.length) {
2656 cfg.cls += ' ' + this.cls;
2659 cfg.style = this.style;
2661 this.el = Roo.get(document.body).createChild(cfg, position);
2663 //var type = this.el.dom.type;
2666 if(this.tabIndex !== undefined){
2667 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2670 this.dialogEl = this.el.select('.modal-dialog',true).first();
2671 this.bodyEl = this.el.select('.modal-body',true).first();
2672 this.closeEl = this.el.select('.modal-header .close', true).first();
2673 this.headerEl = this.el.select('.modal-header',true).first();
2674 this.titleEl = this.el.select('.modal-title',true).first();
2675 this.footerEl = this.el.select('.modal-footer',true).first();
2677 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2679 //this.el.addClass("x-dlg-modal");
2681 if (this.buttons.length) {
2682 Roo.each(this.buttons, function(bb) {
2683 var b = Roo.apply({}, bb);
2684 b.xns = b.xns || Roo.bootstrap;
2685 b.xtype = b.xtype || 'Button';
2686 if (typeof(b.listeners) == 'undefined') {
2687 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2690 var btn = Roo.factory(b);
2692 btn.render(this.el.select('.modal-footer div').first());
2696 // render the children.
2699 if(typeof(this.items) != 'undefined'){
2700 var items = this.items;
2703 for(var i =0;i < items.length;i++) {
2704 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2708 this.items = nitems;
2710 // where are these used - they used to be body/close/footer
2714 //this.el.addClass([this.fieldClass, this.cls]);
2718 getAutoCreate : function(){
2723 html : this.html || ''
2728 cls : 'modal-title',
2732 if(this.specificTitle){
2738 if (this.allow_close) {
2750 if(this.size.length){
2751 size = 'modal-' + this.size;
2758 cls: "modal-dialog " + size,
2761 cls : "modal-content",
2764 cls : 'modal-header',
2769 cls : 'modal-footer',
2773 cls: 'btn-' + this.buttonPosition
2790 modal.cls += ' fade';
2796 getChildContainer : function() {
2801 getButtonContainer : function() {
2802 return this.el.select('.modal-footer div',true).first();
2805 initEvents : function()
2807 if (this.allow_close) {
2808 this.closeEl.on('click', this.hide, this);
2810 Roo.EventManager.onWindowResize(this.resize, this, true);
2817 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2818 if (this.fitwindow) {
2819 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2820 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2825 setSize : function(w,h)
2835 if (!this.rendered) {
2839 //this.el.setStyle('display', 'block');
2840 this.el.removeClass('hideing');
2841 this.el.addClass('show');
2843 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2846 this.el.addClass('in');
2849 this.el.addClass('in');
2853 // not sure how we can show data in here..
2855 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2858 Roo.get(document.body).addClass("x-body-masked");
2860 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2861 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2862 this.maskEl.addClass('show');
2866 this.fireEvent('show', this);
2868 // set zindex here - otherwise it appears to be ignored...
2869 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2872 this.items.forEach( function(e) {
2873 e.layout ? e.layout() : false;
2881 if(this.fireEvent("beforehide", this) !== false){
2882 this.maskEl.removeClass('show');
2883 Roo.get(document.body).removeClass("x-body-masked");
2884 this.el.removeClass('in');
2885 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2887 if(this.animate){ // why
2888 this.el.addClass('hideing');
2890 if (!this.el.hasClass('hideing')) {
2891 return; // it's been shown again...
2893 this.el.removeClass('show');
2894 this.el.removeClass('hideing');
2898 this.el.removeClass('show');
2900 this.fireEvent('hide', this);
2903 isVisible : function()
2906 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2910 addButton : function(str, cb)
2914 var b = Roo.apply({}, { html : str } );
2915 b.xns = b.xns || Roo.bootstrap;
2916 b.xtype = b.xtype || 'Button';
2917 if (typeof(b.listeners) == 'undefined') {
2918 b.listeners = { click : cb.createDelegate(this) };
2921 var btn = Roo.factory(b);
2923 btn.render(this.el.select('.modal-footer div').first());
2929 setDefaultButton : function(btn)
2931 //this.el.select('.modal-footer').()
2935 resizeTo: function(w,h)
2939 this.dialogEl.setWidth(w);
2940 if (this.diff === false) {
2941 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2944 this.bodyEl.setHeight(h-this.diff);
2946 this.fireEvent('resize', this);
2949 setContentSize : function(w, h)
2953 onButtonClick: function(btn,e)
2956 this.fireEvent('btnclick', btn.name, e);
2959 * Set the title of the Dialog
2960 * @param {String} str new Title
2962 setTitle: function(str) {
2963 this.titleEl.dom.innerHTML = str;
2966 * Set the body of the Dialog
2967 * @param {String} str new Title
2969 setBody: function(str) {
2970 this.bodyEl.dom.innerHTML = str;
2973 * Set the body of the Dialog using the template
2974 * @param {Obj} data - apply this data to the template and replace the body contents.
2976 applyBody: function(obj)
2979 Roo.log("Error - using apply Body without a template");
2982 this.tmpl.overwrite(this.bodyEl, obj);
2988 Roo.apply(Roo.bootstrap.Modal, {
2990 * Button config that displays a single OK button
2999 * Button config that displays Yes and No buttons
3015 * Button config that displays OK and Cancel buttons
3030 * Button config that displays Yes, No and Cancel buttons
3054 * messagebox - can be used as a replace
3058 * @class Roo.MessageBox
3059 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3063 Roo.Msg.alert('Status', 'Changes saved successfully.');
3065 // Prompt for user data:
3066 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3068 // process text value...
3072 // Show a dialog using config options:
3074 title:'Save Changes?',
3075 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3076 buttons: Roo.Msg.YESNOCANCEL,
3083 Roo.bootstrap.MessageBox = function(){
3084 var dlg, opt, mask, waitTimer;
3085 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3086 var buttons, activeTextEl, bwidth;
3090 var handleButton = function(button){
3092 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3096 var handleHide = function(){
3098 dlg.el.removeClass(opt.cls);
3101 // Roo.TaskMgr.stop(waitTimer);
3102 // waitTimer = null;
3107 var updateButtons = function(b){
3110 buttons["ok"].hide();
3111 buttons["cancel"].hide();
3112 buttons["yes"].hide();
3113 buttons["no"].hide();
3114 //dlg.footer.dom.style.display = 'none';
3117 dlg.footerEl.dom.style.display = '';
3118 for(var k in buttons){
3119 if(typeof buttons[k] != "function"){
3122 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3123 width += buttons[k].el.getWidth()+15;
3133 var handleEsc = function(d, k, e){
3134 if(opt && opt.closable !== false){
3144 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3145 * @return {Roo.BasicDialog} The BasicDialog element
3147 getDialog : function(){
3149 dlg = new Roo.bootstrap.Modal( {
3152 //constraintoviewport:false,
3154 //collapsible : false,
3159 //buttonAlign:"center",
3160 closeClick : function(){
3161 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3164 handleButton("cancel");
3169 dlg.on("hide", handleHide);
3171 //dlg.addKeyListener(27, handleEsc);
3173 this.buttons = buttons;
3174 var bt = this.buttonText;
3175 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3176 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3177 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3178 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3180 bodyEl = dlg.bodyEl.createChild({
3182 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3183 '<textarea class="roo-mb-textarea"></textarea>' +
3184 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3186 msgEl = bodyEl.dom.firstChild;
3187 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3188 textboxEl.enableDisplayMode();
3189 textboxEl.addKeyListener([10,13], function(){
3190 if(dlg.isVisible() && opt && opt.buttons){
3193 }else if(opt.buttons.yes){
3194 handleButton("yes");
3198 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3199 textareaEl.enableDisplayMode();
3200 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3201 progressEl.enableDisplayMode();
3203 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3204 var pf = progressEl.dom.firstChild;
3206 pp = Roo.get(pf.firstChild);
3207 pp.setHeight(pf.offsetHeight);
3215 * Updates the message box body text
3216 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3217 * the XHTML-compliant non-breaking space character '&#160;')
3218 * @return {Roo.MessageBox} This message box
3220 updateText : function(text)
3222 if(!dlg.isVisible() && !opt.width){
3223 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3224 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3226 msgEl.innerHTML = text || ' ';
3228 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3229 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3231 Math.min(opt.width || cw , this.maxWidth),
3232 Math.max(opt.minWidth || this.minWidth, bwidth)
3235 activeTextEl.setWidth(w);
3237 if(dlg.isVisible()){
3238 dlg.fixedcenter = false;
3240 // to big, make it scroll. = But as usual stupid IE does not support
3243 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3244 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3245 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3247 bodyEl.dom.style.height = '';
3248 bodyEl.dom.style.overflowY = '';
3251 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3253 bodyEl.dom.style.overflowX = '';
3256 dlg.setContentSize(w, bodyEl.getHeight());
3257 if(dlg.isVisible()){
3258 dlg.fixedcenter = true;
3264 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3265 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3266 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3267 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3268 * @return {Roo.MessageBox} This message box
3270 updateProgress : function(value, text){
3272 this.updateText(text);
3275 if (pp) { // weird bug on my firefox - for some reason this is not defined
3276 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3277 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3283 * Returns true if the message box is currently displayed
3284 * @return {Boolean} True if the message box is visible, else false
3286 isVisible : function(){
3287 return dlg && dlg.isVisible();
3291 * Hides the message box if it is displayed
3294 if(this.isVisible()){
3300 * Displays a new message box, or reinitializes an existing message box, based on the config options
3301 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3302 * The following config object properties are supported:
3304 Property Type Description
3305 ---------- --------------- ------------------------------------------------------------------------------------
3306 animEl String/Element An id or Element from which the message box should animate as it opens and
3307 closes (defaults to undefined)
3308 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3309 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3310 closable Boolean False to hide the top-right close button (defaults to true). Note that
3311 progress and wait dialogs will ignore this property and always hide the
3312 close button as they can only be closed programmatically.
3313 cls String A custom CSS class to apply to the message box element
3314 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3315 displayed (defaults to 75)
3316 fn Function A callback function to execute after closing the dialog. The arguments to the
3317 function will be btn (the name of the button that was clicked, if applicable,
3318 e.g. "ok"), and text (the value of the active text field, if applicable).
3319 Progress and wait dialogs will ignore this option since they do not respond to
3320 user actions and can only be closed programmatically, so any required function
3321 should be called by the same code after it closes the dialog.
3322 icon String A CSS class that provides a background image to be used as an icon for
3323 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3324 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3325 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3326 modal Boolean False to allow user interaction with the page while the message box is
3327 displayed (defaults to true)
3328 msg String A string that will replace the existing message box body text (defaults
3329 to the XHTML-compliant non-breaking space character ' ')
3330 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3331 progress Boolean True to display a progress bar (defaults to false)
3332 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3333 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3334 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3335 title String The title text
3336 value String The string value to set into the active textbox element if displayed
3337 wait Boolean True to display a progress bar (defaults to false)
3338 width Number The width of the dialog in pixels
3345 msg: 'Please enter your address:',
3347 buttons: Roo.MessageBox.OKCANCEL,
3350 animEl: 'addAddressBtn'
3353 * @param {Object} config Configuration options
3354 * @return {Roo.MessageBox} This message box
3356 show : function(options)
3359 // this causes nightmares if you show one dialog after another
3360 // especially on callbacks..
3362 if(this.isVisible()){
3365 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3366 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3367 Roo.log("New Dialog Message:" + options.msg )
3368 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3369 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3372 var d = this.getDialog();
3374 d.setTitle(opt.title || " ");
3375 d.closeEl.setDisplayed(opt.closable !== false);
3376 activeTextEl = textboxEl;
3377 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3382 textareaEl.setHeight(typeof opt.multiline == "number" ?
3383 opt.multiline : this.defaultTextHeight);
3384 activeTextEl = textareaEl;
3393 progressEl.setDisplayed(opt.progress === true);
3394 this.updateProgress(0);
3395 activeTextEl.dom.value = opt.value || "";
3397 dlg.setDefaultButton(activeTextEl);
3399 var bs = opt.buttons;
3403 }else if(bs && bs.yes){
3404 db = buttons["yes"];
3406 dlg.setDefaultButton(db);
3408 bwidth = updateButtons(opt.buttons);
3409 this.updateText(opt.msg);
3411 d.el.addClass(opt.cls);
3413 d.proxyDrag = opt.proxyDrag === true;
3414 d.modal = opt.modal !== false;
3415 d.mask = opt.modal !== false ? mask : false;
3417 // force it to the end of the z-index stack so it gets a cursor in FF
3418 document.body.appendChild(dlg.el.dom);
3419 d.animateTarget = null;
3420 d.show(options.animEl);
3426 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3427 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3428 * and closing the message box when the process is complete.
3429 * @param {String} title The title bar text
3430 * @param {String} msg The message box body text
3431 * @return {Roo.MessageBox} This message box
3433 progress : function(title, msg){
3440 minWidth: this.minProgressWidth,
3447 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3448 * If a callback function is passed it will be called after the user clicks the button, and the
3449 * id of the button that was clicked will be passed as the only parameter to the callback
3450 * (could also be the top-right close button).
3451 * @param {String} title The title bar text
3452 * @param {String} msg The message box body text
3453 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3454 * @param {Object} scope (optional) The scope of the callback function
3455 * @return {Roo.MessageBox} This message box
3457 alert : function(title, msg, fn, scope)
3472 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3473 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3474 * You are responsible for closing the message box when the process is complete.
3475 * @param {String} msg The message box body text
3476 * @param {String} title (optional) The title bar text
3477 * @return {Roo.MessageBox} This message box
3479 wait : function(msg, title){
3490 waitTimer = Roo.TaskMgr.start({
3492 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3500 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3501 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3502 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3503 * @param {String} title The title bar text
3504 * @param {String} msg The message box body text
3505 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3506 * @param {Object} scope (optional) The scope of the callback function
3507 * @return {Roo.MessageBox} This message box
3509 confirm : function(title, msg, fn, scope){
3513 buttons: this.YESNO,
3522 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3523 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3524 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3525 * (could also be the top-right close button) and the text that was entered will be passed as the two
3526 * parameters to the callback.
3527 * @param {String} title The title bar text
3528 * @param {String} msg The message box body text
3529 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3530 * @param {Object} scope (optional) The scope of the callback function
3531 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3532 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3533 * @return {Roo.MessageBox} This message box
3535 prompt : function(title, msg, fn, scope, multiline){
3539 buttons: this.OKCANCEL,
3544 multiline: multiline,
3551 * Button config that displays a single OK button
3556 * Button config that displays Yes and No buttons
3559 YESNO : {yes:true, no:true},
3561 * Button config that displays OK and Cancel buttons
3564 OKCANCEL : {ok:true, cancel:true},
3566 * Button config that displays Yes, No and Cancel buttons
3569 YESNOCANCEL : {yes:true, no:true, cancel:true},
3572 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3575 defaultTextHeight : 75,
3577 * The maximum width in pixels of the message box (defaults to 600)
3582 * The minimum width in pixels of the message box (defaults to 100)
3587 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3588 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3591 minProgressWidth : 250,
3593 * An object containing the default button text strings that can be overriden for localized language support.
3594 * Supported properties are: ok, cancel, yes and no.
3595 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3608 * Shorthand for {@link Roo.MessageBox}
3610 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3611 Roo.Msg = Roo.Msg || Roo.MessageBox;
3620 * @class Roo.bootstrap.Navbar
3621 * @extends Roo.bootstrap.Component
3622 * Bootstrap Navbar class
3625 * Create a new Navbar
3626 * @param {Object} config The config object
3630 Roo.bootstrap.Navbar = function(config){
3631 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3635 * @event beforetoggle
3636 * Fire before toggle the menu
3637 * @param {Roo.EventObject} e
3639 "beforetoggle" : true
3643 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3652 getAutoCreate : function(){
3655 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3659 initEvents :function ()
3661 //Roo.log(this.el.select('.navbar-toggle',true));
3662 this.el.select('.navbar-toggle',true).on('click', function() {
3663 if(this.fireEvent('beforetoggle', this) !== false){
3664 this.el.select('.navbar-collapse',true).toggleClass('in');
3674 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3676 var size = this.el.getSize();
3677 this.maskEl.setSize(size.width, size.height);
3678 this.maskEl.enableDisplayMode("block");
3687 getChildContainer : function()
3689 if (this.el.select('.collapse').getCount()) {
3690 return this.el.select('.collapse',true).first();
3723 * @class Roo.bootstrap.NavSimplebar
3724 * @extends Roo.bootstrap.Navbar
3725 * Bootstrap Sidebar class
3727 * @cfg {Boolean} inverse is inverted color
3729 * @cfg {String} type (nav | pills | tabs)
3730 * @cfg {Boolean} arrangement stacked | justified
3731 * @cfg {String} align (left | right) alignment
3733 * @cfg {Boolean} main (true|false) main nav bar? default false
3734 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3736 * @cfg {String} tag (header|footer|nav|div) default is nav
3742 * Create a new Sidebar
3743 * @param {Object} config The config object
3747 Roo.bootstrap.NavSimplebar = function(config){
3748 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3751 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3767 getAutoCreate : function(){
3771 tag : this.tag || 'div',
3784 this.type = this.type || 'nav';
3785 if (['tabs','pills'].indexOf(this.type)!==-1) {
3786 cfg.cn[0].cls += ' nav-' + this.type
3790 if (this.type!=='nav') {
3791 Roo.log('nav type must be nav/tabs/pills')
3793 cfg.cn[0].cls += ' navbar-nav'
3799 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3800 cfg.cn[0].cls += ' nav-' + this.arrangement;
3804 if (this.align === 'right') {
3805 cfg.cn[0].cls += ' navbar-right';
3809 cfg.cls += ' navbar-inverse';
3836 * @class Roo.bootstrap.NavHeaderbar
3837 * @extends Roo.bootstrap.NavSimplebar
3838 * Bootstrap Sidebar class
3840 * @cfg {String} brand what is brand
3841 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3842 * @cfg {String} brand_href href of the brand
3843 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3844 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3845 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3846 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3849 * Create a new Sidebar
3850 * @param {Object} config The config object
3854 Roo.bootstrap.NavHeaderbar = function(config){
3855 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3859 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3866 desktopCenter : false,
3869 getAutoCreate : function(){
3872 tag: this.nav || 'nav',
3879 if (this.desktopCenter) {
3880 cn.push({cls : 'container', cn : []});
3887 cls: 'navbar-header',
3892 cls: 'navbar-toggle',
3893 'data-toggle': 'collapse',
3898 html: 'Toggle navigation'
3920 cls: 'collapse navbar-collapse',
3924 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3926 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3927 cfg.cls += ' navbar-' + this.position;
3929 // tag can override this..
3931 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3934 if (this.brand !== '') {
3937 href: this.brand_href ? this.brand_href : '#',
3938 cls: 'navbar-brand',
3946 cfg.cls += ' main-nav';
3954 getHeaderChildContainer : function()
3956 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3957 return this.el.select('.navbar-header',true).first();
3960 return this.getChildContainer();
3964 initEvents : function()
3966 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3968 if (this.autohide) {
3973 Roo.get(document).on('scroll',function(e) {
3974 var ns = Roo.get(document).getScroll().top;
3975 var os = prevScroll;
3979 ft.removeClass('slideDown');
3980 ft.addClass('slideUp');
3983 ft.removeClass('slideUp');
3984 ft.addClass('slideDown');
4005 * @class Roo.bootstrap.NavSidebar
4006 * @extends Roo.bootstrap.Navbar
4007 * Bootstrap Sidebar class
4010 * Create a new Sidebar
4011 * @param {Object} config The config object
4015 Roo.bootstrap.NavSidebar = function(config){
4016 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4019 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4021 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4023 getAutoCreate : function(){
4028 cls: 'sidebar sidebar-nav'
4050 * @class Roo.bootstrap.NavGroup
4051 * @extends Roo.bootstrap.Component
4052 * Bootstrap NavGroup class
4053 * @cfg {String} align (left|right)
4054 * @cfg {Boolean} inverse
4055 * @cfg {String} type (nav|pills|tab) default nav
4056 * @cfg {String} navId - reference Id for navbar.
4060 * Create a new nav group
4061 * @param {Object} config The config object
4064 Roo.bootstrap.NavGroup = function(config){
4065 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4068 Roo.bootstrap.NavGroup.register(this);
4072 * Fires when the active item changes
4073 * @param {Roo.bootstrap.NavGroup} this
4074 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4075 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4082 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4093 getAutoCreate : function()
4095 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4102 if (['tabs','pills'].indexOf(this.type)!==-1) {
4103 cfg.cls += ' nav-' + this.type
4105 if (this.type!=='nav') {
4106 Roo.log('nav type must be nav/tabs/pills')
4108 cfg.cls += ' navbar-nav'
4111 if (this.parent() && this.parent().sidebar) {
4114 cls: 'dashboard-menu sidebar-menu'
4120 if (this.form === true) {
4126 if (this.align === 'right') {
4127 cfg.cls += ' navbar-right';
4129 cfg.cls += ' navbar-left';
4133 if (this.align === 'right') {
4134 cfg.cls += ' navbar-right';
4138 cfg.cls += ' navbar-inverse';
4146 * sets the active Navigation item
4147 * @param {Roo.bootstrap.NavItem} the new current navitem
4149 setActiveItem : function(item)
4152 Roo.each(this.navItems, function(v){
4157 v.setActive(false, true);
4164 item.setActive(true, true);
4165 this.fireEvent('changed', this, item, prev);
4170 * gets the active Navigation item
4171 * @return {Roo.bootstrap.NavItem} the current navitem
4173 getActive : function()
4177 Roo.each(this.navItems, function(v){
4188 indexOfNav : function()
4192 Roo.each(this.navItems, function(v,i){
4203 * adds a Navigation item
4204 * @param {Roo.bootstrap.NavItem} the navitem to add
4206 addItem : function(cfg)
4208 var cn = new Roo.bootstrap.NavItem(cfg);
4210 cn.parentId = this.id;
4211 cn.onRender(this.el, null);
4215 * register a Navigation item
4216 * @param {Roo.bootstrap.NavItem} the navitem to add
4218 register : function(item)
4220 this.navItems.push( item);
4221 item.navId = this.navId;
4226 * clear all the Navigation item
4229 clearAll : function()
4232 this.el.dom.innerHTML = '';
4235 getNavItem: function(tabId)
4238 Roo.each(this.navItems, function(e) {
4239 if (e.tabId == tabId) {
4249 setActiveNext : function()
4251 var i = this.indexOfNav(this.getActive());
4252 if (i > this.navItems.length) {
4255 this.setActiveItem(this.navItems[i+1]);
4257 setActivePrev : function()
4259 var i = this.indexOfNav(this.getActive());
4263 this.setActiveItem(this.navItems[i-1]);
4265 clearWasActive : function(except) {
4266 Roo.each(this.navItems, function(e) {
4267 if (e.tabId != except.tabId && e.was_active) {
4268 e.was_active = false;
4275 getWasActive : function ()
4278 Roo.each(this.navItems, function(e) {
4293 Roo.apply(Roo.bootstrap.NavGroup, {
4297 * register a Navigation Group
4298 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4300 register : function(navgrp)
4302 this.groups[navgrp.navId] = navgrp;
4306 * fetch a Navigation Group based on the navigation ID
4307 * @param {string} the navgroup to add
4308 * @returns {Roo.bootstrap.NavGroup} the navgroup
4310 get: function(navId) {
4311 if (typeof(this.groups[navId]) == 'undefined') {
4313 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4315 return this.groups[navId] ;
4330 * @class Roo.bootstrap.NavItem
4331 * @extends Roo.bootstrap.Component
4332 * Bootstrap Navbar.NavItem class
4333 * @cfg {String} href link to
4334 * @cfg {String} html content of button
4335 * @cfg {String} badge text inside badge
4336 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4337 * @cfg {String} glyphicon name of glyphicon
4338 * @cfg {String} icon name of font awesome icon
4339 * @cfg {Boolean} active Is item active
4340 * @cfg {Boolean} disabled Is item disabled
4342 * @cfg {Boolean} preventDefault (true | false) default false
4343 * @cfg {String} tabId the tab that this item activates.
4344 * @cfg {String} tagtype (a|span) render as a href or span?
4345 * @cfg {Boolean} animateRef (true|false) link to element default false
4348 * Create a new Navbar Item
4349 * @param {Object} config The config object
4351 Roo.bootstrap.NavItem = function(config){
4352 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4357 * The raw click event for the entire grid.
4358 * @param {Roo.EventObject} e
4363 * Fires when the active item active state changes
4364 * @param {Roo.bootstrap.NavItem} this
4365 * @param {boolean} state the new state
4371 * Fires when scroll to element
4372 * @param {Roo.bootstrap.NavItem} this
4373 * @param {Object} options
4374 * @param {Roo.EventObject} e
4382 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4390 preventDefault : false,
4397 getAutoCreate : function(){
4406 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4408 if (this.disabled) {
4409 cfg.cls += ' disabled';
4412 if (this.href || this.html || this.glyphicon || this.icon) {
4416 href : this.href || "#",
4417 html: this.html || ''
4422 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4425 if(this.glyphicon) {
4426 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4431 cfg.cn[0].html += " <span class='caret'></span>";
4435 if (this.badge !== '') {
4437 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4445 initEvents: function()
4447 if (typeof (this.menu) != 'undefined') {
4448 this.menu.parentType = this.xtype;
4449 this.menu.triggerEl = this.el;
4450 this.menu = this.addxtype(Roo.apply({}, this.menu));
4453 this.el.select('a',true).on('click', this.onClick, this);
4455 if(this.tagtype == 'span'){
4456 this.el.select('span',true).on('click', this.onClick, this);
4459 // at this point parent should be available..
4460 this.parent().register(this);
4463 onClick : function(e)
4465 if (e.getTarget('.dropdown-menu-item')) {
4466 // did you click on a menu itemm.... - then don't trigger onclick..
4471 this.preventDefault ||
4474 Roo.log("NavItem - prevent Default?");
4478 if (this.disabled) {
4482 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4483 if (tg && tg.transition) {
4484 Roo.log("waiting for the transitionend");
4490 //Roo.log("fire event clicked");
4491 if(this.fireEvent('click', this, e) === false){
4495 if(this.tagtype == 'span'){
4499 //Roo.log(this.href);
4500 var ael = this.el.select('a',true).first();
4503 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4504 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4505 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4506 return; // ignore... - it's a 'hash' to another page.
4508 Roo.log("NavItem - prevent Default?");
4510 this.scrollToElement(e);
4514 var p = this.parent();
4516 if (['tabs','pills'].indexOf(p.type)!==-1) {
4517 if (typeof(p.setActiveItem) !== 'undefined') {
4518 p.setActiveItem(this);
4522 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4523 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4524 // remove the collapsed menu expand...
4525 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4529 isActive: function () {
4532 setActive : function(state, fire, is_was_active)
4534 if (this.active && !state && this.navId) {
4535 this.was_active = true;
4536 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4538 nv.clearWasActive(this);
4542 this.active = state;
4545 this.el.removeClass('active');
4546 } else if (!this.el.hasClass('active')) {
4547 this.el.addClass('active');
4550 this.fireEvent('changed', this, state);
4553 // show a panel if it's registered and related..
4555 if (!this.navId || !this.tabId || !state || is_was_active) {
4559 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4563 var pan = tg.getPanelByName(this.tabId);
4567 // if we can not flip to new panel - go back to old nav highlight..
4568 if (false == tg.showPanel(pan)) {
4569 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4571 var onav = nv.getWasActive();
4573 onav.setActive(true, false, true);
4582 // this should not be here...
4583 setDisabled : function(state)
4585 this.disabled = state;
4587 this.el.removeClass('disabled');
4588 } else if (!this.el.hasClass('disabled')) {
4589 this.el.addClass('disabled');
4595 * Fetch the element to display the tooltip on.
4596 * @return {Roo.Element} defaults to this.el
4598 tooltipEl : function()
4600 return this.el.select('' + this.tagtype + '', true).first();
4603 scrollToElement : function(e)
4605 var c = document.body;
4608 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4610 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4611 c = document.documentElement;
4614 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4620 var o = target.calcOffsetsTo(c);
4627 this.fireEvent('scrollto', this, options, e);
4629 Roo.get(c).scrollTo('top', options.value, true);
4642 * <span> icon </span>
4643 * <span> text </span>
4644 * <span>badge </span>
4648 * @class Roo.bootstrap.NavSidebarItem
4649 * @extends Roo.bootstrap.NavItem
4650 * Bootstrap Navbar.NavSidebarItem class
4651 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4652 * {Boolean} open is the menu open
4653 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4654 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4655 * {String} buttonSize (sm|md|lg)the extra classes for the button
4656 * {Boolean} showArrow show arrow next to the text (default true)
4658 * Create a new Navbar Button
4659 * @param {Object} config The config object
4661 Roo.bootstrap.NavSidebarItem = function(config){
4662 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4667 * The raw click event for the entire grid.
4668 * @param {Roo.EventObject} e
4673 * Fires when the active item active state changes
4674 * @param {Roo.bootstrap.NavSidebarItem} this
4675 * @param {boolean} state the new state
4683 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4685 badgeWeight : 'default',
4691 buttonWeight : 'default',
4697 getAutoCreate : function(){
4702 href : this.href || '#',
4708 if(this.buttonView){
4711 href : this.href || '#',
4712 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4725 cfg.cls += ' active';
4728 if (this.disabled) {
4729 cfg.cls += ' disabled';
4732 cfg.cls += ' open x-open';
4735 if (this.glyphicon || this.icon) {
4736 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4737 a.cn.push({ tag : 'i', cls : c }) ;
4740 if(!this.buttonView){
4743 html : this.html || ''
4750 if (this.badge !== '') {
4751 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4757 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4760 a.cls += ' dropdown-toggle treeview' ;
4766 initEvents : function()
4768 if (typeof (this.menu) != 'undefined') {
4769 this.menu.parentType = this.xtype;
4770 this.menu.triggerEl = this.el;
4771 this.menu = this.addxtype(Roo.apply({}, this.menu));
4774 this.el.on('click', this.onClick, this);
4776 if(this.badge !== ''){
4777 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4782 onClick : function(e)
4789 if(this.preventDefault){
4793 this.fireEvent('click', this);
4796 disable : function()
4798 this.setDisabled(true);
4803 this.setDisabled(false);
4806 setDisabled : function(state)
4808 if(this.disabled == state){
4812 this.disabled = state;
4815 this.el.addClass('disabled');
4819 this.el.removeClass('disabled');
4824 setActive : function(state)
4826 if(this.active == state){
4830 this.active = state;
4833 this.el.addClass('active');
4837 this.el.removeClass('active');
4842 isActive: function ()
4847 setBadge : function(str)
4853 this.badgeEl.dom.innerHTML = str;
4870 * @class Roo.bootstrap.Row
4871 * @extends Roo.bootstrap.Component
4872 * Bootstrap Row class (contains columns...)
4876 * @param {Object} config The config object
4879 Roo.bootstrap.Row = function(config){
4880 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4883 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4885 getAutoCreate : function(){
4904 * @class Roo.bootstrap.Element
4905 * @extends Roo.bootstrap.Component
4906 * Bootstrap Element class
4907 * @cfg {String} html contents of the element
4908 * @cfg {String} tag tag of the element
4909 * @cfg {String} cls class of the element
4910 * @cfg {Boolean} preventDefault (true|false) default false
4911 * @cfg {Boolean} clickable (true|false) default false
4914 * Create a new Element
4915 * @param {Object} config The config object
4918 Roo.bootstrap.Element = function(config){
4919 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4925 * When a element is chick
4926 * @param {Roo.bootstrap.Element} this
4927 * @param {Roo.EventObject} e
4933 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4938 preventDefault: false,
4941 getAutoCreate : function(){
4945 // cls: this.cls, double assign in parent class Component.js :: onRender
4952 initEvents: function()
4954 Roo.bootstrap.Element.superclass.initEvents.call(this);
4957 this.el.on('click', this.onClick, this);
4962 onClick : function(e)
4964 if(this.preventDefault){
4968 this.fireEvent('click', this, e);
4971 getValue : function()
4973 return this.el.dom.innerHTML;
4976 setValue : function(value)
4978 this.el.dom.innerHTML = value;
4993 * @class Roo.bootstrap.Pagination
4994 * @extends Roo.bootstrap.Component
4995 * Bootstrap Pagination class
4996 * @cfg {String} size xs | sm | md | lg
4997 * @cfg {Boolean} inverse false | true
5000 * Create a new Pagination
5001 * @param {Object} config The config object
5004 Roo.bootstrap.Pagination = function(config){
5005 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5008 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5014 getAutoCreate : function(){
5020 cfg.cls += ' inverse';
5026 cfg.cls += " " + this.cls;
5044 * @class Roo.bootstrap.PaginationItem
5045 * @extends Roo.bootstrap.Component
5046 * Bootstrap PaginationItem class
5047 * @cfg {String} html text
5048 * @cfg {String} href the link
5049 * @cfg {Boolean} preventDefault (true | false) default true
5050 * @cfg {Boolean} active (true | false) default false
5051 * @cfg {Boolean} disabled default false
5055 * Create a new PaginationItem
5056 * @param {Object} config The config object
5060 Roo.bootstrap.PaginationItem = function(config){
5061 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5066 * The raw click event for the entire grid.
5067 * @param {Roo.EventObject} e
5073 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5077 preventDefault: true,
5082 getAutoCreate : function(){
5088 href : this.href ? this.href : '#',
5089 html : this.html ? this.html : ''
5099 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5103 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5109 initEvents: function() {
5111 this.el.on('click', this.onClick, this);
5114 onClick : function(e)
5116 Roo.log('PaginationItem on click ');
5117 if(this.preventDefault){
5125 this.fireEvent('click', this, e);
5141 * @class Roo.bootstrap.Slider
5142 * @extends Roo.bootstrap.Component
5143 * Bootstrap Slider class
5146 * Create a new Slider
5147 * @param {Object} config The config object
5150 Roo.bootstrap.Slider = function(config){
5151 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5154 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5156 getAutoCreate : function(){
5160 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5164 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5176 * Ext JS Library 1.1.1
5177 * Copyright(c) 2006-2007, Ext JS, LLC.
5179 * Originally Released Under LGPL - original licence link has changed is not relivant.
5182 * <script type="text/javascript">
5187 * @class Roo.grid.ColumnModel
5188 * @extends Roo.util.Observable
5189 * This is the default implementation of a ColumnModel used by the Grid. It defines
5190 * the columns in the grid.
5193 var colModel = new Roo.grid.ColumnModel([
5194 {header: "Ticker", width: 60, sortable: true, locked: true},
5195 {header: "Company Name", width: 150, sortable: true},
5196 {header: "Market Cap.", width: 100, sortable: true},
5197 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5198 {header: "Employees", width: 100, sortable: true, resizable: false}
5203 * The config options listed for this class are options which may appear in each
5204 * individual column definition.
5205 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5207 * @param {Object} config An Array of column config objects. See this class's
5208 * config objects for details.
5210 Roo.grid.ColumnModel = function(config){
5212 * The config passed into the constructor
5214 this.config = config;
5217 // if no id, create one
5218 // if the column does not have a dataIndex mapping,
5219 // map it to the order it is in the config
5220 for(var i = 0, len = config.length; i < len; i++){
5222 if(typeof c.dataIndex == "undefined"){
5225 if(typeof c.renderer == "string"){
5226 c.renderer = Roo.util.Format[c.renderer];
5228 if(typeof c.id == "undefined"){
5231 if(c.editor && c.editor.xtype){
5232 c.editor = Roo.factory(c.editor, Roo.grid);
5234 if(c.editor && c.editor.isFormField){
5235 c.editor = new Roo.grid.GridEditor(c.editor);
5237 this.lookup[c.id] = c;
5241 * The width of columns which have no width specified (defaults to 100)
5244 this.defaultWidth = 100;
5247 * Default sortable of columns which have no sortable specified (defaults to false)
5250 this.defaultSortable = false;
5254 * @event widthchange
5255 * Fires when the width of a column changes.
5256 * @param {ColumnModel} this
5257 * @param {Number} columnIndex The column index
5258 * @param {Number} newWidth The new width
5260 "widthchange": true,
5262 * @event headerchange
5263 * Fires when the text of a header changes.
5264 * @param {ColumnModel} this
5265 * @param {Number} columnIndex The column index
5266 * @param {Number} newText The new header text
5268 "headerchange": true,
5270 * @event hiddenchange
5271 * Fires when a column is hidden or "unhidden".
5272 * @param {ColumnModel} this
5273 * @param {Number} columnIndex The column index
5274 * @param {Boolean} hidden true if hidden, false otherwise
5276 "hiddenchange": true,
5278 * @event columnmoved
5279 * Fires when a column is moved.
5280 * @param {ColumnModel} this
5281 * @param {Number} oldIndex
5282 * @param {Number} newIndex
5284 "columnmoved" : true,
5286 * @event columlockchange
5287 * Fires when a column's locked state is changed
5288 * @param {ColumnModel} this
5289 * @param {Number} colIndex
5290 * @param {Boolean} locked true if locked
5292 "columnlockchange" : true
5294 Roo.grid.ColumnModel.superclass.constructor.call(this);
5296 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5298 * @cfg {String} header The header text to display in the Grid view.
5301 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5302 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5303 * specified, the column's index is used as an index into the Record's data Array.
5306 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5307 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5310 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5311 * Defaults to the value of the {@link #defaultSortable} property.
5312 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5315 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5318 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5321 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5324 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5327 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5328 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5329 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5330 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5333 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5336 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5339 * @cfg {String} cursor (Optional)
5342 * @cfg {String} tooltip (Optional)
5345 * @cfg {Number} xs (Optional)
5348 * @cfg {Number} sm (Optional)
5351 * @cfg {Number} md (Optional)
5354 * @cfg {Number} lg (Optional)
5357 * Returns the id of the column at the specified index.
5358 * @param {Number} index The column index
5359 * @return {String} the id
5361 getColumnId : function(index){
5362 return this.config[index].id;
5366 * Returns the column for a specified id.
5367 * @param {String} id The column id
5368 * @return {Object} the column
5370 getColumnById : function(id){
5371 return this.lookup[id];
5376 * Returns the column for a specified dataIndex.
5377 * @param {String} dataIndex The column dataIndex
5378 * @return {Object|Boolean} the column or false if not found
5380 getColumnByDataIndex: function(dataIndex){
5381 var index = this.findColumnIndex(dataIndex);
5382 return index > -1 ? this.config[index] : false;
5386 * Returns the index for a specified column id.
5387 * @param {String} id The column id
5388 * @return {Number} the index, or -1 if not found
5390 getIndexById : function(id){
5391 for(var i = 0, len = this.config.length; i < len; i++){
5392 if(this.config[i].id == id){
5400 * Returns the index for a specified column dataIndex.
5401 * @param {String} dataIndex The column dataIndex
5402 * @return {Number} the index, or -1 if not found
5405 findColumnIndex : function(dataIndex){
5406 for(var i = 0, len = this.config.length; i < len; i++){
5407 if(this.config[i].dataIndex == dataIndex){
5415 moveColumn : function(oldIndex, newIndex){
5416 var c = this.config[oldIndex];
5417 this.config.splice(oldIndex, 1);
5418 this.config.splice(newIndex, 0, c);
5419 this.dataMap = null;
5420 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5423 isLocked : function(colIndex){
5424 return this.config[colIndex].locked === true;
5427 setLocked : function(colIndex, value, suppressEvent){
5428 if(this.isLocked(colIndex) == value){
5431 this.config[colIndex].locked = value;
5433 this.fireEvent("columnlockchange", this, colIndex, value);
5437 getTotalLockedWidth : function(){
5439 for(var i = 0; i < this.config.length; i++){
5440 if(this.isLocked(i) && !this.isHidden(i)){
5441 this.totalWidth += this.getColumnWidth(i);
5447 getLockedCount : function(){
5448 for(var i = 0, len = this.config.length; i < len; i++){
5449 if(!this.isLocked(i)){
5454 return this.config.length;
5458 * Returns the number of columns.
5461 getColumnCount : function(visibleOnly){
5462 if(visibleOnly === true){
5464 for(var i = 0, len = this.config.length; i < len; i++){
5465 if(!this.isHidden(i)){
5471 return this.config.length;
5475 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5476 * @param {Function} fn
5477 * @param {Object} scope (optional)
5478 * @return {Array} result
5480 getColumnsBy : function(fn, scope){
5482 for(var i = 0, len = this.config.length; i < len; i++){
5483 var c = this.config[i];
5484 if(fn.call(scope||this, c, i) === true){
5492 * Returns true if the specified column is sortable.
5493 * @param {Number} col The column index
5496 isSortable : function(col){
5497 if(typeof this.config[col].sortable == "undefined"){
5498 return this.defaultSortable;
5500 return this.config[col].sortable;
5504 * Returns the rendering (formatting) function defined for the column.
5505 * @param {Number} col The column index.
5506 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5508 getRenderer : function(col){
5509 if(!this.config[col].renderer){
5510 return Roo.grid.ColumnModel.defaultRenderer;
5512 return this.config[col].renderer;
5516 * Sets the rendering (formatting) function for a column.
5517 * @param {Number} col The column index
5518 * @param {Function} fn The function to use to process the cell's raw data
5519 * to return HTML markup for the grid view. The render function is called with
5520 * the following parameters:<ul>
5521 * <li>Data value.</li>
5522 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5523 * <li>css A CSS style string to apply to the table cell.</li>
5524 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5525 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5526 * <li>Row index</li>
5527 * <li>Column index</li>
5528 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5530 setRenderer : function(col, fn){
5531 this.config[col].renderer = fn;
5535 * Returns the width for the specified column.
5536 * @param {Number} col The column index
5539 getColumnWidth : function(col){
5540 return this.config[col].width * 1 || this.defaultWidth;
5544 * Sets the width for a column.
5545 * @param {Number} col The column index
5546 * @param {Number} width The new width
5548 setColumnWidth : function(col, width, suppressEvent){
5549 this.config[col].width = width;
5550 this.totalWidth = null;
5552 this.fireEvent("widthchange", this, col, width);
5557 * Returns the total width of all columns.
5558 * @param {Boolean} includeHidden True to include hidden column widths
5561 getTotalWidth : function(includeHidden){
5562 if(!this.totalWidth){
5563 this.totalWidth = 0;
5564 for(var i = 0, len = this.config.length; i < len; i++){
5565 if(includeHidden || !this.isHidden(i)){
5566 this.totalWidth += this.getColumnWidth(i);
5570 return this.totalWidth;
5574 * Returns the header for the specified column.
5575 * @param {Number} col The column index
5578 getColumnHeader : function(col){
5579 return this.config[col].header;
5583 * Sets the header for a column.
5584 * @param {Number} col The column index
5585 * @param {String} header The new header
5587 setColumnHeader : function(col, header){
5588 this.config[col].header = header;
5589 this.fireEvent("headerchange", this, col, header);
5593 * Returns the tooltip for the specified column.
5594 * @param {Number} col The column index
5597 getColumnTooltip : function(col){
5598 return this.config[col].tooltip;
5601 * Sets the tooltip for a column.
5602 * @param {Number} col The column index
5603 * @param {String} tooltip The new tooltip
5605 setColumnTooltip : function(col, tooltip){
5606 this.config[col].tooltip = tooltip;
5610 * Returns the dataIndex for the specified column.
5611 * @param {Number} col The column index
5614 getDataIndex : function(col){
5615 return this.config[col].dataIndex;
5619 * Sets the dataIndex for a column.
5620 * @param {Number} col The column index
5621 * @param {Number} dataIndex The new dataIndex
5623 setDataIndex : function(col, dataIndex){
5624 this.config[col].dataIndex = dataIndex;
5630 * Returns true if the cell is editable.
5631 * @param {Number} colIndex The column index
5632 * @param {Number} rowIndex The row index - this is nto actually used..?
5635 isCellEditable : function(colIndex, rowIndex){
5636 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5640 * Returns the editor defined for the cell/column.
5641 * return false or null to disable editing.
5642 * @param {Number} colIndex The column index
5643 * @param {Number} rowIndex The row index
5646 getCellEditor : function(colIndex, rowIndex){
5647 return this.config[colIndex].editor;
5651 * Sets if a column is editable.
5652 * @param {Number} col The column index
5653 * @param {Boolean} editable True if the column is editable
5655 setEditable : function(col, editable){
5656 this.config[col].editable = editable;
5661 * Returns true if the column is hidden.
5662 * @param {Number} colIndex The column index
5665 isHidden : function(colIndex){
5666 return this.config[colIndex].hidden;
5671 * Returns true if the column width cannot be changed
5673 isFixed : function(colIndex){
5674 return this.config[colIndex].fixed;
5678 * Returns true if the column can be resized
5681 isResizable : function(colIndex){
5682 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5685 * Sets if a column is hidden.
5686 * @param {Number} colIndex The column index
5687 * @param {Boolean} hidden True if the column is hidden
5689 setHidden : function(colIndex, hidden){
5690 this.config[colIndex].hidden = hidden;
5691 this.totalWidth = null;
5692 this.fireEvent("hiddenchange", this, colIndex, hidden);
5696 * Sets the editor for a column.
5697 * @param {Number} col The column index
5698 * @param {Object} editor The editor object
5700 setEditor : function(col, editor){
5701 this.config[col].editor = editor;
5705 Roo.grid.ColumnModel.defaultRenderer = function(value)
5707 if(typeof value == "object") {
5710 if(typeof value == "string" && value.length < 1){
5714 return String.format("{0}", value);
5717 // Alias for backwards compatibility
5718 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5721 * Ext JS Library 1.1.1
5722 * Copyright(c) 2006-2007, Ext JS, LLC.
5724 * Originally Released Under LGPL - original licence link has changed is not relivant.
5727 * <script type="text/javascript">
5731 * @class Roo.LoadMask
5732 * A simple utility class for generically masking elements while loading data. If the element being masked has
5733 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5734 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5735 * element's UpdateManager load indicator and will be destroyed after the initial load.
5737 * Create a new LoadMask
5738 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5739 * @param {Object} config The config object
5741 Roo.LoadMask = function(el, config){
5742 this.el = Roo.get(el);
5743 Roo.apply(this, config);
5745 this.store.on('beforeload', this.onBeforeLoad, this);
5746 this.store.on('load', this.onLoad, this);
5747 this.store.on('loadexception', this.onLoadException, this);
5748 this.removeMask = false;
5750 var um = this.el.getUpdateManager();
5751 um.showLoadIndicator = false; // disable the default indicator
5752 um.on('beforeupdate', this.onBeforeLoad, this);
5753 um.on('update', this.onLoad, this);
5754 um.on('failure', this.onLoad, this);
5755 this.removeMask = true;
5759 Roo.LoadMask.prototype = {
5761 * @cfg {Boolean} removeMask
5762 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5763 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5767 * The text to display in a centered loading message box (defaults to 'Loading...')
5771 * @cfg {String} msgCls
5772 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5774 msgCls : 'x-mask-loading',
5777 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5783 * Disables the mask to prevent it from being displayed
5785 disable : function(){
5786 this.disabled = true;
5790 * Enables the mask so that it can be displayed
5792 enable : function(){
5793 this.disabled = false;
5796 onLoadException : function()
5800 if (typeof(arguments[3]) != 'undefined') {
5801 Roo.MessageBox.alert("Error loading",arguments[3]);
5805 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5806 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5813 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5818 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5822 onBeforeLoad : function(){
5824 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5829 destroy : function(){
5831 this.store.un('beforeload', this.onBeforeLoad, this);
5832 this.store.un('load', this.onLoad, this);
5833 this.store.un('loadexception', this.onLoadException, this);
5835 var um = this.el.getUpdateManager();
5836 um.un('beforeupdate', this.onBeforeLoad, this);
5837 um.un('update', this.onLoad, this);
5838 um.un('failure', this.onLoad, this);
5849 * @class Roo.bootstrap.Table
5850 * @extends Roo.bootstrap.Component
5851 * Bootstrap Table class
5852 * @cfg {String} cls table class
5853 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5854 * @cfg {String} bgcolor Specifies the background color for a table
5855 * @cfg {Number} border Specifies whether the table cells should have borders or not
5856 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5857 * @cfg {Number} cellspacing Specifies the space between cells
5858 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5859 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5860 * @cfg {String} sortable Specifies that the table should be sortable
5861 * @cfg {String} summary Specifies a summary of the content of a table
5862 * @cfg {Number} width Specifies the width of a table
5863 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5865 * @cfg {boolean} striped Should the rows be alternative striped
5866 * @cfg {boolean} bordered Add borders to the table
5867 * @cfg {boolean} hover Add hover highlighting
5868 * @cfg {boolean} condensed Format condensed
5869 * @cfg {boolean} responsive Format condensed
5870 * @cfg {Boolean} loadMask (true|false) default false
5871 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5872 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5873 * @cfg {Boolean} rowSelection (true|false) default false
5874 * @cfg {Boolean} cellSelection (true|false) default false
5875 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5876 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5877 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5881 * Create a new Table
5882 * @param {Object} config The config object
5885 Roo.bootstrap.Table = function(config){
5886 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5891 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5892 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5893 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5894 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5896 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5898 this.sm.grid = this;
5899 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5900 this.sm = this.selModel;
5901 this.sm.xmodule = this.xmodule || false;
5904 if (this.cm && typeof(this.cm.config) == 'undefined') {
5905 this.colModel = new Roo.grid.ColumnModel(this.cm);
5906 this.cm = this.colModel;
5907 this.cm.xmodule = this.xmodule || false;
5910 this.store= Roo.factory(this.store, Roo.data);
5911 this.ds = this.store;
5912 this.ds.xmodule = this.xmodule || false;
5915 if (this.footer && this.store) {
5916 this.footer.dataSource = this.ds;
5917 this.footer = Roo.factory(this.footer);
5924 * Fires when a cell is clicked
5925 * @param {Roo.bootstrap.Table} this
5926 * @param {Roo.Element} el
5927 * @param {Number} rowIndex
5928 * @param {Number} columnIndex
5929 * @param {Roo.EventObject} e
5933 * @event celldblclick
5934 * Fires when a cell is double clicked
5935 * @param {Roo.bootstrap.Table} this
5936 * @param {Roo.Element} el
5937 * @param {Number} rowIndex
5938 * @param {Number} columnIndex
5939 * @param {Roo.EventObject} e
5941 "celldblclick" : true,
5944 * Fires when a row is clicked
5945 * @param {Roo.bootstrap.Table} this
5946 * @param {Roo.Element} el
5947 * @param {Number} rowIndex
5948 * @param {Roo.EventObject} e
5952 * @event rowdblclick
5953 * Fires when a row is double clicked
5954 * @param {Roo.bootstrap.Table} this
5955 * @param {Roo.Element} el
5956 * @param {Number} rowIndex
5957 * @param {Roo.EventObject} e
5959 "rowdblclick" : true,
5962 * Fires when a mouseover occur
5963 * @param {Roo.bootstrap.Table} this
5964 * @param {Roo.Element} el
5965 * @param {Number} rowIndex
5966 * @param {Number} columnIndex
5967 * @param {Roo.EventObject} e
5972 * Fires when a mouseout occur
5973 * @param {Roo.bootstrap.Table} this
5974 * @param {Roo.Element} el
5975 * @param {Number} rowIndex
5976 * @param {Number} columnIndex
5977 * @param {Roo.EventObject} e
5982 * Fires when a row is rendered, so you can change add a style to it.
5983 * @param {Roo.bootstrap.Table} this
5984 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5988 * @event rowsrendered
5989 * Fires when all the rows have been rendered
5990 * @param {Roo.bootstrap.Table} this
5992 'rowsrendered' : true,
5994 * @event contextmenu
5995 * The raw contextmenu event for the entire grid.
5996 * @param {Roo.EventObject} e
5998 "contextmenu" : true,
6000 * @event rowcontextmenu
6001 * Fires when a row is right clicked
6002 * @param {Roo.bootstrap.Table} this
6003 * @param {Number} rowIndex
6004 * @param {Roo.EventObject} e
6006 "rowcontextmenu" : true,
6008 * @event cellcontextmenu
6009 * Fires when a cell is right clicked
6010 * @param {Roo.bootstrap.Table} this
6011 * @param {Number} rowIndex
6012 * @param {Number} cellIndex
6013 * @param {Roo.EventObject} e
6015 "cellcontextmenu" : true,
6017 * @event headercontextmenu
6018 * Fires when a header is right clicked
6019 * @param {Roo.bootstrap.Table} this
6020 * @param {Number} columnIndex
6021 * @param {Roo.EventObject} e
6023 "headercontextmenu" : true
6027 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6053 rowSelection : false,
6054 cellSelection : false,
6057 // Roo.Element - the tbody
6059 // Roo.Element - thead element
6062 container: false, // used by gridpanel...
6068 getAutoCreate : function()
6070 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6077 if (this.scrollBody) {
6078 cfg.cls += ' table-body-fixed';
6081 cfg.cls += ' table-striped';
6085 cfg.cls += ' table-hover';
6087 if (this.bordered) {
6088 cfg.cls += ' table-bordered';
6090 if (this.condensed) {
6091 cfg.cls += ' table-condensed';
6093 if (this.responsive) {
6094 cfg.cls += ' table-responsive';
6098 cfg.cls+= ' ' +this.cls;
6101 // this lot should be simplifed...
6104 cfg.align=this.align;
6107 cfg.bgcolor=this.bgcolor;
6110 cfg.border=this.border;
6112 if (this.cellpadding) {
6113 cfg.cellpadding=this.cellpadding;
6115 if (this.cellspacing) {
6116 cfg.cellspacing=this.cellspacing;
6119 cfg.frame=this.frame;
6122 cfg.rules=this.rules;
6124 if (this.sortable) {
6125 cfg.sortable=this.sortable;
6128 cfg.summary=this.summary;
6131 cfg.width=this.width;
6134 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6137 if(this.store || this.cm){
6138 if(this.headerShow){
6139 cfg.cn.push(this.renderHeader());
6142 cfg.cn.push(this.renderBody());
6144 if(this.footerShow){
6145 cfg.cn.push(this.renderFooter());
6147 // where does this come from?
6148 //cfg.cls+= ' TableGrid';
6151 return { cn : [ cfg ] };
6154 initEvents : function()
6156 if(!this.store || !this.cm){
6159 if (this.selModel) {
6160 this.selModel.initEvents();
6164 //Roo.log('initEvents with ds!!!!');
6166 this.mainBody = this.el.select('tbody', true).first();
6167 this.mainHead = this.el.select('thead', true).first();
6174 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6175 e.on('click', _this.sort, _this);
6178 this.mainBody.on("click", this.onClick, this);
6179 this.mainBody.on("dblclick", this.onDblClick, this);
6181 // why is this done????? = it breaks dialogs??
6182 //this.parent().el.setStyle('position', 'relative');
6186 this.footer.parentId = this.id;
6187 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6190 this.el.select('tfoot tr td').first().addClass('hide');
6194 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6196 this.store.on('load', this.onLoad, this);
6197 this.store.on('beforeload', this.onBeforeLoad, this);
6198 this.store.on('update', this.onUpdate, this);
6199 this.store.on('add', this.onAdd, this);
6200 this.store.on("clear", this.clear, this);
6202 this.el.on("contextmenu", this.onContextMenu, this);
6204 this.mainBody.on('scroll', this.onBodyScroll, this);
6206 this.cm.on("headerchange", this.onHeaderChange, this);
6208 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6212 onContextMenu : function(e, t)
6214 this.processEvent("contextmenu", e);
6217 processEvent : function(name, e)
6219 if (name != 'touchstart' ) {
6220 this.fireEvent(name, e);
6223 var t = e.getTarget();
6225 var cell = Roo.get(t);
6231 if(cell.findParent('tfoot', false, true)){
6235 if(cell.findParent('thead', false, true)){
6237 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6238 cell = Roo.get(t).findParent('th', false, true);
6240 Roo.log("failed to find th in thead?");
6241 Roo.log(e.getTarget());
6246 var cellIndex = cell.dom.cellIndex;
6248 var ename = name == 'touchstart' ? 'click' : name;
6249 this.fireEvent("header" + ename, this, cellIndex, e);
6254 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6255 cell = Roo.get(t).findParent('td', false, true);
6257 Roo.log("failed to find th in tbody?");
6258 Roo.log(e.getTarget());
6263 var row = cell.findParent('tr', false, true);
6264 var cellIndex = cell.dom.cellIndex;
6265 var rowIndex = row.dom.rowIndex - 1;
6269 this.fireEvent("row" + name, this, rowIndex, e);
6273 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6279 onMouseover : function(e, el)
6281 var cell = Roo.get(el);
6287 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6288 cell = cell.findParent('td', false, true);
6291 var row = cell.findParent('tr', false, true);
6292 var cellIndex = cell.dom.cellIndex;
6293 var rowIndex = row.dom.rowIndex - 1; // start from 0
6295 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6299 onMouseout : function(e, el)
6301 var cell = Roo.get(el);
6307 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6308 cell = cell.findParent('td', false, true);
6311 var row = cell.findParent('tr', false, true);
6312 var cellIndex = cell.dom.cellIndex;
6313 var rowIndex = row.dom.rowIndex - 1; // start from 0
6315 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6319 onClick : function(e, el)
6321 var cell = Roo.get(el);
6323 if(!cell || (!this.cellSelection && !this.rowSelection)){
6327 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6328 cell = cell.findParent('td', false, true);
6331 if(!cell || typeof(cell) == 'undefined'){
6335 var row = cell.findParent('tr', false, true);
6337 if(!row || typeof(row) == 'undefined'){
6341 var cellIndex = cell.dom.cellIndex;
6342 var rowIndex = this.getRowIndex(row);
6344 // why??? - should these not be based on SelectionModel?
6345 if(this.cellSelection){
6346 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6349 if(this.rowSelection){
6350 this.fireEvent('rowclick', this, row, rowIndex, e);
6356 onDblClick : function(e,el)
6358 var cell = Roo.get(el);
6360 if(!cell || (!this.cellSelection && !this.rowSelection)){
6364 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6365 cell = cell.findParent('td', false, true);
6368 if(!cell || typeof(cell) == 'undefined'){
6372 var row = cell.findParent('tr', false, true);
6374 if(!row || typeof(row) == 'undefined'){
6378 var cellIndex = cell.dom.cellIndex;
6379 var rowIndex = this.getRowIndex(row);
6381 if(this.cellSelection){
6382 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6385 if(this.rowSelection){
6386 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6390 sort : function(e,el)
6392 var col = Roo.get(el);
6394 if(!col.hasClass('sortable')){
6398 var sort = col.attr('sort');
6401 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6405 this.store.sortInfo = {field : sort, direction : dir};
6408 Roo.log("calling footer first");
6409 this.footer.onClick('first');
6412 this.store.load({ params : { start : 0 } });
6416 renderHeader : function()
6424 this.totalWidth = 0;
6426 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6428 var config = cm.config[i];
6432 cls : 'x-hcol-' + i,
6434 html: cm.getColumnHeader(i)
6439 if(typeof(config.sortable) != 'undefined' && config.sortable){
6441 c.html = '<i class="glyphicon"></i>' + c.html;
6444 if(typeof(config.lgHeader) != 'undefined'){
6445 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6448 if(typeof(config.mdHeader) != 'undefined'){
6449 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6452 if(typeof(config.smHeader) != 'undefined'){
6453 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6456 if(typeof(config.xsHeader) != 'undefined'){
6457 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6464 if(typeof(config.tooltip) != 'undefined'){
6465 c.tooltip = config.tooltip;
6468 if(typeof(config.colspan) != 'undefined'){
6469 c.colspan = config.colspan;
6472 if(typeof(config.hidden) != 'undefined' && config.hidden){
6473 c.style += ' display:none;';
6476 if(typeof(config.dataIndex) != 'undefined'){
6477 c.sort = config.dataIndex;
6482 if(typeof(config.align) != 'undefined' && config.align.length){
6483 c.style += ' text-align:' + config.align + ';';
6486 if(typeof(config.width) != 'undefined'){
6487 c.style += ' width:' + config.width + 'px;';
6488 this.totalWidth += config.width;
6490 this.totalWidth += 100; // assume minimum of 100 per column?
6493 if(typeof(config.cls) != 'undefined'){
6494 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6497 ['xs','sm','md','lg'].map(function(size){
6499 if(typeof(config[size]) == 'undefined'){
6503 if (!config[size]) { // 0 = hidden
6504 c.cls += ' hidden-' + size;
6508 c.cls += ' col-' + size + '-' + config[size];
6518 renderBody : function()
6528 colspan : this.cm.getColumnCount()
6538 renderFooter : function()
6548 colspan : this.cm.getColumnCount()
6562 // Roo.log('ds onload');
6567 var ds = this.store;
6569 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6570 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6571 if (_this.store.sortInfo) {
6573 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6574 e.select('i', true).addClass(['glyphicon-arrow-up']);
6577 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6578 e.select('i', true).addClass(['glyphicon-arrow-down']);
6583 var tbody = this.mainBody;
6585 if(ds.getCount() > 0){
6586 ds.data.each(function(d,rowIndex){
6587 var row = this.renderRow(cm, ds, rowIndex);
6589 tbody.createChild(row);
6593 if(row.cellObjects.length){
6594 Roo.each(row.cellObjects, function(r){
6595 _this.renderCellObject(r);
6602 Roo.each(this.el.select('tbody td', true).elements, function(e){
6603 e.on('mouseover', _this.onMouseover, _this);
6606 Roo.each(this.el.select('tbody td', true).elements, function(e){
6607 e.on('mouseout', _this.onMouseout, _this);
6609 this.fireEvent('rowsrendered', this);
6610 //if(this.loadMask){
6611 // this.maskEl.hide();
6618 onUpdate : function(ds,record)
6620 this.refreshRow(record);
6624 onRemove : function(ds, record, index, isUpdate){
6625 if(isUpdate !== true){
6626 this.fireEvent("beforerowremoved", this, index, record);
6628 var bt = this.mainBody.dom;
6630 var rows = this.el.select('tbody > tr', true).elements;
6632 if(typeof(rows[index]) != 'undefined'){
6633 bt.removeChild(rows[index].dom);
6636 // if(bt.rows[index]){
6637 // bt.removeChild(bt.rows[index]);
6640 if(isUpdate !== true){
6641 //this.stripeRows(index);
6642 //this.syncRowHeights(index, index);
6644 this.fireEvent("rowremoved", this, index, record);
6648 onAdd : function(ds, records, rowIndex)
6650 //Roo.log('on Add called');
6651 // - note this does not handle multiple adding very well..
6652 var bt = this.mainBody.dom;
6653 for (var i =0 ; i < records.length;i++) {
6654 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6655 //Roo.log(records[i]);
6656 //Roo.log(this.store.getAt(rowIndex+i));
6657 this.insertRow(this.store, rowIndex + i, false);
6664 refreshRow : function(record){
6665 var ds = this.store, index;
6666 if(typeof record == 'number'){
6668 record = ds.getAt(index);
6670 index = ds.indexOf(record);
6672 this.insertRow(ds, index, true);
6674 this.onRemove(ds, record, index+1, true);
6676 //this.syncRowHeights(index, index);
6678 this.fireEvent("rowupdated", this, index, record);
6681 insertRow : function(dm, rowIndex, isUpdate){
6684 this.fireEvent("beforerowsinserted", this, rowIndex);
6686 //var s = this.getScrollState();
6687 var row = this.renderRow(this.cm, this.store, rowIndex);
6688 // insert before rowIndex..
6689 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6693 if(row.cellObjects.length){
6694 Roo.each(row.cellObjects, function(r){
6695 _this.renderCellObject(r);
6700 this.fireEvent("rowsinserted", this, rowIndex);
6701 //this.syncRowHeights(firstRow, lastRow);
6702 //this.stripeRows(firstRow);
6709 getRowDom : function(rowIndex)
6711 var rows = this.el.select('tbody > tr', true).elements;
6713 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6716 // returns the object tree for a tr..
6719 renderRow : function(cm, ds, rowIndex)
6721 var d = ds.getAt(rowIndex);
6725 cls : 'x-row-' + rowIndex,
6729 var cellObjects = [];
6731 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6732 var config = cm.config[i];
6734 var renderer = cm.getRenderer(i);
6738 if(typeof(renderer) !== 'undefined'){
6739 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6741 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6742 // and are rendered into the cells after the row is rendered - using the id for the element.
6744 if(typeof(value) === 'object'){
6754 rowIndex : rowIndex,
6759 this.fireEvent('rowclass', this, rowcfg);
6763 cls : rowcfg.rowClass + ' x-col-' + i,
6765 html: (typeof(value) === 'object') ? '' : value
6772 if(typeof(config.colspan) != 'undefined'){
6773 td.colspan = config.colspan;
6776 if(typeof(config.hidden) != 'undefined' && config.hidden){
6777 td.style += ' display:none;';
6780 if(typeof(config.align) != 'undefined' && config.align.length){
6781 td.style += ' text-align:' + config.align + ';';
6784 if(typeof(config.width) != 'undefined'){
6785 td.style += ' width:' + config.width + 'px;';
6788 if(typeof(config.cursor) != 'undefined'){
6789 td.style += ' cursor:' + config.cursor + ';';
6792 if(typeof(config.cls) != 'undefined'){
6793 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6796 ['xs','sm','md','lg'].map(function(size){
6798 if(typeof(config[size]) == 'undefined'){
6802 if (!config[size]) { // 0 = hidden
6803 td.cls += ' hidden-' + size;
6807 td.cls += ' col-' + size + '-' + config[size];
6815 row.cellObjects = cellObjects;
6823 onBeforeLoad : function()
6825 //Roo.log('ds onBeforeLoad');
6829 //if(this.loadMask){
6830 // this.maskEl.show();
6838 this.el.select('tbody', true).first().dom.innerHTML = '';
6841 * Show or hide a row.
6842 * @param {Number} rowIndex to show or hide
6843 * @param {Boolean} state hide
6845 setRowVisibility : function(rowIndex, state)
6847 var bt = this.mainBody.dom;
6849 var rows = this.el.select('tbody > tr', true).elements;
6851 if(typeof(rows[rowIndex]) == 'undefined'){
6854 rows[rowIndex].dom.style.display = state ? '' : 'none';
6858 getSelectionModel : function(){
6860 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6862 return this.selModel;
6865 * Render the Roo.bootstrap object from renderder
6867 renderCellObject : function(r)
6871 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6873 var t = r.cfg.render(r.container);
6876 Roo.each(r.cfg.cn, function(c){
6878 container: t.getChildContainer(),
6881 _this.renderCellObject(child);
6886 getRowIndex : function(row)
6890 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6901 * Returns the grid's underlying element = used by panel.Grid
6902 * @return {Element} The element
6904 getGridEl : function(){
6908 * Forces a resize - used by panel.Grid
6909 * @return {Element} The element
6911 autoSize : function()
6913 //var ctr = Roo.get(this.container.dom.parentElement);
6914 var ctr = Roo.get(this.el.dom);
6916 var thd = this.getGridEl().select('thead',true).first();
6917 var tbd = this.getGridEl().select('tbody', true).first();
6918 var tfd = this.getGridEl().select('tfoot', true).first();
6920 var cw = ctr.getWidth();
6924 tbd.setSize(ctr.getWidth(),
6925 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6927 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6930 cw = Math.max(cw, this.totalWidth);
6931 this.getGridEl().select('tr',true).setWidth(cw);
6932 // resize 'expandable coloumn?
6934 return; // we doe not have a view in this design..
6937 onBodyScroll: function()
6939 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6941 this.mainHead.setStyle({
6942 'position' : 'relative',
6943 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6949 var scrollHeight = this.mainBody.dom.scrollHeight;
6951 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6953 var height = this.mainBody.getHeight();
6955 if(scrollHeight - height == scrollTop) {
6957 var total = this.ds.getTotalCount();
6959 if(this.footer.cursor + this.footer.pageSize < total){
6961 this.footer.ds.load({
6963 start : this.footer.cursor + this.footer.pageSize,
6964 limit : this.footer.pageSize
6974 onHeaderChange : function()
6976 var header = this.renderHeader();
6977 var table = this.el.select('table', true).first();
6979 this.mainHead.remove();
6980 this.mainHead = table.createChild(header, this.mainBody, false);
6983 onHiddenChange : function(colModel, colIndex, hidden)
6985 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6986 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6988 this.CSS.updateRule(thSelector, "display", "");
6989 this.CSS.updateRule(tdSelector, "display", "");
6992 this.CSS.updateRule(thSelector, "display", "none");
6993 this.CSS.updateRule(tdSelector, "display", "none");
6996 this.onHeaderChange();
7013 * @class Roo.bootstrap.TableCell
7014 * @extends Roo.bootstrap.Component
7015 * Bootstrap TableCell class
7016 * @cfg {String} html cell contain text
7017 * @cfg {String} cls cell class
7018 * @cfg {String} tag cell tag (td|th) default td
7019 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7020 * @cfg {String} align Aligns the content in a cell
7021 * @cfg {String} axis Categorizes cells
7022 * @cfg {String} bgcolor Specifies the background color of a cell
7023 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7024 * @cfg {Number} colspan Specifies the number of columns a cell should span
7025 * @cfg {String} headers Specifies one or more header cells a cell is related to
7026 * @cfg {Number} height Sets the height of a cell
7027 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7028 * @cfg {Number} rowspan Sets the number of rows a cell should span
7029 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7030 * @cfg {String} valign Vertical aligns the content in a cell
7031 * @cfg {Number} width Specifies the width of a cell
7034 * Create a new TableCell
7035 * @param {Object} config The config object
7038 Roo.bootstrap.TableCell = function(config){
7039 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7042 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7062 getAutoCreate : function(){
7063 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7083 cfg.align=this.align
7089 cfg.bgcolor=this.bgcolor
7092 cfg.charoff=this.charoff
7095 cfg.colspan=this.colspan
7098 cfg.headers=this.headers
7101 cfg.height=this.height
7104 cfg.nowrap=this.nowrap
7107 cfg.rowspan=this.rowspan
7110 cfg.scope=this.scope
7113 cfg.valign=this.valign
7116 cfg.width=this.width
7135 * @class Roo.bootstrap.TableRow
7136 * @extends Roo.bootstrap.Component
7137 * Bootstrap TableRow class
7138 * @cfg {String} cls row class
7139 * @cfg {String} align Aligns the content in a table row
7140 * @cfg {String} bgcolor Specifies a background color for a table row
7141 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7142 * @cfg {String} valign Vertical aligns the content in a table row
7145 * Create a new TableRow
7146 * @param {Object} config The config object
7149 Roo.bootstrap.TableRow = function(config){
7150 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7153 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7161 getAutoCreate : function(){
7162 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7172 cfg.align = this.align;
7175 cfg.bgcolor = this.bgcolor;
7178 cfg.charoff = this.charoff;
7181 cfg.valign = this.valign;
7199 * @class Roo.bootstrap.TableBody
7200 * @extends Roo.bootstrap.Component
7201 * Bootstrap TableBody class
7202 * @cfg {String} cls element class
7203 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7204 * @cfg {String} align Aligns the content inside the element
7205 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7206 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7209 * Create a new TableBody
7210 * @param {Object} config The config object
7213 Roo.bootstrap.TableBody = function(config){
7214 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7217 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7225 getAutoCreate : function(){
7226 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7240 cfg.align = this.align;
7243 cfg.charoff = this.charoff;
7246 cfg.valign = this.valign;
7253 // initEvents : function()
7260 // this.store = Roo.factory(this.store, Roo.data);
7261 // this.store.on('load', this.onLoad, this);
7263 // this.store.load();
7267 // onLoad: function ()
7269 // this.fireEvent('load', this);
7279 * Ext JS Library 1.1.1
7280 * Copyright(c) 2006-2007, Ext JS, LLC.
7282 * Originally Released Under LGPL - original licence link has changed is not relivant.
7285 * <script type="text/javascript">
7288 // as we use this in bootstrap.
7289 Roo.namespace('Roo.form');
7291 * @class Roo.form.Action
7292 * Internal Class used to handle form actions
7294 * @param {Roo.form.BasicForm} el The form element or its id
7295 * @param {Object} config Configuration options
7300 // define the action interface
7301 Roo.form.Action = function(form, options){
7303 this.options = options || {};
7306 * Client Validation Failed
7309 Roo.form.Action.CLIENT_INVALID = 'client';
7311 * Server Validation Failed
7314 Roo.form.Action.SERVER_INVALID = 'server';
7316 * Connect to Server Failed
7319 Roo.form.Action.CONNECT_FAILURE = 'connect';
7321 * Reading Data from Server Failed
7324 Roo.form.Action.LOAD_FAILURE = 'load';
7326 Roo.form.Action.prototype = {
7328 failureType : undefined,
7329 response : undefined,
7333 run : function(options){
7338 success : function(response){
7343 handleResponse : function(response){
7347 // default connection failure
7348 failure : function(response){
7350 this.response = response;
7351 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7352 this.form.afterAction(this, false);
7355 processResponse : function(response){
7356 this.response = response;
7357 if(!response.responseText){
7360 this.result = this.handleResponse(response);
7364 // utility functions used internally
7365 getUrl : function(appendParams){
7366 var url = this.options.url || this.form.url || this.form.el.dom.action;
7368 var p = this.getParams();
7370 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7376 getMethod : function(){
7377 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7380 getParams : function(){
7381 var bp = this.form.baseParams;
7382 var p = this.options.params;
7384 if(typeof p == "object"){
7385 p = Roo.urlEncode(Roo.applyIf(p, bp));
7386 }else if(typeof p == 'string' && bp){
7387 p += '&' + Roo.urlEncode(bp);
7390 p = Roo.urlEncode(bp);
7395 createCallback : function(){
7397 success: this.success,
7398 failure: this.failure,
7400 timeout: (this.form.timeout*1000),
7401 upload: this.form.fileUpload ? this.success : undefined
7406 Roo.form.Action.Submit = function(form, options){
7407 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7410 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7413 haveProgress : false,
7414 uploadComplete : false,
7416 // uploadProgress indicator.
7417 uploadProgress : function()
7419 if (!this.form.progressUrl) {
7423 if (!this.haveProgress) {
7424 Roo.MessageBox.progress("Uploading", "Uploading");
7426 if (this.uploadComplete) {
7427 Roo.MessageBox.hide();
7431 this.haveProgress = true;
7433 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7435 var c = new Roo.data.Connection();
7437 url : this.form.progressUrl,
7442 success : function(req){
7443 //console.log(data);
7447 rdata = Roo.decode(req.responseText)
7449 Roo.log("Invalid data from server..");
7453 if (!rdata || !rdata.success) {
7455 Roo.MessageBox.alert(Roo.encode(rdata));
7458 var data = rdata.data;
7460 if (this.uploadComplete) {
7461 Roo.MessageBox.hide();
7466 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7467 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7470 this.uploadProgress.defer(2000,this);
7473 failure: function(data) {
7474 Roo.log('progress url failed ');
7485 // run get Values on the form, so it syncs any secondary forms.
7486 this.form.getValues();
7488 var o = this.options;
7489 var method = this.getMethod();
7490 var isPost = method == 'POST';
7491 if(o.clientValidation === false || this.form.isValid()){
7493 if (this.form.progressUrl) {
7494 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7495 (new Date() * 1) + '' + Math.random());
7500 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7501 form:this.form.el.dom,
7502 url:this.getUrl(!isPost),
7504 params:isPost ? this.getParams() : null,
7505 isUpload: this.form.fileUpload
7508 this.uploadProgress();
7510 }else if (o.clientValidation !== false){ // client validation failed
7511 this.failureType = Roo.form.Action.CLIENT_INVALID;
7512 this.form.afterAction(this, false);
7516 success : function(response)
7518 this.uploadComplete= true;
7519 if (this.haveProgress) {
7520 Roo.MessageBox.hide();
7524 var result = this.processResponse(response);
7525 if(result === true || result.success){
7526 this.form.afterAction(this, true);
7530 this.form.markInvalid(result.errors);
7531 this.failureType = Roo.form.Action.SERVER_INVALID;
7533 this.form.afterAction(this, false);
7535 failure : function(response)
7537 this.uploadComplete= true;
7538 if (this.haveProgress) {
7539 Roo.MessageBox.hide();
7542 this.response = response;
7543 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7544 this.form.afterAction(this, false);
7547 handleResponse : function(response){
7548 if(this.form.errorReader){
7549 var rs = this.form.errorReader.read(response);
7552 for(var i = 0, len = rs.records.length; i < len; i++) {
7553 var r = rs.records[i];
7557 if(errors.length < 1){
7561 success : rs.success,
7567 ret = Roo.decode(response.responseText);
7571 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7581 Roo.form.Action.Load = function(form, options){
7582 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7583 this.reader = this.form.reader;
7586 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7591 Roo.Ajax.request(Roo.apply(
7592 this.createCallback(), {
7593 method:this.getMethod(),
7594 url:this.getUrl(false),
7595 params:this.getParams()
7599 success : function(response){
7601 var result = this.processResponse(response);
7602 if(result === true || !result.success || !result.data){
7603 this.failureType = Roo.form.Action.LOAD_FAILURE;
7604 this.form.afterAction(this, false);
7607 this.form.clearInvalid();
7608 this.form.setValues(result.data);
7609 this.form.afterAction(this, true);
7612 handleResponse : function(response){
7613 if(this.form.reader){
7614 var rs = this.form.reader.read(response);
7615 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7617 success : rs.success,
7621 return Roo.decode(response.responseText);
7625 Roo.form.Action.ACTION_TYPES = {
7626 'load' : Roo.form.Action.Load,
7627 'submit' : Roo.form.Action.Submit
7636 * @class Roo.bootstrap.Form
7637 * @extends Roo.bootstrap.Component
7638 * Bootstrap Form class
7639 * @cfg {String} method GET | POST (default POST)
7640 * @cfg {String} labelAlign top | left (default top)
7641 * @cfg {String} align left | right - for navbars
7642 * @cfg {Boolean} loadMask load mask when submit (default true)
7647 * @param {Object} config The config object
7651 Roo.bootstrap.Form = function(config){
7653 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7655 Roo.bootstrap.Form.popover.apply();
7659 * @event clientvalidation
7660 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7661 * @param {Form} this
7662 * @param {Boolean} valid true if the form has passed client-side validation
7664 clientvalidation: true,
7666 * @event beforeaction
7667 * Fires before any action is performed. Return false to cancel the action.
7668 * @param {Form} this
7669 * @param {Action} action The action to be performed
7673 * @event actionfailed
7674 * Fires when an action fails.
7675 * @param {Form} this
7676 * @param {Action} action The action that failed
7678 actionfailed : true,
7680 * @event actioncomplete
7681 * Fires when an action is completed.
7682 * @param {Form} this
7683 * @param {Action} action The action that completed
7685 actioncomplete : true
7689 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7692 * @cfg {String} method
7693 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7698 * The URL to use for form actions if one isn't supplied in the action options.
7701 * @cfg {Boolean} fileUpload
7702 * Set to true if this form is a file upload.
7706 * @cfg {Object} baseParams
7707 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7711 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7715 * @cfg {Sting} align (left|right) for navbar forms
7720 activeAction : null,
7723 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7724 * element by passing it or its id or mask the form itself by passing in true.
7727 waitMsgTarget : false,
7732 * @cfg {Boolean} errorMask (true|false) default false
7737 * @cfg {Number} maskOffset Default 100
7742 * @cfg {Boolean} maskBody
7746 getAutoCreate : function(){
7750 method : this.method || 'POST',
7751 id : this.id || Roo.id(),
7754 if (this.parent().xtype.match(/^Nav/)) {
7755 cfg.cls = 'navbar-form navbar-' + this.align;
7759 if (this.labelAlign == 'left' ) {
7760 cfg.cls += ' form-horizontal';
7766 initEvents : function()
7768 this.el.on('submit', this.onSubmit, this);
7769 // this was added as random key presses on the form where triggering form submit.
7770 this.el.on('keypress', function(e) {
7771 if (e.getCharCode() != 13) {
7774 // we might need to allow it for textareas.. and some other items.
7775 // check e.getTarget().
7777 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7781 Roo.log("keypress blocked");
7789 onSubmit : function(e){
7794 * Returns true if client-side validation on the form is successful.
7797 isValid : function(){
7798 var items = this.getItems();
7802 items.each(function(f){
7809 if(!target && f.el.isVisible(true)){
7815 if(this.errorMask && !valid){
7816 Roo.bootstrap.Form.popover.mask(this, target);
7823 * Returns true if any fields in this form have changed since their original load.
7826 isDirty : function(){
7828 var items = this.getItems();
7829 items.each(function(f){
7839 * Performs a predefined action (submit or load) or custom actions you define on this form.
7840 * @param {String} actionName The name of the action type
7841 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7842 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7843 * accept other config options):
7845 Property Type Description
7846 ---------------- --------------- ----------------------------------------------------------------------------------
7847 url String The url for the action (defaults to the form's url)
7848 method String The form method to use (defaults to the form's method, or POST if not defined)
7849 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7850 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7851 validate the form on the client (defaults to false)
7853 * @return {BasicForm} this
7855 doAction : function(action, options){
7856 if(typeof action == 'string'){
7857 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7859 if(this.fireEvent('beforeaction', this, action) !== false){
7860 this.beforeAction(action);
7861 action.run.defer(100, action);
7867 beforeAction : function(action){
7868 var o = action.options;
7873 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7875 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7878 // not really supported yet.. ??
7880 //if(this.waitMsgTarget === true){
7881 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7882 //}else if(this.waitMsgTarget){
7883 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7884 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7886 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7892 afterAction : function(action, success){
7893 this.activeAction = null;
7894 var o = action.options;
7899 Roo.get(document.body).unmask();
7905 //if(this.waitMsgTarget === true){
7906 // this.el.unmask();
7907 //}else if(this.waitMsgTarget){
7908 // this.waitMsgTarget.unmask();
7910 // Roo.MessageBox.updateProgress(1);
7911 // Roo.MessageBox.hide();
7918 Roo.callback(o.success, o.scope, [this, action]);
7919 this.fireEvent('actioncomplete', this, action);
7923 // failure condition..
7924 // we have a scenario where updates need confirming.
7925 // eg. if a locking scenario exists..
7926 // we look for { errors : { needs_confirm : true }} in the response.
7928 (typeof(action.result) != 'undefined') &&
7929 (typeof(action.result.errors) != 'undefined') &&
7930 (typeof(action.result.errors.needs_confirm) != 'undefined')
7933 Roo.log("not supported yet");
7936 Roo.MessageBox.confirm(
7937 "Change requires confirmation",
7938 action.result.errorMsg,
7943 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7953 Roo.callback(o.failure, o.scope, [this, action]);
7954 // show an error message if no failed handler is set..
7955 if (!this.hasListener('actionfailed')) {
7956 Roo.log("need to add dialog support");
7958 Roo.MessageBox.alert("Error",
7959 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7960 action.result.errorMsg :
7961 "Saving Failed, please check your entries or try again"
7966 this.fireEvent('actionfailed', this, action);
7971 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7972 * @param {String} id The value to search for
7975 findField : function(id){
7976 var items = this.getItems();
7977 var field = items.get(id);
7979 items.each(function(f){
7980 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7987 return field || null;
7990 * Mark fields in this form invalid in bulk.
7991 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7992 * @return {BasicForm} this
7994 markInvalid : function(errors){
7995 if(errors instanceof Array){
7996 for(var i = 0, len = errors.length; i < len; i++){
7997 var fieldError = errors[i];
7998 var f = this.findField(fieldError.id);
8000 f.markInvalid(fieldError.msg);
8006 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8007 field.markInvalid(errors[id]);
8011 //Roo.each(this.childForms || [], function (f) {
8012 // f.markInvalid(errors);
8019 * Set values for fields in this form in bulk.
8020 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8021 * @return {BasicForm} this
8023 setValues : function(values){
8024 if(values instanceof Array){ // array of objects
8025 for(var i = 0, len = values.length; i < len; i++){
8027 var f = this.findField(v.id);
8029 f.setValue(v.value);
8030 if(this.trackResetOnLoad){
8031 f.originalValue = f.getValue();
8035 }else{ // object hash
8038 if(typeof values[id] != 'function' && (field = this.findField(id))){
8040 if (field.setFromData &&
8042 field.displayField &&
8043 // combos' with local stores can
8044 // be queried via setValue()
8045 // to set their value..
8046 (field.store && !field.store.isLocal)
8050 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8051 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8052 field.setFromData(sd);
8054 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8056 field.setFromData(values);
8059 field.setValue(values[id]);
8063 if(this.trackResetOnLoad){
8064 field.originalValue = field.getValue();
8070 //Roo.each(this.childForms || [], function (f) {
8071 // f.setValues(values);
8078 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8079 * they are returned as an array.
8080 * @param {Boolean} asString
8083 getValues : function(asString){
8084 //if (this.childForms) {
8085 // copy values from the child forms
8086 // Roo.each(this.childForms, function (f) {
8087 // this.setValues(f.getValues());
8093 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8094 if(asString === true){
8097 return Roo.urlDecode(fs);
8101 * Returns the fields in this form as an object with key/value pairs.
8102 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8105 getFieldValues : function(with_hidden)
8107 var items = this.getItems();
8109 items.each(function(f){
8115 var v = f.getValue();
8117 if (f.inputType =='radio') {
8118 if (typeof(ret[f.getName()]) == 'undefined') {
8119 ret[f.getName()] = ''; // empty..
8122 if (!f.el.dom.checked) {
8130 if(f.xtype == 'MoneyField'){
8131 ret[f.currencyName] = f.getCurrency();
8134 // not sure if this supported any more..
8135 if ((typeof(v) == 'object') && f.getRawValue) {
8136 v = f.getRawValue() ; // dates..
8138 // combo boxes where name != hiddenName...
8139 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8140 ret[f.name] = f.getRawValue();
8142 ret[f.getName()] = v;
8149 * Clears all invalid messages in this form.
8150 * @return {BasicForm} this
8152 clearInvalid : function(){
8153 var items = this.getItems();
8155 items.each(function(f){
8164 * @return {BasicForm} this
8167 var items = this.getItems();
8168 items.each(function(f){
8172 Roo.each(this.childForms || [], function (f) {
8180 getItems : function()
8182 var r=new Roo.util.MixedCollection(false, function(o){
8183 return o.id || (o.id = Roo.id());
8185 var iter = function(el) {
8192 Roo.each(el.items,function(e) {
8201 hideFields : function(items)
8203 Roo.each(items, function(i){
8205 var f = this.findField(i);
8211 if(f.xtype == 'DateField'){
8212 f.setVisible(false);
8221 showFields : function(items)
8223 Roo.each(items, function(i){
8225 var f = this.findField(i);
8231 if(f.xtype == 'DateField'){
8243 Roo.apply(Roo.bootstrap.Form, {
8270 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8271 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8272 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8273 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8276 this.maskEl.top.enableDisplayMode("block");
8277 this.maskEl.left.enableDisplayMode("block");
8278 this.maskEl.bottom.enableDisplayMode("block");
8279 this.maskEl.right.enableDisplayMode("block");
8281 this.toolTip = new Roo.bootstrap.Tooltip({
8282 cls : 'roo-form-error-popover',
8284 'left' : ['r-l', [-2,0], 'right'],
8285 'right' : ['l-r', [2,0], 'left'],
8286 'bottom' : ['tl-bl', [0,2], 'top'],
8287 'top' : [ 'bl-tl', [0,-2], 'bottom']
8291 this.toolTip.render(Roo.get(document.body));
8293 this.toolTip.el.enableDisplayMode("block");
8295 Roo.get(document.body).on('click', function(){
8299 Roo.get(document.body).on('touchstart', function(){
8303 this.isApplied = true
8306 mask : function(form, target)
8310 this.target = target;
8312 if(!this.form.errorMask || !target.el){
8316 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8318 Roo.log(scrollable);
8320 var ot = this.target.el.calcOffsetsTo(scrollable);
8322 var scrollTo = ot[1] - this.form.maskOffset;
8324 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8326 scrollable.scrollTo('top', scrollTo);
8328 var box = this.target.el.getBox();
8330 var zIndex = Roo.bootstrap.Modal.zIndex++;
8333 this.maskEl.top.setStyle('position', 'absolute');
8334 this.maskEl.top.setStyle('z-index', zIndex);
8335 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8336 this.maskEl.top.setLeft(0);
8337 this.maskEl.top.setTop(0);
8338 this.maskEl.top.show();
8340 this.maskEl.left.setStyle('position', 'absolute');
8341 this.maskEl.left.setStyle('z-index', zIndex);
8342 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8343 this.maskEl.left.setLeft(0);
8344 this.maskEl.left.setTop(box.y - this.padding);
8345 this.maskEl.left.show();
8347 this.maskEl.bottom.setStyle('position', 'absolute');
8348 this.maskEl.bottom.setStyle('z-index', zIndex);
8349 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8350 this.maskEl.bottom.setLeft(0);
8351 this.maskEl.bottom.setTop(box.bottom + this.padding);
8352 this.maskEl.bottom.show();
8354 this.maskEl.right.setStyle('position', 'absolute');
8355 this.maskEl.right.setStyle('z-index', zIndex);
8356 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8357 this.maskEl.right.setLeft(box.right + this.padding);
8358 this.maskEl.right.setTop(box.y - this.padding);
8359 this.maskEl.right.show();
8361 this.toolTip.bindEl = this.target.el;
8363 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8365 var tip = this.target.blankText;
8367 if(this.target.getValue() !== '' ) {
8369 if (this.target.invalidText.length) {
8370 tip = this.target.invalidText;
8371 } else if (this.target.regexText.length){
8372 tip = this.target.regexText;
8376 this.toolTip.show(tip);
8378 this.intervalID = window.setInterval(function() {
8379 Roo.bootstrap.Form.popover.unmask();
8382 window.onwheel = function(){ return false;};
8384 (function(){ this.isMasked = true; }).defer(500, this);
8390 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8394 this.maskEl.top.setStyle('position', 'absolute');
8395 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8396 this.maskEl.top.hide();
8398 this.maskEl.left.setStyle('position', 'absolute');
8399 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8400 this.maskEl.left.hide();
8402 this.maskEl.bottom.setStyle('position', 'absolute');
8403 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8404 this.maskEl.bottom.hide();
8406 this.maskEl.right.setStyle('position', 'absolute');
8407 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8408 this.maskEl.right.hide();
8410 this.toolTip.hide();
8412 this.toolTip.el.hide();
8414 window.onwheel = function(){ return true;};
8416 if(this.intervalID){
8417 window.clearInterval(this.intervalID);
8418 this.intervalID = false;
8421 this.isMasked = false;
8431 * Ext JS Library 1.1.1
8432 * Copyright(c) 2006-2007, Ext JS, LLC.
8434 * Originally Released Under LGPL - original licence link has changed is not relivant.
8437 * <script type="text/javascript">
8440 * @class Roo.form.VTypes
8441 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8444 Roo.form.VTypes = function(){
8445 // closure these in so they are only created once.
8446 var alpha = /^[a-zA-Z_]+$/;
8447 var alphanum = /^[a-zA-Z0-9_]+$/;
8448 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8449 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8451 // All these messages and functions are configurable
8454 * The function used to validate email addresses
8455 * @param {String} value The email address
8457 'email' : function(v){
8458 return email.test(v);
8461 * The error text to display when the email validation function returns false
8464 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8466 * The keystroke filter mask to be applied on email input
8469 'emailMask' : /[a-z0-9_\.\-@]/i,
8472 * The function used to validate URLs
8473 * @param {String} value The URL
8475 'url' : function(v){
8479 * The error text to display when the url validation function returns false
8482 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8485 * The function used to validate alpha values
8486 * @param {String} value The value
8488 'alpha' : function(v){
8489 return alpha.test(v);
8492 * The error text to display when the alpha validation function returns false
8495 'alphaText' : 'This field should only contain letters and _',
8497 * The keystroke filter mask to be applied on alpha input
8500 'alphaMask' : /[a-z_]/i,
8503 * The function used to validate alphanumeric values
8504 * @param {String} value The value
8506 'alphanum' : function(v){
8507 return alphanum.test(v);
8510 * The error text to display when the alphanumeric validation function returns false
8513 'alphanumText' : 'This field should only contain letters, numbers and _',
8515 * The keystroke filter mask to be applied on alphanumeric input
8518 'alphanumMask' : /[a-z0-9_]/i
8528 * @class Roo.bootstrap.Input
8529 * @extends Roo.bootstrap.Component
8530 * Bootstrap Input class
8531 * @cfg {Boolean} disabled is it disabled
8532 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8533 * @cfg {String} name name of the input
8534 * @cfg {string} fieldLabel - the label associated
8535 * @cfg {string} placeholder - placeholder to put in text.
8536 * @cfg {string} before - input group add on before
8537 * @cfg {string} after - input group add on after
8538 * @cfg {string} size - (lg|sm) or leave empty..
8539 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8540 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8541 * @cfg {Number} md colspan out of 12 for computer-sized screens
8542 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8543 * @cfg {string} value default value of the input
8544 * @cfg {Number} labelWidth set the width of label
8545 * @cfg {Number} labellg set the width of label (1-12)
8546 * @cfg {Number} labelmd set the width of label (1-12)
8547 * @cfg {Number} labelsm set the width of label (1-12)
8548 * @cfg {Number} labelxs set the width of label (1-12)
8549 * @cfg {String} labelAlign (top|left)
8550 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8551 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8552 * @cfg {String} indicatorpos (left|right) default left
8553 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8554 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8556 * @cfg {String} align (left|center|right) Default left
8557 * @cfg {Boolean} forceFeedback (true|false) Default false
8560 * Create a new Input
8561 * @param {Object} config The config object
8564 Roo.bootstrap.Input = function(config){
8566 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8571 * Fires when this field receives input focus.
8572 * @param {Roo.form.Field} this
8577 * Fires when this field loses input focus.
8578 * @param {Roo.form.Field} this
8583 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8584 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8585 * @param {Roo.form.Field} this
8586 * @param {Roo.EventObject} e The event object
8591 * Fires just before the field blurs if the field value has changed.
8592 * @param {Roo.form.Field} this
8593 * @param {Mixed} newValue The new value
8594 * @param {Mixed} oldValue The original value
8599 * Fires after the field has been marked as invalid.
8600 * @param {Roo.form.Field} this
8601 * @param {String} msg The validation message
8606 * Fires after the field has been validated with no errors.
8607 * @param {Roo.form.Field} this
8612 * Fires after the key up
8613 * @param {Roo.form.Field} this
8614 * @param {Roo.EventObject} e The event Object
8620 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8622 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8623 automatic validation (defaults to "keyup").
8625 validationEvent : "keyup",
8627 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8629 validateOnBlur : true,
8631 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8633 validationDelay : 250,
8635 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8637 focusClass : "x-form-focus", // not needed???
8641 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8643 invalidClass : "has-warning",
8646 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8648 validClass : "has-success",
8651 * @cfg {Boolean} hasFeedback (true|false) default true
8656 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8658 invalidFeedbackClass : "glyphicon-warning-sign",
8661 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8663 validFeedbackClass : "glyphicon-ok",
8666 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8668 selectOnFocus : false,
8671 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8675 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8680 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8682 disableKeyFilter : false,
8685 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8689 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8693 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8695 blankText : "Please complete this mandatory field",
8698 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8702 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8704 maxLength : Number.MAX_VALUE,
8706 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8708 minLengthText : "The minimum length for this field is {0}",
8710 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8712 maxLengthText : "The maximum length for this field is {0}",
8716 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8717 * If available, this function will be called only after the basic validators all return true, and will be passed the
8718 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8722 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8723 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8724 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8728 * @cfg {String} regexText -- Depricated - use Invalid Text
8733 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8739 autocomplete: false,
8758 formatedValue : false,
8759 forceFeedback : false,
8761 indicatorpos : 'left',
8771 parentLabelAlign : function()
8774 while (parent.parent()) {
8775 parent = parent.parent();
8776 if (typeof(parent.labelAlign) !='undefined') {
8777 return parent.labelAlign;
8784 getAutoCreate : function()
8786 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8792 if(this.inputType != 'hidden'){
8793 cfg.cls = 'form-group' //input-group
8799 type : this.inputType,
8801 cls : 'form-control',
8802 placeholder : this.placeholder || '',
8803 autocomplete : this.autocomplete || 'new-password'
8806 if(this.capture.length){
8807 input.capture = this.capture;
8810 if(this.accept.length){
8811 input.accept = this.accept + "/*";
8815 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8818 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8819 input.maxLength = this.maxLength;
8822 if (this.disabled) {
8823 input.disabled=true;
8826 if (this.readOnly) {
8827 input.readonly=true;
8831 input.name = this.name;
8835 input.cls += ' input-' + this.size;
8839 ['xs','sm','md','lg'].map(function(size){
8840 if (settings[size]) {
8841 cfg.cls += ' col-' + size + '-' + settings[size];
8845 var inputblock = input;
8849 cls: 'glyphicon form-control-feedback'
8852 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8855 cls : 'has-feedback',
8863 if (this.before || this.after) {
8866 cls : 'input-group',
8870 if (this.before && typeof(this.before) == 'string') {
8872 inputblock.cn.push({
8874 cls : 'roo-input-before input-group-addon',
8878 if (this.before && typeof(this.before) == 'object') {
8879 this.before = Roo.factory(this.before);
8881 inputblock.cn.push({
8883 cls : 'roo-input-before input-group-' +
8884 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8888 inputblock.cn.push(input);
8890 if (this.after && typeof(this.after) == 'string') {
8891 inputblock.cn.push({
8893 cls : 'roo-input-after input-group-addon',
8897 if (this.after && typeof(this.after) == 'object') {
8898 this.after = Roo.factory(this.after);
8900 inputblock.cn.push({
8902 cls : 'roo-input-after input-group-' +
8903 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8907 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8908 inputblock.cls += ' has-feedback';
8909 inputblock.cn.push(feedback);
8913 if (align ==='left' && this.fieldLabel.length) {
8915 cfg.cls += ' roo-form-group-label-left';
8920 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8921 tooltip : 'This field is required'
8926 cls : 'control-label',
8927 html : this.fieldLabel
8938 var labelCfg = cfg.cn[1];
8939 var contentCfg = cfg.cn[2];
8941 if(this.indicatorpos == 'right'){
8946 cls : 'control-label',
8950 html : this.fieldLabel
8954 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8955 tooltip : 'This field is required'
8968 labelCfg = cfg.cn[0];
8969 contentCfg = cfg.cn[1];
8973 if(this.labelWidth > 12){
8974 labelCfg.style = "width: " + this.labelWidth + 'px';
8977 if(this.labelWidth < 13 && this.labelmd == 0){
8978 this.labelmd = this.labelWidth;
8981 if(this.labellg > 0){
8982 labelCfg.cls += ' col-lg-' + this.labellg;
8983 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8986 if(this.labelmd > 0){
8987 labelCfg.cls += ' col-md-' + this.labelmd;
8988 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8991 if(this.labelsm > 0){
8992 labelCfg.cls += ' col-sm-' + this.labelsm;
8993 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8996 if(this.labelxs > 0){
8997 labelCfg.cls += ' col-xs-' + this.labelxs;
8998 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9002 } else if ( this.fieldLabel.length) {
9007 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9008 tooltip : 'This field is required'
9012 //cls : 'input-group-addon',
9013 html : this.fieldLabel
9021 if(this.indicatorpos == 'right'){
9026 //cls : 'input-group-addon',
9027 html : this.fieldLabel
9032 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9033 tooltip : 'This field is required'
9053 if (this.parentType === 'Navbar' && this.parent().bar) {
9054 cfg.cls += ' navbar-form';
9057 if (this.parentType === 'NavGroup') {
9058 cfg.cls += ' navbar-form';
9066 * return the real input element.
9068 inputEl: function ()
9070 return this.el.select('input.form-control',true).first();
9073 tooltipEl : function()
9075 return this.inputEl();
9078 indicatorEl : function()
9080 var indicator = this.el.select('i.roo-required-indicator',true).first();
9090 setDisabled : function(v)
9092 var i = this.inputEl().dom;
9094 i.removeAttribute('disabled');
9098 i.setAttribute('disabled','true');
9100 initEvents : function()
9103 this.inputEl().on("keydown" , this.fireKey, this);
9104 this.inputEl().on("focus", this.onFocus, this);
9105 this.inputEl().on("blur", this.onBlur, this);
9107 this.inputEl().relayEvent('keyup', this);
9109 this.indicator = this.indicatorEl();
9112 this.indicator.addClass('invisible');
9115 // reference to original value for reset
9116 this.originalValue = this.getValue();
9117 //Roo.form.TextField.superclass.initEvents.call(this);
9118 if(this.validationEvent == 'keyup'){
9119 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9120 this.inputEl().on('keyup', this.filterValidation, this);
9122 else if(this.validationEvent !== false){
9123 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9126 if(this.selectOnFocus){
9127 this.on("focus", this.preFocus, this);
9130 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9131 this.inputEl().on("keypress", this.filterKeys, this);
9133 this.inputEl().relayEvent('keypress', this);
9136 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9137 this.el.on("click", this.autoSize, this);
9140 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9141 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9144 if (typeof(this.before) == 'object') {
9145 this.before.render(this.el.select('.roo-input-before',true).first());
9147 if (typeof(this.after) == 'object') {
9148 this.after.render(this.el.select('.roo-input-after',true).first());
9151 this.inputEl().on('change', this.onChange, this);
9154 filterValidation : function(e){
9155 if(!e.isNavKeyPress()){
9156 this.validationTask.delay(this.validationDelay);
9160 * Validates the field value
9161 * @return {Boolean} True if the value is valid, else false
9163 validate : function(){
9164 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9165 if(this.disabled || this.validateValue(this.getRawValue())){
9176 * Validates a value according to the field's validation rules and marks the field as invalid
9177 * if the validation fails
9178 * @param {Mixed} value The value to validate
9179 * @return {Boolean} True if the value is valid, else false
9181 validateValue : function(value)
9183 if(this.getVisibilityEl().hasClass('hidden')){
9187 if(value.length < 1) { // if it's blank
9188 if(this.allowBlank){
9194 if(value.length < this.minLength){
9197 if(value.length > this.maxLength){
9201 var vt = Roo.form.VTypes;
9202 if(!vt[this.vtype](value, this)){
9206 if(typeof this.validator == "function"){
9207 var msg = this.validator(value);
9211 if (typeof(msg) == 'string') {
9212 this.invalidText = msg;
9216 if(this.regex && !this.regex.test(value)){
9224 fireKey : function(e){
9225 //Roo.log('field ' + e.getKey());
9226 if(e.isNavKeyPress()){
9227 this.fireEvent("specialkey", this, e);
9230 focus : function (selectText){
9232 this.inputEl().focus();
9233 if(selectText === true){
9234 this.inputEl().dom.select();
9240 onFocus : function(){
9241 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9242 // this.el.addClass(this.focusClass);
9245 this.hasFocus = true;
9246 this.startValue = this.getValue();
9247 this.fireEvent("focus", this);
9251 beforeBlur : Roo.emptyFn,
9255 onBlur : function(){
9257 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9258 //this.el.removeClass(this.focusClass);
9260 this.hasFocus = false;
9261 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9264 var v = this.getValue();
9265 if(String(v) !== String(this.startValue)){
9266 this.fireEvent('change', this, v, this.startValue);
9268 this.fireEvent("blur", this);
9271 onChange : function(e)
9273 var v = this.getValue();
9274 if(String(v) !== String(this.startValue)){
9275 this.fireEvent('change', this, v, this.startValue);
9281 * Resets the current field value to the originally loaded value and clears any validation messages
9284 this.setValue(this.originalValue);
9288 * Returns the name of the field
9289 * @return {Mixed} name The name field
9291 getName: function(){
9295 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9296 * @return {Mixed} value The field value
9298 getValue : function(){
9300 var v = this.inputEl().getValue();
9305 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9306 * @return {Mixed} value The field value
9308 getRawValue : function(){
9309 var v = this.inputEl().getValue();
9315 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9316 * @param {Mixed} value The value to set
9318 setRawValue : function(v){
9319 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9322 selectText : function(start, end){
9323 var v = this.getRawValue();
9325 start = start === undefined ? 0 : start;
9326 end = end === undefined ? v.length : end;
9327 var d = this.inputEl().dom;
9328 if(d.setSelectionRange){
9329 d.setSelectionRange(start, end);
9330 }else if(d.createTextRange){
9331 var range = d.createTextRange();
9332 range.moveStart("character", start);
9333 range.moveEnd("character", v.length-end);
9340 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9341 * @param {Mixed} value The value to set
9343 setValue : function(v){
9346 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9352 processValue : function(value){
9353 if(this.stripCharsRe){
9354 var newValue = value.replace(this.stripCharsRe, '');
9355 if(newValue !== value){
9356 this.setRawValue(newValue);
9363 preFocus : function(){
9365 if(this.selectOnFocus){
9366 this.inputEl().dom.select();
9369 filterKeys : function(e){
9371 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9374 var c = e.getCharCode(), cc = String.fromCharCode(c);
9375 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9378 if(!this.maskRe.test(cc)){
9383 * Clear any invalid styles/messages for this field
9385 clearInvalid : function(){
9387 if(!this.el || this.preventMark){ // not rendered
9392 this.el.removeClass(this.invalidClass);
9394 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9396 var feedback = this.el.select('.form-control-feedback', true).first();
9399 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9404 this.fireEvent('valid', this);
9408 * Mark this field as valid
9410 markValid : function()
9412 if(!this.el || this.preventMark){ // not rendered...
9416 this.el.removeClass([this.invalidClass, this.validClass]);
9418 var feedback = this.el.select('.form-control-feedback', true).first();
9421 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9425 this.indicator.removeClass('visible');
9426 this.indicator.addClass('invisible');
9433 if(this.allowBlank && !this.getRawValue().length){
9437 this.el.addClass(this.validClass);
9439 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9441 var feedback = this.el.select('.form-control-feedback', true).first();
9444 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9445 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9450 this.fireEvent('valid', this);
9454 * Mark this field as invalid
9455 * @param {String} msg The validation message
9457 markInvalid : function(msg)
9459 if(!this.el || this.preventMark){ // not rendered
9463 this.el.removeClass([this.invalidClass, this.validClass]);
9465 var feedback = this.el.select('.form-control-feedback', true).first();
9468 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9475 if(this.allowBlank && !this.getRawValue().length){
9480 this.indicator.removeClass('invisible');
9481 this.indicator.addClass('visible');
9484 this.el.addClass(this.invalidClass);
9486 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9488 var feedback = this.el.select('.form-control-feedback', true).first();
9491 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9493 if(this.getValue().length || this.forceFeedback){
9494 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9501 this.fireEvent('invalid', this, msg);
9504 SafariOnKeyDown : function(event)
9506 // this is a workaround for a password hang bug on chrome/ webkit.
9507 if (this.inputEl().dom.type != 'password') {
9511 var isSelectAll = false;
9513 if(this.inputEl().dom.selectionEnd > 0){
9514 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9516 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9517 event.preventDefault();
9522 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9524 event.preventDefault();
9525 // this is very hacky as keydown always get's upper case.
9527 var cc = String.fromCharCode(event.getCharCode());
9528 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9532 adjustWidth : function(tag, w){
9533 tag = tag.toLowerCase();
9534 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9535 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9539 if(tag == 'textarea'){
9542 }else if(Roo.isOpera){
9546 if(tag == 'textarea'){
9554 setFieldLabel : function(v)
9561 var ar = this.el.select('label > span',true);
9563 if (ar.elements.length) {
9564 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9565 this.fieldLabel = v;
9569 var br = this.el.select('label',true);
9571 if(br.elements.length) {
9572 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9573 this.fieldLabel = v;
9577 Roo.log('Cannot Found any of label > span || label in input');
9581 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9582 this.fieldLabel = v;
9597 * @class Roo.bootstrap.TextArea
9598 * @extends Roo.bootstrap.Input
9599 * Bootstrap TextArea class
9600 * @cfg {Number} cols Specifies the visible width of a text area
9601 * @cfg {Number} rows Specifies the visible number of lines in a text area
9602 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9603 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9604 * @cfg {string} html text
9607 * Create a new TextArea
9608 * @param {Object} config The config object
9611 Roo.bootstrap.TextArea = function(config){
9612 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9616 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9626 getAutoCreate : function(){
9628 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9634 if(this.inputType != 'hidden'){
9635 cfg.cls = 'form-group' //input-group
9643 value : this.value || '',
9644 html: this.html || '',
9645 cls : 'form-control',
9646 placeholder : this.placeholder || ''
9650 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9651 input.maxLength = this.maxLength;
9655 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9659 input.cols = this.cols;
9662 if (this.readOnly) {
9663 input.readonly = true;
9667 input.name = this.name;
9671 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9675 ['xs','sm','md','lg'].map(function(size){
9676 if (settings[size]) {
9677 cfg.cls += ' col-' + size + '-' + settings[size];
9681 var inputblock = input;
9683 if(this.hasFeedback && !this.allowBlank){
9687 cls: 'glyphicon form-control-feedback'
9691 cls : 'has-feedback',
9700 if (this.before || this.after) {
9703 cls : 'input-group',
9707 inputblock.cn.push({
9709 cls : 'input-group-addon',
9714 inputblock.cn.push(input);
9716 if(this.hasFeedback && !this.allowBlank){
9717 inputblock.cls += ' has-feedback';
9718 inputblock.cn.push(feedback);
9722 inputblock.cn.push({
9724 cls : 'input-group-addon',
9731 if (align ==='left' && this.fieldLabel.length) {
9736 cls : 'control-label',
9737 html : this.fieldLabel
9748 if(this.labelWidth > 12){
9749 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9752 if(this.labelWidth < 13 && this.labelmd == 0){
9753 this.labelmd = this.labelWidth;
9756 if(this.labellg > 0){
9757 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9758 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9761 if(this.labelmd > 0){
9762 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9763 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9766 if(this.labelsm > 0){
9767 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9768 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9771 if(this.labelxs > 0){
9772 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9773 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9776 } else if ( this.fieldLabel.length) {
9781 //cls : 'input-group-addon',
9782 html : this.fieldLabel
9800 if (this.disabled) {
9801 input.disabled=true;
9808 * return the real textarea element.
9810 inputEl: function ()
9812 return this.el.select('textarea.form-control',true).first();
9816 * Clear any invalid styles/messages for this field
9818 clearInvalid : function()
9821 if(!this.el || this.preventMark){ // not rendered
9825 var label = this.el.select('label', true).first();
9826 var icon = this.el.select('i.fa-star', true).first();
9832 this.el.removeClass(this.invalidClass);
9834 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9836 var feedback = this.el.select('.form-control-feedback', true).first();
9839 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9844 this.fireEvent('valid', this);
9848 * Mark this field as valid
9850 markValid : function()
9852 if(!this.el || this.preventMark){ // not rendered
9856 this.el.removeClass([this.invalidClass, this.validClass]);
9858 var feedback = this.el.select('.form-control-feedback', true).first();
9861 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9864 if(this.disabled || this.allowBlank){
9868 var label = this.el.select('label', true).first();
9869 var icon = this.el.select('i.fa-star', true).first();
9875 this.el.addClass(this.validClass);
9877 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9879 var feedback = this.el.select('.form-control-feedback', true).first();
9882 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9883 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9888 this.fireEvent('valid', this);
9892 * Mark this field as invalid
9893 * @param {String} msg The validation message
9895 markInvalid : function(msg)
9897 if(!this.el || this.preventMark){ // not rendered
9901 this.el.removeClass([this.invalidClass, this.validClass]);
9903 var feedback = this.el.select('.form-control-feedback', true).first();
9906 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9909 if(this.disabled || this.allowBlank){
9913 var label = this.el.select('label', true).first();
9914 var icon = this.el.select('i.fa-star', true).first();
9916 if(!this.getValue().length && label && !icon){
9917 this.el.createChild({
9919 cls : 'text-danger fa fa-lg fa-star',
9920 tooltip : 'This field is required',
9921 style : 'margin-right:5px;'
9925 this.el.addClass(this.invalidClass);
9927 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9929 var feedback = this.el.select('.form-control-feedback', true).first();
9932 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9934 if(this.getValue().length || this.forceFeedback){
9935 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9942 this.fireEvent('invalid', this, msg);
9950 * trigger field - base class for combo..
9955 * @class Roo.bootstrap.TriggerField
9956 * @extends Roo.bootstrap.Input
9957 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9958 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9959 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9960 * for which you can provide a custom implementation. For example:
9962 var trigger = new Roo.bootstrap.TriggerField();
9963 trigger.onTriggerClick = myTriggerFn;
9964 trigger.applyTo('my-field');
9967 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9968 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9969 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9970 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9971 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9974 * Create a new TriggerField.
9975 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9976 * to the base TextField)
9978 Roo.bootstrap.TriggerField = function(config){
9979 this.mimicing = false;
9980 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9983 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9985 * @cfg {String} triggerClass A CSS class to apply to the trigger
9988 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9993 * @cfg {Boolean} removable (true|false) special filter default false
9997 /** @cfg {Boolean} grow @hide */
9998 /** @cfg {Number} growMin @hide */
9999 /** @cfg {Number} growMax @hide */
10005 autoSize: Roo.emptyFn,
10009 deferHeight : true,
10012 actionMode : 'wrap',
10017 getAutoCreate : function(){
10019 var align = this.labelAlign || this.parentLabelAlign();
10024 cls: 'form-group' //input-group
10031 type : this.inputType,
10032 cls : 'form-control',
10033 autocomplete: 'new-password',
10034 placeholder : this.placeholder || ''
10038 input.name = this.name;
10041 input.cls += ' input-' + this.size;
10044 if (this.disabled) {
10045 input.disabled=true;
10048 var inputblock = input;
10050 if(this.hasFeedback && !this.allowBlank){
10054 cls: 'glyphicon form-control-feedback'
10057 if(this.removable && !this.editable && !this.tickable){
10059 cls : 'has-feedback',
10065 cls : 'roo-combo-removable-btn close'
10072 cls : 'has-feedback',
10081 if(this.removable && !this.editable && !this.tickable){
10083 cls : 'roo-removable',
10089 cls : 'roo-combo-removable-btn close'
10096 if (this.before || this.after) {
10099 cls : 'input-group',
10103 inputblock.cn.push({
10105 cls : 'input-group-addon',
10110 inputblock.cn.push(input);
10112 if(this.hasFeedback && !this.allowBlank){
10113 inputblock.cls += ' has-feedback';
10114 inputblock.cn.push(feedback);
10118 inputblock.cn.push({
10120 cls : 'input-group-addon',
10133 cls: 'form-hidden-field'
10147 cls: 'form-hidden-field'
10151 cls: 'roo-select2-choices',
10155 cls: 'roo-select2-search-field',
10168 cls: 'roo-select2-container input-group',
10173 // cls: 'typeahead typeahead-long dropdown-menu',
10174 // style: 'display:none'
10179 if(!this.multiple && this.showToggleBtn){
10185 if (this.caret != false) {
10188 cls: 'fa fa-' + this.caret
10195 cls : 'input-group-addon btn dropdown-toggle',
10200 cls: 'combobox-clear',
10214 combobox.cls += ' roo-select2-container-multi';
10217 if (align ==='left' && this.fieldLabel.length) {
10219 cfg.cls += ' roo-form-group-label-left';
10224 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10225 tooltip : 'This field is required'
10230 cls : 'control-label',
10231 html : this.fieldLabel
10243 var labelCfg = cfg.cn[1];
10244 var contentCfg = cfg.cn[2];
10246 if(this.indicatorpos == 'right'){
10251 cls : 'control-label',
10255 html : this.fieldLabel
10259 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10260 tooltip : 'This field is required'
10273 labelCfg = cfg.cn[0];
10274 contentCfg = cfg.cn[1];
10277 if(this.labelWidth > 12){
10278 labelCfg.style = "width: " + this.labelWidth + 'px';
10281 if(this.labelWidth < 13 && this.labelmd == 0){
10282 this.labelmd = this.labelWidth;
10285 if(this.labellg > 0){
10286 labelCfg.cls += ' col-lg-' + this.labellg;
10287 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10290 if(this.labelmd > 0){
10291 labelCfg.cls += ' col-md-' + this.labelmd;
10292 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10295 if(this.labelsm > 0){
10296 labelCfg.cls += ' col-sm-' + this.labelsm;
10297 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10300 if(this.labelxs > 0){
10301 labelCfg.cls += ' col-xs-' + this.labelxs;
10302 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10305 } else if ( this.fieldLabel.length) {
10306 // Roo.log(" label");
10310 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10311 tooltip : 'This field is required'
10315 //cls : 'input-group-addon',
10316 html : this.fieldLabel
10324 if(this.indicatorpos == 'right'){
10332 html : this.fieldLabel
10336 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10337 tooltip : 'This field is required'
10350 // Roo.log(" no label && no align");
10357 ['xs','sm','md','lg'].map(function(size){
10358 if (settings[size]) {
10359 cfg.cls += ' col-' + size + '-' + settings[size];
10370 onResize : function(w, h){
10371 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10372 // if(typeof w == 'number'){
10373 // var x = w - this.trigger.getWidth();
10374 // this.inputEl().setWidth(this.adjustWidth('input', x));
10375 // this.trigger.setStyle('left', x+'px');
10380 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10383 getResizeEl : function(){
10384 return this.inputEl();
10388 getPositionEl : function(){
10389 return this.inputEl();
10393 alignErrorIcon : function(){
10394 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10398 initEvents : function(){
10402 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10403 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10404 if(!this.multiple && this.showToggleBtn){
10405 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10406 if(this.hideTrigger){
10407 this.trigger.setDisplayed(false);
10409 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10413 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10416 if(this.removable && !this.editable && !this.tickable){
10417 var close = this.closeTriggerEl();
10420 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10421 close.on('click', this.removeBtnClick, this, close);
10425 //this.trigger.addClassOnOver('x-form-trigger-over');
10426 //this.trigger.addClassOnClick('x-form-trigger-click');
10429 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10433 closeTriggerEl : function()
10435 var close = this.el.select('.roo-combo-removable-btn', true).first();
10436 return close ? close : false;
10439 removeBtnClick : function(e, h, el)
10441 e.preventDefault();
10443 if(this.fireEvent("remove", this) !== false){
10445 this.fireEvent("afterremove", this)
10449 createList : function()
10451 this.list = Roo.get(document.body).createChild({
10453 cls: 'typeahead typeahead-long dropdown-menu',
10454 style: 'display:none'
10457 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10462 initTrigger : function(){
10467 onDestroy : function(){
10469 this.trigger.removeAllListeners();
10470 // this.trigger.remove();
10473 // this.wrap.remove();
10475 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10479 onFocus : function(){
10480 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10482 if(!this.mimicing){
10483 this.wrap.addClass('x-trigger-wrap-focus');
10484 this.mimicing = true;
10485 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10486 if(this.monitorTab){
10487 this.el.on("keydown", this.checkTab, this);
10494 checkTab : function(e){
10495 if(e.getKey() == e.TAB){
10496 this.triggerBlur();
10501 onBlur : function(){
10506 mimicBlur : function(e, t){
10508 if(!this.wrap.contains(t) && this.validateBlur()){
10509 this.triggerBlur();
10515 triggerBlur : function(){
10516 this.mimicing = false;
10517 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10518 if(this.monitorTab){
10519 this.el.un("keydown", this.checkTab, this);
10521 //this.wrap.removeClass('x-trigger-wrap-focus');
10522 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10526 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10527 validateBlur : function(e, t){
10532 onDisable : function(){
10533 this.inputEl().dom.disabled = true;
10534 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10536 // this.wrap.addClass('x-item-disabled');
10541 onEnable : function(){
10542 this.inputEl().dom.disabled = false;
10543 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10545 // this.el.removeClass('x-item-disabled');
10550 onShow : function(){
10551 var ae = this.getActionEl();
10554 ae.dom.style.display = '';
10555 ae.dom.style.visibility = 'visible';
10561 onHide : function(){
10562 var ae = this.getActionEl();
10563 ae.dom.style.display = 'none';
10567 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10568 * by an implementing function.
10570 * @param {EventObject} e
10572 onTriggerClick : Roo.emptyFn
10576 * Ext JS Library 1.1.1
10577 * Copyright(c) 2006-2007, Ext JS, LLC.
10579 * Originally Released Under LGPL - original licence link has changed is not relivant.
10582 * <script type="text/javascript">
10587 * @class Roo.data.SortTypes
10589 * Defines the default sorting (casting?) comparison functions used when sorting data.
10591 Roo.data.SortTypes = {
10593 * Default sort that does nothing
10594 * @param {Mixed} s The value being converted
10595 * @return {Mixed} The comparison value
10597 none : function(s){
10602 * The regular expression used to strip tags
10606 stripTagsRE : /<\/?[^>]+>/gi,
10609 * Strips all HTML tags to sort on text only
10610 * @param {Mixed} s The value being converted
10611 * @return {String} The comparison value
10613 asText : function(s){
10614 return String(s).replace(this.stripTagsRE, "");
10618 * Strips all HTML tags to sort on text only - Case insensitive
10619 * @param {Mixed} s The value being converted
10620 * @return {String} The comparison value
10622 asUCText : function(s){
10623 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10627 * Case insensitive string
10628 * @param {Mixed} s The value being converted
10629 * @return {String} The comparison value
10631 asUCString : function(s) {
10632 return String(s).toUpperCase();
10637 * @param {Mixed} s The value being converted
10638 * @return {Number} The comparison value
10640 asDate : function(s) {
10644 if(s instanceof Date){
10645 return s.getTime();
10647 return Date.parse(String(s));
10652 * @param {Mixed} s The value being converted
10653 * @return {Float} The comparison value
10655 asFloat : function(s) {
10656 var val = parseFloat(String(s).replace(/,/g, ""));
10665 * @param {Mixed} s The value being converted
10666 * @return {Number} The comparison value
10668 asInt : function(s) {
10669 var val = parseInt(String(s).replace(/,/g, ""));
10677 * Ext JS Library 1.1.1
10678 * Copyright(c) 2006-2007, Ext JS, LLC.
10680 * Originally Released Under LGPL - original licence link has changed is not relivant.
10683 * <script type="text/javascript">
10687 * @class Roo.data.Record
10688 * Instances of this class encapsulate both record <em>definition</em> information, and record
10689 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10690 * to access Records cached in an {@link Roo.data.Store} object.<br>
10692 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10693 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10696 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10698 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10699 * {@link #create}. The parameters are the same.
10700 * @param {Array} data An associative Array of data values keyed by the field name.
10701 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10702 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10703 * not specified an integer id is generated.
10705 Roo.data.Record = function(data, id){
10706 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10711 * Generate a constructor for a specific record layout.
10712 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10713 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10714 * Each field definition object may contain the following properties: <ul>
10715 * <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,
10716 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10717 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10718 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10719 * is being used, then this is a string containing the javascript expression to reference the data relative to
10720 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10721 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10722 * this may be omitted.</p></li>
10723 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10724 * <ul><li>auto (Default, implies no conversion)</li>
10729 * <li>date</li></ul></p></li>
10730 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10731 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10732 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10733 * by the Reader into an object that will be stored in the Record. It is passed the
10734 * following parameters:<ul>
10735 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10737 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10739 * <br>usage:<br><pre><code>
10740 var TopicRecord = Roo.data.Record.create(
10741 {name: 'title', mapping: 'topic_title'},
10742 {name: 'author', mapping: 'username'},
10743 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10744 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10745 {name: 'lastPoster', mapping: 'user2'},
10746 {name: 'excerpt', mapping: 'post_text'}
10749 var myNewRecord = new TopicRecord({
10750 title: 'Do my job please',
10753 lastPost: new Date(),
10754 lastPoster: 'Animal',
10755 excerpt: 'No way dude!'
10757 myStore.add(myNewRecord);
10762 Roo.data.Record.create = function(o){
10763 var f = function(){
10764 f.superclass.constructor.apply(this, arguments);
10766 Roo.extend(f, Roo.data.Record);
10767 var p = f.prototype;
10768 p.fields = new Roo.util.MixedCollection(false, function(field){
10771 for(var i = 0, len = o.length; i < len; i++){
10772 p.fields.add(new Roo.data.Field(o[i]));
10774 f.getField = function(name){
10775 return p.fields.get(name);
10780 Roo.data.Record.AUTO_ID = 1000;
10781 Roo.data.Record.EDIT = 'edit';
10782 Roo.data.Record.REJECT = 'reject';
10783 Roo.data.Record.COMMIT = 'commit';
10785 Roo.data.Record.prototype = {
10787 * Readonly flag - true if this record has been modified.
10796 join : function(store){
10797 this.store = store;
10801 * Set the named field to the specified value.
10802 * @param {String} name The name of the field to set.
10803 * @param {Object} value The value to set the field to.
10805 set : function(name, value){
10806 if(this.data[name] == value){
10810 if(!this.modified){
10811 this.modified = {};
10813 if(typeof this.modified[name] == 'undefined'){
10814 this.modified[name] = this.data[name];
10816 this.data[name] = value;
10817 if(!this.editing && this.store){
10818 this.store.afterEdit(this);
10823 * Get the value of the named field.
10824 * @param {String} name The name of the field to get the value of.
10825 * @return {Object} The value of the field.
10827 get : function(name){
10828 return this.data[name];
10832 beginEdit : function(){
10833 this.editing = true;
10834 this.modified = {};
10838 cancelEdit : function(){
10839 this.editing = false;
10840 delete this.modified;
10844 endEdit : function(){
10845 this.editing = false;
10846 if(this.dirty && this.store){
10847 this.store.afterEdit(this);
10852 * Usually called by the {@link Roo.data.Store} which owns the Record.
10853 * Rejects all changes made to the Record since either creation, or the last commit operation.
10854 * Modified fields are reverted to their original values.
10856 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10857 * of reject operations.
10859 reject : function(){
10860 var m = this.modified;
10862 if(typeof m[n] != "function"){
10863 this.data[n] = m[n];
10866 this.dirty = false;
10867 delete this.modified;
10868 this.editing = false;
10870 this.store.afterReject(this);
10875 * Usually called by the {@link Roo.data.Store} which owns the Record.
10876 * Commits all changes made to the Record since either creation, or the last commit operation.
10878 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10879 * of commit operations.
10881 commit : function(){
10882 this.dirty = false;
10883 delete this.modified;
10884 this.editing = false;
10886 this.store.afterCommit(this);
10891 hasError : function(){
10892 return this.error != null;
10896 clearError : function(){
10901 * Creates a copy of this record.
10902 * @param {String} id (optional) A new record id if you don't want to use this record's id
10905 copy : function(newId) {
10906 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10910 * Ext JS Library 1.1.1
10911 * Copyright(c) 2006-2007, Ext JS, LLC.
10913 * Originally Released Under LGPL - original licence link has changed is not relivant.
10916 * <script type="text/javascript">
10922 * @class Roo.data.Store
10923 * @extends Roo.util.Observable
10924 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10925 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10927 * 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
10928 * has no knowledge of the format of the data returned by the Proxy.<br>
10930 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10931 * instances from the data object. These records are cached and made available through accessor functions.
10933 * Creates a new Store.
10934 * @param {Object} config A config object containing the objects needed for the Store to access data,
10935 * and read the data into Records.
10937 Roo.data.Store = function(config){
10938 this.data = new Roo.util.MixedCollection(false);
10939 this.data.getKey = function(o){
10942 this.baseParams = {};
10944 this.paramNames = {
10949 "multisort" : "_multisort"
10952 if(config && config.data){
10953 this.inlineData = config.data;
10954 delete config.data;
10957 Roo.apply(this, config);
10959 if(this.reader){ // reader passed
10960 this.reader = Roo.factory(this.reader, Roo.data);
10961 this.reader.xmodule = this.xmodule || false;
10962 if(!this.recordType){
10963 this.recordType = this.reader.recordType;
10965 if(this.reader.onMetaChange){
10966 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10970 if(this.recordType){
10971 this.fields = this.recordType.prototype.fields;
10973 this.modified = [];
10977 * @event datachanged
10978 * Fires when the data cache has changed, and a widget which is using this Store
10979 * as a Record cache should refresh its view.
10980 * @param {Store} this
10982 datachanged : true,
10984 * @event metachange
10985 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10986 * @param {Store} this
10987 * @param {Object} meta The JSON metadata
10992 * Fires when Records have been added to the Store
10993 * @param {Store} this
10994 * @param {Roo.data.Record[]} records The array of Records added
10995 * @param {Number} index The index at which the record(s) were added
11000 * Fires when a Record has been removed from the Store
11001 * @param {Store} this
11002 * @param {Roo.data.Record} record The Record that was removed
11003 * @param {Number} index The index at which the record was removed
11008 * Fires when a Record has been updated
11009 * @param {Store} this
11010 * @param {Roo.data.Record} record The Record that was updated
11011 * @param {String} operation The update operation being performed. Value may be one of:
11013 Roo.data.Record.EDIT
11014 Roo.data.Record.REJECT
11015 Roo.data.Record.COMMIT
11021 * Fires when the data cache has been cleared.
11022 * @param {Store} this
11026 * @event beforeload
11027 * Fires before a request is made for a new data object. If the beforeload handler returns false
11028 * the load action will be canceled.
11029 * @param {Store} this
11030 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11034 * @event beforeloadadd
11035 * Fires after a new set of Records has been loaded.
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)
11040 beforeloadadd : true,
11043 * Fires after a new set of Records has been loaded, before they are added to the store.
11044 * @param {Store} this
11045 * @param {Roo.data.Record[]} records The Records that were loaded
11046 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11047 * @params {Object} return from reader
11051 * @event loadexception
11052 * Fires if an exception occurs in the Proxy during loading.
11053 * Called with the signature of the Proxy's "loadexception" event.
11054 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11057 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11058 * @param {Object} load options
11059 * @param {Object} jsonData from your request (normally this contains the Exception)
11061 loadexception : true
11065 this.proxy = Roo.factory(this.proxy, Roo.data);
11066 this.proxy.xmodule = this.xmodule || false;
11067 this.relayEvents(this.proxy, ["loadexception"]);
11069 this.sortToggle = {};
11070 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11072 Roo.data.Store.superclass.constructor.call(this);
11074 if(this.inlineData){
11075 this.loadData(this.inlineData);
11076 delete this.inlineData;
11080 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11082 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11083 * without a remote query - used by combo/forms at present.
11087 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11090 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11093 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11094 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11097 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11098 * on any HTTP request
11101 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11104 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11108 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11109 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11111 remoteSort : false,
11114 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11115 * loaded or when a record is removed. (defaults to false).
11117 pruneModifiedRecords : false,
11120 lastOptions : null,
11123 * Add Records to the Store and fires the add event.
11124 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11126 add : function(records){
11127 records = [].concat(records);
11128 for(var i = 0, len = records.length; i < len; i++){
11129 records[i].join(this);
11131 var index = this.data.length;
11132 this.data.addAll(records);
11133 this.fireEvent("add", this, records, index);
11137 * Remove a Record from the Store and fires the remove event.
11138 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11140 remove : function(record){
11141 var index = this.data.indexOf(record);
11142 this.data.removeAt(index);
11144 if(this.pruneModifiedRecords){
11145 this.modified.remove(record);
11147 this.fireEvent("remove", this, record, index);
11151 * Remove all Records from the Store and fires the clear event.
11153 removeAll : function(){
11155 if(this.pruneModifiedRecords){
11156 this.modified = [];
11158 this.fireEvent("clear", this);
11162 * Inserts Records to the Store at the given index and fires the add event.
11163 * @param {Number} index The start index at which to insert the passed Records.
11164 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11166 insert : function(index, records){
11167 records = [].concat(records);
11168 for(var i = 0, len = records.length; i < len; i++){
11169 this.data.insert(index, records[i]);
11170 records[i].join(this);
11172 this.fireEvent("add", this, records, index);
11176 * Get the index within the cache of the passed Record.
11177 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11178 * @return {Number} The index of the passed Record. Returns -1 if not found.
11180 indexOf : function(record){
11181 return this.data.indexOf(record);
11185 * Get the index within the cache of the Record with the passed id.
11186 * @param {String} id The id of the Record to find.
11187 * @return {Number} The index of the Record. Returns -1 if not found.
11189 indexOfId : function(id){
11190 return this.data.indexOfKey(id);
11194 * Get the Record with the specified id.
11195 * @param {String} id The id of the Record to find.
11196 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11198 getById : function(id){
11199 return this.data.key(id);
11203 * Get the Record at the specified index.
11204 * @param {Number} index The index of the Record to find.
11205 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11207 getAt : function(index){
11208 return this.data.itemAt(index);
11212 * Returns a range of Records between specified indices.
11213 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11214 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11215 * @return {Roo.data.Record[]} An array of Records
11217 getRange : function(start, end){
11218 return this.data.getRange(start, end);
11222 storeOptions : function(o){
11223 o = Roo.apply({}, o);
11226 this.lastOptions = o;
11230 * Loads the Record cache from the configured Proxy using the configured Reader.
11232 * If using remote paging, then the first load call must specify the <em>start</em>
11233 * and <em>limit</em> properties in the options.params property to establish the initial
11234 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11236 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11237 * and this call will return before the new data has been loaded. Perform any post-processing
11238 * in a callback function, or in a "load" event handler.</strong>
11240 * @param {Object} options An object containing properties which control loading options:<ul>
11241 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11242 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11243 * passed the following arguments:<ul>
11244 * <li>r : Roo.data.Record[]</li>
11245 * <li>options: Options object from the load call</li>
11246 * <li>success: Boolean success indicator</li></ul></li>
11247 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11248 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11251 load : function(options){
11252 options = options || {};
11253 if(this.fireEvent("beforeload", this, options) !== false){
11254 this.storeOptions(options);
11255 var p = Roo.apply(options.params || {}, this.baseParams);
11256 // if meta was not loaded from remote source.. try requesting it.
11257 if (!this.reader.metaFromRemote) {
11258 p._requestMeta = 1;
11260 if(this.sortInfo && this.remoteSort){
11261 var pn = this.paramNames;
11262 p[pn["sort"]] = this.sortInfo.field;
11263 p[pn["dir"]] = this.sortInfo.direction;
11265 if (this.multiSort) {
11266 var pn = this.paramNames;
11267 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11270 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11275 * Reloads the Record cache from the configured Proxy using the configured Reader and
11276 * the options from the last load operation performed.
11277 * @param {Object} options (optional) An object containing properties which may override the options
11278 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11279 * the most recently used options are reused).
11281 reload : function(options){
11282 this.load(Roo.applyIf(options||{}, this.lastOptions));
11286 // Called as a callback by the Reader during a load operation.
11287 loadRecords : function(o, options, success){
11288 if(!o || success === false){
11289 if(success !== false){
11290 this.fireEvent("load", this, [], options, o);
11292 if(options.callback){
11293 options.callback.call(options.scope || this, [], options, false);
11297 // if data returned failure - throw an exception.
11298 if (o.success === false) {
11299 // show a message if no listener is registered.
11300 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11301 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11303 // loadmask wil be hooked into this..
11304 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11307 var r = o.records, t = o.totalRecords || r.length;
11309 this.fireEvent("beforeloadadd", this, r, options, o);
11311 if(!options || options.add !== true){
11312 if(this.pruneModifiedRecords){
11313 this.modified = [];
11315 for(var i = 0, len = r.length; i < len; i++){
11319 this.data = this.snapshot;
11320 delete this.snapshot;
11323 this.data.addAll(r);
11324 this.totalLength = t;
11326 this.fireEvent("datachanged", this);
11328 this.totalLength = Math.max(t, this.data.length+r.length);
11332 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11334 var e = new Roo.data.Record({});
11336 e.set(this.parent.displayField, this.parent.emptyTitle);
11337 e.set(this.parent.valueField, '');
11342 this.fireEvent("load", this, r, options, o);
11343 if(options.callback){
11344 options.callback.call(options.scope || this, r, options, true);
11350 * Loads data from a passed data block. A Reader which understands the format of the data
11351 * must have been configured in the constructor.
11352 * @param {Object} data The data block from which to read the Records. The format of the data expected
11353 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11354 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11356 loadData : function(o, append){
11357 var r = this.reader.readRecords(o);
11358 this.loadRecords(r, {add: append}, true);
11362 * Gets the number of cached records.
11364 * <em>If using paging, this may not be the total size of the dataset. If the data object
11365 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11366 * the data set size</em>
11368 getCount : function(){
11369 return this.data.length || 0;
11373 * Gets the total number of records in the dataset as returned by the server.
11375 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11376 * the dataset size</em>
11378 getTotalCount : function(){
11379 return this.totalLength || 0;
11383 * Returns the sort state of the Store as an object with two properties:
11385 field {String} The name of the field by which the Records are sorted
11386 direction {String} The sort order, "ASC" or "DESC"
11389 getSortState : function(){
11390 return this.sortInfo;
11394 applySort : function(){
11395 if(this.sortInfo && !this.remoteSort){
11396 var s = this.sortInfo, f = s.field;
11397 var st = this.fields.get(f).sortType;
11398 var fn = function(r1, r2){
11399 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11400 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11402 this.data.sort(s.direction, fn);
11403 if(this.snapshot && this.snapshot != this.data){
11404 this.snapshot.sort(s.direction, fn);
11410 * Sets the default sort column and order to be used by the next load operation.
11411 * @param {String} fieldName The name of the field to sort by.
11412 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11414 setDefaultSort : function(field, dir){
11415 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11419 * Sort the Records.
11420 * If remote sorting is used, the sort is performed on the server, and the cache is
11421 * reloaded. If local sorting is used, the cache is sorted internally.
11422 * @param {String} fieldName The name of the field to sort by.
11423 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11425 sort : function(fieldName, dir){
11426 var f = this.fields.get(fieldName);
11428 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11430 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11431 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11436 this.sortToggle[f.name] = dir;
11437 this.sortInfo = {field: f.name, direction: dir};
11438 if(!this.remoteSort){
11440 this.fireEvent("datachanged", this);
11442 this.load(this.lastOptions);
11447 * Calls the specified function for each of the Records in the cache.
11448 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11449 * Returning <em>false</em> aborts and exits the iteration.
11450 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11452 each : function(fn, scope){
11453 this.data.each(fn, scope);
11457 * Gets all records modified since the last commit. Modified records are persisted across load operations
11458 * (e.g., during paging).
11459 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11461 getModifiedRecords : function(){
11462 return this.modified;
11466 createFilterFn : function(property, value, anyMatch){
11467 if(!value.exec){ // not a regex
11468 value = String(value);
11469 if(value.length == 0){
11472 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11474 return function(r){
11475 return value.test(r.data[property]);
11480 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11481 * @param {String} property A field on your records
11482 * @param {Number} start The record index to start at (defaults to 0)
11483 * @param {Number} end The last record index to include (defaults to length - 1)
11484 * @return {Number} The sum
11486 sum : function(property, start, end){
11487 var rs = this.data.items, v = 0;
11488 start = start || 0;
11489 end = (end || end === 0) ? end : rs.length-1;
11491 for(var i = start; i <= end; i++){
11492 v += (rs[i].data[property] || 0);
11498 * Filter the records by a specified property.
11499 * @param {String} field A field on your records
11500 * @param {String/RegExp} value Either a string that the field
11501 * should start with or a RegExp to test against the field
11502 * @param {Boolean} anyMatch True to match any part not just the beginning
11504 filter : function(property, value, anyMatch){
11505 var fn = this.createFilterFn(property, value, anyMatch);
11506 return fn ? this.filterBy(fn) : this.clearFilter();
11510 * Filter by a function. The specified function will be called with each
11511 * record in this data source. If the function returns true the record is included,
11512 * otherwise it is filtered.
11513 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11514 * @param {Object} scope (optional) The scope of the function (defaults to this)
11516 filterBy : function(fn, scope){
11517 this.snapshot = this.snapshot || this.data;
11518 this.data = this.queryBy(fn, scope||this);
11519 this.fireEvent("datachanged", this);
11523 * Query the records by a specified property.
11524 * @param {String} field A field on your records
11525 * @param {String/RegExp} value Either a string that the field
11526 * should start with or a RegExp to test against the field
11527 * @param {Boolean} anyMatch True to match any part not just the beginning
11528 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11530 query : function(property, value, anyMatch){
11531 var fn = this.createFilterFn(property, value, anyMatch);
11532 return fn ? this.queryBy(fn) : this.data.clone();
11536 * Query by a function. The specified function will be called with each
11537 * record in this data source. If the function returns true the record is included
11539 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11540 * @param {Object} scope (optional) The scope of the function (defaults to this)
11541 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11543 queryBy : function(fn, scope){
11544 var data = this.snapshot || this.data;
11545 return data.filterBy(fn, scope||this);
11549 * Collects unique values for a particular dataIndex from this store.
11550 * @param {String} dataIndex The property to collect
11551 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11552 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11553 * @return {Array} An array of the unique values
11555 collect : function(dataIndex, allowNull, bypassFilter){
11556 var d = (bypassFilter === true && this.snapshot) ?
11557 this.snapshot.items : this.data.items;
11558 var v, sv, r = [], l = {};
11559 for(var i = 0, len = d.length; i < len; i++){
11560 v = d[i].data[dataIndex];
11562 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11571 * Revert to a view of the Record cache with no filtering applied.
11572 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11574 clearFilter : function(suppressEvent){
11575 if(this.snapshot && this.snapshot != this.data){
11576 this.data = this.snapshot;
11577 delete this.snapshot;
11578 if(suppressEvent !== true){
11579 this.fireEvent("datachanged", this);
11585 afterEdit : function(record){
11586 if(this.modified.indexOf(record) == -1){
11587 this.modified.push(record);
11589 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11593 afterReject : function(record){
11594 this.modified.remove(record);
11595 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11599 afterCommit : function(record){
11600 this.modified.remove(record);
11601 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11605 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11606 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11608 commitChanges : function(){
11609 var m = this.modified.slice(0);
11610 this.modified = [];
11611 for(var i = 0, len = m.length; i < len; i++){
11617 * Cancel outstanding changes on all changed records.
11619 rejectChanges : function(){
11620 var m = this.modified.slice(0);
11621 this.modified = [];
11622 for(var i = 0, len = m.length; i < len; i++){
11627 onMetaChange : function(meta, rtype, o){
11628 this.recordType = rtype;
11629 this.fields = rtype.prototype.fields;
11630 delete this.snapshot;
11631 this.sortInfo = meta.sortInfo || this.sortInfo;
11632 this.modified = [];
11633 this.fireEvent('metachange', this, this.reader.meta);
11636 moveIndex : function(data, type)
11638 var index = this.indexOf(data);
11640 var newIndex = index + type;
11644 this.insert(newIndex, data);
11649 * Ext JS Library 1.1.1
11650 * Copyright(c) 2006-2007, Ext JS, LLC.
11652 * Originally Released Under LGPL - original licence link has changed is not relivant.
11655 * <script type="text/javascript">
11659 * @class Roo.data.SimpleStore
11660 * @extends Roo.data.Store
11661 * Small helper class to make creating Stores from Array data easier.
11662 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11663 * @cfg {Array} fields An array of field definition objects, or field name strings.
11664 * @cfg {Array} data The multi-dimensional array of data
11666 * @param {Object} config
11668 Roo.data.SimpleStore = function(config){
11669 Roo.data.SimpleStore.superclass.constructor.call(this, {
11671 reader: new Roo.data.ArrayReader({
11674 Roo.data.Record.create(config.fields)
11676 proxy : new Roo.data.MemoryProxy(config.data)
11680 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11682 * Ext JS Library 1.1.1
11683 * Copyright(c) 2006-2007, Ext JS, LLC.
11685 * Originally Released Under LGPL - original licence link has changed is not relivant.
11688 * <script type="text/javascript">
11693 * @extends Roo.data.Store
11694 * @class Roo.data.JsonStore
11695 * Small helper class to make creating Stores for JSON data easier. <br/>
11697 var store = new Roo.data.JsonStore({
11698 url: 'get-images.php',
11700 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11703 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11704 * JsonReader and HttpProxy (unless inline data is provided).</b>
11705 * @cfg {Array} fields An array of field definition objects, or field name strings.
11707 * @param {Object} config
11709 Roo.data.JsonStore = function(c){
11710 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11711 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11712 reader: new Roo.data.JsonReader(c, c.fields)
11715 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11717 * Ext JS Library 1.1.1
11718 * Copyright(c) 2006-2007, Ext JS, LLC.
11720 * Originally Released Under LGPL - original licence link has changed is not relivant.
11723 * <script type="text/javascript">
11727 Roo.data.Field = function(config){
11728 if(typeof config == "string"){
11729 config = {name: config};
11731 Roo.apply(this, config);
11734 this.type = "auto";
11737 var st = Roo.data.SortTypes;
11738 // named sortTypes are supported, here we look them up
11739 if(typeof this.sortType == "string"){
11740 this.sortType = st[this.sortType];
11743 // set default sortType for strings and dates
11744 if(!this.sortType){
11747 this.sortType = st.asUCString;
11750 this.sortType = st.asDate;
11753 this.sortType = st.none;
11758 var stripRe = /[\$,%]/g;
11760 // prebuilt conversion function for this field, instead of
11761 // switching every time we're reading a value
11763 var cv, dateFormat = this.dateFormat;
11768 cv = function(v){ return v; };
11771 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11775 return v !== undefined && v !== null && v !== '' ?
11776 parseInt(String(v).replace(stripRe, ""), 10) : '';
11781 return v !== undefined && v !== null && v !== '' ?
11782 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11787 cv = function(v){ return v === true || v === "true" || v == 1; };
11794 if(v instanceof Date){
11798 if(dateFormat == "timestamp"){
11799 return new Date(v*1000);
11801 return Date.parseDate(v, dateFormat);
11803 var parsed = Date.parse(v);
11804 return parsed ? new Date(parsed) : null;
11813 Roo.data.Field.prototype = {
11821 * Ext JS Library 1.1.1
11822 * Copyright(c) 2006-2007, Ext JS, LLC.
11824 * Originally Released Under LGPL - original licence link has changed is not relivant.
11827 * <script type="text/javascript">
11830 // Base class for reading structured data from a data source. This class is intended to be
11831 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11834 * @class Roo.data.DataReader
11835 * Base class for reading structured data from a data source. This class is intended to be
11836 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11839 Roo.data.DataReader = function(meta, recordType){
11843 this.recordType = recordType instanceof Array ?
11844 Roo.data.Record.create(recordType) : recordType;
11847 Roo.data.DataReader.prototype = {
11849 * Create an empty record
11850 * @param {Object} data (optional) - overlay some values
11851 * @return {Roo.data.Record} record created.
11853 newRow : function(d) {
11855 this.recordType.prototype.fields.each(function(c) {
11857 case 'int' : da[c.name] = 0; break;
11858 case 'date' : da[c.name] = new Date(); break;
11859 case 'float' : da[c.name] = 0.0; break;
11860 case 'boolean' : da[c.name] = false; break;
11861 default : da[c.name] = ""; break;
11865 return new this.recordType(Roo.apply(da, d));
11870 * Ext JS Library 1.1.1
11871 * Copyright(c) 2006-2007, Ext JS, LLC.
11873 * Originally Released Under LGPL - original licence link has changed is not relivant.
11876 * <script type="text/javascript">
11880 * @class Roo.data.DataProxy
11881 * @extends Roo.data.Observable
11882 * This class is an abstract base class for implementations which provide retrieval of
11883 * unformatted data objects.<br>
11885 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11886 * (of the appropriate type which knows how to parse the data object) to provide a block of
11887 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11889 * Custom implementations must implement the load method as described in
11890 * {@link Roo.data.HttpProxy#load}.
11892 Roo.data.DataProxy = function(){
11895 * @event beforeload
11896 * Fires before a network request is made to retrieve a data object.
11897 * @param {Object} This DataProxy object.
11898 * @param {Object} params The params parameter to the load function.
11903 * Fires before the load method's callback is called.
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.
11910 * @event loadexception
11911 * Fires if an Exception occurs during data retrieval.
11912 * @param {Object} This DataProxy object.
11913 * @param {Object} o The data object.
11914 * @param {Object} arg The callback argument object passed to the load function.
11915 * @param {Object} e The Exception.
11917 loadexception : true
11919 Roo.data.DataProxy.superclass.constructor.call(this);
11922 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11925 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11929 * Ext JS Library 1.1.1
11930 * Copyright(c) 2006-2007, Ext JS, LLC.
11932 * Originally Released Under LGPL - original licence link has changed is not relivant.
11935 * <script type="text/javascript">
11938 * @class Roo.data.MemoryProxy
11939 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11940 * to the Reader when its load method is called.
11942 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11944 Roo.data.MemoryProxy = function(data){
11948 Roo.data.MemoryProxy.superclass.constructor.call(this);
11952 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11955 * Load data from the requested source (in this case an in-memory
11956 * data object passed to the constructor), read the data object into
11957 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11958 * process that block using the passed callback.
11959 * @param {Object} params This parameter is not used by the MemoryProxy class.
11960 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11961 * object into a block of Roo.data.Records.
11962 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11963 * The function must be passed <ul>
11964 * <li>The Record block object</li>
11965 * <li>The "arg" argument from the load function</li>
11966 * <li>A boolean success indicator</li>
11968 * @param {Object} scope The scope in which to call the callback
11969 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11971 load : function(params, reader, callback, scope, arg){
11972 params = params || {};
11975 result = reader.readRecords(this.data);
11977 this.fireEvent("loadexception", this, arg, null, e);
11978 callback.call(scope, null, arg, false);
11981 callback.call(scope, result, arg, true);
11985 update : function(params, records){
11990 * Ext JS Library 1.1.1
11991 * Copyright(c) 2006-2007, Ext JS, LLC.
11993 * Originally Released Under LGPL - original licence link has changed is not relivant.
11996 * <script type="text/javascript">
11999 * @class Roo.data.HttpProxy
12000 * @extends Roo.data.DataProxy
12001 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12002 * configured to reference a certain URL.<br><br>
12004 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12005 * from which the running page was served.<br><br>
12007 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12009 * Be aware that to enable the browser to parse an XML document, the server must set
12010 * the Content-Type header in the HTTP response to "text/xml".
12012 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12013 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12014 * will be used to make the request.
12016 Roo.data.HttpProxy = function(conn){
12017 Roo.data.HttpProxy.superclass.constructor.call(this);
12018 // is conn a conn config or a real conn?
12020 this.useAjax = !conn || !conn.events;
12024 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12025 // thse are take from connection...
12028 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12031 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12032 * extra parameters to each request made by this object. (defaults to undefined)
12035 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12036 * to each request made by this object. (defaults to undefined)
12039 * @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)
12042 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12045 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12051 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12055 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12056 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12057 * a finer-grained basis than the DataProxy events.
12059 getConnection : function(){
12060 return this.useAjax ? Roo.Ajax : this.conn;
12064 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12065 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12066 * process that block using the passed callback.
12067 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12068 * for the request to the remote server.
12069 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12070 * object into a block of Roo.data.Records.
12071 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12072 * The function must be passed <ul>
12073 * <li>The Record block object</li>
12074 * <li>The "arg" argument from the load function</li>
12075 * <li>A boolean success indicator</li>
12077 * @param {Object} scope The scope in which to call the callback
12078 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12080 load : function(params, reader, callback, scope, arg){
12081 if(this.fireEvent("beforeload", this, params) !== false){
12083 params : params || {},
12085 callback : callback,
12090 callback : this.loadResponse,
12094 Roo.applyIf(o, this.conn);
12095 if(this.activeRequest){
12096 Roo.Ajax.abort(this.activeRequest);
12098 this.activeRequest = Roo.Ajax.request(o);
12100 this.conn.request(o);
12103 callback.call(scope||this, null, arg, false);
12108 loadResponse : function(o, success, response){
12109 delete this.activeRequest;
12111 this.fireEvent("loadexception", this, o, response);
12112 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12117 result = o.reader.read(response);
12119 this.fireEvent("loadexception", this, o, response, e);
12120 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12124 this.fireEvent("load", this, o, o.request.arg);
12125 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12129 update : function(dataSet){
12134 updateResponse : function(dataSet){
12139 * Ext JS Library 1.1.1
12140 * Copyright(c) 2006-2007, Ext JS, LLC.
12142 * Originally Released Under LGPL - original licence link has changed is not relivant.
12145 * <script type="text/javascript">
12149 * @class Roo.data.ScriptTagProxy
12150 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12151 * other than the originating domain of the running page.<br><br>
12153 * <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
12154 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12156 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12157 * source code that is used as the source inside a <script> tag.<br><br>
12159 * In order for the browser to process the returned data, the server must wrap the data object
12160 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12161 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12162 * depending on whether the callback name was passed:
12165 boolean scriptTag = false;
12166 String cb = request.getParameter("callback");
12169 response.setContentType("text/javascript");
12171 response.setContentType("application/x-json");
12173 Writer out = response.getWriter();
12175 out.write(cb + "(");
12177 out.print(dataBlock.toJsonString());
12184 * @param {Object} config A configuration object.
12186 Roo.data.ScriptTagProxy = function(config){
12187 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12188 Roo.apply(this, config);
12189 this.head = document.getElementsByTagName("head")[0];
12192 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12194 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12196 * @cfg {String} url The URL from which to request the data object.
12199 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12203 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12204 * the server the name of the callback function set up by the load call to process the returned data object.
12205 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12206 * javascript output which calls this named function passing the data object as its only parameter.
12208 callbackParam : "callback",
12210 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12211 * name to the request.
12216 * Load data from the configured URL, read the data object into
12217 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12218 * process that block using the passed callback.
12219 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12220 * for the request to the remote server.
12221 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12222 * object into a block of Roo.data.Records.
12223 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12224 * The function must be passed <ul>
12225 * <li>The Record block object</li>
12226 * <li>The "arg" argument from the load function</li>
12227 * <li>A boolean success indicator</li>
12229 * @param {Object} scope The scope in which to call the callback
12230 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12232 load : function(params, reader, callback, scope, arg){
12233 if(this.fireEvent("beforeload", this, params) !== false){
12235 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12237 var url = this.url;
12238 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12240 url += "&_dc=" + (new Date().getTime());
12242 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12245 cb : "stcCallback"+transId,
12246 scriptId : "stcScript"+transId,
12250 callback : callback,
12256 window[trans.cb] = function(o){
12257 conn.handleResponse(o, trans);
12260 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12262 if(this.autoAbort !== false){
12266 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12268 var script = document.createElement("script");
12269 script.setAttribute("src", url);
12270 script.setAttribute("type", "text/javascript");
12271 script.setAttribute("id", trans.scriptId);
12272 this.head.appendChild(script);
12274 this.trans = trans;
12276 callback.call(scope||this, null, arg, false);
12281 isLoading : function(){
12282 return this.trans ? true : false;
12286 * Abort the current server request.
12288 abort : function(){
12289 if(this.isLoading()){
12290 this.destroyTrans(this.trans);
12295 destroyTrans : function(trans, isLoaded){
12296 this.head.removeChild(document.getElementById(trans.scriptId));
12297 clearTimeout(trans.timeoutId);
12299 window[trans.cb] = undefined;
12301 delete window[trans.cb];
12304 // if hasn't been loaded, wait for load to remove it to prevent script error
12305 window[trans.cb] = function(){
12306 window[trans.cb] = undefined;
12308 delete window[trans.cb];
12315 handleResponse : function(o, trans){
12316 this.trans = false;
12317 this.destroyTrans(trans, true);
12320 result = trans.reader.readRecords(o);
12322 this.fireEvent("loadexception", this, o, trans.arg, e);
12323 trans.callback.call(trans.scope||window, null, trans.arg, false);
12326 this.fireEvent("load", this, o, trans.arg);
12327 trans.callback.call(trans.scope||window, result, trans.arg, true);
12331 handleFailure : function(trans){
12332 this.trans = false;
12333 this.destroyTrans(trans, false);
12334 this.fireEvent("loadexception", this, null, trans.arg);
12335 trans.callback.call(trans.scope||window, null, trans.arg, false);
12339 * Ext JS Library 1.1.1
12340 * Copyright(c) 2006-2007, Ext JS, LLC.
12342 * Originally Released Under LGPL - original licence link has changed is not relivant.
12345 * <script type="text/javascript">
12349 * @class Roo.data.JsonReader
12350 * @extends Roo.data.DataReader
12351 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12352 * based on mappings in a provided Roo.data.Record constructor.
12354 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12355 * in the reply previously.
12360 var RecordDef = Roo.data.Record.create([
12361 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12362 {name: 'occupation'} // This field will use "occupation" as the mapping.
12364 var myReader = new Roo.data.JsonReader({
12365 totalProperty: "results", // The property which contains the total dataset size (optional)
12366 root: "rows", // The property which contains an Array of row objects
12367 id: "id" // The property within each row object that provides an ID for the record (optional)
12371 * This would consume a JSON file like this:
12373 { 'results': 2, 'rows': [
12374 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12375 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12378 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12379 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12380 * paged from the remote server.
12381 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12382 * @cfg {String} root name of the property which contains the Array of row objects.
12383 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12384 * @cfg {Array} fields Array of field definition objects
12386 * Create a new JsonReader
12387 * @param {Object} meta Metadata configuration options
12388 * @param {Object} recordType Either an Array of field definition objects,
12389 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12391 Roo.data.JsonReader = function(meta, recordType){
12394 // set some defaults:
12395 Roo.applyIf(meta, {
12396 totalProperty: 'total',
12397 successProperty : 'success',
12402 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12404 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12407 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12408 * Used by Store query builder to append _requestMeta to params.
12411 metaFromRemote : false,
12413 * This method is only used by a DataProxy which has retrieved data from a remote server.
12414 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12415 * @return {Object} data A data block which is used by an Roo.data.Store object as
12416 * a cache of Roo.data.Records.
12418 read : function(response){
12419 var json = response.responseText;
12421 var o = /* eval:var:o */ eval("("+json+")");
12423 throw {message: "JsonReader.read: Json object not found"};
12429 this.metaFromRemote = true;
12430 this.meta = o.metaData;
12431 this.recordType = Roo.data.Record.create(o.metaData.fields);
12432 this.onMetaChange(this.meta, this.recordType, o);
12434 return this.readRecords(o);
12437 // private function a store will implement
12438 onMetaChange : function(meta, recordType, o){
12445 simpleAccess: function(obj, subsc) {
12452 getJsonAccessor: function(){
12454 return function(expr) {
12456 return(re.test(expr))
12457 ? new Function("obj", "return obj." + expr)
12462 return Roo.emptyFn;
12467 * Create a data block containing Roo.data.Records from an XML document.
12468 * @param {Object} o An object which contains an Array of row objects in the property specified
12469 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12470 * which contains the total size of the dataset.
12471 * @return {Object} data A data block which is used by an Roo.data.Store object as
12472 * a cache of Roo.data.Records.
12474 readRecords : function(o){
12476 * After any data loads, the raw JSON data is available for further custom processing.
12480 var s = this.meta, Record = this.recordType,
12481 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12483 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12485 if(s.totalProperty) {
12486 this.getTotal = this.getJsonAccessor(s.totalProperty);
12488 if(s.successProperty) {
12489 this.getSuccess = this.getJsonAccessor(s.successProperty);
12491 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12493 var g = this.getJsonAccessor(s.id);
12494 this.getId = function(rec) {
12496 return (r === undefined || r === "") ? null : r;
12499 this.getId = function(){return null;};
12502 for(var jj = 0; jj < fl; jj++){
12504 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12505 this.ef[jj] = this.getJsonAccessor(map);
12509 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12510 if(s.totalProperty){
12511 var vt = parseInt(this.getTotal(o), 10);
12516 if(s.successProperty){
12517 var vs = this.getSuccess(o);
12518 if(vs === false || vs === 'false'){
12523 for(var i = 0; i < c; i++){
12526 var id = this.getId(n);
12527 for(var j = 0; j < fl; j++){
12529 var v = this.ef[j](n);
12531 Roo.log('missing convert for ' + f.name);
12535 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12537 var record = new Record(values, id);
12539 records[i] = record;
12545 totalRecords : totalRecords
12550 * Ext JS Library 1.1.1
12551 * Copyright(c) 2006-2007, Ext JS, LLC.
12553 * Originally Released Under LGPL - original licence link has changed is not relivant.
12556 * <script type="text/javascript">
12560 * @class Roo.data.ArrayReader
12561 * @extends Roo.data.DataReader
12562 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12563 * Each element of that Array represents a row of data fields. The
12564 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12565 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12569 var RecordDef = Roo.data.Record.create([
12570 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12571 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12573 var myReader = new Roo.data.ArrayReader({
12574 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12578 * This would consume an Array like this:
12580 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12582 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12584 * Create a new JsonReader
12585 * @param {Object} meta Metadata configuration options.
12586 * @param {Object} recordType Either an Array of field definition objects
12587 * as specified to {@link Roo.data.Record#create},
12588 * or an {@link Roo.data.Record} object
12589 * created using {@link Roo.data.Record#create}.
12591 Roo.data.ArrayReader = function(meta, recordType){
12592 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12595 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12597 * Create a data block containing Roo.data.Records from an XML document.
12598 * @param {Object} o An Array of row objects which represents the dataset.
12599 * @return {Object} data A data block which is used by an Roo.data.Store object as
12600 * a cache of Roo.data.Records.
12602 readRecords : function(o){
12603 var sid = this.meta ? this.meta.id : null;
12604 var recordType = this.recordType, fields = recordType.prototype.fields;
12607 for(var i = 0; i < root.length; i++){
12610 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12611 for(var j = 0, jlen = fields.length; j < jlen; j++){
12612 var f = fields.items[j];
12613 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12614 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12616 values[f.name] = v;
12618 var record = new recordType(values, id);
12620 records[records.length] = record;
12624 totalRecords : records.length
12633 * @class Roo.bootstrap.ComboBox
12634 * @extends Roo.bootstrap.TriggerField
12635 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12636 * @cfg {Boolean} append (true|false) default false
12637 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12638 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12639 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12640 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12641 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12642 * @cfg {Boolean} animate default true
12643 * @cfg {Boolean} emptyResultText only for touch device
12644 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12645 * @cfg {String} emptyTitle default ''
12647 * Create a new ComboBox.
12648 * @param {Object} config Configuration options
12650 Roo.bootstrap.ComboBox = function(config){
12651 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12655 * Fires when the dropdown list is expanded
12656 * @param {Roo.bootstrap.ComboBox} combo This combo box
12661 * Fires when the dropdown list is collapsed
12662 * @param {Roo.bootstrap.ComboBox} combo This combo box
12666 * @event beforeselect
12667 * Fires before a list item is selected. Return false to cancel the selection.
12668 * @param {Roo.bootstrap.ComboBox} combo This combo box
12669 * @param {Roo.data.Record} record The data record returned from the underlying store
12670 * @param {Number} index The index of the selected item in the dropdown list
12672 'beforeselect' : true,
12675 * Fires when a list item is selected
12676 * @param {Roo.bootstrap.ComboBox} combo This combo box
12677 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12678 * @param {Number} index The index of the selected item in the dropdown list
12682 * @event beforequery
12683 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12684 * The event object passed has these properties:
12685 * @param {Roo.bootstrap.ComboBox} combo This combo box
12686 * @param {String} query The query
12687 * @param {Boolean} forceAll true to force "all" query
12688 * @param {Boolean} cancel true to cancel the query
12689 * @param {Object} e The query event object
12691 'beforequery': true,
12694 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12695 * @param {Roo.bootstrap.ComboBox} combo This combo box
12700 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12701 * @param {Roo.bootstrap.ComboBox} combo This combo box
12702 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12707 * Fires when the remove value from the combobox array
12708 * @param {Roo.bootstrap.ComboBox} combo This combo box
12712 * @event afterremove
12713 * Fires when the remove value from the combobox array
12714 * @param {Roo.bootstrap.ComboBox} combo This combo box
12716 'afterremove' : true,
12718 * @event specialfilter
12719 * Fires when specialfilter
12720 * @param {Roo.bootstrap.ComboBox} combo This combo box
12722 'specialfilter' : true,
12725 * Fires when tick the element
12726 * @param {Roo.bootstrap.ComboBox} combo This combo box
12730 * @event touchviewdisplay
12731 * Fires when touch view require special display (default is using displayField)
12732 * @param {Roo.bootstrap.ComboBox} combo This combo box
12733 * @param {Object} cfg set html .
12735 'touchviewdisplay' : true
12740 this.tickItems = [];
12742 this.selectedIndex = -1;
12743 if(this.mode == 'local'){
12744 if(config.queryDelay === undefined){
12745 this.queryDelay = 10;
12747 if(config.minChars === undefined){
12753 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12756 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12757 * rendering into an Roo.Editor, defaults to false)
12760 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12761 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12764 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12767 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12768 * the dropdown list (defaults to undefined, with no header element)
12772 * @cfg {String/Roo.Template} tpl The template to use to render the output
12776 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12778 listWidth: undefined,
12780 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12781 * mode = 'remote' or 'text' if mode = 'local')
12783 displayField: undefined,
12786 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12787 * mode = 'remote' or 'value' if mode = 'local').
12788 * Note: use of a valueField requires the user make a selection
12789 * in order for a value to be mapped.
12791 valueField: undefined,
12793 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12798 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12799 * field's data value (defaults to the underlying DOM element's name)
12801 hiddenName: undefined,
12803 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12807 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12809 selectedClass: 'active',
12812 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12816 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12817 * anchor positions (defaults to 'tl-bl')
12819 listAlign: 'tl-bl?',
12821 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12825 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12826 * query specified by the allQuery config option (defaults to 'query')
12828 triggerAction: 'query',
12830 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12831 * (defaults to 4, does not apply if editable = false)
12835 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12836 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12840 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12841 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12845 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12846 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12850 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12851 * when editable = true (defaults to false)
12853 selectOnFocus:false,
12855 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12857 queryParam: 'query',
12859 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12860 * when mode = 'remote' (defaults to 'Loading...')
12862 loadingText: 'Loading...',
12864 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12868 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12872 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12873 * traditional select (defaults to true)
12877 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12881 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12885 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12886 * listWidth has a higher value)
12890 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12891 * allow the user to set arbitrary text into the field (defaults to false)
12893 forceSelection:false,
12895 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12896 * if typeAhead = true (defaults to 250)
12898 typeAheadDelay : 250,
12900 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12901 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12903 valueNotFoundText : undefined,
12905 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12907 blockFocus : false,
12910 * @cfg {Boolean} disableClear Disable showing of clear button.
12912 disableClear : false,
12914 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12916 alwaysQuery : false,
12919 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12924 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12926 invalidClass : "has-warning",
12929 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12931 validClass : "has-success",
12934 * @cfg {Boolean} specialFilter (true|false) special filter default false
12936 specialFilter : false,
12939 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12941 mobileTouchView : true,
12944 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12946 useNativeIOS : false,
12948 ios_options : false,
12960 btnPosition : 'right',
12961 triggerList : true,
12962 showToggleBtn : true,
12964 emptyResultText: 'Empty',
12965 triggerText : 'Select',
12968 // element that contains real text value.. (when hidden is used..)
12970 getAutoCreate : function()
12975 * Render classic select for iso
12978 if(Roo.isIOS && this.useNativeIOS){
12979 cfg = this.getAutoCreateNativeIOS();
12987 if(Roo.isTouch && this.mobileTouchView){
12988 cfg = this.getAutoCreateTouchView();
12995 if(!this.tickable){
12996 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13001 * ComboBox with tickable selections
13004 var align = this.labelAlign || this.parentLabelAlign();
13007 cls : 'form-group roo-combobox-tickable' //input-group
13010 var btn_text_select = '';
13011 var btn_text_done = '';
13012 var btn_text_cancel = '';
13014 if (this.btn_text_show) {
13015 btn_text_select = 'Select';
13016 btn_text_done = 'Done';
13017 btn_text_cancel = 'Cancel';
13022 cls : 'tickable-buttons',
13027 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13028 //html : this.triggerText
13029 html: btn_text_select
13035 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13037 html: btn_text_done
13043 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13045 html: btn_text_cancel
13051 buttons.cn.unshift({
13053 cls: 'roo-select2-search-field-input'
13059 Roo.each(buttons.cn, function(c){
13061 c.cls += ' btn-' + _this.size;
13064 if (_this.disabled) {
13075 cls: 'form-hidden-field'
13079 cls: 'roo-select2-choices',
13083 cls: 'roo-select2-search-field',
13094 cls: 'roo-select2-container input-group roo-select2-container-multi',
13099 // cls: 'typeahead typeahead-long dropdown-menu',
13100 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13105 if(this.hasFeedback && !this.allowBlank){
13109 cls: 'glyphicon form-control-feedback'
13112 combobox.cn.push(feedback);
13116 if (align ==='left' && this.fieldLabel.length) {
13118 cfg.cls += ' roo-form-group-label-left';
13123 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13124 tooltip : 'This field is required'
13129 cls : 'control-label',
13130 html : this.fieldLabel
13142 var labelCfg = cfg.cn[1];
13143 var contentCfg = cfg.cn[2];
13146 if(this.indicatorpos == 'right'){
13152 cls : 'control-label',
13156 html : this.fieldLabel
13160 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13161 tooltip : 'This field is required'
13176 labelCfg = cfg.cn[0];
13177 contentCfg = cfg.cn[1];
13181 if(this.labelWidth > 12){
13182 labelCfg.style = "width: " + this.labelWidth + 'px';
13185 if(this.labelWidth < 13 && this.labelmd == 0){
13186 this.labelmd = this.labelWidth;
13189 if(this.labellg > 0){
13190 labelCfg.cls += ' col-lg-' + this.labellg;
13191 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13194 if(this.labelmd > 0){
13195 labelCfg.cls += ' col-md-' + this.labelmd;
13196 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13199 if(this.labelsm > 0){
13200 labelCfg.cls += ' col-sm-' + this.labelsm;
13201 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13204 if(this.labelxs > 0){
13205 labelCfg.cls += ' col-xs-' + this.labelxs;
13206 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13210 } else if ( this.fieldLabel.length) {
13211 // Roo.log(" label");
13215 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13216 tooltip : 'This field is required'
13220 //cls : 'input-group-addon',
13221 html : this.fieldLabel
13226 if(this.indicatorpos == 'right'){
13230 //cls : 'input-group-addon',
13231 html : this.fieldLabel
13235 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13236 tooltip : 'This field is required'
13245 // Roo.log(" no label && no align");
13252 ['xs','sm','md','lg'].map(function(size){
13253 if (settings[size]) {
13254 cfg.cls += ' col-' + size + '-' + settings[size];
13262 _initEventsCalled : false,
13265 initEvents: function()
13267 if (this._initEventsCalled) { // as we call render... prevent looping...
13270 this._initEventsCalled = true;
13273 throw "can not find store for combo";
13276 this.indicator = this.indicatorEl();
13278 this.store = Roo.factory(this.store, Roo.data);
13279 this.store.parent = this;
13281 // if we are building from html. then this element is so complex, that we can not really
13282 // use the rendered HTML.
13283 // so we have to trash and replace the previous code.
13284 if (Roo.XComponent.build_from_html) {
13285 // remove this element....
13286 var e = this.el.dom, k=0;
13287 while (e ) { e = e.previousSibling; ++k;}
13292 this.rendered = false;
13294 this.render(this.parent().getChildContainer(true), k);
13297 if(Roo.isIOS && this.useNativeIOS){
13298 this.initIOSView();
13306 if(Roo.isTouch && this.mobileTouchView){
13307 this.initTouchView();
13312 this.initTickableEvents();
13316 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13318 if(this.hiddenName){
13320 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13322 this.hiddenField.dom.value =
13323 this.hiddenValue !== undefined ? this.hiddenValue :
13324 this.value !== undefined ? this.value : '';
13326 // prevent input submission
13327 this.el.dom.removeAttribute('name');
13328 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13333 // this.el.dom.setAttribute('autocomplete', 'off');
13336 var cls = 'x-combo-list';
13338 //this.list = new Roo.Layer({
13339 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13345 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13346 _this.list.setWidth(lw);
13349 this.list.on('mouseover', this.onViewOver, this);
13350 this.list.on('mousemove', this.onViewMove, this);
13351 this.list.on('scroll', this.onViewScroll, this);
13354 this.list.swallowEvent('mousewheel');
13355 this.assetHeight = 0;
13358 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13359 this.assetHeight += this.header.getHeight();
13362 this.innerList = this.list.createChild({cls:cls+'-inner'});
13363 this.innerList.on('mouseover', this.onViewOver, this);
13364 this.innerList.on('mousemove', this.onViewMove, this);
13365 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13367 if(this.allowBlank && !this.pageSize && !this.disableClear){
13368 this.footer = this.list.createChild({cls:cls+'-ft'});
13369 this.pageTb = new Roo.Toolbar(this.footer);
13373 this.footer = this.list.createChild({cls:cls+'-ft'});
13374 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13375 {pageSize: this.pageSize});
13379 if (this.pageTb && this.allowBlank && !this.disableClear) {
13381 this.pageTb.add(new Roo.Toolbar.Fill(), {
13382 cls: 'x-btn-icon x-btn-clear',
13384 handler: function()
13387 _this.clearValue();
13388 _this.onSelect(false, -1);
13393 this.assetHeight += this.footer.getHeight();
13398 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13401 this.view = new Roo.View(this.list, this.tpl, {
13402 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13404 //this.view.wrapEl.setDisplayed(false);
13405 this.view.on('click', this.onViewClick, this);
13408 this.store.on('beforeload', this.onBeforeLoad, this);
13409 this.store.on('load', this.onLoad, this);
13410 this.store.on('loadexception', this.onLoadException, this);
13412 if(this.resizable){
13413 this.resizer = new Roo.Resizable(this.list, {
13414 pinned:true, handles:'se'
13416 this.resizer.on('resize', function(r, w, h){
13417 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13418 this.listWidth = w;
13419 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13420 this.restrictHeight();
13422 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13425 if(!this.editable){
13426 this.editable = true;
13427 this.setEditable(false);
13432 if (typeof(this.events.add.listeners) != 'undefined') {
13434 this.addicon = this.wrap.createChild(
13435 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13437 this.addicon.on('click', function(e) {
13438 this.fireEvent('add', this);
13441 if (typeof(this.events.edit.listeners) != 'undefined') {
13443 this.editicon = this.wrap.createChild(
13444 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13445 if (this.addicon) {
13446 this.editicon.setStyle('margin-left', '40px');
13448 this.editicon.on('click', function(e) {
13450 // we fire even if inothing is selected..
13451 this.fireEvent('edit', this, this.lastData );
13457 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13458 "up" : function(e){
13459 this.inKeyMode = true;
13463 "down" : function(e){
13464 if(!this.isExpanded()){
13465 this.onTriggerClick();
13467 this.inKeyMode = true;
13472 "enter" : function(e){
13473 // this.onViewClick();
13477 if(this.fireEvent("specialkey", this, e)){
13478 this.onViewClick(false);
13484 "esc" : function(e){
13488 "tab" : function(e){
13491 if(this.fireEvent("specialkey", this, e)){
13492 this.onViewClick(false);
13500 doRelay : function(foo, bar, hname){
13501 if(hname == 'down' || this.scope.isExpanded()){
13502 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13511 this.queryDelay = Math.max(this.queryDelay || 10,
13512 this.mode == 'local' ? 10 : 250);
13515 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13517 if(this.typeAhead){
13518 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13520 if(this.editable !== false){
13521 this.inputEl().on("keyup", this.onKeyUp, this);
13523 if(this.forceSelection){
13524 this.inputEl().on('blur', this.doForce, this);
13528 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13529 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13533 initTickableEvents: function()
13537 if(this.hiddenName){
13539 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13541 this.hiddenField.dom.value =
13542 this.hiddenValue !== undefined ? this.hiddenValue :
13543 this.value !== undefined ? this.value : '';
13545 // prevent input submission
13546 this.el.dom.removeAttribute('name');
13547 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13552 // this.list = this.el.select('ul.dropdown-menu',true).first();
13554 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13555 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13556 if(this.triggerList){
13557 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13560 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13561 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13563 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13564 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13566 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13567 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13569 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13570 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13571 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13574 this.cancelBtn.hide();
13579 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13580 _this.list.setWidth(lw);
13583 this.list.on('mouseover', this.onViewOver, this);
13584 this.list.on('mousemove', this.onViewMove, this);
13586 this.list.on('scroll', this.onViewScroll, this);
13589 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>';
13592 this.view = new Roo.View(this.list, this.tpl, {
13593 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13596 //this.view.wrapEl.setDisplayed(false);
13597 this.view.on('click', this.onViewClick, this);
13601 this.store.on('beforeload', this.onBeforeLoad, this);
13602 this.store.on('load', this.onLoad, this);
13603 this.store.on('loadexception', this.onLoadException, this);
13606 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13607 "up" : function(e){
13608 this.inKeyMode = true;
13612 "down" : function(e){
13613 this.inKeyMode = true;
13617 "enter" : function(e){
13618 if(this.fireEvent("specialkey", this, e)){
13619 this.onViewClick(false);
13625 "esc" : function(e){
13626 this.onTickableFooterButtonClick(e, false, false);
13629 "tab" : function(e){
13630 this.fireEvent("specialkey", this, e);
13632 this.onTickableFooterButtonClick(e, false, false);
13639 doRelay : function(e, fn, key){
13640 if(this.scope.isExpanded()){
13641 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13650 this.queryDelay = Math.max(this.queryDelay || 10,
13651 this.mode == 'local' ? 10 : 250);
13654 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13656 if(this.typeAhead){
13657 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13660 if(this.editable !== false){
13661 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13664 this.indicator = this.indicatorEl();
13666 if(this.indicator){
13667 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13668 this.indicator.hide();
13673 onDestroy : function(){
13675 this.view.setStore(null);
13676 this.view.el.removeAllListeners();
13677 this.view.el.remove();
13678 this.view.purgeListeners();
13681 this.list.dom.innerHTML = '';
13685 this.store.un('beforeload', this.onBeforeLoad, this);
13686 this.store.un('load', this.onLoad, this);
13687 this.store.un('loadexception', this.onLoadException, this);
13689 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13693 fireKey : function(e){
13694 if(e.isNavKeyPress() && !this.list.isVisible()){
13695 this.fireEvent("specialkey", this, e);
13700 onResize: function(w, h){
13701 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13703 // if(typeof w != 'number'){
13704 // // we do not handle it!?!?
13707 // var tw = this.trigger.getWidth();
13708 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13709 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13711 // this.inputEl().setWidth( this.adjustWidth('input', x));
13713 // //this.trigger.setStyle('left', x+'px');
13715 // if(this.list && this.listWidth === undefined){
13716 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13717 // this.list.setWidth(lw);
13718 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13726 * Allow or prevent the user from directly editing the field text. If false is passed,
13727 * the user will only be able to select from the items defined in the dropdown list. This method
13728 * is the runtime equivalent of setting the 'editable' config option at config time.
13729 * @param {Boolean} value True to allow the user to directly edit the field text
13731 setEditable : function(value){
13732 if(value == this.editable){
13735 this.editable = value;
13737 this.inputEl().dom.setAttribute('readOnly', true);
13738 this.inputEl().on('mousedown', this.onTriggerClick, this);
13739 this.inputEl().addClass('x-combo-noedit');
13741 this.inputEl().dom.setAttribute('readOnly', false);
13742 this.inputEl().un('mousedown', this.onTriggerClick, this);
13743 this.inputEl().removeClass('x-combo-noedit');
13749 onBeforeLoad : function(combo,opts){
13750 if(!this.hasFocus){
13754 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13756 this.restrictHeight();
13757 this.selectedIndex = -1;
13761 onLoad : function(){
13763 this.hasQuery = false;
13765 if(!this.hasFocus){
13769 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13770 this.loading.hide();
13773 if(this.store.getCount() > 0){
13776 this.restrictHeight();
13777 if(this.lastQuery == this.allQuery){
13778 if(this.editable && !this.tickable){
13779 this.inputEl().dom.select();
13783 !this.selectByValue(this.value, true) &&
13786 !this.store.lastOptions ||
13787 typeof(this.store.lastOptions.add) == 'undefined' ||
13788 this.store.lastOptions.add != true
13791 this.select(0, true);
13794 if(this.autoFocus){
13797 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13798 this.taTask.delay(this.typeAheadDelay);
13802 this.onEmptyResults();
13808 onLoadException : function()
13810 this.hasQuery = false;
13812 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13813 this.loading.hide();
13816 if(this.tickable && this.editable){
13821 // only causes errors at present
13822 //Roo.log(this.store.reader.jsonData);
13823 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13825 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13831 onTypeAhead : function(){
13832 if(this.store.getCount() > 0){
13833 var r = this.store.getAt(0);
13834 var newValue = r.data[this.displayField];
13835 var len = newValue.length;
13836 var selStart = this.getRawValue().length;
13838 if(selStart != len){
13839 this.setRawValue(newValue);
13840 this.selectText(selStart, newValue.length);
13846 onSelect : function(record, index){
13848 if(this.fireEvent('beforeselect', this, record, index) !== false){
13850 this.setFromData(index > -1 ? record.data : false);
13853 this.fireEvent('select', this, record, index);
13858 * Returns the currently selected field value or empty string if no value is set.
13859 * @return {String} value The selected value
13861 getValue : function()
13863 if(Roo.isIOS && this.useNativeIOS){
13864 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13868 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13871 if(this.valueField){
13872 return typeof this.value != 'undefined' ? this.value : '';
13874 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13878 getRawValue : function()
13880 if(Roo.isIOS && this.useNativeIOS){
13881 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13884 var v = this.inputEl().getValue();
13890 * Clears any text/value currently set in the field
13892 clearValue : function(){
13894 if(this.hiddenField){
13895 this.hiddenField.dom.value = '';
13898 this.setRawValue('');
13899 this.lastSelectionText = '';
13900 this.lastData = false;
13902 var close = this.closeTriggerEl();
13913 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13914 * will be displayed in the field. If the value does not match the data value of an existing item,
13915 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13916 * Otherwise the field will be blank (although the value will still be set).
13917 * @param {String} value The value to match
13919 setValue : function(v)
13921 if(Roo.isIOS && this.useNativeIOS){
13922 this.setIOSValue(v);
13932 if(this.valueField){
13933 var r = this.findRecord(this.valueField, v);
13935 text = r.data[this.displayField];
13936 }else if(this.valueNotFoundText !== undefined){
13937 text = this.valueNotFoundText;
13940 this.lastSelectionText = text;
13941 if(this.hiddenField){
13942 this.hiddenField.dom.value = v;
13944 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13947 var close = this.closeTriggerEl();
13950 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13956 * @property {Object} the last set data for the element
13961 * Sets the value of the field based on a object which is related to the record format for the store.
13962 * @param {Object} value the value to set as. or false on reset?
13964 setFromData : function(o){
13971 var dv = ''; // display value
13972 var vv = ''; // value value..
13974 if (this.displayField) {
13975 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13977 // this is an error condition!!!
13978 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13981 if(this.valueField){
13982 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13985 var close = this.closeTriggerEl();
13988 if(dv.length || vv * 1 > 0){
13990 this.blockFocus=true;
13996 if(this.hiddenField){
13997 this.hiddenField.dom.value = vv;
13999 this.lastSelectionText = dv;
14000 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14004 // no hidden field.. - we store the value in 'value', but still display
14005 // display field!!!!
14006 this.lastSelectionText = dv;
14007 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14014 reset : function(){
14015 // overridden so that last data is reset..
14022 this.setValue(this.originalValue);
14023 //this.clearInvalid();
14024 this.lastData = false;
14026 this.view.clearSelections();
14032 findRecord : function(prop, value){
14034 if(this.store.getCount() > 0){
14035 this.store.each(function(r){
14036 if(r.data[prop] == value){
14046 getName: function()
14048 // returns hidden if it's set..
14049 if (!this.rendered) {return ''};
14050 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14054 onViewMove : function(e, t){
14055 this.inKeyMode = false;
14059 onViewOver : function(e, t){
14060 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14063 var item = this.view.findItemFromChild(t);
14066 var index = this.view.indexOf(item);
14067 this.select(index, false);
14072 onViewClick : function(view, doFocus, el, e)
14074 var index = this.view.getSelectedIndexes()[0];
14076 var r = this.store.getAt(index);
14080 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14087 Roo.each(this.tickItems, function(v,k){
14089 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14091 _this.tickItems.splice(k, 1);
14093 if(typeof(e) == 'undefined' && view == false){
14094 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14106 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14107 this.tickItems.push(r.data);
14110 if(typeof(e) == 'undefined' && view == false){
14111 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14118 this.onSelect(r, index);
14120 if(doFocus !== false && !this.blockFocus){
14121 this.inputEl().focus();
14126 restrictHeight : function(){
14127 //this.innerList.dom.style.height = '';
14128 //var inner = this.innerList.dom;
14129 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14130 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14131 //this.list.beginUpdate();
14132 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14133 this.list.alignTo(this.inputEl(), this.listAlign);
14134 this.list.alignTo(this.inputEl(), this.listAlign);
14135 //this.list.endUpdate();
14139 onEmptyResults : function(){
14141 if(this.tickable && this.editable){
14142 this.hasFocus = false;
14143 this.restrictHeight();
14151 * Returns true if the dropdown list is expanded, else false.
14153 isExpanded : function(){
14154 return this.list.isVisible();
14158 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14159 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14160 * @param {String} value The data value of the item to select
14161 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14162 * selected item if it is not currently in view (defaults to true)
14163 * @return {Boolean} True if the value matched an item in the list, else false
14165 selectByValue : function(v, scrollIntoView){
14166 if(v !== undefined && v !== null){
14167 var r = this.findRecord(this.valueField || this.displayField, v);
14169 this.select(this.store.indexOf(r), scrollIntoView);
14177 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14178 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14179 * @param {Number} index The zero-based index of the list item to select
14180 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14181 * selected item if it is not currently in view (defaults to true)
14183 select : function(index, scrollIntoView){
14184 this.selectedIndex = index;
14185 this.view.select(index);
14186 if(scrollIntoView !== false){
14187 var el = this.view.getNode(index);
14189 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14192 this.list.scrollChildIntoView(el, false);
14198 selectNext : function(){
14199 var ct = this.store.getCount();
14201 if(this.selectedIndex == -1){
14203 }else if(this.selectedIndex < ct-1){
14204 this.select(this.selectedIndex+1);
14210 selectPrev : function(){
14211 var ct = this.store.getCount();
14213 if(this.selectedIndex == -1){
14215 }else if(this.selectedIndex != 0){
14216 this.select(this.selectedIndex-1);
14222 onKeyUp : function(e){
14223 if(this.editable !== false && !e.isSpecialKey()){
14224 this.lastKey = e.getKey();
14225 this.dqTask.delay(this.queryDelay);
14230 validateBlur : function(){
14231 return !this.list || !this.list.isVisible();
14235 initQuery : function(){
14237 var v = this.getRawValue();
14239 if(this.tickable && this.editable){
14240 v = this.tickableInputEl().getValue();
14247 doForce : function(){
14248 if(this.inputEl().dom.value.length > 0){
14249 this.inputEl().dom.value =
14250 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14256 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14257 * query allowing the query action to be canceled if needed.
14258 * @param {String} query The SQL query to execute
14259 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14260 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14261 * saved in the current store (defaults to false)
14263 doQuery : function(q, forceAll){
14265 if(q === undefined || q === null){
14270 forceAll: forceAll,
14274 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14279 forceAll = qe.forceAll;
14280 if(forceAll === true || (q.length >= this.minChars)){
14282 this.hasQuery = true;
14284 if(this.lastQuery != q || this.alwaysQuery){
14285 this.lastQuery = q;
14286 if(this.mode == 'local'){
14287 this.selectedIndex = -1;
14289 this.store.clearFilter();
14292 if(this.specialFilter){
14293 this.fireEvent('specialfilter', this);
14298 this.store.filter(this.displayField, q);
14301 this.store.fireEvent("datachanged", this.store);
14308 this.store.baseParams[this.queryParam] = q;
14310 var options = {params : this.getParams(q)};
14313 options.add = true;
14314 options.params.start = this.page * this.pageSize;
14317 this.store.load(options);
14320 * this code will make the page width larger, at the beginning, the list not align correctly,
14321 * we should expand the list on onLoad
14322 * so command out it
14327 this.selectedIndex = -1;
14332 this.loadNext = false;
14336 getParams : function(q){
14338 //p[this.queryParam] = q;
14342 p.limit = this.pageSize;
14348 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14350 collapse : function(){
14351 if(!this.isExpanded()){
14357 this.hasFocus = false;
14361 this.cancelBtn.hide();
14362 this.trigger.show();
14365 this.tickableInputEl().dom.value = '';
14366 this.tickableInputEl().blur();
14371 Roo.get(document).un('mousedown', this.collapseIf, this);
14372 Roo.get(document).un('mousewheel', this.collapseIf, this);
14373 if (!this.editable) {
14374 Roo.get(document).un('keydown', this.listKeyPress, this);
14376 this.fireEvent('collapse', this);
14382 collapseIf : function(e){
14383 var in_combo = e.within(this.el);
14384 var in_list = e.within(this.list);
14385 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14387 if (in_combo || in_list || is_list) {
14388 //e.stopPropagation();
14393 this.onTickableFooterButtonClick(e, false, false);
14401 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14403 expand : function(){
14405 if(this.isExpanded() || !this.hasFocus){
14409 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14410 this.list.setWidth(lw);
14416 this.restrictHeight();
14420 this.tickItems = Roo.apply([], this.item);
14423 this.cancelBtn.show();
14424 this.trigger.hide();
14427 this.tickableInputEl().focus();
14432 Roo.get(document).on('mousedown', this.collapseIf, this);
14433 Roo.get(document).on('mousewheel', this.collapseIf, this);
14434 if (!this.editable) {
14435 Roo.get(document).on('keydown', this.listKeyPress, this);
14438 this.fireEvent('expand', this);
14442 // Implements the default empty TriggerField.onTriggerClick function
14443 onTriggerClick : function(e)
14445 Roo.log('trigger click');
14447 if(this.disabled || !this.triggerList){
14452 this.loadNext = false;
14454 if(this.isExpanded()){
14456 if (!this.blockFocus) {
14457 this.inputEl().focus();
14461 this.hasFocus = true;
14462 if(this.triggerAction == 'all') {
14463 this.doQuery(this.allQuery, true);
14465 this.doQuery(this.getRawValue());
14467 if (!this.blockFocus) {
14468 this.inputEl().focus();
14473 onTickableTriggerClick : function(e)
14480 this.loadNext = false;
14481 this.hasFocus = true;
14483 if(this.triggerAction == 'all') {
14484 this.doQuery(this.allQuery, true);
14486 this.doQuery(this.getRawValue());
14490 onSearchFieldClick : function(e)
14492 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14493 this.onTickableFooterButtonClick(e, false, false);
14497 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14502 this.loadNext = false;
14503 this.hasFocus = true;
14505 if(this.triggerAction == 'all') {
14506 this.doQuery(this.allQuery, true);
14508 this.doQuery(this.getRawValue());
14512 listKeyPress : function(e)
14514 //Roo.log('listkeypress');
14515 // scroll to first matching element based on key pres..
14516 if (e.isSpecialKey()) {
14519 var k = String.fromCharCode(e.getKey()).toUpperCase();
14522 var csel = this.view.getSelectedNodes();
14523 var cselitem = false;
14525 var ix = this.view.indexOf(csel[0]);
14526 cselitem = this.store.getAt(ix);
14527 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14533 this.store.each(function(v) {
14535 // start at existing selection.
14536 if (cselitem.id == v.id) {
14542 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14543 match = this.store.indexOf(v);
14549 if (match === false) {
14550 return true; // no more action?
14553 this.view.select(match);
14554 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14555 sn.scrollIntoView(sn.dom.parentNode, false);
14558 onViewScroll : function(e, t){
14560 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){
14564 this.hasQuery = true;
14566 this.loading = this.list.select('.loading', true).first();
14568 if(this.loading === null){
14569 this.list.createChild({
14571 cls: 'loading roo-select2-more-results roo-select2-active',
14572 html: 'Loading more results...'
14575 this.loading = this.list.select('.loading', true).first();
14577 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14579 this.loading.hide();
14582 this.loading.show();
14587 this.loadNext = true;
14589 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14594 addItem : function(o)
14596 var dv = ''; // display value
14598 if (this.displayField) {
14599 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14601 // this is an error condition!!!
14602 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14609 var choice = this.choices.createChild({
14611 cls: 'roo-select2-search-choice',
14620 cls: 'roo-select2-search-choice-close fa fa-times',
14625 }, this.searchField);
14627 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14629 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14637 this.inputEl().dom.value = '';
14642 onRemoveItem : function(e, _self, o)
14644 e.preventDefault();
14646 this.lastItem = Roo.apply([], this.item);
14648 var index = this.item.indexOf(o.data) * 1;
14651 Roo.log('not this item?!');
14655 this.item.splice(index, 1);
14660 this.fireEvent('remove', this, e);
14666 syncValue : function()
14668 if(!this.item.length){
14675 Roo.each(this.item, function(i){
14676 if(_this.valueField){
14677 value.push(i[_this.valueField]);
14684 this.value = value.join(',');
14686 if(this.hiddenField){
14687 this.hiddenField.dom.value = this.value;
14690 this.store.fireEvent("datachanged", this.store);
14695 clearItem : function()
14697 if(!this.multiple){
14703 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14711 if(this.tickable && !Roo.isTouch){
14712 this.view.refresh();
14716 inputEl: function ()
14718 if(Roo.isIOS && this.useNativeIOS){
14719 return this.el.select('select.roo-ios-select', true).first();
14722 if(Roo.isTouch && this.mobileTouchView){
14723 return this.el.select('input.form-control',true).first();
14727 return this.searchField;
14730 return this.el.select('input.form-control',true).first();
14733 onTickableFooterButtonClick : function(e, btn, el)
14735 e.preventDefault();
14737 this.lastItem = Roo.apply([], this.item);
14739 if(btn && btn.name == 'cancel'){
14740 this.tickItems = Roo.apply([], this.item);
14749 Roo.each(this.tickItems, function(o){
14757 validate : function()
14759 if(this.getVisibilityEl().hasClass('hidden')){
14763 var v = this.getRawValue();
14766 v = this.getValue();
14769 if(this.disabled || this.allowBlank || v.length){
14774 this.markInvalid();
14778 tickableInputEl : function()
14780 if(!this.tickable || !this.editable){
14781 return this.inputEl();
14784 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14788 getAutoCreateTouchView : function()
14793 cls: 'form-group' //input-group
14799 type : this.inputType,
14800 cls : 'form-control x-combo-noedit',
14801 autocomplete: 'new-password',
14802 placeholder : this.placeholder || '',
14807 input.name = this.name;
14811 input.cls += ' input-' + this.size;
14814 if (this.disabled) {
14815 input.disabled = true;
14826 inputblock.cls += ' input-group';
14828 inputblock.cn.unshift({
14830 cls : 'input-group-addon',
14835 if(this.removable && !this.multiple){
14836 inputblock.cls += ' roo-removable';
14838 inputblock.cn.push({
14841 cls : 'roo-combo-removable-btn close'
14845 if(this.hasFeedback && !this.allowBlank){
14847 inputblock.cls += ' has-feedback';
14849 inputblock.cn.push({
14851 cls: 'glyphicon form-control-feedback'
14858 inputblock.cls += (this.before) ? '' : ' input-group';
14860 inputblock.cn.push({
14862 cls : 'input-group-addon',
14873 cls: 'form-hidden-field'
14887 cls: 'form-hidden-field'
14891 cls: 'roo-select2-choices',
14895 cls: 'roo-select2-search-field',
14908 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14914 if(!this.multiple && this.showToggleBtn){
14921 if (this.caret != false) {
14924 cls: 'fa fa-' + this.caret
14931 cls : 'input-group-addon btn dropdown-toggle',
14936 cls: 'combobox-clear',
14950 combobox.cls += ' roo-select2-container-multi';
14953 var align = this.labelAlign || this.parentLabelAlign();
14955 if (align ==='left' && this.fieldLabel.length) {
14960 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14961 tooltip : 'This field is required'
14965 cls : 'control-label',
14966 html : this.fieldLabel
14977 var labelCfg = cfg.cn[1];
14978 var contentCfg = cfg.cn[2];
14981 if(this.indicatorpos == 'right'){
14986 cls : 'control-label',
14990 html : this.fieldLabel
14994 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14995 tooltip : 'This field is required'
15008 labelCfg = cfg.cn[0];
15009 contentCfg = cfg.cn[1];
15014 if(this.labelWidth > 12){
15015 labelCfg.style = "width: " + this.labelWidth + 'px';
15018 if(this.labelWidth < 13 && this.labelmd == 0){
15019 this.labelmd = this.labelWidth;
15022 if(this.labellg > 0){
15023 labelCfg.cls += ' col-lg-' + this.labellg;
15024 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15027 if(this.labelmd > 0){
15028 labelCfg.cls += ' col-md-' + this.labelmd;
15029 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15032 if(this.labelsm > 0){
15033 labelCfg.cls += ' col-sm-' + this.labelsm;
15034 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15037 if(this.labelxs > 0){
15038 labelCfg.cls += ' col-xs-' + this.labelxs;
15039 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15043 } else if ( this.fieldLabel.length) {
15047 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15048 tooltip : 'This field is required'
15052 cls : 'control-label',
15053 html : this.fieldLabel
15064 if(this.indicatorpos == 'right'){
15068 cls : 'control-label',
15069 html : this.fieldLabel,
15073 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15074 tooltip : 'This field is required'
15091 var settings = this;
15093 ['xs','sm','md','lg'].map(function(size){
15094 if (settings[size]) {
15095 cfg.cls += ' col-' + size + '-' + settings[size];
15102 initTouchView : function()
15104 this.renderTouchView();
15106 this.touchViewEl.on('scroll', function(){
15107 this.el.dom.scrollTop = 0;
15110 this.originalValue = this.getValue();
15112 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15114 this.inputEl().on("click", this.showTouchView, this);
15115 if (this.triggerEl) {
15116 this.triggerEl.on("click", this.showTouchView, this);
15120 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15121 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15123 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15125 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15126 this.store.on('load', this.onTouchViewLoad, this);
15127 this.store.on('loadexception', this.onTouchViewLoadException, this);
15129 if(this.hiddenName){
15131 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15133 this.hiddenField.dom.value =
15134 this.hiddenValue !== undefined ? this.hiddenValue :
15135 this.value !== undefined ? this.value : '';
15137 this.el.dom.removeAttribute('name');
15138 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15142 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15143 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15146 if(this.removable && !this.multiple){
15147 var close = this.closeTriggerEl();
15149 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15150 close.on('click', this.removeBtnClick, this, close);
15154 * fix the bug in Safari iOS8
15156 this.inputEl().on("focus", function(e){
15157 document.activeElement.blur();
15165 renderTouchView : function()
15167 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15168 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15170 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15171 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15173 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15174 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15175 this.touchViewBodyEl.setStyle('overflow', 'auto');
15177 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15178 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15180 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15181 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15185 showTouchView : function()
15191 this.touchViewHeaderEl.hide();
15193 if(this.modalTitle.length){
15194 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15195 this.touchViewHeaderEl.show();
15198 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15199 this.touchViewEl.show();
15201 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15203 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15204 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15206 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15208 if(this.modalTitle.length){
15209 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15212 this.touchViewBodyEl.setHeight(bodyHeight);
15216 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15218 this.touchViewEl.addClass('in');
15221 this.doTouchViewQuery();
15225 hideTouchView : function()
15227 this.touchViewEl.removeClass('in');
15231 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15233 this.touchViewEl.setStyle('display', 'none');
15238 setTouchViewValue : function()
15245 Roo.each(this.tickItems, function(o){
15250 this.hideTouchView();
15253 doTouchViewQuery : function()
15262 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15266 if(!this.alwaysQuery || this.mode == 'local'){
15267 this.onTouchViewLoad();
15274 onTouchViewBeforeLoad : function(combo,opts)
15280 onTouchViewLoad : function()
15282 if(this.store.getCount() < 1){
15283 this.onTouchViewEmptyResults();
15287 this.clearTouchView();
15289 var rawValue = this.getRawValue();
15291 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15293 this.tickItems = [];
15295 this.store.data.each(function(d, rowIndex){
15296 var row = this.touchViewListGroup.createChild(template);
15298 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15299 row.addClass(d.data.cls);
15302 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15305 html : d.data[this.displayField]
15308 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15309 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15312 row.removeClass('selected');
15313 if(!this.multiple && this.valueField &&
15314 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15317 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15318 row.addClass('selected');
15321 if(this.multiple && this.valueField &&
15322 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15326 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15327 this.tickItems.push(d.data);
15330 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15334 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15336 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15338 if(this.modalTitle.length){
15339 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15342 var listHeight = this.touchViewListGroup.getHeight();
15346 if(firstChecked && listHeight > bodyHeight){
15347 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15352 onTouchViewLoadException : function()
15354 this.hideTouchView();
15357 onTouchViewEmptyResults : function()
15359 this.clearTouchView();
15361 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15363 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15367 clearTouchView : function()
15369 this.touchViewListGroup.dom.innerHTML = '';
15372 onTouchViewClick : function(e, el, o)
15374 e.preventDefault();
15377 var rowIndex = o.rowIndex;
15379 var r = this.store.getAt(rowIndex);
15381 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15383 if(!this.multiple){
15384 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15385 c.dom.removeAttribute('checked');
15388 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15390 this.setFromData(r.data);
15392 var close = this.closeTriggerEl();
15398 this.hideTouchView();
15400 this.fireEvent('select', this, r, rowIndex);
15405 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15406 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15407 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15411 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15412 this.addItem(r.data);
15413 this.tickItems.push(r.data);
15417 getAutoCreateNativeIOS : function()
15420 cls: 'form-group' //input-group,
15425 cls : 'roo-ios-select'
15429 combobox.name = this.name;
15432 if (this.disabled) {
15433 combobox.disabled = true;
15436 var settings = this;
15438 ['xs','sm','md','lg'].map(function(size){
15439 if (settings[size]) {
15440 cfg.cls += ' col-' + size + '-' + settings[size];
15450 initIOSView : function()
15452 this.store.on('load', this.onIOSViewLoad, this);
15457 onIOSViewLoad : function()
15459 if(this.store.getCount() < 1){
15463 this.clearIOSView();
15465 if(this.allowBlank) {
15467 var default_text = '-- SELECT --';
15469 if(this.placeholder.length){
15470 default_text = this.placeholder;
15473 if(this.emptyTitle.length){
15474 default_text += ' - ' + this.emptyTitle + ' -';
15477 var opt = this.inputEl().createChild({
15480 html : default_text
15484 o[this.valueField] = 0;
15485 o[this.displayField] = default_text;
15487 this.ios_options.push({
15494 this.store.data.each(function(d, rowIndex){
15498 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15499 html = d.data[this.displayField];
15504 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15505 value = d.data[this.valueField];
15514 if(this.value == d.data[this.valueField]){
15515 option['selected'] = true;
15518 var opt = this.inputEl().createChild(option);
15520 this.ios_options.push({
15527 this.inputEl().on('change', function(){
15528 this.fireEvent('select', this);
15533 clearIOSView: function()
15535 this.inputEl().dom.innerHTML = '';
15537 this.ios_options = [];
15540 setIOSValue: function(v)
15544 if(!this.ios_options){
15548 Roo.each(this.ios_options, function(opts){
15550 opts.el.dom.removeAttribute('selected');
15552 if(opts.data[this.valueField] != v){
15556 opts.el.dom.setAttribute('selected', true);
15562 * @cfg {Boolean} grow
15566 * @cfg {Number} growMin
15570 * @cfg {Number} growMax
15579 Roo.apply(Roo.bootstrap.ComboBox, {
15583 cls: 'modal-header',
15605 cls: 'list-group-item',
15609 cls: 'roo-combobox-list-group-item-value'
15613 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15627 listItemCheckbox : {
15629 cls: 'list-group-item',
15633 cls: 'roo-combobox-list-group-item-value'
15637 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15653 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15658 cls: 'modal-footer',
15666 cls: 'col-xs-6 text-left',
15669 cls: 'btn btn-danger roo-touch-view-cancel',
15675 cls: 'col-xs-6 text-right',
15678 cls: 'btn btn-success roo-touch-view-ok',
15689 Roo.apply(Roo.bootstrap.ComboBox, {
15691 touchViewTemplate : {
15693 cls: 'modal fade roo-combobox-touch-view',
15697 cls: 'modal-dialog',
15698 style : 'position:fixed', // we have to fix position....
15702 cls: 'modal-content',
15704 Roo.bootstrap.ComboBox.header,
15705 Roo.bootstrap.ComboBox.body,
15706 Roo.bootstrap.ComboBox.footer
15715 * Ext JS Library 1.1.1
15716 * Copyright(c) 2006-2007, Ext JS, LLC.
15718 * Originally Released Under LGPL - original licence link has changed is not relivant.
15721 * <script type="text/javascript">
15726 * @extends Roo.util.Observable
15727 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15728 * This class also supports single and multi selection modes. <br>
15729 * Create a data model bound view:
15731 var store = new Roo.data.Store(...);
15733 var view = new Roo.View({
15735 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15737 singleSelect: true,
15738 selectedClass: "ydataview-selected",
15742 // listen for node click?
15743 view.on("click", function(vw, index, node, e){
15744 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15748 dataModel.load("foobar.xml");
15750 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15752 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15753 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15755 * Note: old style constructor is still suported (container, template, config)
15758 * Create a new View
15759 * @param {Object} config The config object
15762 Roo.View = function(config, depreciated_tpl, depreciated_config){
15764 this.parent = false;
15766 if (typeof(depreciated_tpl) == 'undefined') {
15767 // new way.. - universal constructor.
15768 Roo.apply(this, config);
15769 this.el = Roo.get(this.el);
15772 this.el = Roo.get(config);
15773 this.tpl = depreciated_tpl;
15774 Roo.apply(this, depreciated_config);
15776 this.wrapEl = this.el.wrap().wrap();
15777 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15780 if(typeof(this.tpl) == "string"){
15781 this.tpl = new Roo.Template(this.tpl);
15783 // support xtype ctors..
15784 this.tpl = new Roo.factory(this.tpl, Roo);
15788 this.tpl.compile();
15793 * @event beforeclick
15794 * Fires before a click is processed. Returns false to cancel the default action.
15795 * @param {Roo.View} this
15796 * @param {Number} index The index of the target node
15797 * @param {HTMLElement} node The target node
15798 * @param {Roo.EventObject} e The raw event object
15800 "beforeclick" : true,
15803 * Fires when a template node is clicked.
15804 * @param {Roo.View} this
15805 * @param {Number} index The index of the target node
15806 * @param {HTMLElement} node The target node
15807 * @param {Roo.EventObject} e The raw event object
15812 * Fires when a template node is double clicked.
15813 * @param {Roo.View} this
15814 * @param {Number} index The index of the target node
15815 * @param {HTMLElement} node The target node
15816 * @param {Roo.EventObject} e The raw event object
15820 * @event contextmenu
15821 * Fires when a template node is right clicked.
15822 * @param {Roo.View} this
15823 * @param {Number} index The index of the target node
15824 * @param {HTMLElement} node The target node
15825 * @param {Roo.EventObject} e The raw event object
15827 "contextmenu" : true,
15829 * @event selectionchange
15830 * Fires when the selected nodes change.
15831 * @param {Roo.View} this
15832 * @param {Array} selections Array of the selected nodes
15834 "selectionchange" : true,
15837 * @event beforeselect
15838 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15839 * @param {Roo.View} this
15840 * @param {HTMLElement} node The node to be selected
15841 * @param {Array} selections Array of currently selected nodes
15843 "beforeselect" : true,
15845 * @event preparedata
15846 * Fires on every row to render, to allow you to change the data.
15847 * @param {Roo.View} this
15848 * @param {Object} data to be rendered (change this)
15850 "preparedata" : true
15858 "click": this.onClick,
15859 "dblclick": this.onDblClick,
15860 "contextmenu": this.onContextMenu,
15864 this.selections = [];
15866 this.cmp = new Roo.CompositeElementLite([]);
15868 this.store = Roo.factory(this.store, Roo.data);
15869 this.setStore(this.store, true);
15872 if ( this.footer && this.footer.xtype) {
15874 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15876 this.footer.dataSource = this.store;
15877 this.footer.container = fctr;
15878 this.footer = Roo.factory(this.footer, Roo);
15879 fctr.insertFirst(this.el);
15881 // this is a bit insane - as the paging toolbar seems to detach the el..
15882 // dom.parentNode.parentNode.parentNode
15883 // they get detached?
15887 Roo.View.superclass.constructor.call(this);
15892 Roo.extend(Roo.View, Roo.util.Observable, {
15895 * @cfg {Roo.data.Store} store Data store to load data from.
15900 * @cfg {String|Roo.Element} el The container element.
15905 * @cfg {String|Roo.Template} tpl The template used by this View
15909 * @cfg {String} dataName the named area of the template to use as the data area
15910 * Works with domtemplates roo-name="name"
15914 * @cfg {String} selectedClass The css class to add to selected nodes
15916 selectedClass : "x-view-selected",
15918 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15923 * @cfg {String} text to display on mask (default Loading)
15927 * @cfg {Boolean} multiSelect Allow multiple selection
15929 multiSelect : false,
15931 * @cfg {Boolean} singleSelect Allow single selection
15933 singleSelect: false,
15936 * @cfg {Boolean} toggleSelect - selecting
15938 toggleSelect : false,
15941 * @cfg {Boolean} tickable - selecting
15946 * Returns the element this view is bound to.
15947 * @return {Roo.Element}
15949 getEl : function(){
15950 return this.wrapEl;
15956 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15958 refresh : function(){
15959 //Roo.log('refresh');
15962 // if we are using something like 'domtemplate', then
15963 // the what gets used is:
15964 // t.applySubtemplate(NAME, data, wrapping data..)
15965 // the outer template then get' applied with
15966 // the store 'extra data'
15967 // and the body get's added to the
15968 // roo-name="data" node?
15969 // <span class='roo-tpl-{name}'></span> ?????
15973 this.clearSelections();
15974 this.el.update("");
15976 var records = this.store.getRange();
15977 if(records.length < 1) {
15979 // is this valid?? = should it render a template??
15981 this.el.update(this.emptyText);
15985 if (this.dataName) {
15986 this.el.update(t.apply(this.store.meta)); //????
15987 el = this.el.child('.roo-tpl-' + this.dataName);
15990 for(var i = 0, len = records.length; i < len; i++){
15991 var data = this.prepareData(records[i].data, i, records[i]);
15992 this.fireEvent("preparedata", this, data, i, records[i]);
15994 var d = Roo.apply({}, data);
15997 Roo.apply(d, {'roo-id' : Roo.id()});
16001 Roo.each(this.parent.item, function(item){
16002 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16005 Roo.apply(d, {'roo-data-checked' : 'checked'});
16009 html[html.length] = Roo.util.Format.trim(
16011 t.applySubtemplate(this.dataName, d, this.store.meta) :
16018 el.update(html.join(""));
16019 this.nodes = el.dom.childNodes;
16020 this.updateIndexes(0);
16025 * Function to override to reformat the data that is sent to
16026 * the template for each node.
16027 * DEPRICATED - use the preparedata event handler.
16028 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16029 * a JSON object for an UpdateManager bound view).
16031 prepareData : function(data, index, record)
16033 this.fireEvent("preparedata", this, data, index, record);
16037 onUpdate : function(ds, record){
16038 // Roo.log('on update');
16039 this.clearSelections();
16040 var index = this.store.indexOf(record);
16041 var n = this.nodes[index];
16042 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16043 n.parentNode.removeChild(n);
16044 this.updateIndexes(index, index);
16050 onAdd : function(ds, records, index)
16052 //Roo.log(['on Add', ds, records, index] );
16053 this.clearSelections();
16054 if(this.nodes.length == 0){
16058 var n = this.nodes[index];
16059 for(var i = 0, len = records.length; i < len; i++){
16060 var d = this.prepareData(records[i].data, i, records[i]);
16062 this.tpl.insertBefore(n, d);
16065 this.tpl.append(this.el, d);
16068 this.updateIndexes(index);
16071 onRemove : function(ds, record, index){
16072 // Roo.log('onRemove');
16073 this.clearSelections();
16074 var el = this.dataName ?
16075 this.el.child('.roo-tpl-' + this.dataName) :
16078 el.dom.removeChild(this.nodes[index]);
16079 this.updateIndexes(index);
16083 * Refresh an individual node.
16084 * @param {Number} index
16086 refreshNode : function(index){
16087 this.onUpdate(this.store, this.store.getAt(index));
16090 updateIndexes : function(startIndex, endIndex){
16091 var ns = this.nodes;
16092 startIndex = startIndex || 0;
16093 endIndex = endIndex || ns.length - 1;
16094 for(var i = startIndex; i <= endIndex; i++){
16095 ns[i].nodeIndex = i;
16100 * Changes the data store this view uses and refresh the view.
16101 * @param {Store} store
16103 setStore : function(store, initial){
16104 if(!initial && this.store){
16105 this.store.un("datachanged", this.refresh);
16106 this.store.un("add", this.onAdd);
16107 this.store.un("remove", this.onRemove);
16108 this.store.un("update", this.onUpdate);
16109 this.store.un("clear", this.refresh);
16110 this.store.un("beforeload", this.onBeforeLoad);
16111 this.store.un("load", this.onLoad);
16112 this.store.un("loadexception", this.onLoad);
16116 store.on("datachanged", this.refresh, this);
16117 store.on("add", this.onAdd, this);
16118 store.on("remove", this.onRemove, this);
16119 store.on("update", this.onUpdate, this);
16120 store.on("clear", this.refresh, this);
16121 store.on("beforeload", this.onBeforeLoad, this);
16122 store.on("load", this.onLoad, this);
16123 store.on("loadexception", this.onLoad, this);
16131 * onbeforeLoad - masks the loading area.
16134 onBeforeLoad : function(store,opts)
16136 //Roo.log('onBeforeLoad');
16138 this.el.update("");
16140 this.el.mask(this.mask ? this.mask : "Loading" );
16142 onLoad : function ()
16149 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16150 * @param {HTMLElement} node
16151 * @return {HTMLElement} The template node
16153 findItemFromChild : function(node){
16154 var el = this.dataName ?
16155 this.el.child('.roo-tpl-' + this.dataName,true) :
16158 if(!node || node.parentNode == el){
16161 var p = node.parentNode;
16162 while(p && p != el){
16163 if(p.parentNode == el){
16172 onClick : function(e){
16173 var item = this.findItemFromChild(e.getTarget());
16175 var index = this.indexOf(item);
16176 if(this.onItemClick(item, index, e) !== false){
16177 this.fireEvent("click", this, index, item, e);
16180 this.clearSelections();
16185 onContextMenu : function(e){
16186 var item = this.findItemFromChild(e.getTarget());
16188 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16193 onDblClick : function(e){
16194 var item = this.findItemFromChild(e.getTarget());
16196 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16200 onItemClick : function(item, index, e)
16202 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16205 if (this.toggleSelect) {
16206 var m = this.isSelected(item) ? 'unselect' : 'select';
16209 _t[m](item, true, false);
16212 if(this.multiSelect || this.singleSelect){
16213 if(this.multiSelect && e.shiftKey && this.lastSelection){
16214 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16216 this.select(item, this.multiSelect && e.ctrlKey);
16217 this.lastSelection = item;
16220 if(!this.tickable){
16221 e.preventDefault();
16229 * Get the number of selected nodes.
16232 getSelectionCount : function(){
16233 return this.selections.length;
16237 * Get the currently selected nodes.
16238 * @return {Array} An array of HTMLElements
16240 getSelectedNodes : function(){
16241 return this.selections;
16245 * Get the indexes of the selected nodes.
16248 getSelectedIndexes : function(){
16249 var indexes = [], s = this.selections;
16250 for(var i = 0, len = s.length; i < len; i++){
16251 indexes.push(s[i].nodeIndex);
16257 * Clear all selections
16258 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16260 clearSelections : function(suppressEvent){
16261 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16262 this.cmp.elements = this.selections;
16263 this.cmp.removeClass(this.selectedClass);
16264 this.selections = [];
16265 if(!suppressEvent){
16266 this.fireEvent("selectionchange", this, this.selections);
16272 * Returns true if the passed node is selected
16273 * @param {HTMLElement/Number} node The node or node index
16274 * @return {Boolean}
16276 isSelected : function(node){
16277 var s = this.selections;
16281 node = this.getNode(node);
16282 return s.indexOf(node) !== -1;
16287 * @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
16288 * @param {Boolean} keepExisting (optional) true to keep existing selections
16289 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16291 select : function(nodeInfo, keepExisting, suppressEvent){
16292 if(nodeInfo instanceof Array){
16294 this.clearSelections(true);
16296 for(var i = 0, len = nodeInfo.length; i < len; i++){
16297 this.select(nodeInfo[i], true, true);
16301 var node = this.getNode(nodeInfo);
16302 if(!node || this.isSelected(node)){
16303 return; // already selected.
16306 this.clearSelections(true);
16309 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16310 Roo.fly(node).addClass(this.selectedClass);
16311 this.selections.push(node);
16312 if(!suppressEvent){
16313 this.fireEvent("selectionchange", this, this.selections);
16321 * @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
16322 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16323 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16325 unselect : function(nodeInfo, keepExisting, suppressEvent)
16327 if(nodeInfo instanceof Array){
16328 Roo.each(this.selections, function(s) {
16329 this.unselect(s, nodeInfo);
16333 var node = this.getNode(nodeInfo);
16334 if(!node || !this.isSelected(node)){
16335 //Roo.log("not selected");
16336 return; // not selected.
16340 Roo.each(this.selections, function(s) {
16342 Roo.fly(node).removeClass(this.selectedClass);
16349 this.selections= ns;
16350 this.fireEvent("selectionchange", this, this.selections);
16354 * Gets a template node.
16355 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16356 * @return {HTMLElement} The node or null if it wasn't found
16358 getNode : function(nodeInfo){
16359 if(typeof nodeInfo == "string"){
16360 return document.getElementById(nodeInfo);
16361 }else if(typeof nodeInfo == "number"){
16362 return this.nodes[nodeInfo];
16368 * Gets a range template nodes.
16369 * @param {Number} startIndex
16370 * @param {Number} endIndex
16371 * @return {Array} An array of nodes
16373 getNodes : function(start, end){
16374 var ns = this.nodes;
16375 start = start || 0;
16376 end = typeof end == "undefined" ? ns.length - 1 : end;
16379 for(var i = start; i <= end; i++){
16383 for(var i = start; i >= end; i--){
16391 * Finds the index of the passed node
16392 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16393 * @return {Number} The index of the node or -1
16395 indexOf : function(node){
16396 node = this.getNode(node);
16397 if(typeof node.nodeIndex == "number"){
16398 return node.nodeIndex;
16400 var ns = this.nodes;
16401 for(var i = 0, len = ns.length; i < len; i++){
16412 * based on jquery fullcalendar
16416 Roo.bootstrap = Roo.bootstrap || {};
16418 * @class Roo.bootstrap.Calendar
16419 * @extends Roo.bootstrap.Component
16420 * Bootstrap Calendar class
16421 * @cfg {Boolean} loadMask (true|false) default false
16422 * @cfg {Object} header generate the user specific header of the calendar, default false
16425 * Create a new Container
16426 * @param {Object} config The config object
16431 Roo.bootstrap.Calendar = function(config){
16432 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16436 * Fires when a date is selected
16437 * @param {DatePicker} this
16438 * @param {Date} date The selected date
16442 * @event monthchange
16443 * Fires when the displayed month changes
16444 * @param {DatePicker} this
16445 * @param {Date} date The selected month
16447 'monthchange': true,
16449 * @event evententer
16450 * Fires when mouse over an event
16451 * @param {Calendar} this
16452 * @param {event} Event
16454 'evententer': true,
16456 * @event eventleave
16457 * Fires when the mouse leaves an
16458 * @param {Calendar} this
16461 'eventleave': true,
16463 * @event eventclick
16464 * Fires when the mouse click an
16465 * @param {Calendar} this
16474 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16477 * @cfg {Number} startDay
16478 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16486 getAutoCreate : function(){
16489 var fc_button = function(name, corner, style, content ) {
16490 return Roo.apply({},{
16492 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16494 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16497 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16508 style : 'width:100%',
16515 cls : 'fc-header-left',
16517 fc_button('prev', 'left', 'arrow', '‹' ),
16518 fc_button('next', 'right', 'arrow', '›' ),
16519 { tag: 'span', cls: 'fc-header-space' },
16520 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16528 cls : 'fc-header-center',
16532 cls: 'fc-header-title',
16535 html : 'month / year'
16543 cls : 'fc-header-right',
16545 /* fc_button('month', 'left', '', 'month' ),
16546 fc_button('week', '', '', 'week' ),
16547 fc_button('day', 'right', '', 'day' )
16559 header = this.header;
16562 var cal_heads = function() {
16564 // fixme - handle this.
16566 for (var i =0; i < Date.dayNames.length; i++) {
16567 var d = Date.dayNames[i];
16570 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16571 html : d.substring(0,3)
16575 ret[0].cls += ' fc-first';
16576 ret[6].cls += ' fc-last';
16579 var cal_cell = function(n) {
16582 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16587 cls: 'fc-day-number',
16591 cls: 'fc-day-content',
16595 style: 'position: relative;' // height: 17px;
16607 var cal_rows = function() {
16610 for (var r = 0; r < 6; r++) {
16617 for (var i =0; i < Date.dayNames.length; i++) {
16618 var d = Date.dayNames[i];
16619 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16622 row.cn[0].cls+=' fc-first';
16623 row.cn[0].cn[0].style = 'min-height:90px';
16624 row.cn[6].cls+=' fc-last';
16628 ret[0].cls += ' fc-first';
16629 ret[4].cls += ' fc-prev-last';
16630 ret[5].cls += ' fc-last';
16637 cls: 'fc-border-separate',
16638 style : 'width:100%',
16646 cls : 'fc-first fc-last',
16664 cls : 'fc-content',
16665 style : "position: relative;",
16668 cls : 'fc-view fc-view-month fc-grid',
16669 style : 'position: relative',
16670 unselectable : 'on',
16673 cls : 'fc-event-container',
16674 style : 'position:absolute;z-index:8;top:0;left:0;'
16692 initEvents : function()
16695 throw "can not find store for calendar";
16701 style: "text-align:center",
16705 style: "background-color:white;width:50%;margin:250 auto",
16709 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16720 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16722 var size = this.el.select('.fc-content', true).first().getSize();
16723 this.maskEl.setSize(size.width, size.height);
16724 this.maskEl.enableDisplayMode("block");
16725 if(!this.loadMask){
16726 this.maskEl.hide();
16729 this.store = Roo.factory(this.store, Roo.data);
16730 this.store.on('load', this.onLoad, this);
16731 this.store.on('beforeload', this.onBeforeLoad, this);
16735 this.cells = this.el.select('.fc-day',true);
16736 //Roo.log(this.cells);
16737 this.textNodes = this.el.query('.fc-day-number');
16738 this.cells.addClassOnOver('fc-state-hover');
16740 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16741 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16742 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16743 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16745 this.on('monthchange', this.onMonthChange, this);
16747 this.update(new Date().clearTime());
16750 resize : function() {
16751 var sz = this.el.getSize();
16753 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16754 this.el.select('.fc-day-content div',true).setHeight(34);
16759 showPrevMonth : function(e){
16760 this.update(this.activeDate.add("mo", -1));
16762 showToday : function(e){
16763 this.update(new Date().clearTime());
16766 showNextMonth : function(e){
16767 this.update(this.activeDate.add("mo", 1));
16771 showPrevYear : function(){
16772 this.update(this.activeDate.add("y", -1));
16776 showNextYear : function(){
16777 this.update(this.activeDate.add("y", 1));
16782 update : function(date)
16784 var vd = this.activeDate;
16785 this.activeDate = date;
16786 // if(vd && this.el){
16787 // var t = date.getTime();
16788 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16789 // Roo.log('using add remove');
16791 // this.fireEvent('monthchange', this, date);
16793 // this.cells.removeClass("fc-state-highlight");
16794 // this.cells.each(function(c){
16795 // if(c.dateValue == t){
16796 // c.addClass("fc-state-highlight");
16797 // setTimeout(function(){
16798 // try{c.dom.firstChild.focus();}catch(e){}
16808 var days = date.getDaysInMonth();
16810 var firstOfMonth = date.getFirstDateOfMonth();
16811 var startingPos = firstOfMonth.getDay()-this.startDay;
16813 if(startingPos < this.startDay){
16817 var pm = date.add(Date.MONTH, -1);
16818 var prevStart = pm.getDaysInMonth()-startingPos;
16820 this.cells = this.el.select('.fc-day',true);
16821 this.textNodes = this.el.query('.fc-day-number');
16822 this.cells.addClassOnOver('fc-state-hover');
16824 var cells = this.cells.elements;
16825 var textEls = this.textNodes;
16827 Roo.each(cells, function(cell){
16828 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16831 days += startingPos;
16833 // convert everything to numbers so it's fast
16834 var day = 86400000;
16835 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16838 //Roo.log(prevStart);
16840 var today = new Date().clearTime().getTime();
16841 var sel = date.clearTime().getTime();
16842 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16843 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16844 var ddMatch = this.disabledDatesRE;
16845 var ddText = this.disabledDatesText;
16846 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16847 var ddaysText = this.disabledDaysText;
16848 var format = this.format;
16850 var setCellClass = function(cal, cell){
16854 //Roo.log('set Cell Class');
16856 var t = d.getTime();
16860 cell.dateValue = t;
16862 cell.className += " fc-today";
16863 cell.className += " fc-state-highlight";
16864 cell.title = cal.todayText;
16867 // disable highlight in other month..
16868 //cell.className += " fc-state-highlight";
16873 cell.className = " fc-state-disabled";
16874 cell.title = cal.minText;
16878 cell.className = " fc-state-disabled";
16879 cell.title = cal.maxText;
16883 if(ddays.indexOf(d.getDay()) != -1){
16884 cell.title = ddaysText;
16885 cell.className = " fc-state-disabled";
16888 if(ddMatch && format){
16889 var fvalue = d.dateFormat(format);
16890 if(ddMatch.test(fvalue)){
16891 cell.title = ddText.replace("%0", fvalue);
16892 cell.className = " fc-state-disabled";
16896 if (!cell.initialClassName) {
16897 cell.initialClassName = cell.dom.className;
16900 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16905 for(; i < startingPos; i++) {
16906 textEls[i].innerHTML = (++prevStart);
16907 d.setDate(d.getDate()+1);
16909 cells[i].className = "fc-past fc-other-month";
16910 setCellClass(this, cells[i]);
16915 for(; i < days; i++){
16916 intDay = i - startingPos + 1;
16917 textEls[i].innerHTML = (intDay);
16918 d.setDate(d.getDate()+1);
16920 cells[i].className = ''; // "x-date-active";
16921 setCellClass(this, cells[i]);
16925 for(; i < 42; i++) {
16926 textEls[i].innerHTML = (++extraDays);
16927 d.setDate(d.getDate()+1);
16929 cells[i].className = "fc-future fc-other-month";
16930 setCellClass(this, cells[i]);
16933 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16935 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16937 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16938 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16940 if(totalRows != 6){
16941 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16942 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16945 this.fireEvent('monthchange', this, date);
16949 if(!this.internalRender){
16950 var main = this.el.dom.firstChild;
16951 var w = main.offsetWidth;
16952 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16953 Roo.fly(main).setWidth(w);
16954 this.internalRender = true;
16955 // opera does not respect the auto grow header center column
16956 // then, after it gets a width opera refuses to recalculate
16957 // without a second pass
16958 if(Roo.isOpera && !this.secondPass){
16959 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16960 this.secondPass = true;
16961 this.update.defer(10, this, [date]);
16968 findCell : function(dt) {
16969 dt = dt.clearTime().getTime();
16971 this.cells.each(function(c){
16972 //Roo.log("check " +c.dateValue + '?=' + dt);
16973 if(c.dateValue == dt){
16983 findCells : function(ev) {
16984 var s = ev.start.clone().clearTime().getTime();
16986 var e= ev.end.clone().clearTime().getTime();
16989 this.cells.each(function(c){
16990 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16992 if(c.dateValue > e){
16995 if(c.dateValue < s){
17004 // findBestRow: function(cells)
17008 // for (var i =0 ; i < cells.length;i++) {
17009 // ret = Math.max(cells[i].rows || 0,ret);
17016 addItem : function(ev)
17018 // look for vertical location slot in
17019 var cells = this.findCells(ev);
17021 // ev.row = this.findBestRow(cells);
17023 // work out the location.
17027 for(var i =0; i < cells.length; i++) {
17029 cells[i].row = cells[0].row;
17032 cells[i].row = cells[i].row + 1;
17042 if (crow.start.getY() == cells[i].getY()) {
17044 crow.end = cells[i];
17061 cells[0].events.push(ev);
17063 this.calevents.push(ev);
17066 clearEvents: function() {
17068 if(!this.calevents){
17072 Roo.each(this.cells.elements, function(c){
17078 Roo.each(this.calevents, function(e) {
17079 Roo.each(e.els, function(el) {
17080 el.un('mouseenter' ,this.onEventEnter, this);
17081 el.un('mouseleave' ,this.onEventLeave, this);
17086 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17092 renderEvents: function()
17096 this.cells.each(function(c) {
17105 if(c.row != c.events.length){
17106 r = 4 - (4 - (c.row - c.events.length));
17109 c.events = ev.slice(0, r);
17110 c.more = ev.slice(r);
17112 if(c.more.length && c.more.length == 1){
17113 c.events.push(c.more.pop());
17116 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17120 this.cells.each(function(c) {
17122 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17125 for (var e = 0; e < c.events.length; e++){
17126 var ev = c.events[e];
17127 var rows = ev.rows;
17129 for(var i = 0; i < rows.length; i++) {
17131 // how many rows should it span..
17134 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17135 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17137 unselectable : "on",
17140 cls: 'fc-event-inner',
17144 // cls: 'fc-event-time',
17145 // html : cells.length > 1 ? '' : ev.time
17149 cls: 'fc-event-title',
17150 html : String.format('{0}', ev.title)
17157 cls: 'ui-resizable-handle ui-resizable-e',
17158 html : '  '
17165 cfg.cls += ' fc-event-start';
17167 if ((i+1) == rows.length) {
17168 cfg.cls += ' fc-event-end';
17171 var ctr = _this.el.select('.fc-event-container',true).first();
17172 var cg = ctr.createChild(cfg);
17174 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17175 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17177 var r = (c.more.length) ? 1 : 0;
17178 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17179 cg.setWidth(ebox.right - sbox.x -2);
17181 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17182 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17183 cg.on('click', _this.onEventClick, _this, ev);
17194 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17195 style : 'position: absolute',
17196 unselectable : "on",
17199 cls: 'fc-event-inner',
17203 cls: 'fc-event-title',
17211 cls: 'ui-resizable-handle ui-resizable-e',
17212 html : '  '
17218 var ctr = _this.el.select('.fc-event-container',true).first();
17219 var cg = ctr.createChild(cfg);
17221 var sbox = c.select('.fc-day-content',true).first().getBox();
17222 var ebox = c.select('.fc-day-content',true).first().getBox();
17224 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17225 cg.setWidth(ebox.right - sbox.x -2);
17227 cg.on('click', _this.onMoreEventClick, _this, c.more);
17237 onEventEnter: function (e, el,event,d) {
17238 this.fireEvent('evententer', this, el, event);
17241 onEventLeave: function (e, el,event,d) {
17242 this.fireEvent('eventleave', this, el, event);
17245 onEventClick: function (e, el,event,d) {
17246 this.fireEvent('eventclick', this, el, event);
17249 onMonthChange: function () {
17253 onMoreEventClick: function(e, el, more)
17257 this.calpopover.placement = 'right';
17258 this.calpopover.setTitle('More');
17260 this.calpopover.setContent('');
17262 var ctr = this.calpopover.el.select('.popover-content', true).first();
17264 Roo.each(more, function(m){
17266 cls : 'fc-event-hori fc-event-draggable',
17269 var cg = ctr.createChild(cfg);
17271 cg.on('click', _this.onEventClick, _this, m);
17274 this.calpopover.show(el);
17279 onLoad: function ()
17281 this.calevents = [];
17284 if(this.store.getCount() > 0){
17285 this.store.data.each(function(d){
17288 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17289 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17290 time : d.data.start_time,
17291 title : d.data.title,
17292 description : d.data.description,
17293 venue : d.data.venue
17298 this.renderEvents();
17300 if(this.calevents.length && this.loadMask){
17301 this.maskEl.hide();
17305 onBeforeLoad: function()
17307 this.clearEvents();
17309 this.maskEl.show();
17323 * @class Roo.bootstrap.Popover
17324 * @extends Roo.bootstrap.Component
17325 * Bootstrap Popover class
17326 * @cfg {String} html contents of the popover (or false to use children..)
17327 * @cfg {String} title of popover (or false to hide)
17328 * @cfg {String} placement how it is placed
17329 * @cfg {String} trigger click || hover (or false to trigger manually)
17330 * @cfg {String} over what (parent or false to trigger manually.)
17331 * @cfg {Number} delay - delay before showing
17334 * Create a new Popover
17335 * @param {Object} config The config object
17338 Roo.bootstrap.Popover = function(config){
17339 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17345 * After the popover show
17347 * @param {Roo.bootstrap.Popover} this
17352 * After the popover hide
17354 * @param {Roo.bootstrap.Popover} this
17360 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17362 title: 'Fill in a title',
17365 placement : 'right',
17366 trigger : 'hover', // hover
17372 can_build_overlaid : false,
17374 getChildContainer : function()
17376 return this.el.select('.popover-content',true).first();
17379 getAutoCreate : function(){
17382 cls : 'popover roo-dynamic',
17383 style: 'display:block',
17389 cls : 'popover-inner',
17393 cls: 'popover-title',
17397 cls : 'popover-content',
17408 setTitle: function(str)
17411 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17413 setContent: function(str)
17416 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17418 // as it get's added to the bottom of the page.
17419 onRender : function(ct, position)
17421 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17423 var cfg = Roo.apply({}, this.getAutoCreate());
17427 cfg.cls += ' ' + this.cls;
17430 cfg.style = this.style;
17432 //Roo.log("adding to ");
17433 this.el = Roo.get(document.body).createChild(cfg, position);
17434 // Roo.log(this.el);
17439 initEvents : function()
17441 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17442 this.el.enableDisplayMode('block');
17444 if (this.over === false) {
17447 if (this.triggers === false) {
17450 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17451 var triggers = this.trigger ? this.trigger.split(' ') : [];
17452 Roo.each(triggers, function(trigger) {
17454 if (trigger == 'click') {
17455 on_el.on('click', this.toggle, this);
17456 } else if (trigger != 'manual') {
17457 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17458 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17460 on_el.on(eventIn ,this.enter, this);
17461 on_el.on(eventOut, this.leave, this);
17472 toggle : function () {
17473 this.hoverState == 'in' ? this.leave() : this.enter();
17476 enter : function () {
17478 clearTimeout(this.timeout);
17480 this.hoverState = 'in';
17482 if (!this.delay || !this.delay.show) {
17487 this.timeout = setTimeout(function () {
17488 if (_t.hoverState == 'in') {
17491 }, this.delay.show)
17494 leave : function() {
17495 clearTimeout(this.timeout);
17497 this.hoverState = 'out';
17499 if (!this.delay || !this.delay.hide) {
17504 this.timeout = setTimeout(function () {
17505 if (_t.hoverState == 'out') {
17508 }, this.delay.hide)
17511 show : function (on_el)
17514 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17518 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17519 if (this.html !== false) {
17520 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17522 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17523 if (!this.title.length) {
17524 this.el.select('.popover-title',true).hide();
17527 var placement = typeof this.placement == 'function' ?
17528 this.placement.call(this, this.el, on_el) :
17531 var autoToken = /\s?auto?\s?/i;
17532 var autoPlace = autoToken.test(placement);
17534 placement = placement.replace(autoToken, '') || 'top';
17538 //this.el.setXY([0,0]);
17540 this.el.dom.style.display='block';
17541 this.el.addClass(placement);
17543 //this.el.appendTo(on_el);
17545 var p = this.getPosition();
17546 var box = this.el.getBox();
17551 var align = Roo.bootstrap.Popover.alignment[placement];
17554 this.el.alignTo(on_el, align[0],align[1]);
17555 //var arrow = this.el.select('.arrow',true).first();
17556 //arrow.set(align[2],
17558 this.el.addClass('in');
17561 if (this.el.hasClass('fade')) {
17565 this.hoverState = 'in';
17567 this.fireEvent('show', this);
17572 this.el.setXY([0,0]);
17573 this.el.removeClass('in');
17575 this.hoverState = null;
17577 this.fireEvent('hide', this);
17582 Roo.bootstrap.Popover.alignment = {
17583 'left' : ['r-l', [-10,0], 'right'],
17584 'right' : ['l-r', [10,0], 'left'],
17585 'bottom' : ['t-b', [0,10], 'top'],
17586 'top' : [ 'b-t', [0,-10], 'bottom']
17597 * @class Roo.bootstrap.Progress
17598 * @extends Roo.bootstrap.Component
17599 * Bootstrap Progress class
17600 * @cfg {Boolean} striped striped of the progress bar
17601 * @cfg {Boolean} active animated of the progress bar
17605 * Create a new Progress
17606 * @param {Object} config The config object
17609 Roo.bootstrap.Progress = function(config){
17610 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17613 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17618 getAutoCreate : function(){
17626 cfg.cls += ' progress-striped';
17630 cfg.cls += ' active';
17649 * @class Roo.bootstrap.ProgressBar
17650 * @extends Roo.bootstrap.Component
17651 * Bootstrap ProgressBar class
17652 * @cfg {Number} aria_valuenow aria-value now
17653 * @cfg {Number} aria_valuemin aria-value min
17654 * @cfg {Number} aria_valuemax aria-value max
17655 * @cfg {String} label label for the progress bar
17656 * @cfg {String} panel (success | info | warning | danger )
17657 * @cfg {String} role role of the progress bar
17658 * @cfg {String} sr_only text
17662 * Create a new ProgressBar
17663 * @param {Object} config The config object
17666 Roo.bootstrap.ProgressBar = function(config){
17667 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17670 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17674 aria_valuemax : 100,
17680 getAutoCreate : function()
17685 cls: 'progress-bar',
17686 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17698 cfg.role = this.role;
17701 if(this.aria_valuenow){
17702 cfg['aria-valuenow'] = this.aria_valuenow;
17705 if(this.aria_valuemin){
17706 cfg['aria-valuemin'] = this.aria_valuemin;
17709 if(this.aria_valuemax){
17710 cfg['aria-valuemax'] = this.aria_valuemax;
17713 if(this.label && !this.sr_only){
17714 cfg.html = this.label;
17718 cfg.cls += ' progress-bar-' + this.panel;
17724 update : function(aria_valuenow)
17726 this.aria_valuenow = aria_valuenow;
17728 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17743 * @class Roo.bootstrap.TabGroup
17744 * @extends Roo.bootstrap.Column
17745 * Bootstrap Column class
17746 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17747 * @cfg {Boolean} carousel true to make the group behave like a carousel
17748 * @cfg {Boolean} bullets show bullets for the panels
17749 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17750 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17751 * @cfg {Boolean} showarrow (true|false) show arrow default true
17754 * Create a new TabGroup
17755 * @param {Object} config The config object
17758 Roo.bootstrap.TabGroup = function(config){
17759 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17761 this.navId = Roo.id();
17764 Roo.bootstrap.TabGroup.register(this);
17768 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17771 transition : false,
17776 slideOnTouch : false,
17779 getAutoCreate : function()
17781 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17783 cfg.cls += ' tab-content';
17785 if (this.carousel) {
17786 cfg.cls += ' carousel slide';
17789 cls : 'carousel-inner',
17793 if(this.bullets && !Roo.isTouch){
17796 cls : 'carousel-bullets',
17800 if(this.bullets_cls){
17801 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17808 cfg.cn[0].cn.push(bullets);
17811 if(this.showarrow){
17812 cfg.cn[0].cn.push({
17814 class : 'carousel-arrow',
17818 class : 'carousel-prev',
17822 class : 'fa fa-chevron-left'
17828 class : 'carousel-next',
17832 class : 'fa fa-chevron-right'
17845 initEvents: function()
17847 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17848 // this.el.on("touchstart", this.onTouchStart, this);
17851 if(this.autoslide){
17854 this.slideFn = window.setInterval(function() {
17855 _this.showPanelNext();
17859 if(this.showarrow){
17860 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17861 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17867 // onTouchStart : function(e, el, o)
17869 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17873 // this.showPanelNext();
17877 getChildContainer : function()
17879 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17883 * register a Navigation item
17884 * @param {Roo.bootstrap.NavItem} the navitem to add
17886 register : function(item)
17888 this.tabs.push( item);
17889 item.navId = this.navId; // not really needed..
17894 getActivePanel : function()
17897 Roo.each(this.tabs, function(t) {
17907 getPanelByName : function(n)
17910 Roo.each(this.tabs, function(t) {
17911 if (t.tabId == n) {
17919 indexOfPanel : function(p)
17922 Roo.each(this.tabs, function(t,i) {
17923 if (t.tabId == p.tabId) {
17932 * show a specific panel
17933 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17934 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17936 showPanel : function (pan)
17938 if(this.transition || typeof(pan) == 'undefined'){
17939 Roo.log("waiting for the transitionend");
17943 if (typeof(pan) == 'number') {
17944 pan = this.tabs[pan];
17947 if (typeof(pan) == 'string') {
17948 pan = this.getPanelByName(pan);
17951 var cur = this.getActivePanel();
17954 Roo.log('pan or acitve pan is undefined');
17958 if (pan.tabId == this.getActivePanel().tabId) {
17962 if (false === cur.fireEvent('beforedeactivate')) {
17966 if(this.bullets > 0 && !Roo.isTouch){
17967 this.setActiveBullet(this.indexOfPanel(pan));
17970 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17972 this.transition = true;
17973 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17974 var lr = dir == 'next' ? 'left' : 'right';
17975 pan.el.addClass(dir); // or prev
17976 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17977 cur.el.addClass(lr); // or right
17978 pan.el.addClass(lr);
17981 cur.el.on('transitionend', function() {
17982 Roo.log("trans end?");
17984 pan.el.removeClass([lr,dir]);
17985 pan.setActive(true);
17987 cur.el.removeClass([lr]);
17988 cur.setActive(false);
17990 _this.transition = false;
17992 }, this, { single: true } );
17997 cur.setActive(false);
17998 pan.setActive(true);
18003 showPanelNext : function()
18005 var i = this.indexOfPanel(this.getActivePanel());
18007 if (i >= this.tabs.length - 1 && !this.autoslide) {
18011 if (i >= this.tabs.length - 1 && this.autoslide) {
18015 this.showPanel(this.tabs[i+1]);
18018 showPanelPrev : function()
18020 var i = this.indexOfPanel(this.getActivePanel());
18022 if (i < 1 && !this.autoslide) {
18026 if (i < 1 && this.autoslide) {
18027 i = this.tabs.length;
18030 this.showPanel(this.tabs[i-1]);
18034 addBullet: function()
18036 if(!this.bullets || Roo.isTouch){
18039 var ctr = this.el.select('.carousel-bullets',true).first();
18040 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18041 var bullet = ctr.createChild({
18042 cls : 'bullet bullet-' + i
18043 },ctr.dom.lastChild);
18048 bullet.on('click', (function(e, el, o, ii, t){
18050 e.preventDefault();
18052 this.showPanel(ii);
18054 if(this.autoslide && this.slideFn){
18055 clearInterval(this.slideFn);
18056 this.slideFn = window.setInterval(function() {
18057 _this.showPanelNext();
18061 }).createDelegate(this, [i, bullet], true));
18066 setActiveBullet : function(i)
18072 Roo.each(this.el.select('.bullet', true).elements, function(el){
18073 el.removeClass('selected');
18076 var bullet = this.el.select('.bullet-' + i, true).first();
18082 bullet.addClass('selected');
18093 Roo.apply(Roo.bootstrap.TabGroup, {
18097 * register a Navigation Group
18098 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18100 register : function(navgrp)
18102 this.groups[navgrp.navId] = navgrp;
18106 * fetch a Navigation Group based on the navigation ID
18107 * if one does not exist , it will get created.
18108 * @param {string} the navgroup to add
18109 * @returns {Roo.bootstrap.NavGroup} the navgroup
18111 get: function(navId) {
18112 if (typeof(this.groups[navId]) == 'undefined') {
18113 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18115 return this.groups[navId] ;
18130 * @class Roo.bootstrap.TabPanel
18131 * @extends Roo.bootstrap.Component
18132 * Bootstrap TabPanel class
18133 * @cfg {Boolean} active panel active
18134 * @cfg {String} html panel content
18135 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18136 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18137 * @cfg {String} href click to link..
18141 * Create a new TabPanel
18142 * @param {Object} config The config object
18145 Roo.bootstrap.TabPanel = function(config){
18146 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18150 * Fires when the active status changes
18151 * @param {Roo.bootstrap.TabPanel} this
18152 * @param {Boolean} state the new state
18157 * @event beforedeactivate
18158 * Fires before a tab is de-activated - can be used to do validation on a form.
18159 * @param {Roo.bootstrap.TabPanel} this
18160 * @return {Boolean} false if there is an error
18163 'beforedeactivate': true
18166 this.tabId = this.tabId || Roo.id();
18170 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18178 getAutoCreate : function(){
18181 // item is needed for carousel - not sure if it has any effect otherwise
18182 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18183 html: this.html || ''
18187 cfg.cls += ' active';
18191 cfg.tabId = this.tabId;
18198 initEvents: function()
18200 var p = this.parent();
18202 this.navId = this.navId || p.navId;
18204 if (typeof(this.navId) != 'undefined') {
18205 // not really needed.. but just in case.. parent should be a NavGroup.
18206 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18210 var i = tg.tabs.length - 1;
18212 if(this.active && tg.bullets > 0 && i < tg.bullets){
18213 tg.setActiveBullet(i);
18217 this.el.on('click', this.onClick, this);
18220 this.el.on("touchstart", this.onTouchStart, this);
18221 this.el.on("touchmove", this.onTouchMove, this);
18222 this.el.on("touchend", this.onTouchEnd, this);
18227 onRender : function(ct, position)
18229 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18232 setActive : function(state)
18234 Roo.log("panel - set active " + this.tabId + "=" + state);
18236 this.active = state;
18238 this.el.removeClass('active');
18240 } else if (!this.el.hasClass('active')) {
18241 this.el.addClass('active');
18244 this.fireEvent('changed', this, state);
18247 onClick : function(e)
18249 e.preventDefault();
18251 if(!this.href.length){
18255 window.location.href = this.href;
18264 onTouchStart : function(e)
18266 this.swiping = false;
18268 this.startX = e.browserEvent.touches[0].clientX;
18269 this.startY = e.browserEvent.touches[0].clientY;
18272 onTouchMove : function(e)
18274 this.swiping = true;
18276 this.endX = e.browserEvent.touches[0].clientX;
18277 this.endY = e.browserEvent.touches[0].clientY;
18280 onTouchEnd : function(e)
18287 var tabGroup = this.parent();
18289 if(this.endX > this.startX){ // swiping right
18290 tabGroup.showPanelPrev();
18294 if(this.startX > this.endX){ // swiping left
18295 tabGroup.showPanelNext();
18314 * @class Roo.bootstrap.DateField
18315 * @extends Roo.bootstrap.Input
18316 * Bootstrap DateField class
18317 * @cfg {Number} weekStart default 0
18318 * @cfg {String} viewMode default empty, (months|years)
18319 * @cfg {String} minViewMode default empty, (months|years)
18320 * @cfg {Number} startDate default -Infinity
18321 * @cfg {Number} endDate default Infinity
18322 * @cfg {Boolean} todayHighlight default false
18323 * @cfg {Boolean} todayBtn default false
18324 * @cfg {Boolean} calendarWeeks default false
18325 * @cfg {Object} daysOfWeekDisabled default empty
18326 * @cfg {Boolean} singleMode default false (true | false)
18328 * @cfg {Boolean} keyboardNavigation default true
18329 * @cfg {String} language default en
18332 * Create a new DateField
18333 * @param {Object} config The config object
18336 Roo.bootstrap.DateField = function(config){
18337 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18341 * Fires when this field show.
18342 * @param {Roo.bootstrap.DateField} this
18343 * @param {Mixed} date The date value
18348 * Fires when this field hide.
18349 * @param {Roo.bootstrap.DateField} this
18350 * @param {Mixed} date The date value
18355 * Fires when select a date.
18356 * @param {Roo.bootstrap.DateField} this
18357 * @param {Mixed} date The date value
18361 * @event beforeselect
18362 * Fires when before select a date.
18363 * @param {Roo.bootstrap.DateField} this
18364 * @param {Mixed} date The date value
18366 beforeselect : true
18370 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18373 * @cfg {String} format
18374 * The default date format string which can be overriden for localization support. The format must be
18375 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18379 * @cfg {String} altFormats
18380 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18381 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18383 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18391 todayHighlight : false,
18397 keyboardNavigation: true,
18399 calendarWeeks: false,
18401 startDate: -Infinity,
18405 daysOfWeekDisabled: [],
18409 singleMode : false,
18411 UTCDate: function()
18413 return new Date(Date.UTC.apply(Date, arguments));
18416 UTCToday: function()
18418 var today = new Date();
18419 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18422 getDate: function() {
18423 var d = this.getUTCDate();
18424 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18427 getUTCDate: function() {
18431 setDate: function(d) {
18432 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18435 setUTCDate: function(d) {
18437 this.setValue(this.formatDate(this.date));
18440 onRender: function(ct, position)
18443 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18445 this.language = this.language || 'en';
18446 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18447 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18449 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18450 this.format = this.format || 'm/d/y';
18451 this.isInline = false;
18452 this.isInput = true;
18453 this.component = this.el.select('.add-on', true).first() || false;
18454 this.component = (this.component && this.component.length === 0) ? false : this.component;
18455 this.hasInput = this.component && this.inputEl().length;
18457 if (typeof(this.minViewMode === 'string')) {
18458 switch (this.minViewMode) {
18460 this.minViewMode = 1;
18463 this.minViewMode = 2;
18466 this.minViewMode = 0;
18471 if (typeof(this.viewMode === 'string')) {
18472 switch (this.viewMode) {
18485 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18487 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18489 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18491 this.picker().on('mousedown', this.onMousedown, this);
18492 this.picker().on('click', this.onClick, this);
18494 this.picker().addClass('datepicker-dropdown');
18496 this.startViewMode = this.viewMode;
18498 if(this.singleMode){
18499 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18500 v.setVisibilityMode(Roo.Element.DISPLAY);
18504 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18505 v.setStyle('width', '189px');
18509 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18510 if(!this.calendarWeeks){
18515 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18516 v.attr('colspan', function(i, val){
18517 return parseInt(val) + 1;
18522 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18524 this.setStartDate(this.startDate);
18525 this.setEndDate(this.endDate);
18527 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18534 if(this.isInline) {
18539 picker : function()
18541 return this.pickerEl;
18542 // return this.el.select('.datepicker', true).first();
18545 fillDow: function()
18547 var dowCnt = this.weekStart;
18556 if(this.calendarWeeks){
18564 while (dowCnt < this.weekStart + 7) {
18568 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18572 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18575 fillMonths: function()
18578 var months = this.picker().select('>.datepicker-months td', true).first();
18580 months.dom.innerHTML = '';
18586 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18589 months.createChild(month);
18596 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;
18598 if (this.date < this.startDate) {
18599 this.viewDate = new Date(this.startDate);
18600 } else if (this.date > this.endDate) {
18601 this.viewDate = new Date(this.endDate);
18603 this.viewDate = new Date(this.date);
18611 var d = new Date(this.viewDate),
18612 year = d.getUTCFullYear(),
18613 month = d.getUTCMonth(),
18614 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18615 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18616 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18617 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18618 currentDate = this.date && this.date.valueOf(),
18619 today = this.UTCToday();
18621 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18623 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18625 // this.picker.select('>tfoot th.today').
18626 // .text(dates[this.language].today)
18627 // .toggle(this.todayBtn !== false);
18629 this.updateNavArrows();
18632 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18634 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18636 prevMonth.setUTCDate(day);
18638 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18640 var nextMonth = new Date(prevMonth);
18642 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18644 nextMonth = nextMonth.valueOf();
18646 var fillMonths = false;
18648 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18650 while(prevMonth.valueOf() < nextMonth) {
18653 if (prevMonth.getUTCDay() === this.weekStart) {
18655 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18663 if(this.calendarWeeks){
18664 // ISO 8601: First week contains first thursday.
18665 // ISO also states week starts on Monday, but we can be more abstract here.
18667 // Start of current week: based on weekstart/current date
18668 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18669 // Thursday of this week
18670 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18671 // First Thursday of year, year from thursday
18672 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18673 // Calendar week: ms between thursdays, div ms per day, div 7 days
18674 calWeek = (th - yth) / 864e5 / 7 + 1;
18676 fillMonths.cn.push({
18684 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18686 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18689 if (this.todayHighlight &&
18690 prevMonth.getUTCFullYear() == today.getFullYear() &&
18691 prevMonth.getUTCMonth() == today.getMonth() &&
18692 prevMonth.getUTCDate() == today.getDate()) {
18693 clsName += ' today';
18696 if (currentDate && prevMonth.valueOf() === currentDate) {
18697 clsName += ' active';
18700 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18701 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18702 clsName += ' disabled';
18705 fillMonths.cn.push({
18707 cls: 'day ' + clsName,
18708 html: prevMonth.getDate()
18711 prevMonth.setDate(prevMonth.getDate()+1);
18714 var currentYear = this.date && this.date.getUTCFullYear();
18715 var currentMonth = this.date && this.date.getUTCMonth();
18717 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18719 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18720 v.removeClass('active');
18722 if(currentYear === year && k === currentMonth){
18723 v.addClass('active');
18726 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18727 v.addClass('disabled');
18733 year = parseInt(year/10, 10) * 10;
18735 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18737 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18740 for (var i = -1; i < 11; i++) {
18741 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18743 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18751 showMode: function(dir)
18754 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18757 Roo.each(this.picker().select('>div',true).elements, function(v){
18758 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18761 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18766 if(this.isInline) {
18770 this.picker().removeClass(['bottom', 'top']);
18772 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18774 * place to the top of element!
18778 this.picker().addClass('top');
18779 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18784 this.picker().addClass('bottom');
18786 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18789 parseDate : function(value)
18791 if(!value || value instanceof Date){
18794 var v = Date.parseDate(value, this.format);
18795 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18796 v = Date.parseDate(value, 'Y-m-d');
18798 if(!v && this.altFormats){
18799 if(!this.altFormatsArray){
18800 this.altFormatsArray = this.altFormats.split("|");
18802 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18803 v = Date.parseDate(value, this.altFormatsArray[i]);
18809 formatDate : function(date, fmt)
18811 return (!date || !(date instanceof Date)) ?
18812 date : date.dateFormat(fmt || this.format);
18815 onFocus : function()
18817 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18821 onBlur : function()
18823 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18825 var d = this.inputEl().getValue();
18834 this.picker().show();
18838 this.fireEvent('show', this, this.date);
18843 if(this.isInline) {
18846 this.picker().hide();
18847 this.viewMode = this.startViewMode;
18850 this.fireEvent('hide', this, this.date);
18854 onMousedown: function(e)
18856 e.stopPropagation();
18857 e.preventDefault();
18862 Roo.bootstrap.DateField.superclass.keyup.call(this);
18866 setValue: function(v)
18868 if(this.fireEvent('beforeselect', this, v) !== false){
18869 var d = new Date(this.parseDate(v) ).clearTime();
18871 if(isNaN(d.getTime())){
18872 this.date = this.viewDate = '';
18873 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18877 v = this.formatDate(d);
18879 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18881 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18885 this.fireEvent('select', this, this.date);
18889 getValue: function()
18891 return this.formatDate(this.date);
18894 fireKey: function(e)
18896 if (!this.picker().isVisible()){
18897 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18903 var dateChanged = false,
18905 newDate, newViewDate;
18910 e.preventDefault();
18914 if (!this.keyboardNavigation) {
18917 dir = e.keyCode == 37 ? -1 : 1;
18920 newDate = this.moveYear(this.date, dir);
18921 newViewDate = this.moveYear(this.viewDate, dir);
18922 } else if (e.shiftKey){
18923 newDate = this.moveMonth(this.date, dir);
18924 newViewDate = this.moveMonth(this.viewDate, dir);
18926 newDate = new Date(this.date);
18927 newDate.setUTCDate(this.date.getUTCDate() + dir);
18928 newViewDate = new Date(this.viewDate);
18929 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18931 if (this.dateWithinRange(newDate)){
18932 this.date = newDate;
18933 this.viewDate = newViewDate;
18934 this.setValue(this.formatDate(this.date));
18936 e.preventDefault();
18937 dateChanged = true;
18942 if (!this.keyboardNavigation) {
18945 dir = e.keyCode == 38 ? -1 : 1;
18947 newDate = this.moveYear(this.date, dir);
18948 newViewDate = this.moveYear(this.viewDate, dir);
18949 } else if (e.shiftKey){
18950 newDate = this.moveMonth(this.date, dir);
18951 newViewDate = this.moveMonth(this.viewDate, dir);
18953 newDate = new Date(this.date);
18954 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18955 newViewDate = new Date(this.viewDate);
18956 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18958 if (this.dateWithinRange(newDate)){
18959 this.date = newDate;
18960 this.viewDate = newViewDate;
18961 this.setValue(this.formatDate(this.date));
18963 e.preventDefault();
18964 dateChanged = true;
18968 this.setValue(this.formatDate(this.date));
18970 e.preventDefault();
18973 this.setValue(this.formatDate(this.date));
18987 onClick: function(e)
18989 e.stopPropagation();
18990 e.preventDefault();
18992 var target = e.getTarget();
18994 if(target.nodeName.toLowerCase() === 'i'){
18995 target = Roo.get(target).dom.parentNode;
18998 var nodeName = target.nodeName;
18999 var className = target.className;
19000 var html = target.innerHTML;
19001 //Roo.log(nodeName);
19003 switch(nodeName.toLowerCase()) {
19005 switch(className) {
19011 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19012 switch(this.viewMode){
19014 this.viewDate = this.moveMonth(this.viewDate, dir);
19018 this.viewDate = this.moveYear(this.viewDate, dir);
19024 var date = new Date();
19025 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19027 this.setValue(this.formatDate(this.date));
19034 if (className.indexOf('disabled') < 0) {
19035 this.viewDate.setUTCDate(1);
19036 if (className.indexOf('month') > -1) {
19037 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19039 var year = parseInt(html, 10) || 0;
19040 this.viewDate.setUTCFullYear(year);
19044 if(this.singleMode){
19045 this.setValue(this.formatDate(this.viewDate));
19056 //Roo.log(className);
19057 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19058 var day = parseInt(html, 10) || 1;
19059 var year = this.viewDate.getUTCFullYear(),
19060 month = this.viewDate.getUTCMonth();
19062 if (className.indexOf('old') > -1) {
19069 } else if (className.indexOf('new') > -1) {
19077 //Roo.log([year,month,day]);
19078 this.date = this.UTCDate(year, month, day,0,0,0,0);
19079 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19081 //Roo.log(this.formatDate(this.date));
19082 this.setValue(this.formatDate(this.date));
19089 setStartDate: function(startDate)
19091 this.startDate = startDate || -Infinity;
19092 if (this.startDate !== -Infinity) {
19093 this.startDate = this.parseDate(this.startDate);
19096 this.updateNavArrows();
19099 setEndDate: function(endDate)
19101 this.endDate = endDate || Infinity;
19102 if (this.endDate !== Infinity) {
19103 this.endDate = this.parseDate(this.endDate);
19106 this.updateNavArrows();
19109 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19111 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19112 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19113 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19115 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19116 return parseInt(d, 10);
19119 this.updateNavArrows();
19122 updateNavArrows: function()
19124 if(this.singleMode){
19128 var d = new Date(this.viewDate),
19129 year = d.getUTCFullYear(),
19130 month = d.getUTCMonth();
19132 Roo.each(this.picker().select('.prev', true).elements, function(v){
19134 switch (this.viewMode) {
19137 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19143 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19150 Roo.each(this.picker().select('.next', true).elements, function(v){
19152 switch (this.viewMode) {
19155 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19161 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19169 moveMonth: function(date, dir)
19174 var new_date = new Date(date.valueOf()),
19175 day = new_date.getUTCDate(),
19176 month = new_date.getUTCMonth(),
19177 mag = Math.abs(dir),
19179 dir = dir > 0 ? 1 : -1;
19182 // If going back one month, make sure month is not current month
19183 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19185 return new_date.getUTCMonth() == month;
19187 // If going forward one month, make sure month is as expected
19188 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19190 return new_date.getUTCMonth() != new_month;
19192 new_month = month + dir;
19193 new_date.setUTCMonth(new_month);
19194 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19195 if (new_month < 0 || new_month > 11) {
19196 new_month = (new_month + 12) % 12;
19199 // For magnitudes >1, move one month at a time...
19200 for (var i=0; i<mag; i++) {
19201 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19202 new_date = this.moveMonth(new_date, dir);
19204 // ...then reset the day, keeping it in the new month
19205 new_month = new_date.getUTCMonth();
19206 new_date.setUTCDate(day);
19208 return new_month != new_date.getUTCMonth();
19211 // Common date-resetting loop -- if date is beyond end of month, make it
19214 new_date.setUTCDate(--day);
19215 new_date.setUTCMonth(new_month);
19220 moveYear: function(date, dir)
19222 return this.moveMonth(date, dir*12);
19225 dateWithinRange: function(date)
19227 return date >= this.startDate && date <= this.endDate;
19233 this.picker().remove();
19236 validateValue : function(value)
19238 if(this.getVisibilityEl().hasClass('hidden')){
19242 if(value.length < 1) {
19243 if(this.allowBlank){
19249 if(value.length < this.minLength){
19252 if(value.length > this.maxLength){
19256 var vt = Roo.form.VTypes;
19257 if(!vt[this.vtype](value, this)){
19261 if(typeof this.validator == "function"){
19262 var msg = this.validator(value);
19268 if(this.regex && !this.regex.test(value)){
19272 if(typeof(this.parseDate(value)) == 'undefined'){
19276 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19280 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19288 setVisible : function(visible)
19294 this.getEl().removeClass('hidden');
19300 this.getEl().addClass('hidden');
19305 Roo.apply(Roo.bootstrap.DateField, {
19316 html: '<i class="fa fa-arrow-left"/>'
19326 html: '<i class="fa fa-arrow-right"/>'
19368 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19369 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19370 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19371 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19372 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19385 navFnc: 'FullYear',
19390 navFnc: 'FullYear',
19395 Roo.apply(Roo.bootstrap.DateField, {
19399 cls: 'datepicker dropdown-menu roo-dynamic',
19403 cls: 'datepicker-days',
19407 cls: 'table-condensed',
19409 Roo.bootstrap.DateField.head,
19413 Roo.bootstrap.DateField.footer
19420 cls: 'datepicker-months',
19424 cls: 'table-condensed',
19426 Roo.bootstrap.DateField.head,
19427 Roo.bootstrap.DateField.content,
19428 Roo.bootstrap.DateField.footer
19435 cls: 'datepicker-years',
19439 cls: 'table-condensed',
19441 Roo.bootstrap.DateField.head,
19442 Roo.bootstrap.DateField.content,
19443 Roo.bootstrap.DateField.footer
19462 * @class Roo.bootstrap.TimeField
19463 * @extends Roo.bootstrap.Input
19464 * Bootstrap DateField class
19468 * Create a new TimeField
19469 * @param {Object} config The config object
19472 Roo.bootstrap.TimeField = function(config){
19473 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19477 * Fires when this field show.
19478 * @param {Roo.bootstrap.DateField} thisthis
19479 * @param {Mixed} date The date value
19484 * Fires when this field hide.
19485 * @param {Roo.bootstrap.DateField} this
19486 * @param {Mixed} date The date value
19491 * Fires when select a date.
19492 * @param {Roo.bootstrap.DateField} this
19493 * @param {Mixed} date The date value
19499 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19502 * @cfg {String} format
19503 * The default time format string which can be overriden for localization support. The format must be
19504 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19508 onRender: function(ct, position)
19511 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19513 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19515 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19517 this.pop = this.picker().select('>.datepicker-time',true).first();
19518 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19520 this.picker().on('mousedown', this.onMousedown, this);
19521 this.picker().on('click', this.onClick, this);
19523 this.picker().addClass('datepicker-dropdown');
19528 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19529 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19530 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19531 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19532 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19533 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19537 fireKey: function(e){
19538 if (!this.picker().isVisible()){
19539 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19545 e.preventDefault();
19553 this.onTogglePeriod();
19556 this.onIncrementMinutes();
19559 this.onDecrementMinutes();
19568 onClick: function(e) {
19569 e.stopPropagation();
19570 e.preventDefault();
19573 picker : function()
19575 return this.el.select('.datepicker', true).first();
19578 fillTime: function()
19580 var time = this.pop.select('tbody', true).first();
19582 time.dom.innerHTML = '';
19597 cls: 'hours-up glyphicon glyphicon-chevron-up'
19617 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19638 cls: 'timepicker-hour',
19653 cls: 'timepicker-minute',
19668 cls: 'btn btn-primary period',
19690 cls: 'hours-down glyphicon glyphicon-chevron-down'
19710 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19728 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19735 var hours = this.time.getHours();
19736 var minutes = this.time.getMinutes();
19749 hours = hours - 12;
19753 hours = '0' + hours;
19757 minutes = '0' + minutes;
19760 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19761 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19762 this.pop.select('button', true).first().dom.innerHTML = period;
19768 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19770 var cls = ['bottom'];
19772 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19779 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19784 this.picker().addClass(cls.join('-'));
19788 Roo.each(cls, function(c){
19790 _this.picker().setTop(_this.inputEl().getHeight());
19794 _this.picker().setTop(0 - _this.picker().getHeight());
19799 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19803 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19810 onFocus : function()
19812 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19816 onBlur : function()
19818 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19824 this.picker().show();
19829 this.fireEvent('show', this, this.date);
19834 this.picker().hide();
19837 this.fireEvent('hide', this, this.date);
19840 setTime : function()
19843 this.setValue(this.time.format(this.format));
19845 this.fireEvent('select', this, this.date);
19850 onMousedown: function(e){
19851 e.stopPropagation();
19852 e.preventDefault();
19855 onIncrementHours: function()
19857 Roo.log('onIncrementHours');
19858 this.time = this.time.add(Date.HOUR, 1);
19863 onDecrementHours: function()
19865 Roo.log('onDecrementHours');
19866 this.time = this.time.add(Date.HOUR, -1);
19870 onIncrementMinutes: function()
19872 Roo.log('onIncrementMinutes');
19873 this.time = this.time.add(Date.MINUTE, 1);
19877 onDecrementMinutes: function()
19879 Roo.log('onDecrementMinutes');
19880 this.time = this.time.add(Date.MINUTE, -1);
19884 onTogglePeriod: function()
19886 Roo.log('onTogglePeriod');
19887 this.time = this.time.add(Date.HOUR, 12);
19894 Roo.apply(Roo.bootstrap.TimeField, {
19924 cls: 'btn btn-info ok',
19936 Roo.apply(Roo.bootstrap.TimeField, {
19940 cls: 'datepicker dropdown-menu',
19944 cls: 'datepicker-time',
19948 cls: 'table-condensed',
19950 Roo.bootstrap.TimeField.content,
19951 Roo.bootstrap.TimeField.footer
19970 * @class Roo.bootstrap.MonthField
19971 * @extends Roo.bootstrap.Input
19972 * Bootstrap MonthField class
19974 * @cfg {String} language default en
19977 * Create a new MonthField
19978 * @param {Object} config The config object
19981 Roo.bootstrap.MonthField = function(config){
19982 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19987 * Fires when this field show.
19988 * @param {Roo.bootstrap.MonthField} this
19989 * @param {Mixed} date The date value
19994 * Fires when this field hide.
19995 * @param {Roo.bootstrap.MonthField} this
19996 * @param {Mixed} date The date value
20001 * Fires when select a date.
20002 * @param {Roo.bootstrap.MonthField} this
20003 * @param {String} oldvalue The old value
20004 * @param {String} newvalue The new value
20010 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20012 onRender: function(ct, position)
20015 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20017 this.language = this.language || 'en';
20018 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20019 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20021 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20022 this.isInline = false;
20023 this.isInput = true;
20024 this.component = this.el.select('.add-on', true).first() || false;
20025 this.component = (this.component && this.component.length === 0) ? false : this.component;
20026 this.hasInput = this.component && this.inputEL().length;
20028 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20030 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20032 this.picker().on('mousedown', this.onMousedown, this);
20033 this.picker().on('click', this.onClick, this);
20035 this.picker().addClass('datepicker-dropdown');
20037 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20038 v.setStyle('width', '189px');
20045 if(this.isInline) {
20051 setValue: function(v, suppressEvent)
20053 var o = this.getValue();
20055 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20059 if(suppressEvent !== true){
20060 this.fireEvent('select', this, o, v);
20065 getValue: function()
20070 onClick: function(e)
20072 e.stopPropagation();
20073 e.preventDefault();
20075 var target = e.getTarget();
20077 if(target.nodeName.toLowerCase() === 'i'){
20078 target = Roo.get(target).dom.parentNode;
20081 var nodeName = target.nodeName;
20082 var className = target.className;
20083 var html = target.innerHTML;
20085 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20089 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20091 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20097 picker : function()
20099 return this.pickerEl;
20102 fillMonths: function()
20105 var months = this.picker().select('>.datepicker-months td', true).first();
20107 months.dom.innerHTML = '';
20113 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20116 months.createChild(month);
20125 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20126 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20129 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20130 e.removeClass('active');
20132 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20133 e.addClass('active');
20140 if(this.isInline) {
20144 this.picker().removeClass(['bottom', 'top']);
20146 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20148 * place to the top of element!
20152 this.picker().addClass('top');
20153 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20158 this.picker().addClass('bottom');
20160 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20163 onFocus : function()
20165 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20169 onBlur : function()
20171 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20173 var d = this.inputEl().getValue();
20182 this.picker().show();
20183 this.picker().select('>.datepicker-months', true).first().show();
20187 this.fireEvent('show', this, this.date);
20192 if(this.isInline) {
20195 this.picker().hide();
20196 this.fireEvent('hide', this, this.date);
20200 onMousedown: function(e)
20202 e.stopPropagation();
20203 e.preventDefault();
20208 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20212 fireKey: function(e)
20214 if (!this.picker().isVisible()){
20215 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20226 e.preventDefault();
20230 dir = e.keyCode == 37 ? -1 : 1;
20232 this.vIndex = this.vIndex + dir;
20234 if(this.vIndex < 0){
20238 if(this.vIndex > 11){
20242 if(isNaN(this.vIndex)){
20246 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20252 dir = e.keyCode == 38 ? -1 : 1;
20254 this.vIndex = this.vIndex + dir * 4;
20256 if(this.vIndex < 0){
20260 if(this.vIndex > 11){
20264 if(isNaN(this.vIndex)){
20268 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20273 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20274 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20278 e.preventDefault();
20281 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20282 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20298 this.picker().remove();
20303 Roo.apply(Roo.bootstrap.MonthField, {
20322 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20323 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20328 Roo.apply(Roo.bootstrap.MonthField, {
20332 cls: 'datepicker dropdown-menu roo-dynamic',
20336 cls: 'datepicker-months',
20340 cls: 'table-condensed',
20342 Roo.bootstrap.DateField.content
20362 * @class Roo.bootstrap.CheckBox
20363 * @extends Roo.bootstrap.Input
20364 * Bootstrap CheckBox class
20366 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20367 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20368 * @cfg {String} boxLabel The text that appears beside the checkbox
20369 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20370 * @cfg {Boolean} checked initnal the element
20371 * @cfg {Boolean} inline inline the element (default false)
20372 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20373 * @cfg {String} tooltip label tooltip
20376 * Create a new CheckBox
20377 * @param {Object} config The config object
20380 Roo.bootstrap.CheckBox = function(config){
20381 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20386 * Fires when the element is checked or unchecked.
20387 * @param {Roo.bootstrap.CheckBox} this This input
20388 * @param {Boolean} checked The new checked value
20393 * Fires when the element is click.
20394 * @param {Roo.bootstrap.CheckBox} this This input
20401 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20403 inputType: 'checkbox',
20412 getAutoCreate : function()
20414 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20420 cfg.cls = 'form-group ' + this.inputType; //input-group
20423 cfg.cls += ' ' + this.inputType + '-inline';
20429 type : this.inputType,
20430 value : this.inputValue,
20431 cls : 'roo-' + this.inputType, //'form-box',
20432 placeholder : this.placeholder || ''
20436 if(this.inputType != 'radio'){
20440 cls : 'roo-hidden-value',
20441 value : this.checked ? this.inputValue : this.valueOff
20446 if (this.weight) { // Validity check?
20447 cfg.cls += " " + this.inputType + "-" + this.weight;
20450 if (this.disabled) {
20451 input.disabled=true;
20455 input.checked = this.checked;
20460 input.name = this.name;
20462 if(this.inputType != 'radio'){
20463 hidden.name = this.name;
20464 input.name = '_hidden_' + this.name;
20469 input.cls += ' input-' + this.size;
20474 ['xs','sm','md','lg'].map(function(size){
20475 if (settings[size]) {
20476 cfg.cls += ' col-' + size + '-' + settings[size];
20480 var inputblock = input;
20482 if (this.before || this.after) {
20485 cls : 'input-group',
20490 inputblock.cn.push({
20492 cls : 'input-group-addon',
20497 inputblock.cn.push(input);
20499 if(this.inputType != 'radio'){
20500 inputblock.cn.push(hidden);
20504 inputblock.cn.push({
20506 cls : 'input-group-addon',
20513 if (align ==='left' && this.fieldLabel.length) {
20514 // Roo.log("left and has label");
20519 cls : 'control-label',
20520 html : this.fieldLabel
20530 if(this.labelWidth > 12){
20531 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20534 if(this.labelWidth < 13 && this.labelmd == 0){
20535 this.labelmd = this.labelWidth;
20538 if(this.labellg > 0){
20539 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20540 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20543 if(this.labelmd > 0){
20544 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20545 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20548 if(this.labelsm > 0){
20549 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20550 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20553 if(this.labelxs > 0){
20554 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20555 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20558 } else if ( this.fieldLabel.length) {
20559 // Roo.log(" label");
20563 tag: this.boxLabel ? 'span' : 'label',
20565 cls: 'control-label box-input-label',
20566 //cls : 'input-group-addon',
20567 html : this.fieldLabel
20576 // Roo.log(" no label && no align");
20577 cfg.cn = [ inputblock ] ;
20583 var boxLabelCfg = {
20585 //'for': id, // box label is handled by onclick - so no for...
20587 html: this.boxLabel
20591 boxLabelCfg.tooltip = this.tooltip;
20594 cfg.cn.push(boxLabelCfg);
20597 if(this.inputType != 'radio'){
20598 cfg.cn.push(hidden);
20606 * return the real input element.
20608 inputEl: function ()
20610 return this.el.select('input.roo-' + this.inputType,true).first();
20612 hiddenEl: function ()
20614 return this.el.select('input.roo-hidden-value',true).first();
20617 labelEl: function()
20619 return this.el.select('label.control-label',true).first();
20621 /* depricated... */
20625 return this.labelEl();
20628 boxLabelEl: function()
20630 return this.el.select('label.box-label',true).first();
20633 initEvents : function()
20635 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20637 this.inputEl().on('click', this.onClick, this);
20639 if (this.boxLabel) {
20640 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20643 this.startValue = this.getValue();
20646 Roo.bootstrap.CheckBox.register(this);
20650 onClick : function(e)
20652 if(this.fireEvent('click', this, e) !== false){
20653 this.setChecked(!this.checked);
20658 setChecked : function(state,suppressEvent)
20660 this.startValue = this.getValue();
20662 if(this.inputType == 'radio'){
20664 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20665 e.dom.checked = false;
20668 this.inputEl().dom.checked = true;
20670 this.inputEl().dom.value = this.inputValue;
20672 if(suppressEvent !== true){
20673 this.fireEvent('check', this, true);
20681 this.checked = state;
20683 this.inputEl().dom.checked = state;
20686 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20688 if(suppressEvent !== true){
20689 this.fireEvent('check', this, state);
20695 getValue : function()
20697 if(this.inputType == 'radio'){
20698 return this.getGroupValue();
20701 return this.hiddenEl().dom.value;
20705 getGroupValue : function()
20707 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20711 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20714 setValue : function(v,suppressEvent)
20716 if(this.inputType == 'radio'){
20717 this.setGroupValue(v, suppressEvent);
20721 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20726 setGroupValue : function(v, suppressEvent)
20728 this.startValue = this.getValue();
20730 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20731 e.dom.checked = false;
20733 if(e.dom.value == v){
20734 e.dom.checked = true;
20738 if(suppressEvent !== true){
20739 this.fireEvent('check', this, true);
20747 validate : function()
20749 if(this.getVisibilityEl().hasClass('hidden')){
20755 (this.inputType == 'radio' && this.validateRadio()) ||
20756 (this.inputType == 'checkbox' && this.validateCheckbox())
20762 this.markInvalid();
20766 validateRadio : function()
20768 if(this.getVisibilityEl().hasClass('hidden')){
20772 if(this.allowBlank){
20778 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20779 if(!e.dom.checked){
20791 validateCheckbox : function()
20794 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20795 //return (this.getValue() == this.inputValue) ? true : false;
20798 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20806 for(var i in group){
20807 if(group[i].el.isVisible(true)){
20815 for(var i in group){
20820 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20827 * Mark this field as valid
20829 markValid : function()
20833 this.fireEvent('valid', this);
20835 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20838 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20845 if(this.inputType == 'radio'){
20846 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20847 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20848 e.findParent('.form-group', false, true).addClass(_this.validClass);
20855 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20856 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20860 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20866 for(var i in group){
20867 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20868 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20873 * Mark this field as invalid
20874 * @param {String} msg The validation message
20876 markInvalid : function(msg)
20878 if(this.allowBlank){
20884 this.fireEvent('invalid', this, msg);
20886 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20889 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20893 label.markInvalid();
20896 if(this.inputType == 'radio'){
20897 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20898 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20899 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20906 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20907 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20911 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20917 for(var i in group){
20918 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20919 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20924 clearInvalid : function()
20926 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20928 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20930 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20932 if (label && label.iconEl) {
20933 label.iconEl.removeClass(label.validClass);
20934 label.iconEl.removeClass(label.invalidClass);
20938 disable : function()
20940 if(this.inputType != 'radio'){
20941 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20948 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20949 _this.getActionEl().addClass(this.disabledClass);
20950 e.dom.disabled = true;
20954 this.disabled = true;
20955 this.fireEvent("disable", this);
20959 enable : function()
20961 if(this.inputType != 'radio'){
20962 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20969 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20970 _this.getActionEl().removeClass(this.disabledClass);
20971 e.dom.disabled = false;
20975 this.disabled = false;
20976 this.fireEvent("enable", this);
20980 setBoxLabel : function(v)
20985 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20991 Roo.apply(Roo.bootstrap.CheckBox, {
20996 * register a CheckBox Group
20997 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20999 register : function(checkbox)
21001 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21002 this.groups[checkbox.groupId] = {};
21005 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21009 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21013 * fetch a CheckBox Group based on the group ID
21014 * @param {string} the group ID
21015 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21017 get: function(groupId) {
21018 if (typeof(this.groups[groupId]) == 'undefined') {
21022 return this.groups[groupId] ;
21035 * @class Roo.bootstrap.Radio
21036 * @extends Roo.bootstrap.Component
21037 * Bootstrap Radio class
21038 * @cfg {String} boxLabel - the label associated
21039 * @cfg {String} value - the value of radio
21042 * Create a new Radio
21043 * @param {Object} config The config object
21045 Roo.bootstrap.Radio = function(config){
21046 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21050 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21056 getAutoCreate : function()
21060 cls : 'form-group radio',
21065 html : this.boxLabel
21073 initEvents : function()
21075 this.parent().register(this);
21077 this.el.on('click', this.onClick, this);
21081 onClick : function(e)
21083 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21084 this.setChecked(true);
21088 setChecked : function(state, suppressEvent)
21090 this.parent().setValue(this.value, suppressEvent);
21094 setBoxLabel : function(v)
21099 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21114 * @class Roo.bootstrap.SecurePass
21115 * @extends Roo.bootstrap.Input
21116 * Bootstrap SecurePass class
21120 * Create a new SecurePass
21121 * @param {Object} config The config object
21124 Roo.bootstrap.SecurePass = function (config) {
21125 // these go here, so the translation tool can replace them..
21127 PwdEmpty: "Please type a password, and then retype it to confirm.",
21128 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21129 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21130 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21131 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21132 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21133 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21134 TooWeak: "Your password is Too Weak."
21136 this.meterLabel = "Password strength:";
21137 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21138 this.meterClass = [
21139 "roo-password-meter-tooweak",
21140 "roo-password-meter-weak",
21141 "roo-password-meter-medium",
21142 "roo-password-meter-strong",
21143 "roo-password-meter-grey"
21148 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21151 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21153 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21155 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21156 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21157 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21158 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21159 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21160 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21161 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21171 * @cfg {String/Object} Label for the strength meter (defaults to
21172 * 'Password strength:')
21177 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21178 * ['Weak', 'Medium', 'Strong'])
21181 pwdStrengths: false,
21194 initEvents: function ()
21196 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21198 if (this.el.is('input[type=password]') && Roo.isSafari) {
21199 this.el.on('keydown', this.SafariOnKeyDown, this);
21202 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21205 onRender: function (ct, position)
21207 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21208 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21209 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21211 this.trigger.createChild({
21216 cls: 'roo-password-meter-grey col-xs-12',
21219 //width: this.meterWidth + 'px'
21223 cls: 'roo-password-meter-text'
21229 if (this.hideTrigger) {
21230 this.trigger.setDisplayed(false);
21232 this.setSize(this.width || '', this.height || '');
21235 onDestroy: function ()
21237 if (this.trigger) {
21238 this.trigger.removeAllListeners();
21239 this.trigger.remove();
21242 this.wrap.remove();
21244 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21247 checkStrength: function ()
21249 var pwd = this.inputEl().getValue();
21250 if (pwd == this._lastPwd) {
21255 if (this.ClientSideStrongPassword(pwd)) {
21257 } else if (this.ClientSideMediumPassword(pwd)) {
21259 } else if (this.ClientSideWeakPassword(pwd)) {
21265 Roo.log('strength1: ' + strength);
21267 //var pm = this.trigger.child('div/div/div').dom;
21268 var pm = this.trigger.child('div/div');
21269 pm.removeClass(this.meterClass);
21270 pm.addClass(this.meterClass[strength]);
21273 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21275 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21277 this._lastPwd = pwd;
21281 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21283 this._lastPwd = '';
21285 var pm = this.trigger.child('div/div');
21286 pm.removeClass(this.meterClass);
21287 pm.addClass('roo-password-meter-grey');
21290 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21293 this.inputEl().dom.type='password';
21296 validateValue: function (value)
21299 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21302 if (value.length == 0) {
21303 if (this.allowBlank) {
21304 this.clearInvalid();
21308 this.markInvalid(this.errors.PwdEmpty);
21309 this.errorMsg = this.errors.PwdEmpty;
21317 if ('[\x21-\x7e]*'.match(value)) {
21318 this.markInvalid(this.errors.PwdBadChar);
21319 this.errorMsg = this.errors.PwdBadChar;
21322 if (value.length < 6) {
21323 this.markInvalid(this.errors.PwdShort);
21324 this.errorMsg = this.errors.PwdShort;
21327 if (value.length > 16) {
21328 this.markInvalid(this.errors.PwdLong);
21329 this.errorMsg = this.errors.PwdLong;
21333 if (this.ClientSideStrongPassword(value)) {
21335 } else if (this.ClientSideMediumPassword(value)) {
21337 } else if (this.ClientSideWeakPassword(value)) {
21344 if (strength < 2) {
21345 //this.markInvalid(this.errors.TooWeak);
21346 this.errorMsg = this.errors.TooWeak;
21351 console.log('strength2: ' + strength);
21353 //var pm = this.trigger.child('div/div/div').dom;
21355 var pm = this.trigger.child('div/div');
21356 pm.removeClass(this.meterClass);
21357 pm.addClass(this.meterClass[strength]);
21359 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21361 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21363 this.errorMsg = '';
21367 CharacterSetChecks: function (type)
21370 this.fResult = false;
21373 isctype: function (character, type)
21376 case this.kCapitalLetter:
21377 if (character >= 'A' && character <= 'Z') {
21382 case this.kSmallLetter:
21383 if (character >= 'a' && character <= 'z') {
21389 if (character >= '0' && character <= '9') {
21394 case this.kPunctuation:
21395 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21406 IsLongEnough: function (pwd, size)
21408 return !(pwd == null || isNaN(size) || pwd.length < size);
21411 SpansEnoughCharacterSets: function (word, nb)
21413 if (!this.IsLongEnough(word, nb))
21418 var characterSetChecks = new Array(
21419 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21420 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21423 for (var index = 0; index < word.length; ++index) {
21424 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21425 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21426 characterSetChecks[nCharSet].fResult = true;
21433 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21434 if (characterSetChecks[nCharSet].fResult) {
21439 if (nCharSets < nb) {
21445 ClientSideStrongPassword: function (pwd)
21447 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21450 ClientSideMediumPassword: function (pwd)
21452 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21455 ClientSideWeakPassword: function (pwd)
21457 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21460 })//<script type="text/javascript">
21463 * Based Ext JS Library 1.1.1
21464 * Copyright(c) 2006-2007, Ext JS, LLC.
21470 * @class Roo.HtmlEditorCore
21471 * @extends Roo.Component
21472 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21474 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21477 Roo.HtmlEditorCore = function(config){
21480 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21485 * @event initialize
21486 * Fires when the editor is fully initialized (including the iframe)
21487 * @param {Roo.HtmlEditorCore} this
21492 * Fires when the editor is first receives the focus. Any insertion must wait
21493 * until after this event.
21494 * @param {Roo.HtmlEditorCore} this
21498 * @event beforesync
21499 * Fires before the textarea is updated with content from the editor iframe. Return false
21500 * to cancel the sync.
21501 * @param {Roo.HtmlEditorCore} this
21502 * @param {String} html
21506 * @event beforepush
21507 * Fires before the iframe editor is updated with content from the textarea. Return false
21508 * to cancel the push.
21509 * @param {Roo.HtmlEditorCore} this
21510 * @param {String} html
21515 * Fires when the textarea is updated with content from the editor iframe.
21516 * @param {Roo.HtmlEditorCore} this
21517 * @param {String} html
21522 * Fires when the iframe editor is updated with content from the textarea.
21523 * @param {Roo.HtmlEditorCore} this
21524 * @param {String} html
21529 * @event editorevent
21530 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21531 * @param {Roo.HtmlEditorCore} this
21537 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21539 // defaults : white / black...
21540 this.applyBlacklists();
21547 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21551 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21557 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21562 * @cfg {Number} height (in pixels)
21566 * @cfg {Number} width (in pixels)
21571 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21574 stylesheets: false,
21579 // private properties
21580 validationEvent : false,
21582 initialized : false,
21584 sourceEditMode : false,
21585 onFocus : Roo.emptyFn,
21587 hideMode:'offsets',
21591 // blacklist + whitelisted elements..
21598 * Protected method that will not generally be called directly. It
21599 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21600 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21602 getDocMarkup : function(){
21606 // inherit styels from page...??
21607 if (this.stylesheets === false) {
21609 Roo.get(document.head).select('style').each(function(node) {
21610 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21613 Roo.get(document.head).select('link').each(function(node) {
21614 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21617 } else if (!this.stylesheets.length) {
21619 st = '<style type="text/css">' +
21620 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21623 st = '<style type="text/css">' +
21628 st += '<style type="text/css">' +
21629 'IMG { cursor: pointer } ' +
21632 var cls = 'roo-htmleditor-body';
21634 if(this.bodyCls.length){
21635 cls += ' ' + this.bodyCls;
21638 return '<html><head>' + st +
21639 //<style type="text/css">' +
21640 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21642 ' </head><body class="' + cls + '"></body></html>';
21646 onRender : function(ct, position)
21649 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21650 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21653 this.el.dom.style.border = '0 none';
21654 this.el.dom.setAttribute('tabIndex', -1);
21655 this.el.addClass('x-hidden hide');
21659 if(Roo.isIE){ // fix IE 1px bogus margin
21660 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21664 this.frameId = Roo.id();
21668 var iframe = this.owner.wrap.createChild({
21670 cls: 'form-control', // bootstrap..
21672 name: this.frameId,
21673 frameBorder : 'no',
21674 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21679 this.iframe = iframe.dom;
21681 this.assignDocWin();
21683 this.doc.designMode = 'on';
21686 this.doc.write(this.getDocMarkup());
21690 var task = { // must defer to wait for browser to be ready
21692 //console.log("run task?" + this.doc.readyState);
21693 this.assignDocWin();
21694 if(this.doc.body || this.doc.readyState == 'complete'){
21696 this.doc.designMode="on";
21700 Roo.TaskMgr.stop(task);
21701 this.initEditor.defer(10, this);
21708 Roo.TaskMgr.start(task);
21713 onResize : function(w, h)
21715 Roo.log('resize: ' +w + ',' + h );
21716 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21720 if(typeof w == 'number'){
21722 this.iframe.style.width = w + 'px';
21724 if(typeof h == 'number'){
21726 this.iframe.style.height = h + 'px';
21728 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21735 * Toggles the editor between standard and source edit mode.
21736 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21738 toggleSourceEdit : function(sourceEditMode){
21740 this.sourceEditMode = sourceEditMode === true;
21742 if(this.sourceEditMode){
21744 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21747 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21748 //this.iframe.className = '';
21751 //this.setSize(this.owner.wrap.getSize());
21752 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21759 * Protected method that will not generally be called directly. If you need/want
21760 * custom HTML cleanup, this is the method you should override.
21761 * @param {String} html The HTML to be cleaned
21762 * return {String} The cleaned HTML
21764 cleanHtml : function(html){
21765 html = String(html);
21766 if(html.length > 5){
21767 if(Roo.isSafari){ // strip safari nonsense
21768 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21771 if(html == ' '){
21778 * HTML Editor -> Textarea
21779 * Protected method that will not generally be called directly. Syncs the contents
21780 * of the editor iframe with the textarea.
21782 syncValue : function(){
21783 if(this.initialized){
21784 var bd = (this.doc.body || this.doc.documentElement);
21785 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21786 var html = bd.innerHTML;
21788 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21789 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21791 html = '<div style="'+m[0]+'">' + html + '</div>';
21794 html = this.cleanHtml(html);
21795 // fix up the special chars.. normaly like back quotes in word...
21796 // however we do not want to do this with chinese..
21797 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21798 var cc = b.charCodeAt();
21800 (cc >= 0x4E00 && cc < 0xA000 ) ||
21801 (cc >= 0x3400 && cc < 0x4E00 ) ||
21802 (cc >= 0xf900 && cc < 0xfb00 )
21808 if(this.owner.fireEvent('beforesync', this, html) !== false){
21809 this.el.dom.value = html;
21810 this.owner.fireEvent('sync', this, html);
21816 * Protected method that will not generally be called directly. Pushes the value of the textarea
21817 * into the iframe editor.
21819 pushValue : function(){
21820 if(this.initialized){
21821 var v = this.el.dom.value.trim();
21823 // if(v.length < 1){
21827 if(this.owner.fireEvent('beforepush', this, v) !== false){
21828 var d = (this.doc.body || this.doc.documentElement);
21830 this.cleanUpPaste();
21831 this.el.dom.value = d.innerHTML;
21832 this.owner.fireEvent('push', this, v);
21838 deferFocus : function(){
21839 this.focus.defer(10, this);
21843 focus : function(){
21844 if(this.win && !this.sourceEditMode){
21851 assignDocWin: function()
21853 var iframe = this.iframe;
21856 this.doc = iframe.contentWindow.document;
21857 this.win = iframe.contentWindow;
21859 // if (!Roo.get(this.frameId)) {
21862 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21863 // this.win = Roo.get(this.frameId).dom.contentWindow;
21865 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21869 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21870 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21875 initEditor : function(){
21876 //console.log("INIT EDITOR");
21877 this.assignDocWin();
21881 this.doc.designMode="on";
21883 this.doc.write(this.getDocMarkup());
21886 var dbody = (this.doc.body || this.doc.documentElement);
21887 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21888 // this copies styles from the containing element into thsi one..
21889 // not sure why we need all of this..
21890 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21892 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21893 //ss['background-attachment'] = 'fixed'; // w3c
21894 dbody.bgProperties = 'fixed'; // ie
21895 //Roo.DomHelper.applyStyles(dbody, ss);
21896 Roo.EventManager.on(this.doc, {
21897 //'mousedown': this.onEditorEvent,
21898 'mouseup': this.onEditorEvent,
21899 'dblclick': this.onEditorEvent,
21900 'click': this.onEditorEvent,
21901 'keyup': this.onEditorEvent,
21906 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21908 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21909 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21911 this.initialized = true;
21913 this.owner.fireEvent('initialize', this);
21918 onDestroy : function(){
21924 //for (var i =0; i < this.toolbars.length;i++) {
21925 // // fixme - ask toolbars for heights?
21926 // this.toolbars[i].onDestroy();
21929 //this.wrap.dom.innerHTML = '';
21930 //this.wrap.remove();
21935 onFirstFocus : function(){
21937 this.assignDocWin();
21940 this.activated = true;
21943 if(Roo.isGecko){ // prevent silly gecko errors
21945 var s = this.win.getSelection();
21946 if(!s.focusNode || s.focusNode.nodeType != 3){
21947 var r = s.getRangeAt(0);
21948 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21953 this.execCmd('useCSS', true);
21954 this.execCmd('styleWithCSS', false);
21957 this.owner.fireEvent('activate', this);
21961 adjustFont: function(btn){
21962 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21963 //if(Roo.isSafari){ // safari
21966 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21967 if(Roo.isSafari){ // safari
21968 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21969 v = (v < 10) ? 10 : v;
21970 v = (v > 48) ? 48 : v;
21971 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21976 v = Math.max(1, v+adjust);
21978 this.execCmd('FontSize', v );
21981 onEditorEvent : function(e)
21983 this.owner.fireEvent('editorevent', this, e);
21984 // this.updateToolbar();
21985 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21988 insertTag : function(tg)
21990 // could be a bit smarter... -> wrap the current selected tRoo..
21991 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21993 range = this.createRange(this.getSelection());
21994 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21995 wrappingNode.appendChild(range.extractContents());
21996 range.insertNode(wrappingNode);
22003 this.execCmd("formatblock", tg);
22007 insertText : function(txt)
22011 var range = this.createRange();
22012 range.deleteContents();
22013 //alert(Sender.getAttribute('label'));
22015 range.insertNode(this.doc.createTextNode(txt));
22021 * Executes a Midas editor command on the editor document and performs necessary focus and
22022 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22023 * @param {String} cmd The Midas command
22024 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22026 relayCmd : function(cmd, value){
22028 this.execCmd(cmd, value);
22029 this.owner.fireEvent('editorevent', this);
22030 //this.updateToolbar();
22031 this.owner.deferFocus();
22035 * Executes a Midas editor command directly on the editor document.
22036 * For visual commands, you should use {@link #relayCmd} instead.
22037 * <b>This should only be called after the editor is initialized.</b>
22038 * @param {String} cmd The Midas command
22039 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22041 execCmd : function(cmd, value){
22042 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22049 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22051 * @param {String} text | dom node..
22053 insertAtCursor : function(text)
22056 if(!this.activated){
22062 var r = this.doc.selection.createRange();
22073 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22077 // from jquery ui (MIT licenced)
22079 var win = this.win;
22081 if (win.getSelection && win.getSelection().getRangeAt) {
22082 range = win.getSelection().getRangeAt(0);
22083 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22084 range.insertNode(node);
22085 } else if (win.document.selection && win.document.selection.createRange) {
22086 // no firefox support
22087 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22088 win.document.selection.createRange().pasteHTML(txt);
22090 // no firefox support
22091 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22092 this.execCmd('InsertHTML', txt);
22101 mozKeyPress : function(e){
22103 var c = e.getCharCode(), cmd;
22106 c = String.fromCharCode(c).toLowerCase();
22120 this.cleanUpPaste.defer(100, this);
22128 e.preventDefault();
22136 fixKeys : function(){ // load time branching for fastest keydown performance
22138 return function(e){
22139 var k = e.getKey(), r;
22142 r = this.doc.selection.createRange();
22145 r.pasteHTML('    ');
22152 r = this.doc.selection.createRange();
22154 var target = r.parentElement();
22155 if(!target || target.tagName.toLowerCase() != 'li'){
22157 r.pasteHTML('<br />');
22163 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22164 this.cleanUpPaste.defer(100, this);
22170 }else if(Roo.isOpera){
22171 return function(e){
22172 var k = e.getKey();
22176 this.execCmd('InsertHTML','    ');
22179 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22180 this.cleanUpPaste.defer(100, this);
22185 }else if(Roo.isSafari){
22186 return function(e){
22187 var k = e.getKey();
22191 this.execCmd('InsertText','\t');
22195 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22196 this.cleanUpPaste.defer(100, this);
22204 getAllAncestors: function()
22206 var p = this.getSelectedNode();
22209 a.push(p); // push blank onto stack..
22210 p = this.getParentElement();
22214 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22218 a.push(this.doc.body);
22222 lastSelNode : false,
22225 getSelection : function()
22227 this.assignDocWin();
22228 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22231 getSelectedNode: function()
22233 // this may only work on Gecko!!!
22235 // should we cache this!!!!
22240 var range = this.createRange(this.getSelection()).cloneRange();
22243 var parent = range.parentElement();
22245 var testRange = range.duplicate();
22246 testRange.moveToElementText(parent);
22247 if (testRange.inRange(range)) {
22250 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22253 parent = parent.parentElement;
22258 // is ancestor a text element.
22259 var ac = range.commonAncestorContainer;
22260 if (ac.nodeType == 3) {
22261 ac = ac.parentNode;
22264 var ar = ac.childNodes;
22267 var other_nodes = [];
22268 var has_other_nodes = false;
22269 for (var i=0;i<ar.length;i++) {
22270 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22273 // fullly contained node.
22275 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22280 // probably selected..
22281 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22282 other_nodes.push(ar[i]);
22286 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22291 has_other_nodes = true;
22293 if (!nodes.length && other_nodes.length) {
22294 nodes= other_nodes;
22296 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22302 createRange: function(sel)
22304 // this has strange effects when using with
22305 // top toolbar - not sure if it's a great idea.
22306 //this.editor.contentWindow.focus();
22307 if (typeof sel != "undefined") {
22309 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22311 return this.doc.createRange();
22314 return this.doc.createRange();
22317 getParentElement: function()
22320 this.assignDocWin();
22321 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22323 var range = this.createRange(sel);
22326 var p = range.commonAncestorContainer;
22327 while (p.nodeType == 3) { // text node
22338 * Range intersection.. the hard stuff...
22342 * [ -- selected range --- ]
22346 * if end is before start or hits it. fail.
22347 * if start is after end or hits it fail.
22349 * if either hits (but other is outside. - then it's not
22355 // @see http://www.thismuchiknow.co.uk/?p=64.
22356 rangeIntersectsNode : function(range, node)
22358 var nodeRange = node.ownerDocument.createRange();
22360 nodeRange.selectNode(node);
22362 nodeRange.selectNodeContents(node);
22365 var rangeStartRange = range.cloneRange();
22366 rangeStartRange.collapse(true);
22368 var rangeEndRange = range.cloneRange();
22369 rangeEndRange.collapse(false);
22371 var nodeStartRange = nodeRange.cloneRange();
22372 nodeStartRange.collapse(true);
22374 var nodeEndRange = nodeRange.cloneRange();
22375 nodeEndRange.collapse(false);
22377 return rangeStartRange.compareBoundaryPoints(
22378 Range.START_TO_START, nodeEndRange) == -1 &&
22379 rangeEndRange.compareBoundaryPoints(
22380 Range.START_TO_START, nodeStartRange) == 1;
22384 rangeCompareNode : function(range, node)
22386 var nodeRange = node.ownerDocument.createRange();
22388 nodeRange.selectNode(node);
22390 nodeRange.selectNodeContents(node);
22394 range.collapse(true);
22396 nodeRange.collapse(true);
22398 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22399 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22401 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22403 var nodeIsBefore = ss == 1;
22404 var nodeIsAfter = ee == -1;
22406 if (nodeIsBefore && nodeIsAfter) {
22409 if (!nodeIsBefore && nodeIsAfter) {
22410 return 1; //right trailed.
22413 if (nodeIsBefore && !nodeIsAfter) {
22414 return 2; // left trailed.
22420 // private? - in a new class?
22421 cleanUpPaste : function()
22423 // cleans up the whole document..
22424 Roo.log('cleanuppaste');
22426 this.cleanUpChildren(this.doc.body);
22427 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22428 if (clean != this.doc.body.innerHTML) {
22429 this.doc.body.innerHTML = clean;
22434 cleanWordChars : function(input) {// change the chars to hex code
22435 var he = Roo.HtmlEditorCore;
22437 var output = input;
22438 Roo.each(he.swapCodes, function(sw) {
22439 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22441 output = output.replace(swapper, sw[1]);
22448 cleanUpChildren : function (n)
22450 if (!n.childNodes.length) {
22453 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22454 this.cleanUpChild(n.childNodes[i]);
22461 cleanUpChild : function (node)
22464 //console.log(node);
22465 if (node.nodeName == "#text") {
22466 // clean up silly Windows -- stuff?
22469 if (node.nodeName == "#comment") {
22470 node.parentNode.removeChild(node);
22471 // clean up silly Windows -- stuff?
22474 var lcname = node.tagName.toLowerCase();
22475 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22476 // whitelist of tags..
22478 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22480 node.parentNode.removeChild(node);
22485 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22487 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22488 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22490 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22491 // remove_keep_children = true;
22494 if (remove_keep_children) {
22495 this.cleanUpChildren(node);
22496 // inserts everything just before this node...
22497 while (node.childNodes.length) {
22498 var cn = node.childNodes[0];
22499 node.removeChild(cn);
22500 node.parentNode.insertBefore(cn, node);
22502 node.parentNode.removeChild(node);
22506 if (!node.attributes || !node.attributes.length) {
22507 this.cleanUpChildren(node);
22511 function cleanAttr(n,v)
22514 if (v.match(/^\./) || v.match(/^\//)) {
22517 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22520 if (v.match(/^#/)) {
22523 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22524 node.removeAttribute(n);
22528 var cwhite = this.cwhite;
22529 var cblack = this.cblack;
22531 function cleanStyle(n,v)
22533 if (v.match(/expression/)) { //XSS?? should we even bother..
22534 node.removeAttribute(n);
22538 var parts = v.split(/;/);
22541 Roo.each(parts, function(p) {
22542 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22546 var l = p.split(':').shift().replace(/\s+/g,'');
22547 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22549 if ( cwhite.length && cblack.indexOf(l) > -1) {
22550 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22551 //node.removeAttribute(n);
22555 // only allow 'c whitelisted system attributes'
22556 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22557 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22558 //node.removeAttribute(n);
22568 if (clean.length) {
22569 node.setAttribute(n, clean.join(';'));
22571 node.removeAttribute(n);
22577 for (var i = node.attributes.length-1; i > -1 ; i--) {
22578 var a = node.attributes[i];
22581 if (a.name.toLowerCase().substr(0,2)=='on') {
22582 node.removeAttribute(a.name);
22585 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22586 node.removeAttribute(a.name);
22589 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22590 cleanAttr(a.name,a.value); // fixme..
22593 if (a.name == 'style') {
22594 cleanStyle(a.name,a.value);
22597 /// clean up MS crap..
22598 // tecnically this should be a list of valid class'es..
22601 if (a.name == 'class') {
22602 if (a.value.match(/^Mso/)) {
22603 node.className = '';
22606 if (a.value.match(/^body$/)) {
22607 node.className = '';
22618 this.cleanUpChildren(node);
22624 * Clean up MS wordisms...
22626 cleanWord : function(node)
22631 this.cleanWord(this.doc.body);
22634 if (node.nodeName == "#text") {
22635 // clean up silly Windows -- stuff?
22638 if (node.nodeName == "#comment") {
22639 node.parentNode.removeChild(node);
22640 // clean up silly Windows -- stuff?
22644 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22645 node.parentNode.removeChild(node);
22649 // remove - but keep children..
22650 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22651 while (node.childNodes.length) {
22652 var cn = node.childNodes[0];
22653 node.removeChild(cn);
22654 node.parentNode.insertBefore(cn, node);
22656 node.parentNode.removeChild(node);
22657 this.iterateChildren(node, this.cleanWord);
22661 if (node.className.length) {
22663 var cn = node.className.split(/\W+/);
22665 Roo.each(cn, function(cls) {
22666 if (cls.match(/Mso[a-zA-Z]+/)) {
22671 node.className = cna.length ? cna.join(' ') : '';
22673 node.removeAttribute("class");
22677 if (node.hasAttribute("lang")) {
22678 node.removeAttribute("lang");
22681 if (node.hasAttribute("style")) {
22683 var styles = node.getAttribute("style").split(";");
22685 Roo.each(styles, function(s) {
22686 if (!s.match(/:/)) {
22689 var kv = s.split(":");
22690 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22693 // what ever is left... we allow.
22696 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22697 if (!nstyle.length) {
22698 node.removeAttribute('style');
22701 this.iterateChildren(node, this.cleanWord);
22707 * iterateChildren of a Node, calling fn each time, using this as the scole..
22708 * @param {DomNode} node node to iterate children of.
22709 * @param {Function} fn method of this class to call on each item.
22711 iterateChildren : function(node, fn)
22713 if (!node.childNodes.length) {
22716 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22717 fn.call(this, node.childNodes[i])
22723 * cleanTableWidths.
22725 * Quite often pasting from word etc.. results in tables with column and widths.
22726 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22729 cleanTableWidths : function(node)
22734 this.cleanTableWidths(this.doc.body);
22739 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22742 Roo.log(node.tagName);
22743 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22744 this.iterateChildren(node, this.cleanTableWidths);
22747 if (node.hasAttribute('width')) {
22748 node.removeAttribute('width');
22752 if (node.hasAttribute("style")) {
22755 var styles = node.getAttribute("style").split(";");
22757 Roo.each(styles, function(s) {
22758 if (!s.match(/:/)) {
22761 var kv = s.split(":");
22762 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22765 // what ever is left... we allow.
22768 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22769 if (!nstyle.length) {
22770 node.removeAttribute('style');
22774 this.iterateChildren(node, this.cleanTableWidths);
22782 domToHTML : function(currentElement, depth, nopadtext) {
22784 depth = depth || 0;
22785 nopadtext = nopadtext || false;
22787 if (!currentElement) {
22788 return this.domToHTML(this.doc.body);
22791 //Roo.log(currentElement);
22793 var allText = false;
22794 var nodeName = currentElement.nodeName;
22795 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22797 if (nodeName == '#text') {
22799 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22804 if (nodeName != 'BODY') {
22807 // Prints the node tagName, such as <A>, <IMG>, etc
22810 for(i = 0; i < currentElement.attributes.length;i++) {
22812 var aname = currentElement.attributes.item(i).name;
22813 if (!currentElement.attributes.item(i).value.length) {
22816 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22819 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22828 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22831 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22836 // Traverse the tree
22838 var currentElementChild = currentElement.childNodes.item(i);
22839 var allText = true;
22840 var innerHTML = '';
22842 while (currentElementChild) {
22843 // Formatting code (indent the tree so it looks nice on the screen)
22844 var nopad = nopadtext;
22845 if (lastnode == 'SPAN') {
22849 if (currentElementChild.nodeName == '#text') {
22850 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22851 toadd = nopadtext ? toadd : toadd.trim();
22852 if (!nopad && toadd.length > 80) {
22853 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22855 innerHTML += toadd;
22858 currentElementChild = currentElement.childNodes.item(i);
22864 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22866 // Recursively traverse the tree structure of the child node
22867 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22868 lastnode = currentElementChild.nodeName;
22870 currentElementChild=currentElement.childNodes.item(i);
22876 // The remaining code is mostly for formatting the tree
22877 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22882 ret+= "</"+tagName+">";
22888 applyBlacklists : function()
22890 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22891 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22895 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22896 if (b.indexOf(tag) > -1) {
22899 this.white.push(tag);
22903 Roo.each(w, function(tag) {
22904 if (b.indexOf(tag) > -1) {
22907 if (this.white.indexOf(tag) > -1) {
22910 this.white.push(tag);
22915 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22916 if (w.indexOf(tag) > -1) {
22919 this.black.push(tag);
22923 Roo.each(b, function(tag) {
22924 if (w.indexOf(tag) > -1) {
22927 if (this.black.indexOf(tag) > -1) {
22930 this.black.push(tag);
22935 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22936 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22940 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22941 if (b.indexOf(tag) > -1) {
22944 this.cwhite.push(tag);
22948 Roo.each(w, function(tag) {
22949 if (b.indexOf(tag) > -1) {
22952 if (this.cwhite.indexOf(tag) > -1) {
22955 this.cwhite.push(tag);
22960 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22961 if (w.indexOf(tag) > -1) {
22964 this.cblack.push(tag);
22968 Roo.each(b, function(tag) {
22969 if (w.indexOf(tag) > -1) {
22972 if (this.cblack.indexOf(tag) > -1) {
22975 this.cblack.push(tag);
22980 setStylesheets : function(stylesheets)
22982 if(typeof(stylesheets) == 'string'){
22983 Roo.get(this.iframe.contentDocument.head).createChild({
22985 rel : 'stylesheet',
22994 Roo.each(stylesheets, function(s) {
22999 Roo.get(_this.iframe.contentDocument.head).createChild({
23001 rel : 'stylesheet',
23010 removeStylesheets : function()
23014 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23019 setStyle : function(style)
23021 Roo.get(this.iframe.contentDocument.head).createChild({
23030 // hide stuff that is not compatible
23044 * @event specialkey
23048 * @cfg {String} fieldClass @hide
23051 * @cfg {String} focusClass @hide
23054 * @cfg {String} autoCreate @hide
23057 * @cfg {String} inputType @hide
23060 * @cfg {String} invalidClass @hide
23063 * @cfg {String} invalidText @hide
23066 * @cfg {String} msgFx @hide
23069 * @cfg {String} validateOnBlur @hide
23073 Roo.HtmlEditorCore.white = [
23074 'area', 'br', 'img', 'input', 'hr', 'wbr',
23076 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23077 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23078 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23079 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23080 'table', 'ul', 'xmp',
23082 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23085 'dir', 'menu', 'ol', 'ul', 'dl',
23091 Roo.HtmlEditorCore.black = [
23092 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23094 'base', 'basefont', 'bgsound', 'blink', 'body',
23095 'frame', 'frameset', 'head', 'html', 'ilayer',
23096 'iframe', 'layer', 'link', 'meta', 'object',
23097 'script', 'style' ,'title', 'xml' // clean later..
23099 Roo.HtmlEditorCore.clean = [
23100 'script', 'style', 'title', 'xml'
23102 Roo.HtmlEditorCore.remove = [
23107 Roo.HtmlEditorCore.ablack = [
23111 Roo.HtmlEditorCore.aclean = [
23112 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23116 Roo.HtmlEditorCore.pwhite= [
23117 'http', 'https', 'mailto'
23120 // white listed style attributes.
23121 Roo.HtmlEditorCore.cwhite= [
23122 // 'text-align', /// default is to allow most things..
23128 // black listed style attributes.
23129 Roo.HtmlEditorCore.cblack= [
23130 // 'font-size' -- this can be set by the project
23134 Roo.HtmlEditorCore.swapCodes =[
23153 * @class Roo.bootstrap.HtmlEditor
23154 * @extends Roo.bootstrap.TextArea
23155 * Bootstrap HtmlEditor class
23158 * Create a new HtmlEditor
23159 * @param {Object} config The config object
23162 Roo.bootstrap.HtmlEditor = function(config){
23163 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23164 if (!this.toolbars) {
23165 this.toolbars = [];
23168 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23171 * @event initialize
23172 * Fires when the editor is fully initialized (including the iframe)
23173 * @param {HtmlEditor} this
23178 * Fires when the editor is first receives the focus. Any insertion must wait
23179 * until after this event.
23180 * @param {HtmlEditor} this
23184 * @event beforesync
23185 * Fires before the textarea is updated with content from the editor iframe. Return false
23186 * to cancel the sync.
23187 * @param {HtmlEditor} this
23188 * @param {String} html
23192 * @event beforepush
23193 * Fires before the iframe editor is updated with content from the textarea. Return false
23194 * to cancel the push.
23195 * @param {HtmlEditor} this
23196 * @param {String} html
23201 * Fires when the textarea is updated with content from the editor iframe.
23202 * @param {HtmlEditor} this
23203 * @param {String} html
23208 * Fires when the iframe editor is updated with content from the textarea.
23209 * @param {HtmlEditor} this
23210 * @param {String} html
23214 * @event editmodechange
23215 * Fires when the editor switches edit modes
23216 * @param {HtmlEditor} this
23217 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23219 editmodechange: true,
23221 * @event editorevent
23222 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23223 * @param {HtmlEditor} this
23227 * @event firstfocus
23228 * Fires when on first focus - needed by toolbars..
23229 * @param {HtmlEditor} this
23234 * Auto save the htmlEditor value as a file into Events
23235 * @param {HtmlEditor} this
23239 * @event savedpreview
23240 * preview the saved version of htmlEditor
23241 * @param {HtmlEditor} this
23248 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23252 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23257 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23262 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23267 * @cfg {Number} height (in pixels)
23271 * @cfg {Number} width (in pixels)
23276 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23279 stylesheets: false,
23284 // private properties
23285 validationEvent : false,
23287 initialized : false,
23290 onFocus : Roo.emptyFn,
23292 hideMode:'offsets',
23294 tbContainer : false,
23298 toolbarContainer :function() {
23299 return this.wrap.select('.x-html-editor-tb',true).first();
23303 * Protected method that will not generally be called directly. It
23304 * is called when the editor creates its toolbar. Override this method if you need to
23305 * add custom toolbar buttons.
23306 * @param {HtmlEditor} editor
23308 createToolbar : function(){
23309 Roo.log('renewing');
23310 Roo.log("create toolbars");
23312 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23313 this.toolbars[0].render(this.toolbarContainer());
23317 // if (!editor.toolbars || !editor.toolbars.length) {
23318 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23321 // for (var i =0 ; i < editor.toolbars.length;i++) {
23322 // editor.toolbars[i] = Roo.factory(
23323 // typeof(editor.toolbars[i]) == 'string' ?
23324 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23325 // Roo.bootstrap.HtmlEditor);
23326 // editor.toolbars[i].init(editor);
23332 onRender : function(ct, position)
23334 // Roo.log("Call onRender: " + this.xtype);
23336 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23338 this.wrap = this.inputEl().wrap({
23339 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23342 this.editorcore.onRender(ct, position);
23344 if (this.resizable) {
23345 this.resizeEl = new Roo.Resizable(this.wrap, {
23349 minHeight : this.height,
23350 height: this.height,
23351 handles : this.resizable,
23354 resize : function(r, w, h) {
23355 _t.onResize(w,h); // -something
23361 this.createToolbar(this);
23364 if(!this.width && this.resizable){
23365 this.setSize(this.wrap.getSize());
23367 if (this.resizeEl) {
23368 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23369 // should trigger onReize..
23375 onResize : function(w, h)
23377 Roo.log('resize: ' +w + ',' + h );
23378 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23382 if(this.inputEl() ){
23383 if(typeof w == 'number'){
23384 var aw = w - this.wrap.getFrameWidth('lr');
23385 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23388 if(typeof h == 'number'){
23389 var tbh = -11; // fixme it needs to tool bar size!
23390 for (var i =0; i < this.toolbars.length;i++) {
23391 // fixme - ask toolbars for heights?
23392 tbh += this.toolbars[i].el.getHeight();
23393 //if (this.toolbars[i].footer) {
23394 // tbh += this.toolbars[i].footer.el.getHeight();
23402 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23403 ah -= 5; // knock a few pixes off for look..
23404 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23408 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23409 this.editorcore.onResize(ew,eh);
23414 * Toggles the editor between standard and source edit mode.
23415 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23417 toggleSourceEdit : function(sourceEditMode)
23419 this.editorcore.toggleSourceEdit(sourceEditMode);
23421 if(this.editorcore.sourceEditMode){
23422 Roo.log('editor - showing textarea');
23425 // Roo.log(this.syncValue());
23427 this.inputEl().removeClass(['hide', 'x-hidden']);
23428 this.inputEl().dom.removeAttribute('tabIndex');
23429 this.inputEl().focus();
23431 Roo.log('editor - hiding textarea');
23433 // Roo.log(this.pushValue());
23436 this.inputEl().addClass(['hide', 'x-hidden']);
23437 this.inputEl().dom.setAttribute('tabIndex', -1);
23438 //this.deferFocus();
23441 if(this.resizable){
23442 this.setSize(this.wrap.getSize());
23445 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23448 // private (for BoxComponent)
23449 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23451 // private (for BoxComponent)
23452 getResizeEl : function(){
23456 // private (for BoxComponent)
23457 getPositionEl : function(){
23462 initEvents : function(){
23463 this.originalValue = this.getValue();
23467 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23470 // markInvalid : Roo.emptyFn,
23472 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23475 // clearInvalid : Roo.emptyFn,
23477 setValue : function(v){
23478 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23479 this.editorcore.pushValue();
23484 deferFocus : function(){
23485 this.focus.defer(10, this);
23489 focus : function(){
23490 this.editorcore.focus();
23496 onDestroy : function(){
23502 for (var i =0; i < this.toolbars.length;i++) {
23503 // fixme - ask toolbars for heights?
23504 this.toolbars[i].onDestroy();
23507 this.wrap.dom.innerHTML = '';
23508 this.wrap.remove();
23513 onFirstFocus : function(){
23514 //Roo.log("onFirstFocus");
23515 this.editorcore.onFirstFocus();
23516 for (var i =0; i < this.toolbars.length;i++) {
23517 this.toolbars[i].onFirstFocus();
23523 syncValue : function()
23525 this.editorcore.syncValue();
23528 pushValue : function()
23530 this.editorcore.pushValue();
23534 // hide stuff that is not compatible
23548 * @event specialkey
23552 * @cfg {String} fieldClass @hide
23555 * @cfg {String} focusClass @hide
23558 * @cfg {String} autoCreate @hide
23561 * @cfg {String} inputType @hide
23564 * @cfg {String} invalidClass @hide
23567 * @cfg {String} invalidText @hide
23570 * @cfg {String} msgFx @hide
23573 * @cfg {String} validateOnBlur @hide
23582 Roo.namespace('Roo.bootstrap.htmleditor');
23584 * @class Roo.bootstrap.HtmlEditorToolbar1
23589 new Roo.bootstrap.HtmlEditor({
23592 new Roo.bootstrap.HtmlEditorToolbar1({
23593 disable : { fonts: 1 , format: 1, ..., ... , ...],
23599 * @cfg {Object} disable List of elements to disable..
23600 * @cfg {Array} btns List of additional buttons.
23604 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23607 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23610 Roo.apply(this, config);
23612 // default disabled, based on 'good practice'..
23613 this.disable = this.disable || {};
23614 Roo.applyIf(this.disable, {
23617 specialElements : true
23619 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23621 this.editor = config.editor;
23622 this.editorcore = config.editor.editorcore;
23624 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23626 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23627 // dont call parent... till later.
23629 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23634 editorcore : false,
23639 "h1","h2","h3","h4","h5","h6",
23641 "abbr", "acronym", "address", "cite", "samp", "var",
23645 onRender : function(ct, position)
23647 // Roo.log("Call onRender: " + this.xtype);
23649 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23651 this.el.dom.style.marginBottom = '0';
23653 var editorcore = this.editorcore;
23654 var editor= this.editor;
23657 var btn = function(id,cmd , toggle, handler, html){
23659 var event = toggle ? 'toggle' : 'click';
23664 xns: Roo.bootstrap,
23667 enableToggle:toggle !== false,
23669 pressed : toggle ? false : null,
23672 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23673 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23679 // var cb_box = function...
23684 xns: Roo.bootstrap,
23685 glyphicon : 'font',
23689 xns: Roo.bootstrap,
23693 Roo.each(this.formats, function(f) {
23694 style.menu.items.push({
23696 xns: Roo.bootstrap,
23697 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23702 editorcore.insertTag(this.tagname);
23709 children.push(style);
23711 btn('bold',false,true);
23712 btn('italic',false,true);
23713 btn('align-left', 'justifyleft',true);
23714 btn('align-center', 'justifycenter',true);
23715 btn('align-right' , 'justifyright',true);
23716 btn('link', false, false, function(btn) {
23717 //Roo.log("create link?");
23718 var url = prompt(this.createLinkText, this.defaultLinkValue);
23719 if(url && url != 'http:/'+'/'){
23720 this.editorcore.relayCmd('createlink', url);
23723 btn('list','insertunorderedlist',true);
23724 btn('pencil', false,true, function(btn){
23726 this.toggleSourceEdit(btn.pressed);
23729 if (this.editor.btns.length > 0) {
23730 for (var i = 0; i<this.editor.btns.length; i++) {
23731 children.push(this.editor.btns[i]);
23739 xns: Roo.bootstrap,
23744 xns: Roo.bootstrap,
23749 cog.menu.items.push({
23751 xns: Roo.bootstrap,
23752 html : Clean styles,
23757 editorcore.insertTag(this.tagname);
23766 this.xtype = 'NavSimplebar';
23768 for(var i=0;i< children.length;i++) {
23770 this.buttons.add(this.addxtypeChild(children[i]));
23774 editor.on('editorevent', this.updateToolbar, this);
23776 onBtnClick : function(id)
23778 this.editorcore.relayCmd(id);
23779 this.editorcore.focus();
23783 * Protected method that will not generally be called directly. It triggers
23784 * a toolbar update by reading the markup state of the current selection in the editor.
23786 updateToolbar: function(){
23788 if(!this.editorcore.activated){
23789 this.editor.onFirstFocus(); // is this neeed?
23793 var btns = this.buttons;
23794 var doc = this.editorcore.doc;
23795 btns.get('bold').setActive(doc.queryCommandState('bold'));
23796 btns.get('italic').setActive(doc.queryCommandState('italic'));
23797 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23799 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23800 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23801 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23803 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23804 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23807 var ans = this.editorcore.getAllAncestors();
23808 if (this.formatCombo) {
23811 var store = this.formatCombo.store;
23812 this.formatCombo.setValue("");
23813 for (var i =0; i < ans.length;i++) {
23814 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23816 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23824 // hides menus... - so this cant be on a menu...
23825 Roo.bootstrap.MenuMgr.hideAll();
23827 Roo.bootstrap.MenuMgr.hideAll();
23828 //this.editorsyncValue();
23830 onFirstFocus: function() {
23831 this.buttons.each(function(item){
23835 toggleSourceEdit : function(sourceEditMode){
23838 if(sourceEditMode){
23839 Roo.log("disabling buttons");
23840 this.buttons.each( function(item){
23841 if(item.cmd != 'pencil'){
23847 Roo.log("enabling buttons");
23848 if(this.editorcore.initialized){
23849 this.buttons.each( function(item){
23855 Roo.log("calling toggole on editor");
23856 // tell the editor that it's been pressed..
23857 this.editor.toggleSourceEdit(sourceEditMode);
23867 * @class Roo.bootstrap.Table.AbstractSelectionModel
23868 * @extends Roo.util.Observable
23869 * Abstract base class for grid SelectionModels. It provides the interface that should be
23870 * implemented by descendant classes. This class should not be directly instantiated.
23873 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23874 this.locked = false;
23875 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23879 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23880 /** @ignore Called by the grid automatically. Do not call directly. */
23881 init : function(grid){
23887 * Locks the selections.
23890 this.locked = true;
23894 * Unlocks the selections.
23896 unlock : function(){
23897 this.locked = false;
23901 * Returns true if the selections are locked.
23902 * @return {Boolean}
23904 isLocked : function(){
23905 return this.locked;
23909 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23910 * @class Roo.bootstrap.Table.RowSelectionModel
23911 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23912 * It supports multiple selections and keyboard selection/navigation.
23914 * @param {Object} config
23917 Roo.bootstrap.Table.RowSelectionModel = function(config){
23918 Roo.apply(this, config);
23919 this.selections = new Roo.util.MixedCollection(false, function(o){
23924 this.lastActive = false;
23928 * @event selectionchange
23929 * Fires when the selection changes
23930 * @param {SelectionModel} this
23932 "selectionchange" : true,
23934 * @event afterselectionchange
23935 * Fires after the selection changes (eg. by key press or clicking)
23936 * @param {SelectionModel} this
23938 "afterselectionchange" : true,
23940 * @event beforerowselect
23941 * Fires when a row is selected being selected, return false to cancel.
23942 * @param {SelectionModel} this
23943 * @param {Number} rowIndex The selected index
23944 * @param {Boolean} keepExisting False if other selections will be cleared
23946 "beforerowselect" : true,
23949 * Fires when a row is selected.
23950 * @param {SelectionModel} this
23951 * @param {Number} rowIndex The selected index
23952 * @param {Roo.data.Record} r The record
23954 "rowselect" : true,
23956 * @event rowdeselect
23957 * Fires when a row is deselected.
23958 * @param {SelectionModel} this
23959 * @param {Number} rowIndex The selected index
23961 "rowdeselect" : true
23963 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23964 this.locked = false;
23967 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23969 * @cfg {Boolean} singleSelect
23970 * True to allow selection of only one row at a time (defaults to false)
23972 singleSelect : false,
23975 initEvents : function()
23978 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23979 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23980 //}else{ // allow click to work like normal
23981 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23983 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23984 this.grid.on("rowclick", this.handleMouseDown, this);
23986 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23987 "up" : function(e){
23989 this.selectPrevious(e.shiftKey);
23990 }else if(this.last !== false && this.lastActive !== false){
23991 var last = this.last;
23992 this.selectRange(this.last, this.lastActive-1);
23993 this.grid.getView().focusRow(this.lastActive);
23994 if(last !== false){
23998 this.selectFirstRow();
24000 this.fireEvent("afterselectionchange", this);
24002 "down" : function(e){
24004 this.selectNext(e.shiftKey);
24005 }else if(this.last !== false && this.lastActive !== false){
24006 var last = this.last;
24007 this.selectRange(this.last, this.lastActive+1);
24008 this.grid.getView().focusRow(this.lastActive);
24009 if(last !== false){
24013 this.selectFirstRow();
24015 this.fireEvent("afterselectionchange", this);
24019 this.grid.store.on('load', function(){
24020 this.selections.clear();
24023 var view = this.grid.view;
24024 view.on("refresh", this.onRefresh, this);
24025 view.on("rowupdated", this.onRowUpdated, this);
24026 view.on("rowremoved", this.onRemove, this);
24031 onRefresh : function()
24033 var ds = this.grid.store, i, v = this.grid.view;
24034 var s = this.selections;
24035 s.each(function(r){
24036 if((i = ds.indexOfId(r.id)) != -1){
24045 onRemove : function(v, index, r){
24046 this.selections.remove(r);
24050 onRowUpdated : function(v, index, r){
24051 if(this.isSelected(r)){
24052 v.onRowSelect(index);
24058 * @param {Array} records The records to select
24059 * @param {Boolean} keepExisting (optional) True to keep existing selections
24061 selectRecords : function(records, keepExisting)
24064 this.clearSelections();
24066 var ds = this.grid.store;
24067 for(var i = 0, len = records.length; i < len; i++){
24068 this.selectRow(ds.indexOf(records[i]), true);
24073 * Gets the number of selected rows.
24076 getCount : function(){
24077 return this.selections.length;
24081 * Selects the first row in the grid.
24083 selectFirstRow : function(){
24088 * Select the last row.
24089 * @param {Boolean} keepExisting (optional) True to keep existing selections
24091 selectLastRow : function(keepExisting){
24092 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24093 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24097 * Selects the row immediately following the last selected row.
24098 * @param {Boolean} keepExisting (optional) True to keep existing selections
24100 selectNext : function(keepExisting)
24102 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24103 this.selectRow(this.last+1, keepExisting);
24104 this.grid.getView().focusRow(this.last);
24109 * Selects the row that precedes the last selected row.
24110 * @param {Boolean} keepExisting (optional) True to keep existing selections
24112 selectPrevious : function(keepExisting){
24114 this.selectRow(this.last-1, keepExisting);
24115 this.grid.getView().focusRow(this.last);
24120 * Returns the selected records
24121 * @return {Array} Array of selected records
24123 getSelections : function(){
24124 return [].concat(this.selections.items);
24128 * Returns the first selected record.
24131 getSelected : function(){
24132 return this.selections.itemAt(0);
24137 * Clears all selections.
24139 clearSelections : function(fast)
24145 var ds = this.grid.store;
24146 var s = this.selections;
24147 s.each(function(r){
24148 this.deselectRow(ds.indexOfId(r.id));
24152 this.selections.clear();
24159 * Selects all rows.
24161 selectAll : function(){
24165 this.selections.clear();
24166 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24167 this.selectRow(i, true);
24172 * Returns True if there is a selection.
24173 * @return {Boolean}
24175 hasSelection : function(){
24176 return this.selections.length > 0;
24180 * Returns True if the specified row is selected.
24181 * @param {Number/Record} record The record or index of the record to check
24182 * @return {Boolean}
24184 isSelected : function(index){
24185 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24186 return (r && this.selections.key(r.id) ? true : false);
24190 * Returns True if the specified record id is selected.
24191 * @param {String} id The id of record to check
24192 * @return {Boolean}
24194 isIdSelected : function(id){
24195 return (this.selections.key(id) ? true : false);
24200 handleMouseDBClick : function(e, t){
24204 handleMouseDown : function(e, t)
24206 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24207 if(this.isLocked() || rowIndex < 0 ){
24210 if(e.shiftKey && this.last !== false){
24211 var last = this.last;
24212 this.selectRange(last, rowIndex, e.ctrlKey);
24213 this.last = last; // reset the last
24217 var isSelected = this.isSelected(rowIndex);
24218 //Roo.log("select row:" + rowIndex);
24220 this.deselectRow(rowIndex);
24222 this.selectRow(rowIndex, true);
24226 if(e.button !== 0 && isSelected){
24227 alert('rowIndex 2: ' + rowIndex);
24228 view.focusRow(rowIndex);
24229 }else if(e.ctrlKey && isSelected){
24230 this.deselectRow(rowIndex);
24231 }else if(!isSelected){
24232 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24233 view.focusRow(rowIndex);
24237 this.fireEvent("afterselectionchange", this);
24240 handleDragableRowClick : function(grid, rowIndex, e)
24242 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24243 this.selectRow(rowIndex, false);
24244 grid.view.focusRow(rowIndex);
24245 this.fireEvent("afterselectionchange", this);
24250 * Selects multiple rows.
24251 * @param {Array} rows Array of the indexes of the row to select
24252 * @param {Boolean} keepExisting (optional) True to keep existing selections
24254 selectRows : function(rows, keepExisting){
24256 this.clearSelections();
24258 for(var i = 0, len = rows.length; i < len; i++){
24259 this.selectRow(rows[i], true);
24264 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24265 * @param {Number} startRow The index of the first row in the range
24266 * @param {Number} endRow The index of the last row in the range
24267 * @param {Boolean} keepExisting (optional) True to retain existing selections
24269 selectRange : function(startRow, endRow, keepExisting){
24274 this.clearSelections();
24276 if(startRow <= endRow){
24277 for(var i = startRow; i <= endRow; i++){
24278 this.selectRow(i, true);
24281 for(var i = startRow; i >= endRow; i--){
24282 this.selectRow(i, true);
24288 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24289 * @param {Number} startRow The index of the first row in the range
24290 * @param {Number} endRow The index of the last row in the range
24292 deselectRange : function(startRow, endRow, preventViewNotify){
24296 for(var i = startRow; i <= endRow; i++){
24297 this.deselectRow(i, preventViewNotify);
24303 * @param {Number} row The index of the row to select
24304 * @param {Boolean} keepExisting (optional) True to keep existing selections
24306 selectRow : function(index, keepExisting, preventViewNotify)
24308 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24311 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24312 if(!keepExisting || this.singleSelect){
24313 this.clearSelections();
24316 var r = this.grid.store.getAt(index);
24317 //console.log('selectRow - record id :' + r.id);
24319 this.selections.add(r);
24320 this.last = this.lastActive = index;
24321 if(!preventViewNotify){
24322 var proxy = new Roo.Element(
24323 this.grid.getRowDom(index)
24325 proxy.addClass('bg-info info');
24327 this.fireEvent("rowselect", this, index, r);
24328 this.fireEvent("selectionchange", this);
24334 * @param {Number} row The index of the row to deselect
24336 deselectRow : function(index, preventViewNotify)
24341 if(this.last == index){
24344 if(this.lastActive == index){
24345 this.lastActive = false;
24348 var r = this.grid.store.getAt(index);
24353 this.selections.remove(r);
24354 //.console.log('deselectRow - record id :' + r.id);
24355 if(!preventViewNotify){
24357 var proxy = new Roo.Element(
24358 this.grid.getRowDom(index)
24360 proxy.removeClass('bg-info info');
24362 this.fireEvent("rowdeselect", this, index);
24363 this.fireEvent("selectionchange", this);
24367 restoreLast : function(){
24369 this.last = this._last;
24374 acceptsNav : function(row, col, cm){
24375 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24379 onEditorKey : function(field, e){
24380 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24385 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24387 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24389 }else if(k == e.ENTER && !e.ctrlKey){
24393 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24395 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24397 }else if(k == e.ESC){
24401 g.startEditing(newCell[0], newCell[1]);
24407 * Ext JS Library 1.1.1
24408 * Copyright(c) 2006-2007, Ext JS, LLC.
24410 * Originally Released Under LGPL - original licence link has changed is not relivant.
24413 * <script type="text/javascript">
24417 * @class Roo.bootstrap.PagingToolbar
24418 * @extends Roo.bootstrap.NavSimplebar
24419 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24421 * Create a new PagingToolbar
24422 * @param {Object} config The config object
24423 * @param {Roo.data.Store} store
24425 Roo.bootstrap.PagingToolbar = function(config)
24427 // old args format still supported... - xtype is prefered..
24428 // created from xtype...
24430 this.ds = config.dataSource;
24432 if (config.store && !this.ds) {
24433 this.store= Roo.factory(config.store, Roo.data);
24434 this.ds = this.store;
24435 this.ds.xmodule = this.xmodule || false;
24438 this.toolbarItems = [];
24439 if (config.items) {
24440 this.toolbarItems = config.items;
24443 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24448 this.bind(this.ds);
24451 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24455 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24457 * @cfg {Roo.data.Store} dataSource
24458 * The underlying data store providing the paged data
24461 * @cfg {String/HTMLElement/Element} container
24462 * container The id or element that will contain the toolbar
24465 * @cfg {Boolean} displayInfo
24466 * True to display the displayMsg (defaults to false)
24469 * @cfg {Number} pageSize
24470 * The number of records to display per page (defaults to 20)
24474 * @cfg {String} displayMsg
24475 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24477 displayMsg : 'Displaying {0} - {1} of {2}',
24479 * @cfg {String} emptyMsg
24480 * The message to display when no records are found (defaults to "No data to display")
24482 emptyMsg : 'No data to display',
24484 * Customizable piece of the default paging text (defaults to "Page")
24487 beforePageText : "Page",
24489 * Customizable piece of the default paging text (defaults to "of %0")
24492 afterPageText : "of {0}",
24494 * Customizable piece of the default paging text (defaults to "First Page")
24497 firstText : "First Page",
24499 * Customizable piece of the default paging text (defaults to "Previous Page")
24502 prevText : "Previous Page",
24504 * Customizable piece of the default paging text (defaults to "Next Page")
24507 nextText : "Next Page",
24509 * Customizable piece of the default paging text (defaults to "Last Page")
24512 lastText : "Last Page",
24514 * Customizable piece of the default paging text (defaults to "Refresh")
24517 refreshText : "Refresh",
24521 onRender : function(ct, position)
24523 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24524 this.navgroup.parentId = this.id;
24525 this.navgroup.onRender(this.el, null);
24526 // add the buttons to the navgroup
24528 if(this.displayInfo){
24529 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24530 this.displayEl = this.el.select('.x-paging-info', true).first();
24531 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24532 // this.displayEl = navel.el.select('span',true).first();
24538 Roo.each(_this.buttons, function(e){ // this might need to use render????
24539 Roo.factory(e).render(_this.el);
24543 Roo.each(_this.toolbarItems, function(e) {
24544 _this.navgroup.addItem(e);
24548 this.first = this.navgroup.addItem({
24549 tooltip: this.firstText,
24551 icon : 'fa fa-backward',
24553 preventDefault: true,
24554 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24557 this.prev = this.navgroup.addItem({
24558 tooltip: this.prevText,
24560 icon : 'fa fa-step-backward',
24562 preventDefault: true,
24563 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24565 //this.addSeparator();
24568 var field = this.navgroup.addItem( {
24570 cls : 'x-paging-position',
24572 html : this.beforePageText +
24573 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24574 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24577 this.field = field.el.select('input', true).first();
24578 this.field.on("keydown", this.onPagingKeydown, this);
24579 this.field.on("focus", function(){this.dom.select();});
24582 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24583 //this.field.setHeight(18);
24584 //this.addSeparator();
24585 this.next = this.navgroup.addItem({
24586 tooltip: this.nextText,
24588 html : ' <i class="fa fa-step-forward">',
24590 preventDefault: true,
24591 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24593 this.last = this.navgroup.addItem({
24594 tooltip: this.lastText,
24595 icon : 'fa fa-forward',
24598 preventDefault: true,
24599 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24601 //this.addSeparator();
24602 this.loading = this.navgroup.addItem({
24603 tooltip: this.refreshText,
24604 icon: 'fa fa-refresh',
24605 preventDefault: true,
24606 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24612 updateInfo : function(){
24613 if(this.displayEl){
24614 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24615 var msg = count == 0 ?
24619 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24621 this.displayEl.update(msg);
24626 onLoad : function(ds, r, o)
24628 this.cursor = o.params.start ? o.params.start : 0;
24630 var d = this.getPageData(),
24635 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24636 this.field.dom.value = ap;
24637 this.first.setDisabled(ap == 1);
24638 this.prev.setDisabled(ap == 1);
24639 this.next.setDisabled(ap == ps);
24640 this.last.setDisabled(ap == ps);
24641 this.loading.enable();
24646 getPageData : function(){
24647 var total = this.ds.getTotalCount();
24650 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24651 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24656 onLoadError : function(){
24657 this.loading.enable();
24661 onPagingKeydown : function(e){
24662 var k = e.getKey();
24663 var d = this.getPageData();
24665 var v = this.field.dom.value, pageNum;
24666 if(!v || isNaN(pageNum = parseInt(v, 10))){
24667 this.field.dom.value = d.activePage;
24670 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24671 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24674 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))
24676 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24677 this.field.dom.value = pageNum;
24678 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24681 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24683 var v = this.field.dom.value, pageNum;
24684 var increment = (e.shiftKey) ? 10 : 1;
24685 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24688 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24689 this.field.dom.value = d.activePage;
24692 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24694 this.field.dom.value = parseInt(v, 10) + increment;
24695 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24696 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24703 beforeLoad : function(){
24705 this.loading.disable();
24710 onClick : function(which){
24719 ds.load({params:{start: 0, limit: this.pageSize}});
24722 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24725 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24728 var total = ds.getTotalCount();
24729 var extra = total % this.pageSize;
24730 var lastStart = extra ? (total - extra) : total-this.pageSize;
24731 ds.load({params:{start: lastStart, limit: this.pageSize}});
24734 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24740 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24741 * @param {Roo.data.Store} store The data store to unbind
24743 unbind : function(ds){
24744 ds.un("beforeload", this.beforeLoad, this);
24745 ds.un("load", this.onLoad, this);
24746 ds.un("loadexception", this.onLoadError, this);
24747 ds.un("remove", this.updateInfo, this);
24748 ds.un("add", this.updateInfo, this);
24749 this.ds = undefined;
24753 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24754 * @param {Roo.data.Store} store The data store to bind
24756 bind : function(ds){
24757 ds.on("beforeload", this.beforeLoad, this);
24758 ds.on("load", this.onLoad, this);
24759 ds.on("loadexception", this.onLoadError, this);
24760 ds.on("remove", this.updateInfo, this);
24761 ds.on("add", this.updateInfo, this);
24772 * @class Roo.bootstrap.MessageBar
24773 * @extends Roo.bootstrap.Component
24774 * Bootstrap MessageBar class
24775 * @cfg {String} html contents of the MessageBar
24776 * @cfg {String} weight (info | success | warning | danger) default info
24777 * @cfg {String} beforeClass insert the bar before the given class
24778 * @cfg {Boolean} closable (true | false) default false
24779 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24782 * Create a new Element
24783 * @param {Object} config The config object
24786 Roo.bootstrap.MessageBar = function(config){
24787 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24790 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24796 beforeClass: 'bootstrap-sticky-wrap',
24798 getAutoCreate : function(){
24802 cls: 'alert alert-dismissable alert-' + this.weight,
24807 html: this.html || ''
24813 cfg.cls += ' alert-messages-fixed';
24827 onRender : function(ct, position)
24829 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24832 var cfg = Roo.apply({}, this.getAutoCreate());
24836 cfg.cls += ' ' + this.cls;
24839 cfg.style = this.style;
24841 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24843 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24846 this.el.select('>button.close').on('click', this.hide, this);
24852 if (!this.rendered) {
24858 this.fireEvent('show', this);
24864 if (!this.rendered) {
24870 this.fireEvent('hide', this);
24873 update : function()
24875 // var e = this.el.dom.firstChild;
24877 // if(this.closable){
24878 // e = e.nextSibling;
24881 // e.data = this.html || '';
24883 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24899 * @class Roo.bootstrap.Graph
24900 * @extends Roo.bootstrap.Component
24901 * Bootstrap Graph class
24905 @cfg {String} graphtype bar | vbar | pie
24906 @cfg {number} g_x coodinator | centre x (pie)
24907 @cfg {number} g_y coodinator | centre y (pie)
24908 @cfg {number} g_r radius (pie)
24909 @cfg {number} g_height height of the chart (respected by all elements in the set)
24910 @cfg {number} g_width width of the chart (respected by all elements in the set)
24911 @cfg {Object} title The title of the chart
24914 -opts (object) options for the chart
24916 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24917 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24919 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.
24920 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24922 o stretch (boolean)
24924 -opts (object) options for the pie
24927 o startAngle (number)
24928 o endAngle (number)
24932 * Create a new Input
24933 * @param {Object} config The config object
24936 Roo.bootstrap.Graph = function(config){
24937 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24943 * The img click event for the img.
24944 * @param {Roo.EventObject} e
24950 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24961 //g_colors: this.colors,
24968 getAutoCreate : function(){
24979 onRender : function(ct,position){
24982 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24984 if (typeof(Raphael) == 'undefined') {
24985 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24989 this.raphael = Raphael(this.el.dom);
24991 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24992 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24993 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24994 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24996 r.text(160, 10, "Single Series Chart").attr(txtattr);
24997 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24998 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24999 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25001 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25002 r.barchart(330, 10, 300, 220, data1);
25003 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25004 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25007 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25008 // r.barchart(30, 30, 560, 250, xdata, {
25009 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25010 // axis : "0 0 1 1",
25011 // axisxlabels : xdata
25012 // //yvalues : cols,
25015 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25017 // this.load(null,xdata,{
25018 // axis : "0 0 1 1",
25019 // axisxlabels : xdata
25024 load : function(graphtype,xdata,opts)
25026 this.raphael.clear();
25028 graphtype = this.graphtype;
25033 var r = this.raphael,
25034 fin = function () {
25035 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25037 fout = function () {
25038 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25040 pfin = function() {
25041 this.sector.stop();
25042 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25045 this.label[0].stop();
25046 this.label[0].attr({ r: 7.5 });
25047 this.label[1].attr({ "font-weight": 800 });
25050 pfout = function() {
25051 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25054 this.label[0].animate({ r: 5 }, 500, "bounce");
25055 this.label[1].attr({ "font-weight": 400 });
25061 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25064 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25067 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25068 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25070 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25077 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25082 setTitle: function(o)
25087 initEvents: function() {
25090 this.el.on('click', this.onClick, this);
25094 onClick : function(e)
25096 Roo.log('img onclick');
25097 this.fireEvent('click', this, e);
25109 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25112 * @class Roo.bootstrap.dash.NumberBox
25113 * @extends Roo.bootstrap.Component
25114 * Bootstrap NumberBox class
25115 * @cfg {String} headline Box headline
25116 * @cfg {String} content Box content
25117 * @cfg {String} icon Box icon
25118 * @cfg {String} footer Footer text
25119 * @cfg {String} fhref Footer href
25122 * Create a new NumberBox
25123 * @param {Object} config The config object
25127 Roo.bootstrap.dash.NumberBox = function(config){
25128 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25132 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25141 getAutoCreate : function(){
25145 cls : 'small-box ',
25153 cls : 'roo-headline',
25154 html : this.headline
25158 cls : 'roo-content',
25159 html : this.content
25173 cls : 'ion ' + this.icon
25182 cls : 'small-box-footer',
25183 href : this.fhref || '#',
25187 cfg.cn.push(footer);
25194 onRender : function(ct,position){
25195 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25202 setHeadline: function (value)
25204 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25207 setFooter: function (value, href)
25209 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25212 this.el.select('a.small-box-footer',true).first().attr('href', href);
25217 setContent: function (value)
25219 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25222 initEvents: function()
25236 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25239 * @class Roo.bootstrap.dash.TabBox
25240 * @extends Roo.bootstrap.Component
25241 * Bootstrap TabBox class
25242 * @cfg {String} title Title of the TabBox
25243 * @cfg {String} icon Icon of the TabBox
25244 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25245 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25248 * Create a new TabBox
25249 * @param {Object} config The config object
25253 Roo.bootstrap.dash.TabBox = function(config){
25254 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25259 * When a pane is added
25260 * @param {Roo.bootstrap.dash.TabPane} pane
25264 * @event activatepane
25265 * When a pane is activated
25266 * @param {Roo.bootstrap.dash.TabPane} pane
25268 "activatepane" : true
25276 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25281 tabScrollable : false,
25283 getChildContainer : function()
25285 return this.el.select('.tab-content', true).first();
25288 getAutoCreate : function(){
25292 cls: 'pull-left header',
25300 cls: 'fa ' + this.icon
25306 cls: 'nav nav-tabs pull-right',
25312 if(this.tabScrollable){
25319 cls: 'nav nav-tabs pull-right',
25330 cls: 'nav-tabs-custom',
25335 cls: 'tab-content no-padding',
25343 initEvents : function()
25345 //Roo.log('add add pane handler');
25346 this.on('addpane', this.onAddPane, this);
25349 * Updates the box title
25350 * @param {String} html to set the title to.
25352 setTitle : function(value)
25354 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25356 onAddPane : function(pane)
25358 this.panes.push(pane);
25359 //Roo.log('addpane');
25361 // tabs are rendere left to right..
25362 if(!this.showtabs){
25366 var ctr = this.el.select('.nav-tabs', true).first();
25369 var existing = ctr.select('.nav-tab',true);
25370 var qty = existing.getCount();;
25373 var tab = ctr.createChild({
25375 cls : 'nav-tab' + (qty ? '' : ' active'),
25383 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25386 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25388 pane.el.addClass('active');
25393 onTabClick : function(ev,un,ob,pane)
25395 //Roo.log('tab - prev default');
25396 ev.preventDefault();
25399 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25400 pane.tab.addClass('active');
25401 //Roo.log(pane.title);
25402 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25403 // technically we should have a deactivate event.. but maybe add later.
25404 // and it should not de-activate the selected tab...
25405 this.fireEvent('activatepane', pane);
25406 pane.el.addClass('active');
25407 pane.fireEvent('activate');
25412 getActivePane : function()
25415 Roo.each(this.panes, function(p) {
25416 if(p.el.hasClass('active')){
25437 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25439 * @class Roo.bootstrap.TabPane
25440 * @extends Roo.bootstrap.Component
25441 * Bootstrap TabPane class
25442 * @cfg {Boolean} active (false | true) Default false
25443 * @cfg {String} title title of panel
25447 * Create a new TabPane
25448 * @param {Object} config The config object
25451 Roo.bootstrap.dash.TabPane = function(config){
25452 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25458 * When a pane is activated
25459 * @param {Roo.bootstrap.dash.TabPane} pane
25466 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25471 // the tabBox that this is attached to.
25474 getAutoCreate : function()
25482 cfg.cls += ' active';
25487 initEvents : function()
25489 //Roo.log('trigger add pane handler');
25490 this.parent().fireEvent('addpane', this)
25494 * Updates the tab title
25495 * @param {String} html to set the title to.
25497 setTitle: function(str)
25503 this.tab.select('a', true).first().dom.innerHTML = str;
25520 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25523 * @class Roo.bootstrap.menu.Menu
25524 * @extends Roo.bootstrap.Component
25525 * Bootstrap Menu class - container for Menu
25526 * @cfg {String} html Text of the menu
25527 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25528 * @cfg {String} icon Font awesome icon
25529 * @cfg {String} pos Menu align to (top | bottom) default bottom
25533 * Create a new Menu
25534 * @param {Object} config The config object
25538 Roo.bootstrap.menu.Menu = function(config){
25539 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25543 * @event beforeshow
25544 * Fires before this menu is displayed
25545 * @param {Roo.bootstrap.menu.Menu} this
25549 * @event beforehide
25550 * Fires before this menu is hidden
25551 * @param {Roo.bootstrap.menu.Menu} this
25556 * Fires after this menu is displayed
25557 * @param {Roo.bootstrap.menu.Menu} this
25562 * Fires after this menu is hidden
25563 * @param {Roo.bootstrap.menu.Menu} this
25568 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25569 * @param {Roo.bootstrap.menu.Menu} this
25570 * @param {Roo.EventObject} e
25577 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25581 weight : 'default',
25586 getChildContainer : function() {
25587 if(this.isSubMenu){
25591 return this.el.select('ul.dropdown-menu', true).first();
25594 getAutoCreate : function()
25599 cls : 'roo-menu-text',
25607 cls : 'fa ' + this.icon
25618 cls : 'dropdown-button btn btn-' + this.weight,
25623 cls : 'dropdown-toggle btn btn-' + this.weight,
25633 cls : 'dropdown-menu'
25639 if(this.pos == 'top'){
25640 cfg.cls += ' dropup';
25643 if(this.isSubMenu){
25646 cls : 'dropdown-menu'
25653 onRender : function(ct, position)
25655 this.isSubMenu = ct.hasClass('dropdown-submenu');
25657 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25660 initEvents : function()
25662 if(this.isSubMenu){
25666 this.hidden = true;
25668 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25669 this.triggerEl.on('click', this.onTriggerPress, this);
25671 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25672 this.buttonEl.on('click', this.onClick, this);
25678 if(this.isSubMenu){
25682 return this.el.select('ul.dropdown-menu', true).first();
25685 onClick : function(e)
25687 this.fireEvent("click", this, e);
25690 onTriggerPress : function(e)
25692 if (this.isVisible()) {
25699 isVisible : function(){
25700 return !this.hidden;
25705 this.fireEvent("beforeshow", this);
25707 this.hidden = false;
25708 this.el.addClass('open');
25710 Roo.get(document).on("mouseup", this.onMouseUp, this);
25712 this.fireEvent("show", this);
25719 this.fireEvent("beforehide", this);
25721 this.hidden = true;
25722 this.el.removeClass('open');
25724 Roo.get(document).un("mouseup", this.onMouseUp);
25726 this.fireEvent("hide", this);
25729 onMouseUp : function()
25743 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25746 * @class Roo.bootstrap.menu.Item
25747 * @extends Roo.bootstrap.Component
25748 * Bootstrap MenuItem class
25749 * @cfg {Boolean} submenu (true | false) default false
25750 * @cfg {String} html text of the item
25751 * @cfg {String} href the link
25752 * @cfg {Boolean} disable (true | false) default false
25753 * @cfg {Boolean} preventDefault (true | false) default true
25754 * @cfg {String} icon Font awesome icon
25755 * @cfg {String} pos Submenu align to (left | right) default right
25759 * Create a new Item
25760 * @param {Object} config The config object
25764 Roo.bootstrap.menu.Item = function(config){
25765 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25769 * Fires when the mouse is hovering over this menu
25770 * @param {Roo.bootstrap.menu.Item} this
25771 * @param {Roo.EventObject} e
25776 * Fires when the mouse exits this menu
25777 * @param {Roo.bootstrap.menu.Item} this
25778 * @param {Roo.EventObject} e
25784 * The raw click event for the entire grid.
25785 * @param {Roo.EventObject} e
25791 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25796 preventDefault: true,
25801 getAutoCreate : function()
25806 cls : 'roo-menu-item-text',
25814 cls : 'fa ' + this.icon
25823 href : this.href || '#',
25830 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25834 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25836 if(this.pos == 'left'){
25837 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25844 initEvents : function()
25846 this.el.on('mouseover', this.onMouseOver, this);
25847 this.el.on('mouseout', this.onMouseOut, this);
25849 this.el.select('a', true).first().on('click', this.onClick, this);
25853 onClick : function(e)
25855 if(this.preventDefault){
25856 e.preventDefault();
25859 this.fireEvent("click", this, e);
25862 onMouseOver : function(e)
25864 if(this.submenu && this.pos == 'left'){
25865 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25868 this.fireEvent("mouseover", this, e);
25871 onMouseOut : function(e)
25873 this.fireEvent("mouseout", this, e);
25885 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25888 * @class Roo.bootstrap.menu.Separator
25889 * @extends Roo.bootstrap.Component
25890 * Bootstrap Separator class
25893 * Create a new Separator
25894 * @param {Object} config The config object
25898 Roo.bootstrap.menu.Separator = function(config){
25899 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25902 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25904 getAutoCreate : function(){
25925 * @class Roo.bootstrap.Tooltip
25926 * Bootstrap Tooltip class
25927 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25928 * to determine which dom element triggers the tooltip.
25930 * It needs to add support for additional attributes like tooltip-position
25933 * Create a new Toolti
25934 * @param {Object} config The config object
25937 Roo.bootstrap.Tooltip = function(config){
25938 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25940 this.alignment = Roo.bootstrap.Tooltip.alignment;
25942 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25943 this.alignment = config.alignment;
25948 Roo.apply(Roo.bootstrap.Tooltip, {
25950 * @function init initialize tooltip monitoring.
25954 currentTip : false,
25955 currentRegion : false,
25961 Roo.get(document).on('mouseover', this.enter ,this);
25962 Roo.get(document).on('mouseout', this.leave, this);
25965 this.currentTip = new Roo.bootstrap.Tooltip();
25968 enter : function(ev)
25970 var dom = ev.getTarget();
25972 //Roo.log(['enter',dom]);
25973 var el = Roo.fly(dom);
25974 if (this.currentEl) {
25976 //Roo.log(this.currentEl);
25977 //Roo.log(this.currentEl.contains(dom));
25978 if (this.currentEl == el) {
25981 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25987 if (this.currentTip.el) {
25988 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25992 if(!el || el.dom == document){
25998 // you can not look for children, as if el is the body.. then everythign is the child..
25999 if (!el.attr('tooltip')) { //
26000 if (!el.select("[tooltip]").elements.length) {
26003 // is the mouse over this child...?
26004 bindEl = el.select("[tooltip]").first();
26005 var xy = ev.getXY();
26006 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26007 //Roo.log("not in region.");
26010 //Roo.log("child element over..");
26013 this.currentEl = bindEl;
26014 this.currentTip.bind(bindEl);
26015 this.currentRegion = Roo.lib.Region.getRegion(dom);
26016 this.currentTip.enter();
26019 leave : function(ev)
26021 var dom = ev.getTarget();
26022 //Roo.log(['leave',dom]);
26023 if (!this.currentEl) {
26028 if (dom != this.currentEl.dom) {
26031 var xy = ev.getXY();
26032 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26035 // only activate leave if mouse cursor is outside... bounding box..
26040 if (this.currentTip) {
26041 this.currentTip.leave();
26043 //Roo.log('clear currentEl');
26044 this.currentEl = false;
26049 'left' : ['r-l', [-2,0], 'right'],
26050 'right' : ['l-r', [2,0], 'left'],
26051 'bottom' : ['t-b', [0,2], 'top'],
26052 'top' : [ 'b-t', [0,-2], 'bottom']
26058 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26063 delay : null, // can be { show : 300 , hide: 500}
26067 hoverState : null, //???
26069 placement : 'bottom',
26073 getAutoCreate : function(){
26080 cls : 'tooltip-arrow'
26083 cls : 'tooltip-inner'
26090 bind : function(el)
26096 enter : function () {
26098 if (this.timeout != null) {
26099 clearTimeout(this.timeout);
26102 this.hoverState = 'in';
26103 //Roo.log("enter - show");
26104 if (!this.delay || !this.delay.show) {
26109 this.timeout = setTimeout(function () {
26110 if (_t.hoverState == 'in') {
26113 }, this.delay.show);
26117 clearTimeout(this.timeout);
26119 this.hoverState = 'out';
26120 if (!this.delay || !this.delay.hide) {
26126 this.timeout = setTimeout(function () {
26127 //Roo.log("leave - timeout");
26129 if (_t.hoverState == 'out') {
26131 Roo.bootstrap.Tooltip.currentEl = false;
26136 show : function (msg)
26139 this.render(document.body);
26142 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26144 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26146 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26148 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26150 var placement = typeof this.placement == 'function' ?
26151 this.placement.call(this, this.el, on_el) :
26154 var autoToken = /\s?auto?\s?/i;
26155 var autoPlace = autoToken.test(placement);
26157 placement = placement.replace(autoToken, '') || 'top';
26161 //this.el.setXY([0,0]);
26163 //this.el.dom.style.display='block';
26165 //this.el.appendTo(on_el);
26167 var p = this.getPosition();
26168 var box = this.el.getBox();
26174 var align = this.alignment[placement];
26176 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26178 if(placement == 'top' || placement == 'bottom'){
26180 placement = 'right';
26183 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26184 placement = 'left';
26187 var scroll = Roo.select('body', true).first().getScroll();
26189 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26195 this.el.alignTo(this.bindEl, align[0],align[1]);
26196 //var arrow = this.el.select('.arrow',true).first();
26197 //arrow.set(align[2],
26199 this.el.addClass(placement);
26201 this.el.addClass('in fade');
26203 this.hoverState = null;
26205 if (this.el.hasClass('fade')) {
26216 //this.el.setXY([0,0]);
26217 this.el.removeClass('in');
26233 * @class Roo.bootstrap.LocationPicker
26234 * @extends Roo.bootstrap.Component
26235 * Bootstrap LocationPicker class
26236 * @cfg {Number} latitude Position when init default 0
26237 * @cfg {Number} longitude Position when init default 0
26238 * @cfg {Number} zoom default 15
26239 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26240 * @cfg {Boolean} mapTypeControl default false
26241 * @cfg {Boolean} disableDoubleClickZoom default false
26242 * @cfg {Boolean} scrollwheel default true
26243 * @cfg {Boolean} streetViewControl default false
26244 * @cfg {Number} radius default 0
26245 * @cfg {String} locationName
26246 * @cfg {Boolean} draggable default true
26247 * @cfg {Boolean} enableAutocomplete default false
26248 * @cfg {Boolean} enableReverseGeocode default true
26249 * @cfg {String} markerTitle
26252 * Create a new LocationPicker
26253 * @param {Object} config The config object
26257 Roo.bootstrap.LocationPicker = function(config){
26259 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26264 * Fires when the picker initialized.
26265 * @param {Roo.bootstrap.LocationPicker} this
26266 * @param {Google Location} location
26270 * @event positionchanged
26271 * Fires when the picker position changed.
26272 * @param {Roo.bootstrap.LocationPicker} this
26273 * @param {Google Location} location
26275 positionchanged : true,
26278 * Fires when the map resize.
26279 * @param {Roo.bootstrap.LocationPicker} this
26284 * Fires when the map show.
26285 * @param {Roo.bootstrap.LocationPicker} this
26290 * Fires when the map hide.
26291 * @param {Roo.bootstrap.LocationPicker} this
26296 * Fires when click the map.
26297 * @param {Roo.bootstrap.LocationPicker} this
26298 * @param {Map event} e
26302 * @event mapRightClick
26303 * Fires when right click the map.
26304 * @param {Roo.bootstrap.LocationPicker} this
26305 * @param {Map event} e
26307 mapRightClick : true,
26309 * @event markerClick
26310 * Fires when click the marker.
26311 * @param {Roo.bootstrap.LocationPicker} this
26312 * @param {Map event} e
26314 markerClick : true,
26316 * @event markerRightClick
26317 * Fires when right click the marker.
26318 * @param {Roo.bootstrap.LocationPicker} this
26319 * @param {Map event} e
26321 markerRightClick : true,
26323 * @event OverlayViewDraw
26324 * Fires when OverlayView Draw
26325 * @param {Roo.bootstrap.LocationPicker} this
26327 OverlayViewDraw : true,
26329 * @event OverlayViewOnAdd
26330 * Fires when OverlayView Draw
26331 * @param {Roo.bootstrap.LocationPicker} this
26333 OverlayViewOnAdd : true,
26335 * @event OverlayViewOnRemove
26336 * Fires when OverlayView Draw
26337 * @param {Roo.bootstrap.LocationPicker} this
26339 OverlayViewOnRemove : true,
26341 * @event OverlayViewShow
26342 * Fires when OverlayView Draw
26343 * @param {Roo.bootstrap.LocationPicker} this
26344 * @param {Pixel} cpx
26346 OverlayViewShow : true,
26348 * @event OverlayViewHide
26349 * Fires when OverlayView Draw
26350 * @param {Roo.bootstrap.LocationPicker} this
26352 OverlayViewHide : true,
26354 * @event loadexception
26355 * Fires when load google lib failed.
26356 * @param {Roo.bootstrap.LocationPicker} this
26358 loadexception : true
26363 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26365 gMapContext: false,
26371 mapTypeControl: false,
26372 disableDoubleClickZoom: false,
26374 streetViewControl: false,
26378 enableAutocomplete: false,
26379 enableReverseGeocode: true,
26382 getAutoCreate: function()
26387 cls: 'roo-location-picker'
26393 initEvents: function(ct, position)
26395 if(!this.el.getWidth() || this.isApplied()){
26399 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26404 initial: function()
26406 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26407 this.fireEvent('loadexception', this);
26411 if(!this.mapTypeId){
26412 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26415 this.gMapContext = this.GMapContext();
26417 this.initOverlayView();
26419 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26423 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26424 _this.setPosition(_this.gMapContext.marker.position);
26427 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26428 _this.fireEvent('mapClick', this, event);
26432 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26433 _this.fireEvent('mapRightClick', this, event);
26437 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26438 _this.fireEvent('markerClick', this, event);
26442 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26443 _this.fireEvent('markerRightClick', this, event);
26447 this.setPosition(this.gMapContext.location);
26449 this.fireEvent('initial', this, this.gMapContext.location);
26452 initOverlayView: function()
26456 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26460 _this.fireEvent('OverlayViewDraw', _this);
26465 _this.fireEvent('OverlayViewOnAdd', _this);
26468 onRemove: function()
26470 _this.fireEvent('OverlayViewOnRemove', _this);
26473 show: function(cpx)
26475 _this.fireEvent('OverlayViewShow', _this, cpx);
26480 _this.fireEvent('OverlayViewHide', _this);
26486 fromLatLngToContainerPixel: function(event)
26488 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26491 isApplied: function()
26493 return this.getGmapContext() == false ? false : true;
26496 getGmapContext: function()
26498 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26501 GMapContext: function()
26503 var position = new google.maps.LatLng(this.latitude, this.longitude);
26505 var _map = new google.maps.Map(this.el.dom, {
26508 mapTypeId: this.mapTypeId,
26509 mapTypeControl: this.mapTypeControl,
26510 disableDoubleClickZoom: this.disableDoubleClickZoom,
26511 scrollwheel: this.scrollwheel,
26512 streetViewControl: this.streetViewControl,
26513 locationName: this.locationName,
26514 draggable: this.draggable,
26515 enableAutocomplete: this.enableAutocomplete,
26516 enableReverseGeocode: this.enableReverseGeocode
26519 var _marker = new google.maps.Marker({
26520 position: position,
26522 title: this.markerTitle,
26523 draggable: this.draggable
26530 location: position,
26531 radius: this.radius,
26532 locationName: this.locationName,
26533 addressComponents: {
26534 formatted_address: null,
26535 addressLine1: null,
26536 addressLine2: null,
26538 streetNumber: null,
26542 stateOrProvince: null
26545 domContainer: this.el.dom,
26546 geodecoder: new google.maps.Geocoder()
26550 drawCircle: function(center, radius, options)
26552 if (this.gMapContext.circle != null) {
26553 this.gMapContext.circle.setMap(null);
26557 options = Roo.apply({}, options, {
26558 strokeColor: "#0000FF",
26559 strokeOpacity: .35,
26561 fillColor: "#0000FF",
26565 options.map = this.gMapContext.map;
26566 options.radius = radius;
26567 options.center = center;
26568 this.gMapContext.circle = new google.maps.Circle(options);
26569 return this.gMapContext.circle;
26575 setPosition: function(location)
26577 this.gMapContext.location = location;
26578 this.gMapContext.marker.setPosition(location);
26579 this.gMapContext.map.panTo(location);
26580 this.drawCircle(location, this.gMapContext.radius, {});
26584 if (this.gMapContext.settings.enableReverseGeocode) {
26585 this.gMapContext.geodecoder.geocode({
26586 latLng: this.gMapContext.location
26587 }, function(results, status) {
26589 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26590 _this.gMapContext.locationName = results[0].formatted_address;
26591 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26593 _this.fireEvent('positionchanged', this, location);
26600 this.fireEvent('positionchanged', this, location);
26605 google.maps.event.trigger(this.gMapContext.map, "resize");
26607 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26609 this.fireEvent('resize', this);
26612 setPositionByLatLng: function(latitude, longitude)
26614 this.setPosition(new google.maps.LatLng(latitude, longitude));
26617 getCurrentPosition: function()
26620 latitude: this.gMapContext.location.lat(),
26621 longitude: this.gMapContext.location.lng()
26625 getAddressName: function()
26627 return this.gMapContext.locationName;
26630 getAddressComponents: function()
26632 return this.gMapContext.addressComponents;
26635 address_component_from_google_geocode: function(address_components)
26639 for (var i = 0; i < address_components.length; i++) {
26640 var component = address_components[i];
26641 if (component.types.indexOf("postal_code") >= 0) {
26642 result.postalCode = component.short_name;
26643 } else if (component.types.indexOf("street_number") >= 0) {
26644 result.streetNumber = component.short_name;
26645 } else if (component.types.indexOf("route") >= 0) {
26646 result.streetName = component.short_name;
26647 } else if (component.types.indexOf("neighborhood") >= 0) {
26648 result.city = component.short_name;
26649 } else if (component.types.indexOf("locality") >= 0) {
26650 result.city = component.short_name;
26651 } else if (component.types.indexOf("sublocality") >= 0) {
26652 result.district = component.short_name;
26653 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26654 result.stateOrProvince = component.short_name;
26655 } else if (component.types.indexOf("country") >= 0) {
26656 result.country = component.short_name;
26660 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26661 result.addressLine2 = "";
26665 setZoomLevel: function(zoom)
26667 this.gMapContext.map.setZoom(zoom);
26680 this.fireEvent('show', this);
26691 this.fireEvent('hide', this);
26696 Roo.apply(Roo.bootstrap.LocationPicker, {
26698 OverlayView : function(map, options)
26700 options = options || {};
26714 * @class Roo.bootstrap.Alert
26715 * @extends Roo.bootstrap.Component
26716 * Bootstrap Alert class
26717 * @cfg {String} title The title of alert
26718 * @cfg {String} html The content of alert
26719 * @cfg {String} weight ( success | info | warning | danger )
26720 * @cfg {String} faicon font-awesomeicon
26723 * Create a new alert
26724 * @param {Object} config The config object
26728 Roo.bootstrap.Alert = function(config){
26729 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26733 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26740 getAutoCreate : function()
26749 cls : 'roo-alert-icon'
26754 cls : 'roo-alert-title',
26759 cls : 'roo-alert-text',
26766 cfg.cn[0].cls += ' fa ' + this.faicon;
26770 cfg.cls += ' alert-' + this.weight;
26776 initEvents: function()
26778 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26781 setTitle : function(str)
26783 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26786 setText : function(str)
26788 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26791 setWeight : function(weight)
26794 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26797 this.weight = weight;
26799 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26802 setIcon : function(icon)
26805 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26808 this.faicon = icon;
26810 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26831 * @class Roo.bootstrap.UploadCropbox
26832 * @extends Roo.bootstrap.Component
26833 * Bootstrap UploadCropbox class
26834 * @cfg {String} emptyText show when image has been loaded
26835 * @cfg {String} rotateNotify show when image too small to rotate
26836 * @cfg {Number} errorTimeout default 3000
26837 * @cfg {Number} minWidth default 300
26838 * @cfg {Number} minHeight default 300
26839 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26840 * @cfg {Boolean} isDocument (true|false) default false
26841 * @cfg {String} url action url
26842 * @cfg {String} paramName default 'imageUpload'
26843 * @cfg {String} method default POST
26844 * @cfg {Boolean} loadMask (true|false) default true
26845 * @cfg {Boolean} loadingText default 'Loading...'
26848 * Create a new UploadCropbox
26849 * @param {Object} config The config object
26852 Roo.bootstrap.UploadCropbox = function(config){
26853 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26857 * @event beforeselectfile
26858 * Fire before select file
26859 * @param {Roo.bootstrap.UploadCropbox} this
26861 "beforeselectfile" : true,
26864 * Fire after initEvent
26865 * @param {Roo.bootstrap.UploadCropbox} this
26870 * Fire after initEvent
26871 * @param {Roo.bootstrap.UploadCropbox} this
26872 * @param {String} data
26877 * Fire when preparing the file data
26878 * @param {Roo.bootstrap.UploadCropbox} this
26879 * @param {Object} file
26884 * Fire when get exception
26885 * @param {Roo.bootstrap.UploadCropbox} this
26886 * @param {XMLHttpRequest} xhr
26888 "exception" : true,
26890 * @event beforeloadcanvas
26891 * Fire before load the canvas
26892 * @param {Roo.bootstrap.UploadCropbox} this
26893 * @param {String} src
26895 "beforeloadcanvas" : true,
26898 * Fire when trash image
26899 * @param {Roo.bootstrap.UploadCropbox} this
26904 * Fire when download the image
26905 * @param {Roo.bootstrap.UploadCropbox} this
26909 * @event footerbuttonclick
26910 * Fire when footerbuttonclick
26911 * @param {Roo.bootstrap.UploadCropbox} this
26912 * @param {String} type
26914 "footerbuttonclick" : true,
26918 * @param {Roo.bootstrap.UploadCropbox} this
26923 * Fire when rotate the image
26924 * @param {Roo.bootstrap.UploadCropbox} this
26925 * @param {String} pos
26930 * Fire when inspect the file
26931 * @param {Roo.bootstrap.UploadCropbox} this
26932 * @param {Object} file
26937 * Fire when xhr upload the file
26938 * @param {Roo.bootstrap.UploadCropbox} this
26939 * @param {Object} data
26944 * Fire when arrange the file data
26945 * @param {Roo.bootstrap.UploadCropbox} this
26946 * @param {Object} formData
26951 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26954 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26956 emptyText : 'Click to upload image',
26957 rotateNotify : 'Image is too small to rotate',
26958 errorTimeout : 3000,
26972 cropType : 'image/jpeg',
26974 canvasLoaded : false,
26975 isDocument : false,
26977 paramName : 'imageUpload',
26979 loadingText : 'Loading...',
26982 getAutoCreate : function()
26986 cls : 'roo-upload-cropbox',
26990 cls : 'roo-upload-cropbox-selector',
26995 cls : 'roo-upload-cropbox-body',
26996 style : 'cursor:pointer',
27000 cls : 'roo-upload-cropbox-preview'
27004 cls : 'roo-upload-cropbox-thumb'
27008 cls : 'roo-upload-cropbox-empty-notify',
27009 html : this.emptyText
27013 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27014 html : this.rotateNotify
27020 cls : 'roo-upload-cropbox-footer',
27023 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27033 onRender : function(ct, position)
27035 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27037 if (this.buttons.length) {
27039 Roo.each(this.buttons, function(bb) {
27041 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27043 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27049 this.maskEl = this.el;
27053 initEvents : function()
27055 this.urlAPI = (window.createObjectURL && window) ||
27056 (window.URL && URL.revokeObjectURL && URL) ||
27057 (window.webkitURL && webkitURL);
27059 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27060 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27062 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27063 this.selectorEl.hide();
27065 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27066 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27068 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27069 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27070 this.thumbEl.hide();
27072 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27073 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27075 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27076 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27077 this.errorEl.hide();
27079 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27080 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27081 this.footerEl.hide();
27083 this.setThumbBoxSize();
27089 this.fireEvent('initial', this);
27096 window.addEventListener("resize", function() { _this.resize(); } );
27098 this.bodyEl.on('click', this.beforeSelectFile, this);
27101 this.bodyEl.on('touchstart', this.onTouchStart, this);
27102 this.bodyEl.on('touchmove', this.onTouchMove, this);
27103 this.bodyEl.on('touchend', this.onTouchEnd, this);
27107 this.bodyEl.on('mousedown', this.onMouseDown, this);
27108 this.bodyEl.on('mousemove', this.onMouseMove, this);
27109 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27110 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27111 Roo.get(document).on('mouseup', this.onMouseUp, this);
27114 this.selectorEl.on('change', this.onFileSelected, this);
27120 this.baseScale = 1;
27122 this.baseRotate = 1;
27123 this.dragable = false;
27124 this.pinching = false;
27127 this.cropData = false;
27128 this.notifyEl.dom.innerHTML = this.emptyText;
27130 this.selectorEl.dom.value = '';
27134 resize : function()
27136 if(this.fireEvent('resize', this) != false){
27137 this.setThumbBoxPosition();
27138 this.setCanvasPosition();
27142 onFooterButtonClick : function(e, el, o, type)
27145 case 'rotate-left' :
27146 this.onRotateLeft(e);
27148 case 'rotate-right' :
27149 this.onRotateRight(e);
27152 this.beforeSelectFile(e);
27167 this.fireEvent('footerbuttonclick', this, type);
27170 beforeSelectFile : function(e)
27172 e.preventDefault();
27174 if(this.fireEvent('beforeselectfile', this) != false){
27175 this.selectorEl.dom.click();
27179 onFileSelected : function(e)
27181 e.preventDefault();
27183 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27187 var file = this.selectorEl.dom.files[0];
27189 if(this.fireEvent('inspect', this, file) != false){
27190 this.prepare(file);
27195 trash : function(e)
27197 this.fireEvent('trash', this);
27200 download : function(e)
27202 this.fireEvent('download', this);
27205 loadCanvas : function(src)
27207 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27211 this.imageEl = document.createElement('img');
27215 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27217 this.imageEl.src = src;
27221 onLoadCanvas : function()
27223 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27224 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27226 this.bodyEl.un('click', this.beforeSelectFile, this);
27228 this.notifyEl.hide();
27229 this.thumbEl.show();
27230 this.footerEl.show();
27232 this.baseRotateLevel();
27234 if(this.isDocument){
27235 this.setThumbBoxSize();
27238 this.setThumbBoxPosition();
27240 this.baseScaleLevel();
27246 this.canvasLoaded = true;
27249 this.maskEl.unmask();
27254 setCanvasPosition : function()
27256 if(!this.canvasEl){
27260 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27261 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27263 this.previewEl.setLeft(pw);
27264 this.previewEl.setTop(ph);
27268 onMouseDown : function(e)
27272 this.dragable = true;
27273 this.pinching = false;
27275 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27276 this.dragable = false;
27280 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27281 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27285 onMouseMove : function(e)
27289 if(!this.canvasLoaded){
27293 if (!this.dragable){
27297 var minX = Math.ceil(this.thumbEl.getLeft(true));
27298 var minY = Math.ceil(this.thumbEl.getTop(true));
27300 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27301 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27303 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27304 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27306 x = x - this.mouseX;
27307 y = y - this.mouseY;
27309 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27310 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27312 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27313 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27315 this.previewEl.setLeft(bgX);
27316 this.previewEl.setTop(bgY);
27318 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27319 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27322 onMouseUp : function(e)
27326 this.dragable = false;
27329 onMouseWheel : function(e)
27333 this.startScale = this.scale;
27335 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27337 if(!this.zoomable()){
27338 this.scale = this.startScale;
27347 zoomable : function()
27349 var minScale = this.thumbEl.getWidth() / this.minWidth;
27351 if(this.minWidth < this.minHeight){
27352 minScale = this.thumbEl.getHeight() / this.minHeight;
27355 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27356 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27360 (this.rotate == 0 || this.rotate == 180) &&
27362 width > this.imageEl.OriginWidth ||
27363 height > this.imageEl.OriginHeight ||
27364 (width < this.minWidth && height < this.minHeight)
27372 (this.rotate == 90 || this.rotate == 270) &&
27374 width > this.imageEl.OriginWidth ||
27375 height > this.imageEl.OriginHeight ||
27376 (width < this.minHeight && height < this.minWidth)
27383 !this.isDocument &&
27384 (this.rotate == 0 || this.rotate == 180) &&
27386 width < this.minWidth ||
27387 width > this.imageEl.OriginWidth ||
27388 height < this.minHeight ||
27389 height > this.imageEl.OriginHeight
27396 !this.isDocument &&
27397 (this.rotate == 90 || this.rotate == 270) &&
27399 width < this.minHeight ||
27400 width > this.imageEl.OriginWidth ||
27401 height < this.minWidth ||
27402 height > this.imageEl.OriginHeight
27412 onRotateLeft : function(e)
27414 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27416 var minScale = this.thumbEl.getWidth() / this.minWidth;
27418 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27419 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27421 this.startScale = this.scale;
27423 while (this.getScaleLevel() < minScale){
27425 this.scale = this.scale + 1;
27427 if(!this.zoomable()){
27432 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27433 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27438 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27445 this.scale = this.startScale;
27447 this.onRotateFail();
27452 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27454 if(this.isDocument){
27455 this.setThumbBoxSize();
27456 this.setThumbBoxPosition();
27457 this.setCanvasPosition();
27462 this.fireEvent('rotate', this, 'left');
27466 onRotateRight : function(e)
27468 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27470 var minScale = this.thumbEl.getWidth() / this.minWidth;
27472 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27473 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27475 this.startScale = this.scale;
27477 while (this.getScaleLevel() < minScale){
27479 this.scale = this.scale + 1;
27481 if(!this.zoomable()){
27486 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27487 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27492 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27499 this.scale = this.startScale;
27501 this.onRotateFail();
27506 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27508 if(this.isDocument){
27509 this.setThumbBoxSize();
27510 this.setThumbBoxPosition();
27511 this.setCanvasPosition();
27516 this.fireEvent('rotate', this, 'right');
27519 onRotateFail : function()
27521 this.errorEl.show(true);
27525 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27530 this.previewEl.dom.innerHTML = '';
27532 var canvasEl = document.createElement("canvas");
27534 var contextEl = canvasEl.getContext("2d");
27536 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27537 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27538 var center = this.imageEl.OriginWidth / 2;
27540 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27541 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27542 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27543 center = this.imageEl.OriginHeight / 2;
27546 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27548 contextEl.translate(center, center);
27549 contextEl.rotate(this.rotate * Math.PI / 180);
27551 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27553 this.canvasEl = document.createElement("canvas");
27555 this.contextEl = this.canvasEl.getContext("2d");
27557 switch (this.rotate) {
27560 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27561 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27563 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27568 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27569 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27571 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27572 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);
27576 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27581 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27582 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27584 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27585 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);
27589 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);
27594 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27595 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27597 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27598 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27602 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);
27609 this.previewEl.appendChild(this.canvasEl);
27611 this.setCanvasPosition();
27616 if(!this.canvasLoaded){
27620 var imageCanvas = document.createElement("canvas");
27622 var imageContext = imageCanvas.getContext("2d");
27624 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27625 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27627 var center = imageCanvas.width / 2;
27629 imageContext.translate(center, center);
27631 imageContext.rotate(this.rotate * Math.PI / 180);
27633 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27635 var canvas = document.createElement("canvas");
27637 var context = canvas.getContext("2d");
27639 canvas.width = this.minWidth;
27640 canvas.height = this.minHeight;
27642 switch (this.rotate) {
27645 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27646 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27648 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27649 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27651 var targetWidth = this.minWidth - 2 * x;
27652 var targetHeight = this.minHeight - 2 * y;
27656 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27657 scale = targetWidth / width;
27660 if(x > 0 && y == 0){
27661 scale = targetHeight / height;
27664 if(x > 0 && y > 0){
27665 scale = targetWidth / width;
27667 if(width < height){
27668 scale = targetHeight / height;
27672 context.scale(scale, scale);
27674 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27675 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27677 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27678 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27680 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27685 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27686 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27688 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27689 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27691 var targetWidth = this.minWidth - 2 * x;
27692 var targetHeight = this.minHeight - 2 * y;
27696 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27697 scale = targetWidth / width;
27700 if(x > 0 && y == 0){
27701 scale = targetHeight / height;
27704 if(x > 0 && y > 0){
27705 scale = targetWidth / width;
27707 if(width < height){
27708 scale = targetHeight / height;
27712 context.scale(scale, scale);
27714 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27715 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27717 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27718 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27720 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27722 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27727 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27728 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27730 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27731 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27733 var targetWidth = this.minWidth - 2 * x;
27734 var targetHeight = this.minHeight - 2 * y;
27738 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27739 scale = targetWidth / width;
27742 if(x > 0 && y == 0){
27743 scale = targetHeight / height;
27746 if(x > 0 && y > 0){
27747 scale = targetWidth / width;
27749 if(width < height){
27750 scale = targetHeight / height;
27754 context.scale(scale, scale);
27756 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27757 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27759 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27760 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27762 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27763 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27765 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27770 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27771 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27773 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27774 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27776 var targetWidth = this.minWidth - 2 * x;
27777 var targetHeight = this.minHeight - 2 * y;
27781 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27782 scale = targetWidth / width;
27785 if(x > 0 && y == 0){
27786 scale = targetHeight / height;
27789 if(x > 0 && y > 0){
27790 scale = targetWidth / width;
27792 if(width < height){
27793 scale = targetHeight / height;
27797 context.scale(scale, scale);
27799 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27800 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27802 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27803 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27805 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27807 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27814 this.cropData = canvas.toDataURL(this.cropType);
27816 if(this.fireEvent('crop', this, this.cropData) !== false){
27817 this.process(this.file, this.cropData);
27824 setThumbBoxSize : function()
27828 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27829 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27830 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27832 this.minWidth = width;
27833 this.minHeight = height;
27835 if(this.rotate == 90 || this.rotate == 270){
27836 this.minWidth = height;
27837 this.minHeight = width;
27842 width = Math.ceil(this.minWidth * height / this.minHeight);
27844 if(this.minWidth > this.minHeight){
27846 height = Math.ceil(this.minHeight * width / this.minWidth);
27849 this.thumbEl.setStyle({
27850 width : width + 'px',
27851 height : height + 'px'
27858 setThumbBoxPosition : function()
27860 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27861 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27863 this.thumbEl.setLeft(x);
27864 this.thumbEl.setTop(y);
27868 baseRotateLevel : function()
27870 this.baseRotate = 1;
27873 typeof(this.exif) != 'undefined' &&
27874 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27875 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27877 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27880 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27884 baseScaleLevel : function()
27888 if(this.isDocument){
27890 if(this.baseRotate == 6 || this.baseRotate == 8){
27892 height = this.thumbEl.getHeight();
27893 this.baseScale = height / this.imageEl.OriginWidth;
27895 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27896 width = this.thumbEl.getWidth();
27897 this.baseScale = width / this.imageEl.OriginHeight;
27903 height = this.thumbEl.getHeight();
27904 this.baseScale = height / this.imageEl.OriginHeight;
27906 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27907 width = this.thumbEl.getWidth();
27908 this.baseScale = width / this.imageEl.OriginWidth;
27914 if(this.baseRotate == 6 || this.baseRotate == 8){
27916 width = this.thumbEl.getHeight();
27917 this.baseScale = width / this.imageEl.OriginHeight;
27919 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27920 height = this.thumbEl.getWidth();
27921 this.baseScale = height / this.imageEl.OriginHeight;
27924 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27925 height = this.thumbEl.getWidth();
27926 this.baseScale = height / this.imageEl.OriginHeight;
27928 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27929 width = this.thumbEl.getHeight();
27930 this.baseScale = width / this.imageEl.OriginWidth;
27937 width = this.thumbEl.getWidth();
27938 this.baseScale = width / this.imageEl.OriginWidth;
27940 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27941 height = this.thumbEl.getHeight();
27942 this.baseScale = height / this.imageEl.OriginHeight;
27945 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27947 height = this.thumbEl.getHeight();
27948 this.baseScale = height / this.imageEl.OriginHeight;
27950 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27951 width = this.thumbEl.getWidth();
27952 this.baseScale = width / this.imageEl.OriginWidth;
27960 getScaleLevel : function()
27962 return this.baseScale * Math.pow(1.1, this.scale);
27965 onTouchStart : function(e)
27967 if(!this.canvasLoaded){
27968 this.beforeSelectFile(e);
27972 var touches = e.browserEvent.touches;
27978 if(touches.length == 1){
27979 this.onMouseDown(e);
27983 if(touches.length != 2){
27989 for(var i = 0, finger; finger = touches[i]; i++){
27990 coords.push(finger.pageX, finger.pageY);
27993 var x = Math.pow(coords[0] - coords[2], 2);
27994 var y = Math.pow(coords[1] - coords[3], 2);
27996 this.startDistance = Math.sqrt(x + y);
27998 this.startScale = this.scale;
28000 this.pinching = true;
28001 this.dragable = false;
28005 onTouchMove : function(e)
28007 if(!this.pinching && !this.dragable){
28011 var touches = e.browserEvent.touches;
28018 this.onMouseMove(e);
28024 for(var i = 0, finger; finger = touches[i]; i++){
28025 coords.push(finger.pageX, finger.pageY);
28028 var x = Math.pow(coords[0] - coords[2], 2);
28029 var y = Math.pow(coords[1] - coords[3], 2);
28031 this.endDistance = Math.sqrt(x + y);
28033 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28035 if(!this.zoomable()){
28036 this.scale = this.startScale;
28044 onTouchEnd : function(e)
28046 this.pinching = false;
28047 this.dragable = false;
28051 process : function(file, crop)
28054 this.maskEl.mask(this.loadingText);
28057 this.xhr = new XMLHttpRequest();
28059 file.xhr = this.xhr;
28061 this.xhr.open(this.method, this.url, true);
28064 "Accept": "application/json",
28065 "Cache-Control": "no-cache",
28066 "X-Requested-With": "XMLHttpRequest"
28069 for (var headerName in headers) {
28070 var headerValue = headers[headerName];
28072 this.xhr.setRequestHeader(headerName, headerValue);
28078 this.xhr.onload = function()
28080 _this.xhrOnLoad(_this.xhr);
28083 this.xhr.onerror = function()
28085 _this.xhrOnError(_this.xhr);
28088 var formData = new FormData();
28090 formData.append('returnHTML', 'NO');
28093 formData.append('crop', crop);
28096 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28097 formData.append(this.paramName, file, file.name);
28100 if(typeof(file.filename) != 'undefined'){
28101 formData.append('filename', file.filename);
28104 if(typeof(file.mimetype) != 'undefined'){
28105 formData.append('mimetype', file.mimetype);
28108 if(this.fireEvent('arrange', this, formData) != false){
28109 this.xhr.send(formData);
28113 xhrOnLoad : function(xhr)
28116 this.maskEl.unmask();
28119 if (xhr.readyState !== 4) {
28120 this.fireEvent('exception', this, xhr);
28124 var response = Roo.decode(xhr.responseText);
28126 if(!response.success){
28127 this.fireEvent('exception', this, xhr);
28131 var response = Roo.decode(xhr.responseText);
28133 this.fireEvent('upload', this, response);
28137 xhrOnError : function()
28140 this.maskEl.unmask();
28143 Roo.log('xhr on error');
28145 var response = Roo.decode(xhr.responseText);
28151 prepare : function(file)
28154 this.maskEl.mask(this.loadingText);
28160 if(typeof(file) === 'string'){
28161 this.loadCanvas(file);
28165 if(!file || !this.urlAPI){
28170 this.cropType = file.type;
28174 if(this.fireEvent('prepare', this, this.file) != false){
28176 var reader = new FileReader();
28178 reader.onload = function (e) {
28179 if (e.target.error) {
28180 Roo.log(e.target.error);
28184 var buffer = e.target.result,
28185 dataView = new DataView(buffer),
28187 maxOffset = dataView.byteLength - 4,
28191 if (dataView.getUint16(0) === 0xffd8) {
28192 while (offset < maxOffset) {
28193 markerBytes = dataView.getUint16(offset);
28195 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28196 markerLength = dataView.getUint16(offset + 2) + 2;
28197 if (offset + markerLength > dataView.byteLength) {
28198 Roo.log('Invalid meta data: Invalid segment size.');
28202 if(markerBytes == 0xffe1){
28203 _this.parseExifData(
28210 offset += markerLength;
28220 var url = _this.urlAPI.createObjectURL(_this.file);
28222 _this.loadCanvas(url);
28227 reader.readAsArrayBuffer(this.file);
28233 parseExifData : function(dataView, offset, length)
28235 var tiffOffset = offset + 10,
28239 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28240 // No Exif data, might be XMP data instead
28244 // Check for the ASCII code for "Exif" (0x45786966):
28245 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28246 // No Exif data, might be XMP data instead
28249 if (tiffOffset + 8 > dataView.byteLength) {
28250 Roo.log('Invalid Exif data: Invalid segment size.');
28253 // Check for the two null bytes:
28254 if (dataView.getUint16(offset + 8) !== 0x0000) {
28255 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28258 // Check the byte alignment:
28259 switch (dataView.getUint16(tiffOffset)) {
28261 littleEndian = true;
28264 littleEndian = false;
28267 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28270 // Check for the TIFF tag marker (0x002A):
28271 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28272 Roo.log('Invalid Exif data: Missing TIFF marker.');
28275 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28276 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28278 this.parseExifTags(
28281 tiffOffset + dirOffset,
28286 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28291 if (dirOffset + 6 > dataView.byteLength) {
28292 Roo.log('Invalid Exif data: Invalid directory offset.');
28295 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28296 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28297 if (dirEndOffset + 4 > dataView.byteLength) {
28298 Roo.log('Invalid Exif data: Invalid directory size.');
28301 for (i = 0; i < tagsNumber; i += 1) {
28305 dirOffset + 2 + 12 * i, // tag offset
28309 // Return the offset to the next directory:
28310 return dataView.getUint32(dirEndOffset, littleEndian);
28313 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28315 var tag = dataView.getUint16(offset, littleEndian);
28317 this.exif[tag] = this.getExifValue(
28321 dataView.getUint16(offset + 2, littleEndian), // tag type
28322 dataView.getUint32(offset + 4, littleEndian), // tag length
28327 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28329 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28338 Roo.log('Invalid Exif data: Invalid tag type.');
28342 tagSize = tagType.size * length;
28343 // Determine if the value is contained in the dataOffset bytes,
28344 // or if the value at the dataOffset is a pointer to the actual data:
28345 dataOffset = tagSize > 4 ?
28346 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28347 if (dataOffset + tagSize > dataView.byteLength) {
28348 Roo.log('Invalid Exif data: Invalid data offset.');
28351 if (length === 1) {
28352 return tagType.getValue(dataView, dataOffset, littleEndian);
28355 for (i = 0; i < length; i += 1) {
28356 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28359 if (tagType.ascii) {
28361 // Concatenate the chars:
28362 for (i = 0; i < values.length; i += 1) {
28364 // Ignore the terminating NULL byte(s):
28365 if (c === '\u0000') {
28377 Roo.apply(Roo.bootstrap.UploadCropbox, {
28379 'Orientation': 0x0112
28383 1: 0, //'top-left',
28385 3: 180, //'bottom-right',
28386 // 4: 'bottom-left',
28388 6: 90, //'right-top',
28389 // 7: 'right-bottom',
28390 8: 270 //'left-bottom'
28394 // byte, 8-bit unsigned int:
28396 getValue: function (dataView, dataOffset) {
28397 return dataView.getUint8(dataOffset);
28401 // ascii, 8-bit byte:
28403 getValue: function (dataView, dataOffset) {
28404 return String.fromCharCode(dataView.getUint8(dataOffset));
28409 // short, 16 bit int:
28411 getValue: function (dataView, dataOffset, littleEndian) {
28412 return dataView.getUint16(dataOffset, littleEndian);
28416 // long, 32 bit int:
28418 getValue: function (dataView, dataOffset, littleEndian) {
28419 return dataView.getUint32(dataOffset, littleEndian);
28423 // rational = two long values, first is numerator, second is denominator:
28425 getValue: function (dataView, dataOffset, littleEndian) {
28426 return dataView.getUint32(dataOffset, littleEndian) /
28427 dataView.getUint32(dataOffset + 4, littleEndian);
28431 // slong, 32 bit signed int:
28433 getValue: function (dataView, dataOffset, littleEndian) {
28434 return dataView.getInt32(dataOffset, littleEndian);
28438 // srational, two slongs, first is numerator, second is denominator:
28440 getValue: function (dataView, dataOffset, littleEndian) {
28441 return dataView.getInt32(dataOffset, littleEndian) /
28442 dataView.getInt32(dataOffset + 4, littleEndian);
28452 cls : 'btn-group roo-upload-cropbox-rotate-left',
28453 action : 'rotate-left',
28457 cls : 'btn btn-default',
28458 html : '<i class="fa fa-undo"></i>'
28464 cls : 'btn-group roo-upload-cropbox-picture',
28465 action : 'picture',
28469 cls : 'btn btn-default',
28470 html : '<i class="fa fa-picture-o"></i>'
28476 cls : 'btn-group roo-upload-cropbox-rotate-right',
28477 action : 'rotate-right',
28481 cls : 'btn btn-default',
28482 html : '<i class="fa fa-repeat"></i>'
28490 cls : 'btn-group roo-upload-cropbox-rotate-left',
28491 action : 'rotate-left',
28495 cls : 'btn btn-default',
28496 html : '<i class="fa fa-undo"></i>'
28502 cls : 'btn-group roo-upload-cropbox-download',
28503 action : 'download',
28507 cls : 'btn btn-default',
28508 html : '<i class="fa fa-download"></i>'
28514 cls : 'btn-group roo-upload-cropbox-crop',
28519 cls : 'btn btn-default',
28520 html : '<i class="fa fa-crop"></i>'
28526 cls : 'btn-group roo-upload-cropbox-trash',
28531 cls : 'btn btn-default',
28532 html : '<i class="fa fa-trash"></i>'
28538 cls : 'btn-group roo-upload-cropbox-rotate-right',
28539 action : 'rotate-right',
28543 cls : 'btn btn-default',
28544 html : '<i class="fa fa-repeat"></i>'
28552 cls : 'btn-group roo-upload-cropbox-rotate-left',
28553 action : 'rotate-left',
28557 cls : 'btn btn-default',
28558 html : '<i class="fa fa-undo"></i>'
28564 cls : 'btn-group roo-upload-cropbox-rotate-right',
28565 action : 'rotate-right',
28569 cls : 'btn btn-default',
28570 html : '<i class="fa fa-repeat"></i>'
28583 * @class Roo.bootstrap.DocumentManager
28584 * @extends Roo.bootstrap.Component
28585 * Bootstrap DocumentManager class
28586 * @cfg {String} paramName default 'imageUpload'
28587 * @cfg {String} toolTipName default 'filename'
28588 * @cfg {String} method default POST
28589 * @cfg {String} url action url
28590 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28591 * @cfg {Boolean} multiple multiple upload default true
28592 * @cfg {Number} thumbSize default 300
28593 * @cfg {String} fieldLabel
28594 * @cfg {Number} labelWidth default 4
28595 * @cfg {String} labelAlign (left|top) default left
28596 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28597 * @cfg {Number} labellg set the width of label (1-12)
28598 * @cfg {Number} labelmd set the width of label (1-12)
28599 * @cfg {Number} labelsm set the width of label (1-12)
28600 * @cfg {Number} labelxs set the width of label (1-12)
28603 * Create a new DocumentManager
28604 * @param {Object} config The config object
28607 Roo.bootstrap.DocumentManager = function(config){
28608 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28611 this.delegates = [];
28616 * Fire when initial the DocumentManager
28617 * @param {Roo.bootstrap.DocumentManager} this
28622 * inspect selected file
28623 * @param {Roo.bootstrap.DocumentManager} this
28624 * @param {File} file
28629 * Fire when xhr load exception
28630 * @param {Roo.bootstrap.DocumentManager} this
28631 * @param {XMLHttpRequest} xhr
28633 "exception" : true,
28635 * @event afterupload
28636 * Fire when xhr load exception
28637 * @param {Roo.bootstrap.DocumentManager} this
28638 * @param {XMLHttpRequest} xhr
28640 "afterupload" : true,
28643 * prepare the form data
28644 * @param {Roo.bootstrap.DocumentManager} this
28645 * @param {Object} formData
28650 * Fire when remove the file
28651 * @param {Roo.bootstrap.DocumentManager} this
28652 * @param {Object} file
28657 * Fire after refresh the file
28658 * @param {Roo.bootstrap.DocumentManager} this
28663 * Fire after click the image
28664 * @param {Roo.bootstrap.DocumentManager} this
28665 * @param {Object} file
28670 * Fire when upload a image and editable set to true
28671 * @param {Roo.bootstrap.DocumentManager} this
28672 * @param {Object} file
28676 * @event beforeselectfile
28677 * Fire before select file
28678 * @param {Roo.bootstrap.DocumentManager} this
28680 "beforeselectfile" : true,
28683 * Fire before process file
28684 * @param {Roo.bootstrap.DocumentManager} this
28685 * @param {Object} file
28689 * @event previewrendered
28690 * Fire when preview rendered
28691 * @param {Roo.bootstrap.DocumentManager} this
28692 * @param {Object} file
28694 "previewrendered" : true
28699 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28708 paramName : 'imageUpload',
28709 toolTipName : 'filename',
28712 labelAlign : 'left',
28722 getAutoCreate : function()
28724 var managerWidget = {
28726 cls : 'roo-document-manager',
28730 cls : 'roo-document-manager-selector',
28735 cls : 'roo-document-manager-uploader',
28739 cls : 'roo-document-manager-upload-btn',
28740 html : '<i class="fa fa-plus"></i>'
28751 cls : 'column col-md-12',
28756 if(this.fieldLabel.length){
28761 cls : 'column col-md-12',
28762 html : this.fieldLabel
28766 cls : 'column col-md-12',
28771 if(this.labelAlign == 'left'){
28776 html : this.fieldLabel
28785 if(this.labelWidth > 12){
28786 content[0].style = "width: " + this.labelWidth + 'px';
28789 if(this.labelWidth < 13 && this.labelmd == 0){
28790 this.labelmd = this.labelWidth;
28793 if(this.labellg > 0){
28794 content[0].cls += ' col-lg-' + this.labellg;
28795 content[1].cls += ' col-lg-' + (12 - this.labellg);
28798 if(this.labelmd > 0){
28799 content[0].cls += ' col-md-' + this.labelmd;
28800 content[1].cls += ' col-md-' + (12 - this.labelmd);
28803 if(this.labelsm > 0){
28804 content[0].cls += ' col-sm-' + this.labelsm;
28805 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28808 if(this.labelxs > 0){
28809 content[0].cls += ' col-xs-' + this.labelxs;
28810 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28818 cls : 'row clearfix',
28826 initEvents : function()
28828 this.managerEl = this.el.select('.roo-document-manager', true).first();
28829 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28831 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28832 this.selectorEl.hide();
28835 this.selectorEl.attr('multiple', 'multiple');
28838 this.selectorEl.on('change', this.onFileSelected, this);
28840 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28841 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28843 this.uploader.on('click', this.onUploaderClick, this);
28845 this.renderProgressDialog();
28849 window.addEventListener("resize", function() { _this.refresh(); } );
28851 this.fireEvent('initial', this);
28854 renderProgressDialog : function()
28858 this.progressDialog = new Roo.bootstrap.Modal({
28859 cls : 'roo-document-manager-progress-dialog',
28860 allow_close : false,
28870 btnclick : function() {
28871 _this.uploadCancel();
28877 this.progressDialog.render(Roo.get(document.body));
28879 this.progress = new Roo.bootstrap.Progress({
28880 cls : 'roo-document-manager-progress',
28885 this.progress.render(this.progressDialog.getChildContainer());
28887 this.progressBar = new Roo.bootstrap.ProgressBar({
28888 cls : 'roo-document-manager-progress-bar',
28891 aria_valuemax : 12,
28895 this.progressBar.render(this.progress.getChildContainer());
28898 onUploaderClick : function(e)
28900 e.preventDefault();
28902 if(this.fireEvent('beforeselectfile', this) != false){
28903 this.selectorEl.dom.click();
28908 onFileSelected : function(e)
28910 e.preventDefault();
28912 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28916 Roo.each(this.selectorEl.dom.files, function(file){
28917 if(this.fireEvent('inspect', this, file) != false){
28918 this.files.push(file);
28928 this.selectorEl.dom.value = '';
28930 if(!this.files || !this.files.length){
28934 if(this.boxes > 0 && this.files.length > this.boxes){
28935 this.files = this.files.slice(0, this.boxes);
28938 this.uploader.show();
28940 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28941 this.uploader.hide();
28950 Roo.each(this.files, function(file){
28952 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28953 var f = this.renderPreview(file);
28958 if(file.type.indexOf('image') != -1){
28959 this.delegates.push(
28961 _this.process(file);
28962 }).createDelegate(this)
28970 _this.process(file);
28971 }).createDelegate(this)
28976 this.files = files;
28978 this.delegates = this.delegates.concat(docs);
28980 if(!this.delegates.length){
28985 this.progressBar.aria_valuemax = this.delegates.length;
28992 arrange : function()
28994 if(!this.delegates.length){
28995 this.progressDialog.hide();
29000 var delegate = this.delegates.shift();
29002 this.progressDialog.show();
29004 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29006 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29011 refresh : function()
29013 this.uploader.show();
29015 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29016 this.uploader.hide();
29019 Roo.isTouch ? this.closable(false) : this.closable(true);
29021 this.fireEvent('refresh', this);
29024 onRemove : function(e, el, o)
29026 e.preventDefault();
29028 this.fireEvent('remove', this, o);
29032 remove : function(o)
29036 Roo.each(this.files, function(file){
29037 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29046 this.files = files;
29053 Roo.each(this.files, function(file){
29058 file.target.remove();
29067 onClick : function(e, el, o)
29069 e.preventDefault();
29071 this.fireEvent('click', this, o);
29075 closable : function(closable)
29077 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29079 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29091 xhrOnLoad : function(xhr)
29093 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29097 if (xhr.readyState !== 4) {
29099 this.fireEvent('exception', this, xhr);
29103 var response = Roo.decode(xhr.responseText);
29105 if(!response.success){
29107 this.fireEvent('exception', this, xhr);
29111 var file = this.renderPreview(response.data);
29113 this.files.push(file);
29117 this.fireEvent('afterupload', this, xhr);
29121 xhrOnError : function(xhr)
29123 Roo.log('xhr on error');
29125 var response = Roo.decode(xhr.responseText);
29132 process : function(file)
29134 if(this.fireEvent('process', this, file) !== false){
29135 if(this.editable && file.type.indexOf('image') != -1){
29136 this.fireEvent('edit', this, file);
29140 this.uploadStart(file, false);
29147 uploadStart : function(file, crop)
29149 this.xhr = new XMLHttpRequest();
29151 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29156 file.xhr = this.xhr;
29158 this.managerEl.createChild({
29160 cls : 'roo-document-manager-loading',
29164 tooltip : file.name,
29165 cls : 'roo-document-manager-thumb',
29166 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29172 this.xhr.open(this.method, this.url, true);
29175 "Accept": "application/json",
29176 "Cache-Control": "no-cache",
29177 "X-Requested-With": "XMLHttpRequest"
29180 for (var headerName in headers) {
29181 var headerValue = headers[headerName];
29183 this.xhr.setRequestHeader(headerName, headerValue);
29189 this.xhr.onload = function()
29191 _this.xhrOnLoad(_this.xhr);
29194 this.xhr.onerror = function()
29196 _this.xhrOnError(_this.xhr);
29199 var formData = new FormData();
29201 formData.append('returnHTML', 'NO');
29204 formData.append('crop', crop);
29207 formData.append(this.paramName, file, file.name);
29214 if(this.fireEvent('prepare', this, formData, options) != false){
29216 if(options.manually){
29220 this.xhr.send(formData);
29224 this.uploadCancel();
29227 uploadCancel : function()
29233 this.delegates = [];
29235 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29242 renderPreview : function(file)
29244 if(typeof(file.target) != 'undefined' && file.target){
29248 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29250 var previewEl = this.managerEl.createChild({
29252 cls : 'roo-document-manager-preview',
29256 tooltip : file[this.toolTipName],
29257 cls : 'roo-document-manager-thumb',
29258 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29263 html : '<i class="fa fa-times-circle"></i>'
29268 var close = previewEl.select('button.close', true).first();
29270 close.on('click', this.onRemove, this, file);
29272 file.target = previewEl;
29274 var image = previewEl.select('img', true).first();
29278 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29280 image.on('click', this.onClick, this, file);
29282 this.fireEvent('previewrendered', this, file);
29288 onPreviewLoad : function(file, image)
29290 if(typeof(file.target) == 'undefined' || !file.target){
29294 var width = image.dom.naturalWidth || image.dom.width;
29295 var height = image.dom.naturalHeight || image.dom.height;
29297 if(width > height){
29298 file.target.addClass('wide');
29302 file.target.addClass('tall');
29307 uploadFromSource : function(file, crop)
29309 this.xhr = new XMLHttpRequest();
29311 this.managerEl.createChild({
29313 cls : 'roo-document-manager-loading',
29317 tooltip : file.name,
29318 cls : 'roo-document-manager-thumb',
29319 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29325 this.xhr.open(this.method, this.url, true);
29328 "Accept": "application/json",
29329 "Cache-Control": "no-cache",
29330 "X-Requested-With": "XMLHttpRequest"
29333 for (var headerName in headers) {
29334 var headerValue = headers[headerName];
29336 this.xhr.setRequestHeader(headerName, headerValue);
29342 this.xhr.onload = function()
29344 _this.xhrOnLoad(_this.xhr);
29347 this.xhr.onerror = function()
29349 _this.xhrOnError(_this.xhr);
29352 var formData = new FormData();
29354 formData.append('returnHTML', 'NO');
29356 formData.append('crop', crop);
29358 if(typeof(file.filename) != 'undefined'){
29359 formData.append('filename', file.filename);
29362 if(typeof(file.mimetype) != 'undefined'){
29363 formData.append('mimetype', file.mimetype);
29368 if(this.fireEvent('prepare', this, formData) != false){
29369 this.xhr.send(formData);
29379 * @class Roo.bootstrap.DocumentViewer
29380 * @extends Roo.bootstrap.Component
29381 * Bootstrap DocumentViewer class
29382 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29383 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29386 * Create a new DocumentViewer
29387 * @param {Object} config The config object
29390 Roo.bootstrap.DocumentViewer = function(config){
29391 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29396 * Fire after initEvent
29397 * @param {Roo.bootstrap.DocumentViewer} this
29403 * @param {Roo.bootstrap.DocumentViewer} this
29408 * Fire after download button
29409 * @param {Roo.bootstrap.DocumentViewer} this
29414 * Fire after trash button
29415 * @param {Roo.bootstrap.DocumentViewer} this
29422 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29424 showDownload : true,
29428 getAutoCreate : function()
29432 cls : 'roo-document-viewer',
29436 cls : 'roo-document-viewer-body',
29440 cls : 'roo-document-viewer-thumb',
29444 cls : 'roo-document-viewer-image'
29452 cls : 'roo-document-viewer-footer',
29455 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29459 cls : 'btn-group roo-document-viewer-download',
29463 cls : 'btn btn-default',
29464 html : '<i class="fa fa-download"></i>'
29470 cls : 'btn-group roo-document-viewer-trash',
29474 cls : 'btn btn-default',
29475 html : '<i class="fa fa-trash"></i>'
29488 initEvents : function()
29490 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29491 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29493 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29494 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29496 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29497 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29499 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29500 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29502 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29503 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29505 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29506 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29508 this.bodyEl.on('click', this.onClick, this);
29509 this.downloadBtn.on('click', this.onDownload, this);
29510 this.trashBtn.on('click', this.onTrash, this);
29512 this.downloadBtn.hide();
29513 this.trashBtn.hide();
29515 if(this.showDownload){
29516 this.downloadBtn.show();
29519 if(this.showTrash){
29520 this.trashBtn.show();
29523 if(!this.showDownload && !this.showTrash) {
29524 this.footerEl.hide();
29529 initial : function()
29531 this.fireEvent('initial', this);
29535 onClick : function(e)
29537 e.preventDefault();
29539 this.fireEvent('click', this);
29542 onDownload : function(e)
29544 e.preventDefault();
29546 this.fireEvent('download', this);
29549 onTrash : function(e)
29551 e.preventDefault();
29553 this.fireEvent('trash', this);
29565 * @class Roo.bootstrap.NavProgressBar
29566 * @extends Roo.bootstrap.Component
29567 * Bootstrap NavProgressBar class
29570 * Create a new nav progress bar
29571 * @param {Object} config The config object
29574 Roo.bootstrap.NavProgressBar = function(config){
29575 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29577 this.bullets = this.bullets || [];
29579 // Roo.bootstrap.NavProgressBar.register(this);
29583 * Fires when the active item changes
29584 * @param {Roo.bootstrap.NavProgressBar} this
29585 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29586 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29593 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29598 getAutoCreate : function()
29600 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29604 cls : 'roo-navigation-bar-group',
29608 cls : 'roo-navigation-top-bar'
29612 cls : 'roo-navigation-bullets-bar',
29616 cls : 'roo-navigation-bar'
29623 cls : 'roo-navigation-bottom-bar'
29633 initEvents: function()
29638 onRender : function(ct, position)
29640 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29642 if(this.bullets.length){
29643 Roo.each(this.bullets, function(b){
29652 addItem : function(cfg)
29654 var item = new Roo.bootstrap.NavProgressItem(cfg);
29656 item.parentId = this.id;
29657 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29660 var top = new Roo.bootstrap.Element({
29662 cls : 'roo-navigation-bar-text'
29665 var bottom = new Roo.bootstrap.Element({
29667 cls : 'roo-navigation-bar-text'
29670 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29671 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29673 var topText = new Roo.bootstrap.Element({
29675 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29678 var bottomText = new Roo.bootstrap.Element({
29680 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29683 topText.onRender(top.el, null);
29684 bottomText.onRender(bottom.el, null);
29687 item.bottomEl = bottom;
29690 this.barItems.push(item);
29695 getActive : function()
29697 var active = false;
29699 Roo.each(this.barItems, function(v){
29701 if (!v.isActive()) {
29713 setActiveItem : function(item)
29717 Roo.each(this.barItems, function(v){
29718 if (v.rid == item.rid) {
29722 if (v.isActive()) {
29723 v.setActive(false);
29728 item.setActive(true);
29730 this.fireEvent('changed', this, item, prev);
29733 getBarItem: function(rid)
29737 Roo.each(this.barItems, function(e) {
29738 if (e.rid != rid) {
29749 indexOfItem : function(item)
29753 Roo.each(this.barItems, function(v, i){
29755 if (v.rid != item.rid) {
29766 setActiveNext : function()
29768 var i = this.indexOfItem(this.getActive());
29770 if (i > this.barItems.length) {
29774 this.setActiveItem(this.barItems[i+1]);
29777 setActivePrev : function()
29779 var i = this.indexOfItem(this.getActive());
29785 this.setActiveItem(this.barItems[i-1]);
29788 format : function()
29790 if(!this.barItems.length){
29794 var width = 100 / this.barItems.length;
29796 Roo.each(this.barItems, function(i){
29797 i.el.setStyle('width', width + '%');
29798 i.topEl.el.setStyle('width', width + '%');
29799 i.bottomEl.el.setStyle('width', width + '%');
29808 * Nav Progress Item
29813 * @class Roo.bootstrap.NavProgressItem
29814 * @extends Roo.bootstrap.Component
29815 * Bootstrap NavProgressItem class
29816 * @cfg {String} rid the reference id
29817 * @cfg {Boolean} active (true|false) Is item active default false
29818 * @cfg {Boolean} disabled (true|false) Is item active default false
29819 * @cfg {String} html
29820 * @cfg {String} position (top|bottom) text position default bottom
29821 * @cfg {String} icon show icon instead of number
29824 * Create a new NavProgressItem
29825 * @param {Object} config The config object
29827 Roo.bootstrap.NavProgressItem = function(config){
29828 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29833 * The raw click event for the entire grid.
29834 * @param {Roo.bootstrap.NavProgressItem} this
29835 * @param {Roo.EventObject} e
29842 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29848 position : 'bottom',
29851 getAutoCreate : function()
29853 var iconCls = 'roo-navigation-bar-item-icon';
29855 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29859 cls: 'roo-navigation-bar-item',
29869 cfg.cls += ' active';
29872 cfg.cls += ' disabled';
29878 disable : function()
29880 this.setDisabled(true);
29883 enable : function()
29885 this.setDisabled(false);
29888 initEvents: function()
29890 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29892 this.iconEl.on('click', this.onClick, this);
29895 onClick : function(e)
29897 e.preventDefault();
29903 if(this.fireEvent('click', this, e) === false){
29907 this.parent().setActiveItem(this);
29910 isActive: function ()
29912 return this.active;
29915 setActive : function(state)
29917 if(this.active == state){
29921 this.active = state;
29924 this.el.addClass('active');
29928 this.el.removeClass('active');
29933 setDisabled : function(state)
29935 if(this.disabled == state){
29939 this.disabled = state;
29942 this.el.addClass('disabled');
29946 this.el.removeClass('disabled');
29949 tooltipEl : function()
29951 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29964 * @class Roo.bootstrap.FieldLabel
29965 * @extends Roo.bootstrap.Component
29966 * Bootstrap FieldLabel class
29967 * @cfg {String} html contents of the element
29968 * @cfg {String} tag tag of the element default label
29969 * @cfg {String} cls class of the element
29970 * @cfg {String} target label target
29971 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29972 * @cfg {String} invalidClass default "text-warning"
29973 * @cfg {String} validClass default "text-success"
29974 * @cfg {String} iconTooltip default "This field is required"
29975 * @cfg {String} indicatorpos (left|right) default left
29978 * Create a new FieldLabel
29979 * @param {Object} config The config object
29982 Roo.bootstrap.FieldLabel = function(config){
29983 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29988 * Fires after the field has been marked as invalid.
29989 * @param {Roo.form.FieldLabel} this
29990 * @param {String} msg The validation message
29995 * Fires after the field has been validated with no errors.
29996 * @param {Roo.form.FieldLabel} this
30002 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30009 invalidClass : 'has-warning',
30010 validClass : 'has-success',
30011 iconTooltip : 'This field is required',
30012 indicatorpos : 'left',
30014 getAutoCreate : function(){
30018 cls : 'roo-bootstrap-field-label ' + this.cls,
30023 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30024 tooltip : this.iconTooltip
30033 if(this.indicatorpos == 'right'){
30036 cls : 'roo-bootstrap-field-label ' + this.cls,
30045 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30046 tooltip : this.iconTooltip
30055 initEvents: function()
30057 Roo.bootstrap.Element.superclass.initEvents.call(this);
30059 this.indicator = this.indicatorEl();
30061 if(this.indicator){
30062 this.indicator.removeClass('visible');
30063 this.indicator.addClass('invisible');
30066 Roo.bootstrap.FieldLabel.register(this);
30069 indicatorEl : function()
30071 var indicator = this.el.select('i.roo-required-indicator',true).first();
30082 * Mark this field as valid
30084 markValid : function()
30086 if(this.indicator){
30087 this.indicator.removeClass('visible');
30088 this.indicator.addClass('invisible');
30091 this.el.removeClass(this.invalidClass);
30093 this.el.addClass(this.validClass);
30095 this.fireEvent('valid', this);
30099 * Mark this field as invalid
30100 * @param {String} msg The validation message
30102 markInvalid : function(msg)
30104 if(this.indicator){
30105 this.indicator.removeClass('invisible');
30106 this.indicator.addClass('visible');
30109 this.el.removeClass(this.validClass);
30111 this.el.addClass(this.invalidClass);
30113 this.fireEvent('invalid', this, msg);
30119 Roo.apply(Roo.bootstrap.FieldLabel, {
30124 * register a FieldLabel Group
30125 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30127 register : function(label)
30129 if(this.groups.hasOwnProperty(label.target)){
30133 this.groups[label.target] = label;
30137 * fetch a FieldLabel Group based on the target
30138 * @param {string} target
30139 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30141 get: function(target) {
30142 if (typeof(this.groups[target]) == 'undefined') {
30146 return this.groups[target] ;
30155 * page DateSplitField.
30161 * @class Roo.bootstrap.DateSplitField
30162 * @extends Roo.bootstrap.Component
30163 * Bootstrap DateSplitField class
30164 * @cfg {string} fieldLabel - the label associated
30165 * @cfg {Number} labelWidth set the width of label (0-12)
30166 * @cfg {String} labelAlign (top|left)
30167 * @cfg {Boolean} dayAllowBlank (true|false) default false
30168 * @cfg {Boolean} monthAllowBlank (true|false) default false
30169 * @cfg {Boolean} yearAllowBlank (true|false) default false
30170 * @cfg {string} dayPlaceholder
30171 * @cfg {string} monthPlaceholder
30172 * @cfg {string} yearPlaceholder
30173 * @cfg {string} dayFormat default 'd'
30174 * @cfg {string} monthFormat default 'm'
30175 * @cfg {string} yearFormat default 'Y'
30176 * @cfg {Number} labellg set the width of label (1-12)
30177 * @cfg {Number} labelmd set the width of label (1-12)
30178 * @cfg {Number} labelsm set the width of label (1-12)
30179 * @cfg {Number} labelxs set the width of label (1-12)
30183 * Create a new DateSplitField
30184 * @param {Object} config The config object
30187 Roo.bootstrap.DateSplitField = function(config){
30188 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30194 * getting the data of years
30195 * @param {Roo.bootstrap.DateSplitField} this
30196 * @param {Object} years
30201 * getting the data of days
30202 * @param {Roo.bootstrap.DateSplitField} this
30203 * @param {Object} days
30208 * Fires after the field has been marked as invalid.
30209 * @param {Roo.form.Field} this
30210 * @param {String} msg The validation message
30215 * Fires after the field has been validated with no errors.
30216 * @param {Roo.form.Field} this
30222 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30225 labelAlign : 'top',
30227 dayAllowBlank : false,
30228 monthAllowBlank : false,
30229 yearAllowBlank : false,
30230 dayPlaceholder : '',
30231 monthPlaceholder : '',
30232 yearPlaceholder : '',
30236 isFormField : true,
30242 getAutoCreate : function()
30246 cls : 'row roo-date-split-field-group',
30251 cls : 'form-hidden-field roo-date-split-field-group-value',
30257 var labelCls = 'col-md-12';
30258 var contentCls = 'col-md-4';
30260 if(this.fieldLabel){
30264 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30268 html : this.fieldLabel
30273 if(this.labelAlign == 'left'){
30275 if(this.labelWidth > 12){
30276 label.style = "width: " + this.labelWidth + 'px';
30279 if(this.labelWidth < 13 && this.labelmd == 0){
30280 this.labelmd = this.labelWidth;
30283 if(this.labellg > 0){
30284 labelCls = ' col-lg-' + this.labellg;
30285 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30288 if(this.labelmd > 0){
30289 labelCls = ' col-md-' + this.labelmd;
30290 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30293 if(this.labelsm > 0){
30294 labelCls = ' col-sm-' + this.labelsm;
30295 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30298 if(this.labelxs > 0){
30299 labelCls = ' col-xs-' + this.labelxs;
30300 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30304 label.cls += ' ' + labelCls;
30306 cfg.cn.push(label);
30309 Roo.each(['day', 'month', 'year'], function(t){
30312 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30319 inputEl: function ()
30321 return this.el.select('.roo-date-split-field-group-value', true).first();
30324 onRender : function(ct, position)
30328 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30330 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30332 this.dayField = new Roo.bootstrap.ComboBox({
30333 allowBlank : this.dayAllowBlank,
30334 alwaysQuery : true,
30335 displayField : 'value',
30338 forceSelection : true,
30340 placeholder : this.dayPlaceholder,
30341 selectOnFocus : true,
30342 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30343 triggerAction : 'all',
30345 valueField : 'value',
30346 store : new Roo.data.SimpleStore({
30347 data : (function() {
30349 _this.fireEvent('days', _this, days);
30352 fields : [ 'value' ]
30355 select : function (_self, record, index)
30357 _this.setValue(_this.getValue());
30362 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30364 this.monthField = new Roo.bootstrap.MonthField({
30365 after : '<i class=\"fa fa-calendar\"></i>',
30366 allowBlank : this.monthAllowBlank,
30367 placeholder : this.monthPlaceholder,
30370 render : function (_self)
30372 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30373 e.preventDefault();
30377 select : function (_self, oldvalue, newvalue)
30379 _this.setValue(_this.getValue());
30384 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30386 this.yearField = new Roo.bootstrap.ComboBox({
30387 allowBlank : this.yearAllowBlank,
30388 alwaysQuery : true,
30389 displayField : 'value',
30392 forceSelection : true,
30394 placeholder : this.yearPlaceholder,
30395 selectOnFocus : true,
30396 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30397 triggerAction : 'all',
30399 valueField : 'value',
30400 store : new Roo.data.SimpleStore({
30401 data : (function() {
30403 _this.fireEvent('years', _this, years);
30406 fields : [ 'value' ]
30409 select : function (_self, record, index)
30411 _this.setValue(_this.getValue());
30416 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30419 setValue : function(v, format)
30421 this.inputEl.dom.value = v;
30423 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30425 var d = Date.parseDate(v, f);
30432 this.setDay(d.format(this.dayFormat));
30433 this.setMonth(d.format(this.monthFormat));
30434 this.setYear(d.format(this.yearFormat));
30441 setDay : function(v)
30443 this.dayField.setValue(v);
30444 this.inputEl.dom.value = this.getValue();
30449 setMonth : function(v)
30451 this.monthField.setValue(v, true);
30452 this.inputEl.dom.value = this.getValue();
30457 setYear : function(v)
30459 this.yearField.setValue(v);
30460 this.inputEl.dom.value = this.getValue();
30465 getDay : function()
30467 return this.dayField.getValue();
30470 getMonth : function()
30472 return this.monthField.getValue();
30475 getYear : function()
30477 return this.yearField.getValue();
30480 getValue : function()
30482 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30484 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30494 this.inputEl.dom.value = '';
30499 validate : function()
30501 var d = this.dayField.validate();
30502 var m = this.monthField.validate();
30503 var y = this.yearField.validate();
30508 (!this.dayAllowBlank && !d) ||
30509 (!this.monthAllowBlank && !m) ||
30510 (!this.yearAllowBlank && !y)
30515 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30524 this.markInvalid();
30529 markValid : function()
30532 var label = this.el.select('label', true).first();
30533 var icon = this.el.select('i.fa-star', true).first();
30539 this.fireEvent('valid', this);
30543 * Mark this field as invalid
30544 * @param {String} msg The validation message
30546 markInvalid : function(msg)
30549 var label = this.el.select('label', true).first();
30550 var icon = this.el.select('i.fa-star', true).first();
30552 if(label && !icon){
30553 this.el.select('.roo-date-split-field-label', true).createChild({
30555 cls : 'text-danger fa fa-lg fa-star',
30556 tooltip : 'This field is required',
30557 style : 'margin-right:5px;'
30561 this.fireEvent('invalid', this, msg);
30564 clearInvalid : function()
30566 var label = this.el.select('label', true).first();
30567 var icon = this.el.select('i.fa-star', true).first();
30573 this.fireEvent('valid', this);
30576 getName: function()
30586 * http://masonry.desandro.com
30588 * The idea is to render all the bricks based on vertical width...
30590 * The original code extends 'outlayer' - we might need to use that....
30596 * @class Roo.bootstrap.LayoutMasonry
30597 * @extends Roo.bootstrap.Component
30598 * Bootstrap Layout Masonry class
30601 * Create a new Element
30602 * @param {Object} config The config object
30605 Roo.bootstrap.LayoutMasonry = function(config){
30607 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30611 Roo.bootstrap.LayoutMasonry.register(this);
30617 * Fire after layout the items
30618 * @param {Roo.bootstrap.LayoutMasonry} this
30619 * @param {Roo.EventObject} e
30626 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30629 * @cfg {Boolean} isLayoutInstant = no animation?
30631 isLayoutInstant : false, // needed?
30634 * @cfg {Number} boxWidth width of the columns
30639 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30644 * @cfg {Number} padWidth padding below box..
30649 * @cfg {Number} gutter gutter width..
30654 * @cfg {Number} maxCols maximum number of columns
30660 * @cfg {Boolean} isAutoInitial defalut true
30662 isAutoInitial : true,
30667 * @cfg {Boolean} isHorizontal defalut false
30669 isHorizontal : false,
30671 currentSize : null,
30677 bricks: null, //CompositeElement
30681 _isLayoutInited : false,
30683 // isAlternative : false, // only use for vertical layout...
30686 * @cfg {Number} alternativePadWidth padding below box..
30688 alternativePadWidth : 50,
30690 selectedBrick : [],
30692 getAutoCreate : function(){
30694 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30698 cls: 'blog-masonary-wrapper ' + this.cls,
30700 cls : 'mas-boxes masonary'
30707 getChildContainer: function( )
30709 if (this.boxesEl) {
30710 return this.boxesEl;
30713 this.boxesEl = this.el.select('.mas-boxes').first();
30715 return this.boxesEl;
30719 initEvents : function()
30723 if(this.isAutoInitial){
30724 Roo.log('hook children rendered');
30725 this.on('childrenrendered', function() {
30726 Roo.log('children rendered');
30732 initial : function()
30734 this.selectedBrick = [];
30736 this.currentSize = this.el.getBox(true);
30738 Roo.EventManager.onWindowResize(this.resize, this);
30740 if(!this.isAutoInitial){
30748 //this.layout.defer(500,this);
30752 resize : function()
30754 var cs = this.el.getBox(true);
30757 this.currentSize.width == cs.width &&
30758 this.currentSize.x == cs.x &&
30759 this.currentSize.height == cs.height &&
30760 this.currentSize.y == cs.y
30762 Roo.log("no change in with or X or Y");
30766 this.currentSize = cs;
30772 layout : function()
30774 this._resetLayout();
30776 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30778 this.layoutItems( isInstant );
30780 this._isLayoutInited = true;
30782 this.fireEvent('layout', this);
30786 _resetLayout : function()
30788 if(this.isHorizontal){
30789 this.horizontalMeasureColumns();
30793 this.verticalMeasureColumns();
30797 verticalMeasureColumns : function()
30799 this.getContainerWidth();
30801 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30802 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30806 var boxWidth = this.boxWidth + this.padWidth;
30808 if(this.containerWidth < this.boxWidth){
30809 boxWidth = this.containerWidth
30812 var containerWidth = this.containerWidth;
30814 var cols = Math.floor(containerWidth / boxWidth);
30816 this.cols = Math.max( cols, 1 );
30818 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30820 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30822 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30824 this.colWidth = boxWidth + avail - this.padWidth;
30826 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30827 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30830 horizontalMeasureColumns : function()
30832 this.getContainerWidth();
30834 var boxWidth = this.boxWidth;
30836 if(this.containerWidth < boxWidth){
30837 boxWidth = this.containerWidth;
30840 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30842 this.el.setHeight(boxWidth);
30846 getContainerWidth : function()
30848 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30851 layoutItems : function( isInstant )
30853 Roo.log(this.bricks);
30855 var items = Roo.apply([], this.bricks);
30857 if(this.isHorizontal){
30858 this._horizontalLayoutItems( items , isInstant );
30862 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30863 // this._verticalAlternativeLayoutItems( items , isInstant );
30867 this._verticalLayoutItems( items , isInstant );
30871 _verticalLayoutItems : function ( items , isInstant)
30873 if ( !items || !items.length ) {
30878 ['xs', 'xs', 'xs', 'tall'],
30879 ['xs', 'xs', 'tall'],
30880 ['xs', 'xs', 'sm'],
30881 ['xs', 'xs', 'xs'],
30887 ['sm', 'xs', 'xs'],
30891 ['tall', 'xs', 'xs', 'xs'],
30892 ['tall', 'xs', 'xs'],
30904 Roo.each(items, function(item, k){
30906 switch (item.size) {
30907 // these layouts take up a full box,
30918 boxes.push([item]);
30941 var filterPattern = function(box, length)
30949 var pattern = box.slice(0, length);
30953 Roo.each(pattern, function(i){
30954 format.push(i.size);
30957 Roo.each(standard, function(s){
30959 if(String(s) != String(format)){
30968 if(!match && length == 1){
30973 filterPattern(box, length - 1);
30977 queue.push(pattern);
30979 box = box.slice(length, box.length);
30981 filterPattern(box, 4);
30987 Roo.each(boxes, function(box, k){
30993 if(box.length == 1){
30998 filterPattern(box, 4);
31002 this._processVerticalLayoutQueue( queue, isInstant );
31006 // _verticalAlternativeLayoutItems : function( items , isInstant )
31008 // if ( !items || !items.length ) {
31012 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31016 _horizontalLayoutItems : function ( items , isInstant)
31018 if ( !items || !items.length || items.length < 3) {
31024 var eItems = items.slice(0, 3);
31026 items = items.slice(3, items.length);
31029 ['xs', 'xs', 'xs', 'wide'],
31030 ['xs', 'xs', 'wide'],
31031 ['xs', 'xs', 'sm'],
31032 ['xs', 'xs', 'xs'],
31038 ['sm', 'xs', 'xs'],
31042 ['wide', 'xs', 'xs', 'xs'],
31043 ['wide', 'xs', 'xs'],
31056 Roo.each(items, function(item, k){
31058 switch (item.size) {
31069 boxes.push([item]);
31093 var filterPattern = function(box, length)
31101 var pattern = box.slice(0, length);
31105 Roo.each(pattern, function(i){
31106 format.push(i.size);
31109 Roo.each(standard, function(s){
31111 if(String(s) != String(format)){
31120 if(!match && length == 1){
31125 filterPattern(box, length - 1);
31129 queue.push(pattern);
31131 box = box.slice(length, box.length);
31133 filterPattern(box, 4);
31139 Roo.each(boxes, function(box, k){
31145 if(box.length == 1){
31150 filterPattern(box, 4);
31157 var pos = this.el.getBox(true);
31161 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31163 var hit_end = false;
31165 Roo.each(queue, function(box){
31169 Roo.each(box, function(b){
31171 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31181 Roo.each(box, function(b){
31183 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31186 mx = Math.max(mx, b.x);
31190 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31194 Roo.each(box, function(b){
31196 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31210 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31213 /** Sets position of item in DOM
31214 * @param {Element} item
31215 * @param {Number} x - horizontal position
31216 * @param {Number} y - vertical position
31217 * @param {Boolean} isInstant - disables transitions
31219 _processVerticalLayoutQueue : function( queue, isInstant )
31221 var pos = this.el.getBox(true);
31226 for (var i = 0; i < this.cols; i++){
31230 Roo.each(queue, function(box, k){
31232 var col = k % this.cols;
31234 Roo.each(box, function(b,kk){
31236 b.el.position('absolute');
31238 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31239 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31241 if(b.size == 'md-left' || b.size == 'md-right'){
31242 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31243 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31246 b.el.setWidth(width);
31247 b.el.setHeight(height);
31249 b.el.select('iframe',true).setSize(width,height);
31253 for (var i = 0; i < this.cols; i++){
31255 if(maxY[i] < maxY[col]){
31260 col = Math.min(col, i);
31264 x = pos.x + col * (this.colWidth + this.padWidth);
31268 var positions = [];
31270 switch (box.length){
31272 positions = this.getVerticalOneBoxColPositions(x, y, box);
31275 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31278 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31281 positions = this.getVerticalFourBoxColPositions(x, y, box);
31287 Roo.each(box, function(b,kk){
31289 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31291 var sz = b.el.getSize();
31293 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31301 for (var i = 0; i < this.cols; i++){
31302 mY = Math.max(mY, maxY[i]);
31305 this.el.setHeight(mY - pos.y);
31309 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31311 // var pos = this.el.getBox(true);
31314 // var maxX = pos.right;
31316 // var maxHeight = 0;
31318 // Roo.each(items, function(item, k){
31322 // item.el.position('absolute');
31324 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31326 // item.el.setWidth(width);
31328 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31330 // item.el.setHeight(height);
31333 // item.el.setXY([x, y], isInstant ? false : true);
31335 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31338 // y = y + height + this.alternativePadWidth;
31340 // maxHeight = maxHeight + height + this.alternativePadWidth;
31344 // this.el.setHeight(maxHeight);
31348 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31350 var pos = this.el.getBox(true);
31355 var maxX = pos.right;
31357 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31359 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31361 Roo.each(queue, function(box, k){
31363 Roo.each(box, function(b, kk){
31365 b.el.position('absolute');
31367 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31368 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31370 if(b.size == 'md-left' || b.size == 'md-right'){
31371 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31372 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31375 b.el.setWidth(width);
31376 b.el.setHeight(height);
31384 var positions = [];
31386 switch (box.length){
31388 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31391 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31394 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31397 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31403 Roo.each(box, function(b,kk){
31405 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31407 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31415 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31417 Roo.each(eItems, function(b,k){
31419 b.size = (k == 0) ? 'sm' : 'xs';
31420 b.x = (k == 0) ? 2 : 1;
31421 b.y = (k == 0) ? 2 : 1;
31423 b.el.position('absolute');
31425 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31427 b.el.setWidth(width);
31429 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31431 b.el.setHeight(height);
31435 var positions = [];
31438 x : maxX - this.unitWidth * 2 - this.gutter,
31443 x : maxX - this.unitWidth,
31444 y : minY + (this.unitWidth + this.gutter) * 2
31448 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31452 Roo.each(eItems, function(b,k){
31454 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31460 getVerticalOneBoxColPositions : function(x, y, box)
31464 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31466 if(box[0].size == 'md-left'){
31470 if(box[0].size == 'md-right'){
31475 x : x + (this.unitWidth + this.gutter) * rand,
31482 getVerticalTwoBoxColPositions : function(x, y, box)
31486 if(box[0].size == 'xs'){
31490 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31494 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31508 x : x + (this.unitWidth + this.gutter) * 2,
31509 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31516 getVerticalThreeBoxColPositions : function(x, y, box)
31520 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31528 x : x + (this.unitWidth + this.gutter) * 1,
31533 x : x + (this.unitWidth + this.gutter) * 2,
31541 if(box[0].size == 'xs' && box[1].size == 'xs'){
31550 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31554 x : x + (this.unitWidth + this.gutter) * 1,
31568 x : x + (this.unitWidth + this.gutter) * 2,
31573 x : x + (this.unitWidth + this.gutter) * 2,
31574 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31581 getVerticalFourBoxColPositions : function(x, y, box)
31585 if(box[0].size == 'xs'){
31594 y : y + (this.unitHeight + this.gutter) * 1
31599 y : y + (this.unitHeight + this.gutter) * 2
31603 x : x + (this.unitWidth + this.gutter) * 1,
31617 x : x + (this.unitWidth + this.gutter) * 2,
31622 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31623 y : y + (this.unitHeight + this.gutter) * 1
31627 x : x + (this.unitWidth + this.gutter) * 2,
31628 y : y + (this.unitWidth + this.gutter) * 2
31635 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31639 if(box[0].size == 'md-left'){
31641 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31648 if(box[0].size == 'md-right'){
31650 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31651 y : minY + (this.unitWidth + this.gutter) * 1
31657 var rand = Math.floor(Math.random() * (4 - box[0].y));
31660 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31661 y : minY + (this.unitWidth + this.gutter) * rand
31668 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31672 if(box[0].size == 'xs'){
31675 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31680 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31681 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31689 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31694 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31695 y : minY + (this.unitWidth + this.gutter) * 2
31702 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31706 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31709 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31714 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31715 y : minY + (this.unitWidth + this.gutter) * 1
31719 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31720 y : minY + (this.unitWidth + this.gutter) * 2
31727 if(box[0].size == 'xs' && box[1].size == 'xs'){
31730 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31735 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31740 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31741 y : minY + (this.unitWidth + this.gutter) * 1
31749 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31754 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31755 y : minY + (this.unitWidth + this.gutter) * 2
31759 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31760 y : minY + (this.unitWidth + this.gutter) * 2
31767 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31771 if(box[0].size == 'xs'){
31774 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31779 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31784 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),
31789 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31790 y : minY + (this.unitWidth + this.gutter) * 1
31798 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31803 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31804 y : minY + (this.unitWidth + this.gutter) * 2
31808 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31809 y : minY + (this.unitWidth + this.gutter) * 2
31813 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),
31814 y : minY + (this.unitWidth + this.gutter) * 2
31822 * remove a Masonry Brick
31823 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31825 removeBrick : function(brick_id)
31831 for (var i = 0; i<this.bricks.length; i++) {
31832 if (this.bricks[i].id == brick_id) {
31833 this.bricks.splice(i,1);
31834 this.el.dom.removeChild(Roo.get(brick_id).dom);
31841 * adds a Masonry Brick
31842 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31844 addBrick : function(cfg)
31846 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31847 //this.register(cn);
31848 cn.parentId = this.id;
31849 cn.onRender(this.el, null);
31854 * register a Masonry Brick
31855 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31858 register : function(brick)
31860 this.bricks.push(brick);
31861 brick.masonryId = this.id;
31865 * clear all the Masonry Brick
31867 clearAll : function()
31870 //this.getChildContainer().dom.innerHTML = "";
31871 this.el.dom.innerHTML = '';
31874 getSelected : function()
31876 if (!this.selectedBrick) {
31880 return this.selectedBrick;
31884 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31888 * register a Masonry Layout
31889 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31892 register : function(layout)
31894 this.groups[layout.id] = layout;
31897 * fetch a Masonry Layout based on the masonry layout ID
31898 * @param {string} the masonry layout to add
31899 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31902 get: function(layout_id) {
31903 if (typeof(this.groups[layout_id]) == 'undefined') {
31906 return this.groups[layout_id] ;
31918 * http://masonry.desandro.com
31920 * The idea is to render all the bricks based on vertical width...
31922 * The original code extends 'outlayer' - we might need to use that....
31928 * @class Roo.bootstrap.LayoutMasonryAuto
31929 * @extends Roo.bootstrap.Component
31930 * Bootstrap Layout Masonry class
31933 * Create a new Element
31934 * @param {Object} config The config object
31937 Roo.bootstrap.LayoutMasonryAuto = function(config){
31938 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31941 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31944 * @cfg {Boolean} isFitWidth - resize the width..
31946 isFitWidth : false, // options..
31948 * @cfg {Boolean} isOriginLeft = left align?
31950 isOriginLeft : true,
31952 * @cfg {Boolean} isOriginTop = top align?
31954 isOriginTop : false,
31956 * @cfg {Boolean} isLayoutInstant = no animation?
31958 isLayoutInstant : false, // needed?
31960 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31962 isResizingContainer : true,
31964 * @cfg {Number} columnWidth width of the columns
31970 * @cfg {Number} maxCols maximum number of columns
31975 * @cfg {Number} padHeight padding below box..
31981 * @cfg {Boolean} isAutoInitial defalut true
31984 isAutoInitial : true,
31990 initialColumnWidth : 0,
31991 currentSize : null,
31993 colYs : null, // array.
32000 bricks: null, //CompositeElement
32001 cols : 0, // array?
32002 // element : null, // wrapped now this.el
32003 _isLayoutInited : null,
32006 getAutoCreate : function(){
32010 cls: 'blog-masonary-wrapper ' + this.cls,
32012 cls : 'mas-boxes masonary'
32019 getChildContainer: function( )
32021 if (this.boxesEl) {
32022 return this.boxesEl;
32025 this.boxesEl = this.el.select('.mas-boxes').first();
32027 return this.boxesEl;
32031 initEvents : function()
32035 if(this.isAutoInitial){
32036 Roo.log('hook children rendered');
32037 this.on('childrenrendered', function() {
32038 Roo.log('children rendered');
32045 initial : function()
32047 this.reloadItems();
32049 this.currentSize = this.el.getBox(true);
32051 /// was window resize... - let's see if this works..
32052 Roo.EventManager.onWindowResize(this.resize, this);
32054 if(!this.isAutoInitial){
32059 this.layout.defer(500,this);
32062 reloadItems: function()
32064 this.bricks = this.el.select('.masonry-brick', true);
32066 this.bricks.each(function(b) {
32067 //Roo.log(b.getSize());
32068 if (!b.attr('originalwidth')) {
32069 b.attr('originalwidth', b.getSize().width);
32074 Roo.log(this.bricks.elements.length);
32077 resize : function()
32080 var cs = this.el.getBox(true);
32082 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32083 Roo.log("no change in with or X");
32086 this.currentSize = cs;
32090 layout : function()
32093 this._resetLayout();
32094 //this._manageStamps();
32096 // don't animate first layout
32097 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32098 this.layoutItems( isInstant );
32100 // flag for initalized
32101 this._isLayoutInited = true;
32104 layoutItems : function( isInstant )
32106 //var items = this._getItemsForLayout( this.items );
32107 // original code supports filtering layout items.. we just ignore it..
32109 this._layoutItems( this.bricks , isInstant );
32111 this._postLayout();
32113 _layoutItems : function ( items , isInstant)
32115 //this.fireEvent( 'layout', this, items );
32118 if ( !items || !items.elements.length ) {
32119 // no items, emit event with empty array
32124 items.each(function(item) {
32125 Roo.log("layout item");
32127 // get x/y object from method
32128 var position = this._getItemLayoutPosition( item );
32130 position.item = item;
32131 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32132 queue.push( position );
32135 this._processLayoutQueue( queue );
32137 /** Sets position of item in DOM
32138 * @param {Element} item
32139 * @param {Number} x - horizontal position
32140 * @param {Number} y - vertical position
32141 * @param {Boolean} isInstant - disables transitions
32143 _processLayoutQueue : function( queue )
32145 for ( var i=0, len = queue.length; i < len; i++ ) {
32146 var obj = queue[i];
32147 obj.item.position('absolute');
32148 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32154 * Any logic you want to do after each layout,
32155 * i.e. size the container
32157 _postLayout : function()
32159 this.resizeContainer();
32162 resizeContainer : function()
32164 if ( !this.isResizingContainer ) {
32167 var size = this._getContainerSize();
32169 this.el.setSize(size.width,size.height);
32170 this.boxesEl.setSize(size.width,size.height);
32176 _resetLayout : function()
32178 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32179 this.colWidth = this.el.getWidth();
32180 //this.gutter = this.el.getWidth();
32182 this.measureColumns();
32188 this.colYs.push( 0 );
32194 measureColumns : function()
32196 this.getContainerWidth();
32197 // if columnWidth is 0, default to outerWidth of first item
32198 if ( !this.columnWidth ) {
32199 var firstItem = this.bricks.first();
32200 Roo.log(firstItem);
32201 this.columnWidth = this.containerWidth;
32202 if (firstItem && firstItem.attr('originalwidth') ) {
32203 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32205 // columnWidth fall back to item of first element
32206 Roo.log("set column width?");
32207 this.initialColumnWidth = this.columnWidth ;
32209 // if first elem has no width, default to size of container
32214 if (this.initialColumnWidth) {
32215 this.columnWidth = this.initialColumnWidth;
32220 // column width is fixed at the top - however if container width get's smaller we should
32223 // this bit calcs how man columns..
32225 var columnWidth = this.columnWidth += this.gutter;
32227 // calculate columns
32228 var containerWidth = this.containerWidth + this.gutter;
32230 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32231 // fix rounding errors, typically with gutters
32232 var excess = columnWidth - containerWidth % columnWidth;
32235 // if overshoot is less than a pixel, round up, otherwise floor it
32236 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32237 cols = Math[ mathMethod ]( cols );
32238 this.cols = Math.max( cols, 1 );
32239 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32241 // padding positioning..
32242 var totalColWidth = this.cols * this.columnWidth;
32243 var padavail = this.containerWidth - totalColWidth;
32244 // so for 2 columns - we need 3 'pads'
32246 var padNeeded = (1+this.cols) * this.padWidth;
32248 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32250 this.columnWidth += padExtra
32251 //this.padWidth = Math.floor(padavail / ( this.cols));
32253 // adjust colum width so that padding is fixed??
32255 // we have 3 columns ... total = width * 3
32256 // we have X left over... that should be used by
32258 //if (this.expandC) {
32266 getContainerWidth : function()
32268 /* // container is parent if fit width
32269 var container = this.isFitWidth ? this.element.parentNode : this.element;
32270 // check that this.size and size are there
32271 // IE8 triggers resize on body size change, so they might not be
32273 var size = getSize( container ); //FIXME
32274 this.containerWidth = size && size.innerWidth; //FIXME
32277 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32281 _getItemLayoutPosition : function( item ) // what is item?
32283 // we resize the item to our columnWidth..
32285 item.setWidth(this.columnWidth);
32286 item.autoBoxAdjust = false;
32288 var sz = item.getSize();
32290 // how many columns does this brick span
32291 var remainder = this.containerWidth % this.columnWidth;
32293 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32294 // round if off by 1 pixel, otherwise use ceil
32295 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32296 colSpan = Math.min( colSpan, this.cols );
32298 // normally this should be '1' as we dont' currently allow multi width columns..
32300 var colGroup = this._getColGroup( colSpan );
32301 // get the minimum Y value from the columns
32302 var minimumY = Math.min.apply( Math, colGroup );
32303 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32305 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32307 // position the brick
32309 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32310 y: this.currentSize.y + minimumY + this.padHeight
32314 // apply setHeight to necessary columns
32315 var setHeight = minimumY + sz.height + this.padHeight;
32316 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32318 var setSpan = this.cols + 1 - colGroup.length;
32319 for ( var i = 0; i < setSpan; i++ ) {
32320 this.colYs[ shortColIndex + i ] = setHeight ;
32327 * @param {Number} colSpan - number of columns the element spans
32328 * @returns {Array} colGroup
32330 _getColGroup : function( colSpan )
32332 if ( colSpan < 2 ) {
32333 // if brick spans only one column, use all the column Ys
32338 // how many different places could this brick fit horizontally
32339 var groupCount = this.cols + 1 - colSpan;
32340 // for each group potential horizontal position
32341 for ( var i = 0; i < groupCount; i++ ) {
32342 // make an array of colY values for that one group
32343 var groupColYs = this.colYs.slice( i, i + colSpan );
32344 // and get the max value of the array
32345 colGroup[i] = Math.max.apply( Math, groupColYs );
32350 _manageStamp : function( stamp )
32352 var stampSize = stamp.getSize();
32353 var offset = stamp.getBox();
32354 // get the columns that this stamp affects
32355 var firstX = this.isOriginLeft ? offset.x : offset.right;
32356 var lastX = firstX + stampSize.width;
32357 var firstCol = Math.floor( firstX / this.columnWidth );
32358 firstCol = Math.max( 0, firstCol );
32360 var lastCol = Math.floor( lastX / this.columnWidth );
32361 // lastCol should not go over if multiple of columnWidth #425
32362 lastCol -= lastX % this.columnWidth ? 0 : 1;
32363 lastCol = Math.min( this.cols - 1, lastCol );
32365 // set colYs to bottom of the stamp
32366 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32369 for ( var i = firstCol; i <= lastCol; i++ ) {
32370 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32375 _getContainerSize : function()
32377 this.maxY = Math.max.apply( Math, this.colYs );
32382 if ( this.isFitWidth ) {
32383 size.width = this._getContainerFitWidth();
32389 _getContainerFitWidth : function()
32391 var unusedCols = 0;
32392 // count unused columns
32395 if ( this.colYs[i] !== 0 ) {
32400 // fit container to columns that have been used
32401 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32404 needsResizeLayout : function()
32406 var previousWidth = this.containerWidth;
32407 this.getContainerWidth();
32408 return previousWidth !== this.containerWidth;
32423 * @class Roo.bootstrap.MasonryBrick
32424 * @extends Roo.bootstrap.Component
32425 * Bootstrap MasonryBrick class
32428 * Create a new MasonryBrick
32429 * @param {Object} config The config object
32432 Roo.bootstrap.MasonryBrick = function(config){
32434 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32436 Roo.bootstrap.MasonryBrick.register(this);
32442 * When a MasonryBrick is clcik
32443 * @param {Roo.bootstrap.MasonryBrick} this
32444 * @param {Roo.EventObject} e
32450 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32453 * @cfg {String} title
32457 * @cfg {String} html
32461 * @cfg {String} bgimage
32465 * @cfg {String} videourl
32469 * @cfg {String} cls
32473 * @cfg {String} href
32477 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32482 * @cfg {String} placetitle (center|bottom)
32487 * @cfg {Boolean} isFitContainer defalut true
32489 isFitContainer : true,
32492 * @cfg {Boolean} preventDefault defalut false
32494 preventDefault : false,
32497 * @cfg {Boolean} inverse defalut false
32499 maskInverse : false,
32501 getAutoCreate : function()
32503 if(!this.isFitContainer){
32504 return this.getSplitAutoCreate();
32507 var cls = 'masonry-brick masonry-brick-full';
32509 if(this.href.length){
32510 cls += ' masonry-brick-link';
32513 if(this.bgimage.length){
32514 cls += ' masonry-brick-image';
32517 if(this.maskInverse){
32518 cls += ' mask-inverse';
32521 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32522 cls += ' enable-mask';
32526 cls += ' masonry-' + this.size + '-brick';
32529 if(this.placetitle.length){
32531 switch (this.placetitle) {
32533 cls += ' masonry-center-title';
32536 cls += ' masonry-bottom-title';
32543 if(!this.html.length && !this.bgimage.length){
32544 cls += ' masonry-center-title';
32547 if(!this.html.length && this.bgimage.length){
32548 cls += ' masonry-bottom-title';
32553 cls += ' ' + this.cls;
32557 tag: (this.href.length) ? 'a' : 'div',
32562 cls: 'masonry-brick-mask'
32566 cls: 'masonry-brick-paragraph',
32572 if(this.href.length){
32573 cfg.href = this.href;
32576 var cn = cfg.cn[1].cn;
32578 if(this.title.length){
32581 cls: 'masonry-brick-title',
32586 if(this.html.length){
32589 cls: 'masonry-brick-text',
32594 if (!this.title.length && !this.html.length) {
32595 cfg.cn[1].cls += ' hide';
32598 if(this.bgimage.length){
32601 cls: 'masonry-brick-image-view',
32606 if(this.videourl.length){
32607 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32608 // youtube support only?
32611 cls: 'masonry-brick-image-view',
32614 allowfullscreen : true
32622 getSplitAutoCreate : function()
32624 var cls = 'masonry-brick masonry-brick-split';
32626 if(this.href.length){
32627 cls += ' masonry-brick-link';
32630 if(this.bgimage.length){
32631 cls += ' masonry-brick-image';
32635 cls += ' masonry-' + this.size + '-brick';
32638 switch (this.placetitle) {
32640 cls += ' masonry-center-title';
32643 cls += ' masonry-bottom-title';
32646 if(!this.bgimage.length){
32647 cls += ' masonry-center-title';
32650 if(this.bgimage.length){
32651 cls += ' masonry-bottom-title';
32657 cls += ' ' + this.cls;
32661 tag: (this.href.length) ? 'a' : 'div',
32666 cls: 'masonry-brick-split-head',
32670 cls: 'masonry-brick-paragraph',
32677 cls: 'masonry-brick-split-body',
32683 if(this.href.length){
32684 cfg.href = this.href;
32687 if(this.title.length){
32688 cfg.cn[0].cn[0].cn.push({
32690 cls: 'masonry-brick-title',
32695 if(this.html.length){
32696 cfg.cn[1].cn.push({
32698 cls: 'masonry-brick-text',
32703 if(this.bgimage.length){
32704 cfg.cn[0].cn.push({
32706 cls: 'masonry-brick-image-view',
32711 if(this.videourl.length){
32712 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32713 // youtube support only?
32714 cfg.cn[0].cn.cn.push({
32716 cls: 'masonry-brick-image-view',
32719 allowfullscreen : true
32726 initEvents: function()
32728 switch (this.size) {
32761 this.el.on('touchstart', this.onTouchStart, this);
32762 this.el.on('touchmove', this.onTouchMove, this);
32763 this.el.on('touchend', this.onTouchEnd, this);
32764 this.el.on('contextmenu', this.onContextMenu, this);
32766 this.el.on('mouseenter' ,this.enter, this);
32767 this.el.on('mouseleave', this.leave, this);
32768 this.el.on('click', this.onClick, this);
32771 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32772 this.parent().bricks.push(this);
32777 onClick: function(e, el)
32779 var time = this.endTimer - this.startTimer;
32780 // Roo.log(e.preventDefault());
32783 e.preventDefault();
32788 if(!this.preventDefault){
32792 e.preventDefault();
32794 if (this.activeClass != '') {
32795 this.selectBrick();
32798 this.fireEvent('click', this, e);
32801 enter: function(e, el)
32803 e.preventDefault();
32805 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32809 if(this.bgimage.length && this.html.length){
32810 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32814 leave: function(e, el)
32816 e.preventDefault();
32818 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32822 if(this.bgimage.length && this.html.length){
32823 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32827 onTouchStart: function(e, el)
32829 // e.preventDefault();
32831 this.touchmoved = false;
32833 if(!this.isFitContainer){
32837 if(!this.bgimage.length || !this.html.length){
32841 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32843 this.timer = new Date().getTime();
32847 onTouchMove: function(e, el)
32849 this.touchmoved = true;
32852 onContextMenu : function(e,el)
32854 e.preventDefault();
32855 e.stopPropagation();
32859 onTouchEnd: function(e, el)
32861 // e.preventDefault();
32863 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32870 if(!this.bgimage.length || !this.html.length){
32872 if(this.href.length){
32873 window.location.href = this.href;
32879 if(!this.isFitContainer){
32883 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32885 window.location.href = this.href;
32888 //selection on single brick only
32889 selectBrick : function() {
32891 if (!this.parentId) {
32895 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32896 var index = m.selectedBrick.indexOf(this.id);
32899 m.selectedBrick.splice(index,1);
32900 this.el.removeClass(this.activeClass);
32904 for(var i = 0; i < m.selectedBrick.length; i++) {
32905 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32906 b.el.removeClass(b.activeClass);
32909 m.selectedBrick = [];
32911 m.selectedBrick.push(this.id);
32912 this.el.addClass(this.activeClass);
32916 isSelected : function(){
32917 return this.el.hasClass(this.activeClass);
32922 Roo.apply(Roo.bootstrap.MasonryBrick, {
32925 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32927 * register a Masonry Brick
32928 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32931 register : function(brick)
32933 //this.groups[brick.id] = brick;
32934 this.groups.add(brick.id, brick);
32937 * fetch a masonry brick based on the masonry brick ID
32938 * @param {string} the masonry brick to add
32939 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32942 get: function(brick_id)
32944 // if (typeof(this.groups[brick_id]) == 'undefined') {
32947 // return this.groups[brick_id] ;
32949 if(this.groups.key(brick_id)) {
32950 return this.groups.key(brick_id);
32968 * @class Roo.bootstrap.Brick
32969 * @extends Roo.bootstrap.Component
32970 * Bootstrap Brick class
32973 * Create a new Brick
32974 * @param {Object} config The config object
32977 Roo.bootstrap.Brick = function(config){
32978 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32984 * When a Brick is click
32985 * @param {Roo.bootstrap.Brick} this
32986 * @param {Roo.EventObject} e
32992 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32995 * @cfg {String} title
32999 * @cfg {String} html
33003 * @cfg {String} bgimage
33007 * @cfg {String} cls
33011 * @cfg {String} href
33015 * @cfg {String} video
33019 * @cfg {Boolean} square
33023 getAutoCreate : function()
33025 var cls = 'roo-brick';
33027 if(this.href.length){
33028 cls += ' roo-brick-link';
33031 if(this.bgimage.length){
33032 cls += ' roo-brick-image';
33035 if(!this.html.length && !this.bgimage.length){
33036 cls += ' roo-brick-center-title';
33039 if(!this.html.length && this.bgimage.length){
33040 cls += ' roo-brick-bottom-title';
33044 cls += ' ' + this.cls;
33048 tag: (this.href.length) ? 'a' : 'div',
33053 cls: 'roo-brick-paragraph',
33059 if(this.href.length){
33060 cfg.href = this.href;
33063 var cn = cfg.cn[0].cn;
33065 if(this.title.length){
33068 cls: 'roo-brick-title',
33073 if(this.html.length){
33076 cls: 'roo-brick-text',
33083 if(this.bgimage.length){
33086 cls: 'roo-brick-image-view',
33094 initEvents: function()
33096 if(this.title.length || this.html.length){
33097 this.el.on('mouseenter' ,this.enter, this);
33098 this.el.on('mouseleave', this.leave, this);
33101 Roo.EventManager.onWindowResize(this.resize, this);
33103 if(this.bgimage.length){
33104 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33105 this.imageEl.on('load', this.onImageLoad, this);
33112 onImageLoad : function()
33117 resize : function()
33119 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33121 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33123 if(this.bgimage.length){
33124 var image = this.el.select('.roo-brick-image-view', true).first();
33126 image.setWidth(paragraph.getWidth());
33129 image.setHeight(paragraph.getWidth());
33132 this.el.setHeight(image.getHeight());
33133 paragraph.setHeight(image.getHeight());
33139 enter: function(e, el)
33141 e.preventDefault();
33143 if(this.bgimage.length){
33144 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33145 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33149 leave: function(e, el)
33151 e.preventDefault();
33153 if(this.bgimage.length){
33154 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33155 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33170 * @class Roo.bootstrap.NumberField
33171 * @extends Roo.bootstrap.Input
33172 * Bootstrap NumberField class
33178 * Create a new NumberField
33179 * @param {Object} config The config object
33182 Roo.bootstrap.NumberField = function(config){
33183 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33186 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33189 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33191 allowDecimals : true,
33193 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33195 decimalSeparator : ".",
33197 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33199 decimalPrecision : 2,
33201 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33203 allowNegative : true,
33206 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33210 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33212 minValue : Number.NEGATIVE_INFINITY,
33214 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33216 maxValue : Number.MAX_VALUE,
33218 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33220 minText : "The minimum value for this field is {0}",
33222 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33224 maxText : "The maximum value for this field is {0}",
33226 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33227 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33229 nanText : "{0} is not a valid number",
33231 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33235 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33237 thousandsDelimiter : false,
33239 * @cfg {String} valueAlign alignment of value
33241 valueAlign : "left",
33243 getAutoCreate : function()
33245 var hiddenInput = {
33249 cls: 'hidden-number-input'
33253 hiddenInput.name = this.name;
33258 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33260 this.name = hiddenInput.name;
33262 if(cfg.cn.length > 0) {
33263 cfg.cn.push(hiddenInput);
33270 initEvents : function()
33272 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33274 var allowed = "0123456789";
33276 if(this.allowDecimals){
33277 allowed += this.decimalSeparator;
33280 if(this.allowNegative){
33284 if(this.thousandsDelimiter) {
33288 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33290 var keyPress = function(e){
33292 var k = e.getKey();
33294 var c = e.getCharCode();
33297 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33298 allowed.indexOf(String.fromCharCode(c)) === -1
33304 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33308 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33313 this.el.on("keypress", keyPress, this);
33316 validateValue : function(value)
33319 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33323 var num = this.parseValue(value);
33326 this.markInvalid(String.format(this.nanText, value));
33330 if(num < this.minValue){
33331 this.markInvalid(String.format(this.minText, this.minValue));
33335 if(num > this.maxValue){
33336 this.markInvalid(String.format(this.maxText, this.maxValue));
33343 getValue : function()
33345 var v = this.hiddenEl().getValue();
33347 return this.fixPrecision(this.parseValue(v));
33350 parseValue : function(value)
33352 if(this.thousandsDelimiter) {
33354 r = new RegExp(",", "g");
33355 value = value.replace(r, "");
33358 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33359 return isNaN(value) ? '' : value;
33362 fixPrecision : function(value)
33364 if(this.thousandsDelimiter) {
33366 r = new RegExp(",", "g");
33367 value = value.replace(r, "");
33370 var nan = isNaN(value);
33372 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33373 return nan ? '' : value;
33375 return parseFloat(value).toFixed(this.decimalPrecision);
33378 setValue : function(v)
33380 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33386 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33388 this.inputEl().dom.value = (v == '') ? '' :
33389 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33391 if(!this.allowZero && v === '0') {
33392 this.hiddenEl().dom.value = '';
33393 this.inputEl().dom.value = '';
33400 decimalPrecisionFcn : function(v)
33402 return Math.floor(v);
33405 beforeBlur : function()
33411 var v = this.parseValue(this.getRawValue());
33418 hiddenEl : function()
33420 return this.el.select('input.hidden-number-input',true).first();
33432 * @class Roo.bootstrap.DocumentSlider
33433 * @extends Roo.bootstrap.Component
33434 * Bootstrap DocumentSlider class
33437 * Create a new DocumentViewer
33438 * @param {Object} config The config object
33441 Roo.bootstrap.DocumentSlider = function(config){
33442 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33449 * Fire after initEvent
33450 * @param {Roo.bootstrap.DocumentSlider} this
33455 * Fire after update
33456 * @param {Roo.bootstrap.DocumentSlider} this
33462 * @param {Roo.bootstrap.DocumentSlider} this
33468 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33474 getAutoCreate : function()
33478 cls : 'roo-document-slider',
33482 cls : 'roo-document-slider-header',
33486 cls : 'roo-document-slider-header-title'
33492 cls : 'roo-document-slider-body',
33496 cls : 'roo-document-slider-prev',
33500 cls : 'fa fa-chevron-left'
33506 cls : 'roo-document-slider-thumb',
33510 cls : 'roo-document-slider-image'
33516 cls : 'roo-document-slider-next',
33520 cls : 'fa fa-chevron-right'
33532 initEvents : function()
33534 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33535 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33537 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33538 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33540 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33541 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33543 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33544 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33546 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33547 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33549 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33550 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33552 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33553 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33555 this.thumbEl.on('click', this.onClick, this);
33557 this.prevIndicator.on('click', this.prev, this);
33559 this.nextIndicator.on('click', this.next, this);
33563 initial : function()
33565 if(this.files.length){
33566 this.indicator = 1;
33570 this.fireEvent('initial', this);
33573 update : function()
33575 this.imageEl.attr('src', this.files[this.indicator - 1]);
33577 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33579 this.prevIndicator.show();
33581 if(this.indicator == 1){
33582 this.prevIndicator.hide();
33585 this.nextIndicator.show();
33587 if(this.indicator == this.files.length){
33588 this.nextIndicator.hide();
33591 this.thumbEl.scrollTo('top');
33593 this.fireEvent('update', this);
33596 onClick : function(e)
33598 e.preventDefault();
33600 this.fireEvent('click', this);
33605 e.preventDefault();
33607 this.indicator = Math.max(1, this.indicator - 1);
33614 e.preventDefault();
33616 this.indicator = Math.min(this.files.length, this.indicator + 1);
33630 * @class Roo.bootstrap.RadioSet
33631 * @extends Roo.bootstrap.Input
33632 * Bootstrap RadioSet class
33633 * @cfg {String} indicatorpos (left|right) default left
33634 * @cfg {Boolean} inline (true|false) inline the element (default true)
33635 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33637 * Create a new RadioSet
33638 * @param {Object} config The config object
33641 Roo.bootstrap.RadioSet = function(config){
33643 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33647 Roo.bootstrap.RadioSet.register(this);
33652 * Fires when the element is checked or unchecked.
33653 * @param {Roo.bootstrap.RadioSet} this This radio
33654 * @param {Roo.bootstrap.Radio} item The checked item
33659 * Fires when the element is click.
33660 * @param {Roo.bootstrap.RadioSet} this This radio set
33661 * @param {Roo.bootstrap.Radio} item The checked item
33662 * @param {Roo.EventObject} e The event object
33669 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33677 indicatorpos : 'left',
33679 getAutoCreate : function()
33683 cls : 'roo-radio-set-label',
33687 html : this.fieldLabel
33692 if(this.indicatorpos == 'left'){
33695 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33696 tooltip : 'This field is required'
33701 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33702 tooltip : 'This field is required'
33708 cls : 'roo-radio-set-items'
33711 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33713 if (align === 'left' && this.fieldLabel.length) {
33716 cls : "roo-radio-set-right",
33722 if(this.labelWidth > 12){
33723 label.style = "width: " + this.labelWidth + 'px';
33726 if(this.labelWidth < 13 && this.labelmd == 0){
33727 this.labelmd = this.labelWidth;
33730 if(this.labellg > 0){
33731 label.cls += ' col-lg-' + this.labellg;
33732 items.cls += ' col-lg-' + (12 - this.labellg);
33735 if(this.labelmd > 0){
33736 label.cls += ' col-md-' + this.labelmd;
33737 items.cls += ' col-md-' + (12 - this.labelmd);
33740 if(this.labelsm > 0){
33741 label.cls += ' col-sm-' + this.labelsm;
33742 items.cls += ' col-sm-' + (12 - this.labelsm);
33745 if(this.labelxs > 0){
33746 label.cls += ' col-xs-' + this.labelxs;
33747 items.cls += ' col-xs-' + (12 - this.labelxs);
33753 cls : 'roo-radio-set',
33757 cls : 'roo-radio-set-input',
33760 value : this.value ? this.value : ''
33767 if(this.weight.length){
33768 cfg.cls += ' roo-radio-' + this.weight;
33772 cfg.cls += ' roo-radio-set-inline';
33776 ['xs','sm','md','lg'].map(function(size){
33777 if (settings[size]) {
33778 cfg.cls += ' col-' + size + '-' + settings[size];
33786 initEvents : function()
33788 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33789 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33791 if(!this.fieldLabel.length){
33792 this.labelEl.hide();
33795 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33796 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33798 this.indicator = this.indicatorEl();
33800 if(this.indicator){
33801 this.indicator.addClass('invisible');
33804 this.originalValue = this.getValue();
33808 inputEl: function ()
33810 return this.el.select('.roo-radio-set-input', true).first();
33813 getChildContainer : function()
33815 return this.itemsEl;
33818 register : function(item)
33820 this.radioes.push(item);
33824 validate : function()
33826 if(this.getVisibilityEl().hasClass('hidden')){
33832 Roo.each(this.radioes, function(i){
33841 if(this.allowBlank) {
33845 if(this.disabled || valid){
33850 this.markInvalid();
33855 markValid : function()
33857 if(this.labelEl.isVisible(true)){
33858 this.indicatorEl().removeClass('visible');
33859 this.indicatorEl().addClass('invisible');
33862 this.el.removeClass([this.invalidClass, this.validClass]);
33863 this.el.addClass(this.validClass);
33865 this.fireEvent('valid', this);
33868 markInvalid : function(msg)
33870 if(this.allowBlank || this.disabled){
33874 if(this.labelEl.isVisible(true)){
33875 this.indicatorEl().removeClass('invisible');
33876 this.indicatorEl().addClass('visible');
33879 this.el.removeClass([this.invalidClass, this.validClass]);
33880 this.el.addClass(this.invalidClass);
33882 this.fireEvent('invalid', this, msg);
33886 setValue : function(v, suppressEvent)
33888 if(this.value === v){
33895 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33898 Roo.each(this.radioes, function(i){
33900 i.el.removeClass('checked');
33903 Roo.each(this.radioes, function(i){
33905 if(i.value === v || i.value.toString() === v.toString()){
33907 i.el.addClass('checked');
33909 if(suppressEvent !== true){
33910 this.fireEvent('check', this, i);
33921 clearInvalid : function(){
33923 if(!this.el || this.preventMark){
33927 this.el.removeClass([this.invalidClass]);
33929 this.fireEvent('valid', this);
33934 Roo.apply(Roo.bootstrap.RadioSet, {
33938 register : function(set)
33940 this.groups[set.name] = set;
33943 get: function(name)
33945 if (typeof(this.groups[name]) == 'undefined') {
33949 return this.groups[name] ;
33955 * Ext JS Library 1.1.1
33956 * Copyright(c) 2006-2007, Ext JS, LLC.
33958 * Originally Released Under LGPL - original licence link has changed is not relivant.
33961 * <script type="text/javascript">
33966 * @class Roo.bootstrap.SplitBar
33967 * @extends Roo.util.Observable
33968 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33972 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33973 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33974 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33975 split.minSize = 100;
33976 split.maxSize = 600;
33977 split.animate = true;
33978 split.on('moved', splitterMoved);
33981 * Create a new SplitBar
33982 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33983 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33984 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33985 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33986 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33987 position of the SplitBar).
33989 Roo.bootstrap.SplitBar = function(cfg){
33994 // dragElement : elm
33995 // resizingElement: el,
33997 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33998 // placement : Roo.bootstrap.SplitBar.LEFT ,
33999 // existingProxy ???
34002 this.el = Roo.get(cfg.dragElement, true);
34003 this.el.dom.unselectable = "on";
34005 this.resizingEl = Roo.get(cfg.resizingElement, true);
34009 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34010 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34013 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34016 * The minimum size of the resizing element. (Defaults to 0)
34022 * The maximum size of the resizing element. (Defaults to 2000)
34025 this.maxSize = 2000;
34028 * Whether to animate the transition to the new size
34031 this.animate = false;
34034 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34037 this.useShim = false;
34042 if(!cfg.existingProxy){
34044 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34046 this.proxy = Roo.get(cfg.existingProxy).dom;
34049 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34052 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34055 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34058 this.dragSpecs = {};
34061 * @private The adapter to use to positon and resize elements
34063 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34064 this.adapter.init(this);
34066 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34068 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34069 this.el.addClass("roo-splitbar-h");
34072 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34073 this.el.addClass("roo-splitbar-v");
34079 * Fires when the splitter is moved (alias for {@link #event-moved})
34080 * @param {Roo.bootstrap.SplitBar} this
34081 * @param {Number} newSize the new width or height
34086 * Fires when the splitter is moved
34087 * @param {Roo.bootstrap.SplitBar} this
34088 * @param {Number} newSize the new width or height
34092 * @event beforeresize
34093 * Fires before the splitter is dragged
34094 * @param {Roo.bootstrap.SplitBar} this
34096 "beforeresize" : true,
34098 "beforeapply" : true
34101 Roo.util.Observable.call(this);
34104 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34105 onStartProxyDrag : function(x, y){
34106 this.fireEvent("beforeresize", this);
34108 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34110 o.enableDisplayMode("block");
34111 // all splitbars share the same overlay
34112 Roo.bootstrap.SplitBar.prototype.overlay = o;
34114 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34115 this.overlay.show();
34116 Roo.get(this.proxy).setDisplayed("block");
34117 var size = this.adapter.getElementSize(this);
34118 this.activeMinSize = this.getMinimumSize();;
34119 this.activeMaxSize = this.getMaximumSize();;
34120 var c1 = size - this.activeMinSize;
34121 var c2 = Math.max(this.activeMaxSize - size, 0);
34122 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34123 this.dd.resetConstraints();
34124 this.dd.setXConstraint(
34125 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34126 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34128 this.dd.setYConstraint(0, 0);
34130 this.dd.resetConstraints();
34131 this.dd.setXConstraint(0, 0);
34132 this.dd.setYConstraint(
34133 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34134 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34137 this.dragSpecs.startSize = size;
34138 this.dragSpecs.startPoint = [x, y];
34139 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34143 * @private Called after the drag operation by the DDProxy
34145 onEndProxyDrag : function(e){
34146 Roo.get(this.proxy).setDisplayed(false);
34147 var endPoint = Roo.lib.Event.getXY(e);
34149 this.overlay.hide();
34152 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34153 newSize = this.dragSpecs.startSize +
34154 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34155 endPoint[0] - this.dragSpecs.startPoint[0] :
34156 this.dragSpecs.startPoint[0] - endPoint[0]
34159 newSize = this.dragSpecs.startSize +
34160 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34161 endPoint[1] - this.dragSpecs.startPoint[1] :
34162 this.dragSpecs.startPoint[1] - endPoint[1]
34165 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34166 if(newSize != this.dragSpecs.startSize){
34167 if(this.fireEvent('beforeapply', this, newSize) !== false){
34168 this.adapter.setElementSize(this, newSize);
34169 this.fireEvent("moved", this, newSize);
34170 this.fireEvent("resize", this, newSize);
34176 * Get the adapter this SplitBar uses
34177 * @return The adapter object
34179 getAdapter : function(){
34180 return this.adapter;
34184 * Set the adapter this SplitBar uses
34185 * @param {Object} adapter A SplitBar adapter object
34187 setAdapter : function(adapter){
34188 this.adapter = adapter;
34189 this.adapter.init(this);
34193 * Gets the minimum size for the resizing element
34194 * @return {Number} The minimum size
34196 getMinimumSize : function(){
34197 return this.minSize;
34201 * Sets the minimum size for the resizing element
34202 * @param {Number} minSize The minimum size
34204 setMinimumSize : function(minSize){
34205 this.minSize = minSize;
34209 * Gets the maximum size for the resizing element
34210 * @return {Number} The maximum size
34212 getMaximumSize : function(){
34213 return this.maxSize;
34217 * Sets the maximum size for the resizing element
34218 * @param {Number} maxSize The maximum size
34220 setMaximumSize : function(maxSize){
34221 this.maxSize = maxSize;
34225 * Sets the initialize size for the resizing element
34226 * @param {Number} size The initial size
34228 setCurrentSize : function(size){
34229 var oldAnimate = this.animate;
34230 this.animate = false;
34231 this.adapter.setElementSize(this, size);
34232 this.animate = oldAnimate;
34236 * Destroy this splitbar.
34237 * @param {Boolean} removeEl True to remove the element
34239 destroy : function(removeEl){
34241 this.shim.remove();
34244 this.proxy.parentNode.removeChild(this.proxy);
34252 * @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.
34254 Roo.bootstrap.SplitBar.createProxy = function(dir){
34255 var proxy = new Roo.Element(document.createElement("div"));
34256 proxy.unselectable();
34257 var cls = 'roo-splitbar-proxy';
34258 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34259 document.body.appendChild(proxy.dom);
34264 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34265 * Default Adapter. It assumes the splitter and resizing element are not positioned
34266 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34268 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34271 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34272 // do nothing for now
34273 init : function(s){
34277 * Called before drag operations to get the current size of the resizing element.
34278 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34280 getElementSize : function(s){
34281 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34282 return s.resizingEl.getWidth();
34284 return s.resizingEl.getHeight();
34289 * Called after drag operations to set the size of the resizing element.
34290 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34291 * @param {Number} newSize The new size to set
34292 * @param {Function} onComplete A function to be invoked when resizing is complete
34294 setElementSize : function(s, newSize, onComplete){
34295 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34297 s.resizingEl.setWidth(newSize);
34299 onComplete(s, newSize);
34302 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34307 s.resizingEl.setHeight(newSize);
34309 onComplete(s, newSize);
34312 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34319 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34320 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34321 * Adapter that moves the splitter element to align with the resized sizing element.
34322 * Used with an absolute positioned SplitBar.
34323 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34324 * document.body, make sure you assign an id to the body element.
34326 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34327 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34328 this.container = Roo.get(container);
34331 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34332 init : function(s){
34333 this.basic.init(s);
34336 getElementSize : function(s){
34337 return this.basic.getElementSize(s);
34340 setElementSize : function(s, newSize, onComplete){
34341 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34344 moveSplitter : function(s){
34345 var yes = Roo.bootstrap.SplitBar;
34346 switch(s.placement){
34348 s.el.setX(s.resizingEl.getRight());
34351 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34354 s.el.setY(s.resizingEl.getBottom());
34357 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34364 * Orientation constant - Create a vertical SplitBar
34368 Roo.bootstrap.SplitBar.VERTICAL = 1;
34371 * Orientation constant - Create a horizontal SplitBar
34375 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34378 * Placement constant - The resizing element is to the left of the splitter element
34382 Roo.bootstrap.SplitBar.LEFT = 1;
34385 * Placement constant - The resizing element is to the right of the splitter element
34389 Roo.bootstrap.SplitBar.RIGHT = 2;
34392 * Placement constant - The resizing element is positioned above the splitter element
34396 Roo.bootstrap.SplitBar.TOP = 3;
34399 * Placement constant - The resizing element is positioned under splitter element
34403 Roo.bootstrap.SplitBar.BOTTOM = 4;
34404 Roo.namespace("Roo.bootstrap.layout");/*
34406 * Ext JS Library 1.1.1
34407 * Copyright(c) 2006-2007, Ext JS, LLC.
34409 * Originally Released Under LGPL - original licence link has changed is not relivant.
34412 * <script type="text/javascript">
34416 * @class Roo.bootstrap.layout.Manager
34417 * @extends Roo.bootstrap.Component
34418 * Base class for layout managers.
34420 Roo.bootstrap.layout.Manager = function(config)
34422 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34428 /** false to disable window resize monitoring @type Boolean */
34429 this.monitorWindowResize = true;
34434 * Fires when a layout is performed.
34435 * @param {Roo.LayoutManager} this
34439 * @event regionresized
34440 * Fires when the user resizes a region.
34441 * @param {Roo.LayoutRegion} region The resized region
34442 * @param {Number} newSize The new size (width for east/west, height for north/south)
34444 "regionresized" : true,
34446 * @event regioncollapsed
34447 * Fires when a region is collapsed.
34448 * @param {Roo.LayoutRegion} region The collapsed region
34450 "regioncollapsed" : true,
34452 * @event regionexpanded
34453 * Fires when a region is expanded.
34454 * @param {Roo.LayoutRegion} region The expanded region
34456 "regionexpanded" : true
34458 this.updating = false;
34461 this.el = Roo.get(config.el);
34467 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34472 monitorWindowResize : true,
34478 onRender : function(ct, position)
34481 this.el = Roo.get(ct);
34484 //this.fireEvent('render',this);
34488 initEvents: function()
34492 // ie scrollbar fix
34493 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34494 document.body.scroll = "no";
34495 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34496 this.el.position('relative');
34498 this.id = this.el.id;
34499 this.el.addClass("roo-layout-container");
34500 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34501 if(this.el.dom != document.body ) {
34502 this.el.on('resize', this.layout,this);
34503 this.el.on('show', this.layout,this);
34509 * Returns true if this layout is currently being updated
34510 * @return {Boolean}
34512 isUpdating : function(){
34513 return this.updating;
34517 * Suspend the LayoutManager from doing auto-layouts while
34518 * making multiple add or remove calls
34520 beginUpdate : function(){
34521 this.updating = true;
34525 * Restore auto-layouts and optionally disable the manager from performing a layout
34526 * @param {Boolean} noLayout true to disable a layout update
34528 endUpdate : function(noLayout){
34529 this.updating = false;
34535 layout: function(){
34539 onRegionResized : function(region, newSize){
34540 this.fireEvent("regionresized", region, newSize);
34544 onRegionCollapsed : function(region){
34545 this.fireEvent("regioncollapsed", region);
34548 onRegionExpanded : function(region){
34549 this.fireEvent("regionexpanded", region);
34553 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34554 * performs box-model adjustments.
34555 * @return {Object} The size as an object {width: (the width), height: (the height)}
34557 getViewSize : function()
34560 if(this.el.dom != document.body){
34561 size = this.el.getSize();
34563 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34565 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34566 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34571 * Returns the Element this layout is bound to.
34572 * @return {Roo.Element}
34574 getEl : function(){
34579 * Returns the specified region.
34580 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34581 * @return {Roo.LayoutRegion}
34583 getRegion : function(target){
34584 return this.regions[target.toLowerCase()];
34587 onWindowResize : function(){
34588 if(this.monitorWindowResize){
34595 * Ext JS Library 1.1.1
34596 * Copyright(c) 2006-2007, Ext JS, LLC.
34598 * Originally Released Under LGPL - original licence link has changed is not relivant.
34601 * <script type="text/javascript">
34604 * @class Roo.bootstrap.layout.Border
34605 * @extends Roo.bootstrap.layout.Manager
34606 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34607 * please see: examples/bootstrap/nested.html<br><br>
34609 <b>The container the layout is rendered into can be either the body element or any other element.
34610 If it is not the body element, the container needs to either be an absolute positioned element,
34611 or you will need to add "position:relative" to the css of the container. You will also need to specify
34612 the container size if it is not the body element.</b>
34615 * Create a new Border
34616 * @param {Object} config Configuration options
34618 Roo.bootstrap.layout.Border = function(config){
34619 config = config || {};
34620 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34624 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34625 if(config[region]){
34626 config[region].region = region;
34627 this.addRegion(config[region]);
34633 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34635 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34637 * Creates and adds a new region if it doesn't already exist.
34638 * @param {String} target The target region key (north, south, east, west or center).
34639 * @param {Object} config The regions config object
34640 * @return {BorderLayoutRegion} The new region
34642 addRegion : function(config)
34644 if(!this.regions[config.region]){
34645 var r = this.factory(config);
34646 this.bindRegion(r);
34648 return this.regions[config.region];
34652 bindRegion : function(r){
34653 this.regions[r.config.region] = r;
34655 r.on("visibilitychange", this.layout, this);
34656 r.on("paneladded", this.layout, this);
34657 r.on("panelremoved", this.layout, this);
34658 r.on("invalidated", this.layout, this);
34659 r.on("resized", this.onRegionResized, this);
34660 r.on("collapsed", this.onRegionCollapsed, this);
34661 r.on("expanded", this.onRegionExpanded, this);
34665 * Performs a layout update.
34667 layout : function()
34669 if(this.updating) {
34673 // render all the rebions if they have not been done alreayd?
34674 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34675 if(this.regions[region] && !this.regions[region].bodyEl){
34676 this.regions[region].onRender(this.el)
34680 var size = this.getViewSize();
34681 var w = size.width;
34682 var h = size.height;
34687 //var x = 0, y = 0;
34689 var rs = this.regions;
34690 var north = rs["north"];
34691 var south = rs["south"];
34692 var west = rs["west"];
34693 var east = rs["east"];
34694 var center = rs["center"];
34695 //if(this.hideOnLayout){ // not supported anymore
34696 //c.el.setStyle("display", "none");
34698 if(north && north.isVisible()){
34699 var b = north.getBox();
34700 var m = north.getMargins();
34701 b.width = w - (m.left+m.right);
34704 centerY = b.height + b.y + m.bottom;
34705 centerH -= centerY;
34706 north.updateBox(this.safeBox(b));
34708 if(south && south.isVisible()){
34709 var b = south.getBox();
34710 var m = south.getMargins();
34711 b.width = w - (m.left+m.right);
34713 var totalHeight = (b.height + m.top + m.bottom);
34714 b.y = h - totalHeight + m.top;
34715 centerH -= totalHeight;
34716 south.updateBox(this.safeBox(b));
34718 if(west && west.isVisible()){
34719 var b = west.getBox();
34720 var m = west.getMargins();
34721 b.height = centerH - (m.top+m.bottom);
34723 b.y = centerY + m.top;
34724 var totalWidth = (b.width + m.left + m.right);
34725 centerX += totalWidth;
34726 centerW -= totalWidth;
34727 west.updateBox(this.safeBox(b));
34729 if(east && east.isVisible()){
34730 var b = east.getBox();
34731 var m = east.getMargins();
34732 b.height = centerH - (m.top+m.bottom);
34733 var totalWidth = (b.width + m.left + m.right);
34734 b.x = w - totalWidth + m.left;
34735 b.y = centerY + m.top;
34736 centerW -= totalWidth;
34737 east.updateBox(this.safeBox(b));
34740 var m = center.getMargins();
34742 x: centerX + m.left,
34743 y: centerY + m.top,
34744 width: centerW - (m.left+m.right),
34745 height: centerH - (m.top+m.bottom)
34747 //if(this.hideOnLayout){
34748 //center.el.setStyle("display", "block");
34750 center.updateBox(this.safeBox(centerBox));
34753 this.fireEvent("layout", this);
34757 safeBox : function(box){
34758 box.width = Math.max(0, box.width);
34759 box.height = Math.max(0, box.height);
34764 * Adds a ContentPanel (or subclass) to this layout.
34765 * @param {String} target The target region key (north, south, east, west or center).
34766 * @param {Roo.ContentPanel} panel The panel to add
34767 * @return {Roo.ContentPanel} The added panel
34769 add : function(target, panel){
34771 target = target.toLowerCase();
34772 return this.regions[target].add(panel);
34776 * Remove a ContentPanel (or subclass) to this layout.
34777 * @param {String} target The target region key (north, south, east, west or center).
34778 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34779 * @return {Roo.ContentPanel} The removed panel
34781 remove : function(target, panel){
34782 target = target.toLowerCase();
34783 return this.regions[target].remove(panel);
34787 * Searches all regions for a panel with the specified id
34788 * @param {String} panelId
34789 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34791 findPanel : function(panelId){
34792 var rs = this.regions;
34793 for(var target in rs){
34794 if(typeof rs[target] != "function"){
34795 var p = rs[target].getPanel(panelId);
34805 * Searches all regions for a panel with the specified id and activates (shows) it.
34806 * @param {String/ContentPanel} panelId The panels id or the panel itself
34807 * @return {Roo.ContentPanel} The shown panel or null
34809 showPanel : function(panelId) {
34810 var rs = this.regions;
34811 for(var target in rs){
34812 var r = rs[target];
34813 if(typeof r != "function"){
34814 if(r.hasPanel(panelId)){
34815 return r.showPanel(panelId);
34823 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34824 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34827 restoreState : function(provider){
34829 provider = Roo.state.Manager;
34831 var sm = new Roo.LayoutStateManager();
34832 sm.init(this, provider);
34838 * Adds a xtype elements to the layout.
34842 xtype : 'ContentPanel',
34849 xtype : 'NestedLayoutPanel',
34855 items : [ ... list of content panels or nested layout panels.. ]
34859 * @param {Object} cfg Xtype definition of item to add.
34861 addxtype : function(cfg)
34863 // basically accepts a pannel...
34864 // can accept a layout region..!?!?
34865 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34868 // theory? children can only be panels??
34870 //if (!cfg.xtype.match(/Panel$/)) {
34875 if (typeof(cfg.region) == 'undefined') {
34876 Roo.log("Failed to add Panel, region was not set");
34880 var region = cfg.region;
34886 xitems = cfg.items;
34893 case 'Content': // ContentPanel (el, cfg)
34894 case 'Scroll': // ContentPanel (el, cfg)
34896 cfg.autoCreate = true;
34897 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34899 // var el = this.el.createChild();
34900 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34903 this.add(region, ret);
34907 case 'TreePanel': // our new panel!
34908 cfg.el = this.el.createChild();
34909 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34910 this.add(region, ret);
34915 // create a new Layout (which is a Border Layout...
34917 var clayout = cfg.layout;
34918 clayout.el = this.el.createChild();
34919 clayout.items = clayout.items || [];
34923 // replace this exitems with the clayout ones..
34924 xitems = clayout.items;
34926 // force background off if it's in center...
34927 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34928 cfg.background = false;
34930 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34933 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34934 //console.log('adding nested layout panel ' + cfg.toSource());
34935 this.add(region, ret);
34936 nb = {}; /// find first...
34941 // needs grid and region
34943 //var el = this.getRegion(region).el.createChild();
34945 *var el = this.el.createChild();
34946 // create the grid first...
34947 cfg.grid.container = el;
34948 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34951 if (region == 'center' && this.active ) {
34952 cfg.background = false;
34955 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34957 this.add(region, ret);
34959 if (cfg.background) {
34960 // render grid on panel activation (if panel background)
34961 ret.on('activate', function(gp) {
34962 if (!gp.grid.rendered) {
34963 // gp.grid.render(el);
34967 // cfg.grid.render(el);
34973 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34974 // it was the old xcomponent building that caused this before.
34975 // espeically if border is the top element in the tree.
34985 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34987 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34988 this.add(region, ret);
34992 throw "Can not add '" + cfg.xtype + "' to Border";
34998 this.beginUpdate();
35002 Roo.each(xitems, function(i) {
35003 region = nb && i.region ? i.region : false;
35005 var add = ret.addxtype(i);
35008 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35009 if (!i.background) {
35010 abn[region] = nb[region] ;
35017 // make the last non-background panel active..
35018 //if (nb) { Roo.log(abn); }
35021 for(var r in abn) {
35022 region = this.getRegion(r);
35024 // tried using nb[r], but it does not work..
35026 region.showPanel(abn[r]);
35037 factory : function(cfg)
35040 var validRegions = Roo.bootstrap.layout.Border.regions;
35042 var target = cfg.region;
35045 var r = Roo.bootstrap.layout;
35049 return new r.North(cfg);
35051 return new r.South(cfg);
35053 return new r.East(cfg);
35055 return new r.West(cfg);
35057 return new r.Center(cfg);
35059 throw 'Layout region "'+target+'" not supported.';
35066 * Ext JS Library 1.1.1
35067 * Copyright(c) 2006-2007, Ext JS, LLC.
35069 * Originally Released Under LGPL - original licence link has changed is not relivant.
35072 * <script type="text/javascript">
35076 * @class Roo.bootstrap.layout.Basic
35077 * @extends Roo.util.Observable
35078 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35079 * and does not have a titlebar, tabs or any other features. All it does is size and position
35080 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35081 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35082 * @cfg {string} region the region that it inhabits..
35083 * @cfg {bool} skipConfig skip config?
35087 Roo.bootstrap.layout.Basic = function(config){
35089 this.mgr = config.mgr;
35091 this.position = config.region;
35093 var skipConfig = config.skipConfig;
35097 * @scope Roo.BasicLayoutRegion
35101 * @event beforeremove
35102 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35103 * @param {Roo.LayoutRegion} this
35104 * @param {Roo.ContentPanel} panel The panel
35105 * @param {Object} e The cancel event object
35107 "beforeremove" : true,
35109 * @event invalidated
35110 * Fires when the layout for this region is changed.
35111 * @param {Roo.LayoutRegion} this
35113 "invalidated" : true,
35115 * @event visibilitychange
35116 * Fires when this region is shown or hidden
35117 * @param {Roo.LayoutRegion} this
35118 * @param {Boolean} visibility true or false
35120 "visibilitychange" : true,
35122 * @event paneladded
35123 * Fires when a panel is added.
35124 * @param {Roo.LayoutRegion} this
35125 * @param {Roo.ContentPanel} panel The panel
35127 "paneladded" : true,
35129 * @event panelremoved
35130 * Fires when a panel is removed.
35131 * @param {Roo.LayoutRegion} this
35132 * @param {Roo.ContentPanel} panel The panel
35134 "panelremoved" : true,
35136 * @event beforecollapse
35137 * Fires when this region before collapse.
35138 * @param {Roo.LayoutRegion} this
35140 "beforecollapse" : true,
35143 * Fires when this region is collapsed.
35144 * @param {Roo.LayoutRegion} this
35146 "collapsed" : true,
35149 * Fires when this region is expanded.
35150 * @param {Roo.LayoutRegion} this
35155 * Fires when this region is slid into view.
35156 * @param {Roo.LayoutRegion} this
35158 "slideshow" : true,
35161 * Fires when this region slides out of view.
35162 * @param {Roo.LayoutRegion} this
35164 "slidehide" : true,
35166 * @event panelactivated
35167 * Fires when a panel is activated.
35168 * @param {Roo.LayoutRegion} this
35169 * @param {Roo.ContentPanel} panel The activated panel
35171 "panelactivated" : true,
35174 * Fires when the user resizes this region.
35175 * @param {Roo.LayoutRegion} this
35176 * @param {Number} newSize The new size (width for east/west, height for north/south)
35180 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35181 this.panels = new Roo.util.MixedCollection();
35182 this.panels.getKey = this.getPanelId.createDelegate(this);
35184 this.activePanel = null;
35185 // ensure listeners are added...
35187 if (config.listeners || config.events) {
35188 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35189 listeners : config.listeners || {},
35190 events : config.events || {}
35194 if(skipConfig !== true){
35195 this.applyConfig(config);
35199 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35201 getPanelId : function(p){
35205 applyConfig : function(config){
35206 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35207 this.config = config;
35212 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35213 * the width, for horizontal (north, south) the height.
35214 * @param {Number} newSize The new width or height
35216 resizeTo : function(newSize){
35217 var el = this.el ? this.el :
35218 (this.activePanel ? this.activePanel.getEl() : null);
35220 switch(this.position){
35223 el.setWidth(newSize);
35224 this.fireEvent("resized", this, newSize);
35228 el.setHeight(newSize);
35229 this.fireEvent("resized", this, newSize);
35235 getBox : function(){
35236 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35239 getMargins : function(){
35240 return this.margins;
35243 updateBox : function(box){
35245 var el = this.activePanel.getEl();
35246 el.dom.style.left = box.x + "px";
35247 el.dom.style.top = box.y + "px";
35248 this.activePanel.setSize(box.width, box.height);
35252 * Returns the container element for this region.
35253 * @return {Roo.Element}
35255 getEl : function(){
35256 return this.activePanel;
35260 * Returns true if this region is currently visible.
35261 * @return {Boolean}
35263 isVisible : function(){
35264 return this.activePanel ? true : false;
35267 setActivePanel : function(panel){
35268 panel = this.getPanel(panel);
35269 if(this.activePanel && this.activePanel != panel){
35270 this.activePanel.setActiveState(false);
35271 this.activePanel.getEl().setLeftTop(-10000,-10000);
35273 this.activePanel = panel;
35274 panel.setActiveState(true);
35276 panel.setSize(this.box.width, this.box.height);
35278 this.fireEvent("panelactivated", this, panel);
35279 this.fireEvent("invalidated");
35283 * Show the specified panel.
35284 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35285 * @return {Roo.ContentPanel} The shown panel or null
35287 showPanel : function(panel){
35288 panel = this.getPanel(panel);
35290 this.setActivePanel(panel);
35296 * Get the active panel for this region.
35297 * @return {Roo.ContentPanel} The active panel or null
35299 getActivePanel : function(){
35300 return this.activePanel;
35304 * Add the passed ContentPanel(s)
35305 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35306 * @return {Roo.ContentPanel} The panel added (if only one was added)
35308 add : function(panel){
35309 if(arguments.length > 1){
35310 for(var i = 0, len = arguments.length; i < len; i++) {
35311 this.add(arguments[i]);
35315 if(this.hasPanel(panel)){
35316 this.showPanel(panel);
35319 var el = panel.getEl();
35320 if(el.dom.parentNode != this.mgr.el.dom){
35321 this.mgr.el.dom.appendChild(el.dom);
35323 if(panel.setRegion){
35324 panel.setRegion(this);
35326 this.panels.add(panel);
35327 el.setStyle("position", "absolute");
35328 if(!panel.background){
35329 this.setActivePanel(panel);
35330 if(this.config.initialSize && this.panels.getCount()==1){
35331 this.resizeTo(this.config.initialSize);
35334 this.fireEvent("paneladded", this, panel);
35339 * Returns true if the panel is in this region.
35340 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35341 * @return {Boolean}
35343 hasPanel : function(panel){
35344 if(typeof panel == "object"){ // must be panel obj
35345 panel = panel.getId();
35347 return this.getPanel(panel) ? true : false;
35351 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35352 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35353 * @param {Boolean} preservePanel Overrides the config preservePanel option
35354 * @return {Roo.ContentPanel} The panel that was removed
35356 remove : function(panel, preservePanel){
35357 panel = this.getPanel(panel);
35362 this.fireEvent("beforeremove", this, panel, e);
35363 if(e.cancel === true){
35366 var panelId = panel.getId();
35367 this.panels.removeKey(panelId);
35372 * Returns the panel specified or null if it's not in this region.
35373 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35374 * @return {Roo.ContentPanel}
35376 getPanel : function(id){
35377 if(typeof id == "object"){ // must be panel obj
35380 return this.panels.get(id);
35384 * Returns this regions position (north/south/east/west/center).
35387 getPosition: function(){
35388 return this.position;
35392 * Ext JS Library 1.1.1
35393 * Copyright(c) 2006-2007, Ext JS, LLC.
35395 * Originally Released Under LGPL - original licence link has changed is not relivant.
35398 * <script type="text/javascript">
35402 * @class Roo.bootstrap.layout.Region
35403 * @extends Roo.bootstrap.layout.Basic
35404 * This class represents a region in a layout manager.
35406 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35407 * @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})
35408 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35409 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35410 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35411 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35412 * @cfg {String} title The title for the region (overrides panel titles)
35413 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35414 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35415 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35416 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35417 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35418 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35419 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35420 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35421 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35422 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35424 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35425 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35426 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35427 * @cfg {Number} width For East/West panels
35428 * @cfg {Number} height For North/South panels
35429 * @cfg {Boolean} split To show the splitter
35430 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35432 * @cfg {string} cls Extra CSS classes to add to region
35434 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35435 * @cfg {string} region the region that it inhabits..
35438 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35439 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35441 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35442 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35443 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35445 Roo.bootstrap.layout.Region = function(config)
35447 this.applyConfig(config);
35449 var mgr = config.mgr;
35450 var pos = config.region;
35451 config.skipConfig = true;
35452 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35455 this.onRender(mgr.el);
35458 this.visible = true;
35459 this.collapsed = false;
35460 this.unrendered_panels = [];
35463 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35465 position: '', // set by wrapper (eg. north/south etc..)
35466 unrendered_panels : null, // unrendered panels.
35467 createBody : function(){
35468 /** This region's body element
35469 * @type Roo.Element */
35470 this.bodyEl = this.el.createChild({
35472 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35476 onRender: function(ctr, pos)
35478 var dh = Roo.DomHelper;
35479 /** This region's container element
35480 * @type Roo.Element */
35481 this.el = dh.append(ctr.dom, {
35483 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35485 /** This region's title element
35486 * @type Roo.Element */
35488 this.titleEl = dh.append(this.el.dom,
35491 unselectable: "on",
35492 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35494 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35495 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35498 this.titleEl.enableDisplayMode();
35499 /** This region's title text element
35500 * @type HTMLElement */
35501 this.titleTextEl = this.titleEl.dom.firstChild;
35502 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35504 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35505 this.closeBtn.enableDisplayMode();
35506 this.closeBtn.on("click", this.closeClicked, this);
35507 this.closeBtn.hide();
35509 this.createBody(this.config);
35510 if(this.config.hideWhenEmpty){
35512 this.on("paneladded", this.validateVisibility, this);
35513 this.on("panelremoved", this.validateVisibility, this);
35515 if(this.autoScroll){
35516 this.bodyEl.setStyle("overflow", "auto");
35518 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35520 //if(c.titlebar !== false){
35521 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35522 this.titleEl.hide();
35524 this.titleEl.show();
35525 if(this.config.title){
35526 this.titleTextEl.innerHTML = this.config.title;
35530 if(this.config.collapsed){
35531 this.collapse(true);
35533 if(this.config.hidden){
35537 if (this.unrendered_panels && this.unrendered_panels.length) {
35538 for (var i =0;i< this.unrendered_panels.length; i++) {
35539 this.add(this.unrendered_panels[i]);
35541 this.unrendered_panels = null;
35547 applyConfig : function(c)
35550 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35551 var dh = Roo.DomHelper;
35552 if(c.titlebar !== false){
35553 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35554 this.collapseBtn.on("click", this.collapse, this);
35555 this.collapseBtn.enableDisplayMode();
35557 if(c.showPin === true || this.showPin){
35558 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35559 this.stickBtn.enableDisplayMode();
35560 this.stickBtn.on("click", this.expand, this);
35561 this.stickBtn.hide();
35566 /** This region's collapsed element
35567 * @type Roo.Element */
35570 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35571 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35574 if(c.floatable !== false){
35575 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35576 this.collapsedEl.on("click", this.collapseClick, this);
35579 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35580 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35581 id: "message", unselectable: "on", style:{"float":"left"}});
35582 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35584 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35585 this.expandBtn.on("click", this.expand, this);
35589 if(this.collapseBtn){
35590 this.collapseBtn.setVisible(c.collapsible == true);
35593 this.cmargins = c.cmargins || this.cmargins ||
35594 (this.position == "west" || this.position == "east" ?
35595 {top: 0, left: 2, right:2, bottom: 0} :
35596 {top: 2, left: 0, right:0, bottom: 2});
35598 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35601 this.bottomTabs = c.tabPosition != "top";
35603 this.autoScroll = c.autoScroll || false;
35608 this.duration = c.duration || .30;
35609 this.slideDuration = c.slideDuration || .45;
35614 * Returns true if this region is currently visible.
35615 * @return {Boolean}
35617 isVisible : function(){
35618 return this.visible;
35622 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35623 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35625 //setCollapsedTitle : function(title){
35626 // title = title || " ";
35627 // if(this.collapsedTitleTextEl){
35628 // this.collapsedTitleTextEl.innerHTML = title;
35632 getBox : function(){
35634 // if(!this.collapsed){
35635 b = this.el.getBox(false, true);
35637 // b = this.collapsedEl.getBox(false, true);
35642 getMargins : function(){
35643 return this.margins;
35644 //return this.collapsed ? this.cmargins : this.margins;
35647 highlight : function(){
35648 this.el.addClass("x-layout-panel-dragover");
35651 unhighlight : function(){
35652 this.el.removeClass("x-layout-panel-dragover");
35655 updateBox : function(box)
35657 if (!this.bodyEl) {
35658 return; // not rendered yet..
35662 if(!this.collapsed){
35663 this.el.dom.style.left = box.x + "px";
35664 this.el.dom.style.top = box.y + "px";
35665 this.updateBody(box.width, box.height);
35667 this.collapsedEl.dom.style.left = box.x + "px";
35668 this.collapsedEl.dom.style.top = box.y + "px";
35669 this.collapsedEl.setSize(box.width, box.height);
35672 this.tabs.autoSizeTabs();
35676 updateBody : function(w, h)
35679 this.el.setWidth(w);
35680 w -= this.el.getBorderWidth("rl");
35681 if(this.config.adjustments){
35682 w += this.config.adjustments[0];
35685 if(h !== null && h > 0){
35686 this.el.setHeight(h);
35687 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35688 h -= this.el.getBorderWidth("tb");
35689 if(this.config.adjustments){
35690 h += this.config.adjustments[1];
35692 this.bodyEl.setHeight(h);
35694 h = this.tabs.syncHeight(h);
35697 if(this.panelSize){
35698 w = w !== null ? w : this.panelSize.width;
35699 h = h !== null ? h : this.panelSize.height;
35701 if(this.activePanel){
35702 var el = this.activePanel.getEl();
35703 w = w !== null ? w : el.getWidth();
35704 h = h !== null ? h : el.getHeight();
35705 this.panelSize = {width: w, height: h};
35706 this.activePanel.setSize(w, h);
35708 if(Roo.isIE && this.tabs){
35709 this.tabs.el.repaint();
35714 * Returns the container element for this region.
35715 * @return {Roo.Element}
35717 getEl : function(){
35722 * Hides this region.
35725 //if(!this.collapsed){
35726 this.el.dom.style.left = "-2000px";
35729 // this.collapsedEl.dom.style.left = "-2000px";
35730 // this.collapsedEl.hide();
35732 this.visible = false;
35733 this.fireEvent("visibilitychange", this, false);
35737 * Shows this region if it was previously hidden.
35740 //if(!this.collapsed){
35743 // this.collapsedEl.show();
35745 this.visible = true;
35746 this.fireEvent("visibilitychange", this, true);
35749 closeClicked : function(){
35750 if(this.activePanel){
35751 this.remove(this.activePanel);
35755 collapseClick : function(e){
35757 e.stopPropagation();
35760 e.stopPropagation();
35766 * Collapses this region.
35767 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35770 collapse : function(skipAnim, skipCheck = false){
35771 if(this.collapsed) {
35775 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35777 this.collapsed = true;
35779 this.split.el.hide();
35781 if(this.config.animate && skipAnim !== true){
35782 this.fireEvent("invalidated", this);
35783 this.animateCollapse();
35785 this.el.setLocation(-20000,-20000);
35787 this.collapsedEl.show();
35788 this.fireEvent("collapsed", this);
35789 this.fireEvent("invalidated", this);
35795 animateCollapse : function(){
35800 * Expands this region if it was previously collapsed.
35801 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35802 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35805 expand : function(e, skipAnim){
35807 e.stopPropagation();
35809 if(!this.collapsed || this.el.hasActiveFx()) {
35813 this.afterSlideIn();
35816 this.collapsed = false;
35817 if(this.config.animate && skipAnim !== true){
35818 this.animateExpand();
35822 this.split.el.show();
35824 this.collapsedEl.setLocation(-2000,-2000);
35825 this.collapsedEl.hide();
35826 this.fireEvent("invalidated", this);
35827 this.fireEvent("expanded", this);
35831 animateExpand : function(){
35835 initTabs : function()
35837 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35839 var ts = new Roo.bootstrap.panel.Tabs({
35840 el: this.bodyEl.dom,
35841 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35842 disableTooltips: this.config.disableTabTips,
35843 toolbar : this.config.toolbar
35846 if(this.config.hideTabs){
35847 ts.stripWrap.setDisplayed(false);
35850 ts.resizeTabs = this.config.resizeTabs === true;
35851 ts.minTabWidth = this.config.minTabWidth || 40;
35852 ts.maxTabWidth = this.config.maxTabWidth || 250;
35853 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35854 ts.monitorResize = false;
35855 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35856 ts.bodyEl.addClass('roo-layout-tabs-body');
35857 this.panels.each(this.initPanelAsTab, this);
35860 initPanelAsTab : function(panel){
35861 var ti = this.tabs.addTab(
35865 this.config.closeOnTab && panel.isClosable(),
35868 if(panel.tabTip !== undefined){
35869 ti.setTooltip(panel.tabTip);
35871 ti.on("activate", function(){
35872 this.setActivePanel(panel);
35875 if(this.config.closeOnTab){
35876 ti.on("beforeclose", function(t, e){
35878 this.remove(panel);
35882 panel.tabItem = ti;
35887 updatePanelTitle : function(panel, title)
35889 if(this.activePanel == panel){
35890 this.updateTitle(title);
35893 var ti = this.tabs.getTab(panel.getEl().id);
35895 if(panel.tabTip !== undefined){
35896 ti.setTooltip(panel.tabTip);
35901 updateTitle : function(title){
35902 if(this.titleTextEl && !this.config.title){
35903 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35907 setActivePanel : function(panel)
35909 panel = this.getPanel(panel);
35910 if(this.activePanel && this.activePanel != panel){
35911 if(this.activePanel.setActiveState(false) === false){
35915 this.activePanel = panel;
35916 panel.setActiveState(true);
35917 if(this.panelSize){
35918 panel.setSize(this.panelSize.width, this.panelSize.height);
35921 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35923 this.updateTitle(panel.getTitle());
35925 this.fireEvent("invalidated", this);
35927 this.fireEvent("panelactivated", this, panel);
35931 * Shows the specified panel.
35932 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35933 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35935 showPanel : function(panel)
35937 panel = this.getPanel(panel);
35940 var tab = this.tabs.getTab(panel.getEl().id);
35941 if(tab.isHidden()){
35942 this.tabs.unhideTab(tab.id);
35946 this.setActivePanel(panel);
35953 * Get the active panel for this region.
35954 * @return {Roo.ContentPanel} The active panel or null
35956 getActivePanel : function(){
35957 return this.activePanel;
35960 validateVisibility : function(){
35961 if(this.panels.getCount() < 1){
35962 this.updateTitle(" ");
35963 this.closeBtn.hide();
35966 if(!this.isVisible()){
35973 * Adds the passed ContentPanel(s) to this region.
35974 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35975 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35977 add : function(panel)
35979 if(arguments.length > 1){
35980 for(var i = 0, len = arguments.length; i < len; i++) {
35981 this.add(arguments[i]);
35986 // if we have not been rendered yet, then we can not really do much of this..
35987 if (!this.bodyEl) {
35988 this.unrendered_panels.push(panel);
35995 if(this.hasPanel(panel)){
35996 this.showPanel(panel);
35999 panel.setRegion(this);
36000 this.panels.add(panel);
36001 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36002 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36003 // and hide them... ???
36004 this.bodyEl.dom.appendChild(panel.getEl().dom);
36005 if(panel.background !== true){
36006 this.setActivePanel(panel);
36008 this.fireEvent("paneladded", this, panel);
36015 this.initPanelAsTab(panel);
36019 if(panel.background !== true){
36020 this.tabs.activate(panel.getEl().id);
36022 this.fireEvent("paneladded", this, panel);
36027 * Hides the tab for the specified panel.
36028 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36030 hidePanel : function(panel){
36031 if(this.tabs && (panel = this.getPanel(panel))){
36032 this.tabs.hideTab(panel.getEl().id);
36037 * Unhides the tab for a previously hidden panel.
36038 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36040 unhidePanel : function(panel){
36041 if(this.tabs && (panel = this.getPanel(panel))){
36042 this.tabs.unhideTab(panel.getEl().id);
36046 clearPanels : function(){
36047 while(this.panels.getCount() > 0){
36048 this.remove(this.panels.first());
36053 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36054 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36055 * @param {Boolean} preservePanel Overrides the config preservePanel option
36056 * @return {Roo.ContentPanel} The panel that was removed
36058 remove : function(panel, preservePanel)
36060 panel = this.getPanel(panel);
36065 this.fireEvent("beforeremove", this, panel, e);
36066 if(e.cancel === true){
36069 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36070 var panelId = panel.getId();
36071 this.panels.removeKey(panelId);
36073 document.body.appendChild(panel.getEl().dom);
36076 this.tabs.removeTab(panel.getEl().id);
36077 }else if (!preservePanel){
36078 this.bodyEl.dom.removeChild(panel.getEl().dom);
36080 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36081 var p = this.panels.first();
36082 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36083 tempEl.appendChild(p.getEl().dom);
36084 this.bodyEl.update("");
36085 this.bodyEl.dom.appendChild(p.getEl().dom);
36087 this.updateTitle(p.getTitle());
36089 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36090 this.setActivePanel(p);
36092 panel.setRegion(null);
36093 if(this.activePanel == panel){
36094 this.activePanel = null;
36096 if(this.config.autoDestroy !== false && preservePanel !== true){
36097 try{panel.destroy();}catch(e){}
36099 this.fireEvent("panelremoved", this, panel);
36104 * Returns the TabPanel component used by this region
36105 * @return {Roo.TabPanel}
36107 getTabs : function(){
36111 createTool : function(parentEl, className){
36112 var btn = Roo.DomHelper.append(parentEl, {
36114 cls: "x-layout-tools-button",
36117 cls: "roo-layout-tools-button-inner " + className,
36121 btn.addClassOnOver("roo-layout-tools-button-over");
36126 * Ext JS Library 1.1.1
36127 * Copyright(c) 2006-2007, Ext JS, LLC.
36129 * Originally Released Under LGPL - original licence link has changed is not relivant.
36132 * <script type="text/javascript">
36138 * @class Roo.SplitLayoutRegion
36139 * @extends Roo.LayoutRegion
36140 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36142 Roo.bootstrap.layout.Split = function(config){
36143 this.cursor = config.cursor;
36144 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36147 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36149 splitTip : "Drag to resize.",
36150 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36151 useSplitTips : false,
36153 applyConfig : function(config){
36154 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36157 onRender : function(ctr,pos) {
36159 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36160 if(!this.config.split){
36165 var splitEl = Roo.DomHelper.append(ctr.dom, {
36167 id: this.el.id + "-split",
36168 cls: "roo-layout-split roo-layout-split-"+this.position,
36171 /** The SplitBar for this region
36172 * @type Roo.SplitBar */
36173 // does not exist yet...
36174 Roo.log([this.position, this.orientation]);
36176 this.split = new Roo.bootstrap.SplitBar({
36177 dragElement : splitEl,
36178 resizingElement: this.el,
36179 orientation : this.orientation
36182 this.split.on("moved", this.onSplitMove, this);
36183 this.split.useShim = this.config.useShim === true;
36184 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36185 if(this.useSplitTips){
36186 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36188 //if(config.collapsible){
36189 // this.split.el.on("dblclick", this.collapse, this);
36192 if(typeof this.config.minSize != "undefined"){
36193 this.split.minSize = this.config.minSize;
36195 if(typeof this.config.maxSize != "undefined"){
36196 this.split.maxSize = this.config.maxSize;
36198 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36199 this.hideSplitter();
36204 getHMaxSize : function(){
36205 var cmax = this.config.maxSize || 10000;
36206 var center = this.mgr.getRegion("center");
36207 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36210 getVMaxSize : function(){
36211 var cmax = this.config.maxSize || 10000;
36212 var center = this.mgr.getRegion("center");
36213 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36216 onSplitMove : function(split, newSize){
36217 this.fireEvent("resized", this, newSize);
36221 * Returns the {@link Roo.SplitBar} for this region.
36222 * @return {Roo.SplitBar}
36224 getSplitBar : function(){
36229 this.hideSplitter();
36230 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36233 hideSplitter : function(){
36235 this.split.el.setLocation(-2000,-2000);
36236 this.split.el.hide();
36242 this.split.el.show();
36244 Roo.bootstrap.layout.Split.superclass.show.call(this);
36247 beforeSlide: function(){
36248 if(Roo.isGecko){// firefox overflow auto bug workaround
36249 this.bodyEl.clip();
36251 this.tabs.bodyEl.clip();
36253 if(this.activePanel){
36254 this.activePanel.getEl().clip();
36256 if(this.activePanel.beforeSlide){
36257 this.activePanel.beforeSlide();
36263 afterSlide : function(){
36264 if(Roo.isGecko){// firefox overflow auto bug workaround
36265 this.bodyEl.unclip();
36267 this.tabs.bodyEl.unclip();
36269 if(this.activePanel){
36270 this.activePanel.getEl().unclip();
36271 if(this.activePanel.afterSlide){
36272 this.activePanel.afterSlide();
36278 initAutoHide : function(){
36279 if(this.autoHide !== false){
36280 if(!this.autoHideHd){
36281 var st = new Roo.util.DelayedTask(this.slideIn, this);
36282 this.autoHideHd = {
36283 "mouseout": function(e){
36284 if(!e.within(this.el, true)){
36288 "mouseover" : function(e){
36294 this.el.on(this.autoHideHd);
36298 clearAutoHide : function(){
36299 if(this.autoHide !== false){
36300 this.el.un("mouseout", this.autoHideHd.mouseout);
36301 this.el.un("mouseover", this.autoHideHd.mouseover);
36305 clearMonitor : function(){
36306 Roo.get(document).un("click", this.slideInIf, this);
36309 // these names are backwards but not changed for compat
36310 slideOut : function(){
36311 if(this.isSlid || this.el.hasActiveFx()){
36314 this.isSlid = true;
36315 if(this.collapseBtn){
36316 this.collapseBtn.hide();
36318 this.closeBtnState = this.closeBtn.getStyle('display');
36319 this.closeBtn.hide();
36321 this.stickBtn.show();
36324 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36325 this.beforeSlide();
36326 this.el.setStyle("z-index", 10001);
36327 this.el.slideIn(this.getSlideAnchor(), {
36328 callback: function(){
36330 this.initAutoHide();
36331 Roo.get(document).on("click", this.slideInIf, this);
36332 this.fireEvent("slideshow", this);
36339 afterSlideIn : function(){
36340 this.clearAutoHide();
36341 this.isSlid = false;
36342 this.clearMonitor();
36343 this.el.setStyle("z-index", "");
36344 if(this.collapseBtn){
36345 this.collapseBtn.show();
36347 this.closeBtn.setStyle('display', this.closeBtnState);
36349 this.stickBtn.hide();
36351 this.fireEvent("slidehide", this);
36354 slideIn : function(cb){
36355 if(!this.isSlid || this.el.hasActiveFx()){
36359 this.isSlid = false;
36360 this.beforeSlide();
36361 this.el.slideOut(this.getSlideAnchor(), {
36362 callback: function(){
36363 this.el.setLeftTop(-10000, -10000);
36365 this.afterSlideIn();
36373 slideInIf : function(e){
36374 if(!e.within(this.el)){
36379 animateCollapse : function(){
36380 this.beforeSlide();
36381 this.el.setStyle("z-index", 20000);
36382 var anchor = this.getSlideAnchor();
36383 this.el.slideOut(anchor, {
36384 callback : function(){
36385 this.el.setStyle("z-index", "");
36386 this.collapsedEl.slideIn(anchor, {duration:.3});
36388 this.el.setLocation(-10000,-10000);
36390 this.fireEvent("collapsed", this);
36397 animateExpand : function(){
36398 this.beforeSlide();
36399 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36400 this.el.setStyle("z-index", 20000);
36401 this.collapsedEl.hide({
36404 this.el.slideIn(this.getSlideAnchor(), {
36405 callback : function(){
36406 this.el.setStyle("z-index", "");
36409 this.split.el.show();
36411 this.fireEvent("invalidated", this);
36412 this.fireEvent("expanded", this);
36440 getAnchor : function(){
36441 return this.anchors[this.position];
36444 getCollapseAnchor : function(){
36445 return this.canchors[this.position];
36448 getSlideAnchor : function(){
36449 return this.sanchors[this.position];
36452 getAlignAdj : function(){
36453 var cm = this.cmargins;
36454 switch(this.position){
36470 getExpandAdj : function(){
36471 var c = this.collapsedEl, cm = this.cmargins;
36472 switch(this.position){
36474 return [-(cm.right+c.getWidth()+cm.left), 0];
36477 return [cm.right+c.getWidth()+cm.left, 0];
36480 return [0, -(cm.top+cm.bottom+c.getHeight())];
36483 return [0, cm.top+cm.bottom+c.getHeight()];
36489 * Ext JS Library 1.1.1
36490 * Copyright(c) 2006-2007, Ext JS, LLC.
36492 * Originally Released Under LGPL - original licence link has changed is not relivant.
36495 * <script type="text/javascript">
36498 * These classes are private internal classes
36500 Roo.bootstrap.layout.Center = function(config){
36501 config.region = "center";
36502 Roo.bootstrap.layout.Region.call(this, config);
36503 this.visible = true;
36504 this.minWidth = config.minWidth || 20;
36505 this.minHeight = config.minHeight || 20;
36508 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36510 // center panel can't be hidden
36514 // center panel can't be hidden
36517 getMinWidth: function(){
36518 return this.minWidth;
36521 getMinHeight: function(){
36522 return this.minHeight;
36535 Roo.bootstrap.layout.North = function(config)
36537 config.region = 'north';
36538 config.cursor = 'n-resize';
36540 Roo.bootstrap.layout.Split.call(this, config);
36544 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36545 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36546 this.split.el.addClass("roo-layout-split-v");
36548 var size = config.initialSize || config.height;
36549 if(typeof size != "undefined"){
36550 this.el.setHeight(size);
36553 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36555 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36559 getBox : function(){
36560 if(this.collapsed){
36561 return this.collapsedEl.getBox();
36563 var box = this.el.getBox();
36565 box.height += this.split.el.getHeight();
36570 updateBox : function(box){
36571 if(this.split && !this.collapsed){
36572 box.height -= this.split.el.getHeight();
36573 this.split.el.setLeft(box.x);
36574 this.split.el.setTop(box.y+box.height);
36575 this.split.el.setWidth(box.width);
36577 if(this.collapsed){
36578 this.updateBody(box.width, null);
36580 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36588 Roo.bootstrap.layout.South = function(config){
36589 config.region = 'south';
36590 config.cursor = 's-resize';
36591 Roo.bootstrap.layout.Split.call(this, config);
36593 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36594 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36595 this.split.el.addClass("roo-layout-split-v");
36597 var size = config.initialSize || config.height;
36598 if(typeof size != "undefined"){
36599 this.el.setHeight(size);
36603 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36604 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36605 getBox : function(){
36606 if(this.collapsed){
36607 return this.collapsedEl.getBox();
36609 var box = this.el.getBox();
36611 var sh = this.split.el.getHeight();
36618 updateBox : function(box){
36619 if(this.split && !this.collapsed){
36620 var sh = this.split.el.getHeight();
36623 this.split.el.setLeft(box.x);
36624 this.split.el.setTop(box.y-sh);
36625 this.split.el.setWidth(box.width);
36627 if(this.collapsed){
36628 this.updateBody(box.width, null);
36630 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36634 Roo.bootstrap.layout.East = function(config){
36635 config.region = "east";
36636 config.cursor = "e-resize";
36637 Roo.bootstrap.layout.Split.call(this, config);
36639 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36640 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36641 this.split.el.addClass("roo-layout-split-h");
36643 var size = config.initialSize || config.width;
36644 if(typeof size != "undefined"){
36645 this.el.setWidth(size);
36648 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36649 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36650 getBox : function(){
36651 if(this.collapsed){
36652 return this.collapsedEl.getBox();
36654 var box = this.el.getBox();
36656 var sw = this.split.el.getWidth();
36663 updateBox : function(box){
36664 if(this.split && !this.collapsed){
36665 var sw = this.split.el.getWidth();
36667 this.split.el.setLeft(box.x);
36668 this.split.el.setTop(box.y);
36669 this.split.el.setHeight(box.height);
36672 if(this.collapsed){
36673 this.updateBody(null, box.height);
36675 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36679 Roo.bootstrap.layout.West = function(config){
36680 config.region = "west";
36681 config.cursor = "w-resize";
36683 Roo.bootstrap.layout.Split.call(this, config);
36685 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36686 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36687 this.split.el.addClass("roo-layout-split-h");
36691 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36692 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36694 onRender: function(ctr, pos)
36696 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36697 var size = this.config.initialSize || this.config.width;
36698 if(typeof size != "undefined"){
36699 this.el.setWidth(size);
36703 getBox : function(){
36704 if(this.collapsed){
36705 return this.collapsedEl.getBox();
36707 var box = this.el.getBox();
36709 box.width += this.split.el.getWidth();
36714 updateBox : function(box){
36715 if(this.split && !this.collapsed){
36716 var sw = this.split.el.getWidth();
36718 this.split.el.setLeft(box.x+box.width);
36719 this.split.el.setTop(box.y);
36720 this.split.el.setHeight(box.height);
36722 if(this.collapsed){
36723 this.updateBody(null, box.height);
36725 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36728 Roo.namespace("Roo.bootstrap.panel");/*
36730 * Ext JS Library 1.1.1
36731 * Copyright(c) 2006-2007, Ext JS, LLC.
36733 * Originally Released Under LGPL - original licence link has changed is not relivant.
36736 * <script type="text/javascript">
36739 * @class Roo.ContentPanel
36740 * @extends Roo.util.Observable
36741 * A basic ContentPanel element.
36742 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36743 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36744 * @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
36745 * @cfg {Boolean} closable True if the panel can be closed/removed
36746 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36747 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36748 * @cfg {Toolbar} toolbar A toolbar for this panel
36749 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36750 * @cfg {String} title The title for this panel
36751 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36752 * @cfg {String} url Calls {@link #setUrl} with this value
36753 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36754 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36755 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36756 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36757 * @cfg {Boolean} badges render the badges
36760 * Create a new ContentPanel.
36761 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36762 * @param {String/Object} config A string to set only the title or a config object
36763 * @param {String} content (optional) Set the HTML content for this panel
36764 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36766 Roo.bootstrap.panel.Content = function( config){
36768 this.tpl = config.tpl || false;
36770 var el = config.el;
36771 var content = config.content;
36773 if(config.autoCreate){ // xtype is available if this is called from factory
36776 this.el = Roo.get(el);
36777 if(!this.el && config && config.autoCreate){
36778 if(typeof config.autoCreate == "object"){
36779 if(!config.autoCreate.id){
36780 config.autoCreate.id = config.id||el;
36782 this.el = Roo.DomHelper.append(document.body,
36783 config.autoCreate, true);
36785 var elcfg = { tag: "div",
36786 cls: "roo-layout-inactive-content",
36790 elcfg.html = config.html;
36794 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36797 this.closable = false;
36798 this.loaded = false;
36799 this.active = false;
36802 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36804 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36806 this.wrapEl = this.el; //this.el.wrap();
36808 if (config.toolbar.items) {
36809 ti = config.toolbar.items ;
36810 delete config.toolbar.items ;
36814 this.toolbar.render(this.wrapEl, 'before');
36815 for(var i =0;i < ti.length;i++) {
36816 // Roo.log(['add child', items[i]]);
36817 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36819 this.toolbar.items = nitems;
36820 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36821 delete config.toolbar;
36825 // xtype created footer. - not sure if will work as we normally have to render first..
36826 if (this.footer && !this.footer.el && this.footer.xtype) {
36827 if (!this.wrapEl) {
36828 this.wrapEl = this.el.wrap();
36831 this.footer.container = this.wrapEl.createChild();
36833 this.footer = Roo.factory(this.footer, Roo);
36838 if(typeof config == "string"){
36839 this.title = config;
36841 Roo.apply(this, config);
36845 this.resizeEl = Roo.get(this.resizeEl, true);
36847 this.resizeEl = this.el;
36849 // handle view.xtype
36857 * Fires when this panel is activated.
36858 * @param {Roo.ContentPanel} this
36862 * @event deactivate
36863 * Fires when this panel is activated.
36864 * @param {Roo.ContentPanel} this
36866 "deactivate" : true,
36870 * Fires when this panel is resized if fitToFrame is true.
36871 * @param {Roo.ContentPanel} this
36872 * @param {Number} width The width after any component adjustments
36873 * @param {Number} height The height after any component adjustments
36879 * Fires when this tab is created
36880 * @param {Roo.ContentPanel} this
36891 if(this.autoScroll){
36892 this.resizeEl.setStyle("overflow", "auto");
36894 // fix randome scrolling
36895 //this.el.on('scroll', function() {
36896 // Roo.log('fix random scolling');
36897 // this.scrollTo('top',0);
36900 content = content || this.content;
36902 this.setContent(content);
36904 if(config && config.url){
36905 this.setUrl(this.url, this.params, this.loadOnce);
36910 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36912 if (this.view && typeof(this.view.xtype) != 'undefined') {
36913 this.view.el = this.el.appendChild(document.createElement("div"));
36914 this.view = Roo.factory(this.view);
36915 this.view.render && this.view.render(false, '');
36919 this.fireEvent('render', this);
36922 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36926 setRegion : function(region){
36927 this.region = region;
36928 this.setActiveClass(region && !this.background);
36932 setActiveClass: function(state)
36935 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36936 this.el.setStyle('position','relative');
36938 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36939 this.el.setStyle('position', 'absolute');
36944 * Returns the toolbar for this Panel if one was configured.
36945 * @return {Roo.Toolbar}
36947 getToolbar : function(){
36948 return this.toolbar;
36951 setActiveState : function(active)
36953 this.active = active;
36954 this.setActiveClass(active);
36956 if(this.fireEvent("deactivate", this) === false){
36961 this.fireEvent("activate", this);
36965 * Updates this panel's element
36966 * @param {String} content The new content
36967 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36969 setContent : function(content, loadScripts){
36970 this.el.update(content, loadScripts);
36973 ignoreResize : function(w, h){
36974 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36977 this.lastSize = {width: w, height: h};
36982 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36983 * @return {Roo.UpdateManager} The UpdateManager
36985 getUpdateManager : function(){
36986 return this.el.getUpdateManager();
36989 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36990 * @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:
36993 url: "your-url.php",
36994 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36995 callback: yourFunction,
36996 scope: yourObject, //(optional scope)
36999 text: "Loading...",
37004 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37005 * 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.
37006 * @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}
37007 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37008 * @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.
37009 * @return {Roo.ContentPanel} this
37012 var um = this.el.getUpdateManager();
37013 um.update.apply(um, arguments);
37019 * 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.
37020 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37021 * @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)
37022 * @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)
37023 * @return {Roo.UpdateManager} The UpdateManager
37025 setUrl : function(url, params, loadOnce){
37026 if(this.refreshDelegate){
37027 this.removeListener("activate", this.refreshDelegate);
37029 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37030 this.on("activate", this.refreshDelegate);
37031 return this.el.getUpdateManager();
37034 _handleRefresh : function(url, params, loadOnce){
37035 if(!loadOnce || !this.loaded){
37036 var updater = this.el.getUpdateManager();
37037 updater.update(url, params, this._setLoaded.createDelegate(this));
37041 _setLoaded : function(){
37042 this.loaded = true;
37046 * Returns this panel's id
37049 getId : function(){
37054 * Returns this panel's element - used by regiosn to add.
37055 * @return {Roo.Element}
37057 getEl : function(){
37058 return this.wrapEl || this.el;
37063 adjustForComponents : function(width, height)
37065 //Roo.log('adjustForComponents ');
37066 if(this.resizeEl != this.el){
37067 width -= this.el.getFrameWidth('lr');
37068 height -= this.el.getFrameWidth('tb');
37071 var te = this.toolbar.getEl();
37072 te.setWidth(width);
37073 height -= te.getHeight();
37076 var te = this.footer.getEl();
37077 te.setWidth(width);
37078 height -= te.getHeight();
37082 if(this.adjustments){
37083 width += this.adjustments[0];
37084 height += this.adjustments[1];
37086 return {"width": width, "height": height};
37089 setSize : function(width, height){
37090 if(this.fitToFrame && !this.ignoreResize(width, height)){
37091 if(this.fitContainer && this.resizeEl != this.el){
37092 this.el.setSize(width, height);
37094 var size = this.adjustForComponents(width, height);
37095 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37096 this.fireEvent('resize', this, size.width, size.height);
37101 * Returns this panel's title
37104 getTitle : function(){
37106 if (typeof(this.title) != 'object') {
37111 for (var k in this.title) {
37112 if (!this.title.hasOwnProperty(k)) {
37116 if (k.indexOf('-') >= 0) {
37117 var s = k.split('-');
37118 for (var i = 0; i<s.length; i++) {
37119 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37122 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37129 * Set this panel's title
37130 * @param {String} title
37132 setTitle : function(title){
37133 this.title = title;
37135 this.region.updatePanelTitle(this, title);
37140 * Returns true is this panel was configured to be closable
37141 * @return {Boolean}
37143 isClosable : function(){
37144 return this.closable;
37147 beforeSlide : function(){
37149 this.resizeEl.clip();
37152 afterSlide : function(){
37154 this.resizeEl.unclip();
37158 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37159 * Will fail silently if the {@link #setUrl} method has not been called.
37160 * This does not activate the panel, just updates its content.
37162 refresh : function(){
37163 if(this.refreshDelegate){
37164 this.loaded = false;
37165 this.refreshDelegate();
37170 * Destroys this panel
37172 destroy : function(){
37173 this.el.removeAllListeners();
37174 var tempEl = document.createElement("span");
37175 tempEl.appendChild(this.el.dom);
37176 tempEl.innerHTML = "";
37182 * form - if the content panel contains a form - this is a reference to it.
37183 * @type {Roo.form.Form}
37187 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37188 * This contains a reference to it.
37194 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37204 * @param {Object} cfg Xtype definition of item to add.
37208 getChildContainer: function () {
37209 return this.getEl();
37214 var ret = new Roo.factory(cfg);
37219 if (cfg.xtype.match(/^Form$/)) {
37222 //if (this.footer) {
37223 // el = this.footer.container.insertSibling(false, 'before');
37225 el = this.el.createChild();
37228 this.form = new Roo.form.Form(cfg);
37231 if ( this.form.allItems.length) {
37232 this.form.render(el.dom);
37236 // should only have one of theses..
37237 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37238 // views.. should not be just added - used named prop 'view''
37240 cfg.el = this.el.appendChild(document.createElement("div"));
37243 var ret = new Roo.factory(cfg);
37245 ret.render && ret.render(false, ''); // render blank..
37255 * @class Roo.bootstrap.panel.Grid
37256 * @extends Roo.bootstrap.panel.Content
37258 * Create a new GridPanel.
37259 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37260 * @param {Object} config A the config object
37266 Roo.bootstrap.panel.Grid = function(config)
37270 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37271 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37273 config.el = this.wrapper;
37274 //this.el = this.wrapper;
37276 if (config.container) {
37277 // ctor'ed from a Border/panel.grid
37280 this.wrapper.setStyle("overflow", "hidden");
37281 this.wrapper.addClass('roo-grid-container');
37286 if(config.toolbar){
37287 var tool_el = this.wrapper.createChild();
37288 this.toolbar = Roo.factory(config.toolbar);
37290 if (config.toolbar.items) {
37291 ti = config.toolbar.items ;
37292 delete config.toolbar.items ;
37296 this.toolbar.render(tool_el);
37297 for(var i =0;i < ti.length;i++) {
37298 // Roo.log(['add child', items[i]]);
37299 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37301 this.toolbar.items = nitems;
37303 delete config.toolbar;
37306 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37307 config.grid.scrollBody = true;;
37308 config.grid.monitorWindowResize = false; // turn off autosizing
37309 config.grid.autoHeight = false;
37310 config.grid.autoWidth = false;
37312 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37314 if (config.background) {
37315 // render grid on panel activation (if panel background)
37316 this.on('activate', function(gp) {
37317 if (!gp.grid.rendered) {
37318 gp.grid.render(this.wrapper);
37319 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37324 this.grid.render(this.wrapper);
37325 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37328 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37329 // ??? needed ??? config.el = this.wrapper;
37334 // xtype created footer. - not sure if will work as we normally have to render first..
37335 if (this.footer && !this.footer.el && this.footer.xtype) {
37337 var ctr = this.grid.getView().getFooterPanel(true);
37338 this.footer.dataSource = this.grid.dataSource;
37339 this.footer = Roo.factory(this.footer, Roo);
37340 this.footer.render(ctr);
37350 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37351 getId : function(){
37352 return this.grid.id;
37356 * Returns the grid for this panel
37357 * @return {Roo.bootstrap.Table}
37359 getGrid : function(){
37363 setSize : function(width, height){
37364 if(!this.ignoreResize(width, height)){
37365 var grid = this.grid;
37366 var size = this.adjustForComponents(width, height);
37367 var gridel = grid.getGridEl();
37368 gridel.setSize(size.width, size.height);
37370 var thd = grid.getGridEl().select('thead',true).first();
37371 var tbd = grid.getGridEl().select('tbody', true).first();
37373 tbd.setSize(width, height - thd.getHeight());
37382 beforeSlide : function(){
37383 this.grid.getView().scroller.clip();
37386 afterSlide : function(){
37387 this.grid.getView().scroller.unclip();
37390 destroy : function(){
37391 this.grid.destroy();
37393 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37398 * @class Roo.bootstrap.panel.Nest
37399 * @extends Roo.bootstrap.panel.Content
37401 * Create a new Panel, that can contain a layout.Border.
37404 * @param {Roo.BorderLayout} layout The layout for this panel
37405 * @param {String/Object} config A string to set only the title or a config object
37407 Roo.bootstrap.panel.Nest = function(config)
37409 // construct with only one argument..
37410 /* FIXME - implement nicer consturctors
37411 if (layout.layout) {
37413 layout = config.layout;
37414 delete config.layout;
37416 if (layout.xtype && !layout.getEl) {
37417 // then layout needs constructing..
37418 layout = Roo.factory(layout, Roo);
37422 config.el = config.layout.getEl();
37424 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37426 config.layout.monitorWindowResize = false; // turn off autosizing
37427 this.layout = config.layout;
37428 this.layout.getEl().addClass("roo-layout-nested-layout");
37435 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37437 setSize : function(width, height){
37438 if(!this.ignoreResize(width, height)){
37439 var size = this.adjustForComponents(width, height);
37440 var el = this.layout.getEl();
37441 if (size.height < 1) {
37442 el.setWidth(size.width);
37444 el.setSize(size.width, size.height);
37446 var touch = el.dom.offsetWidth;
37447 this.layout.layout();
37448 // ie requires a double layout on the first pass
37449 if(Roo.isIE && !this.initialized){
37450 this.initialized = true;
37451 this.layout.layout();
37456 // activate all subpanels if not currently active..
37458 setActiveState : function(active){
37459 this.active = active;
37460 this.setActiveClass(active);
37463 this.fireEvent("deactivate", this);
37467 this.fireEvent("activate", this);
37468 // not sure if this should happen before or after..
37469 if (!this.layout) {
37470 return; // should not happen..
37473 for (var r in this.layout.regions) {
37474 reg = this.layout.getRegion(r);
37475 if (reg.getActivePanel()) {
37476 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37477 reg.setActivePanel(reg.getActivePanel());
37480 if (!reg.panels.length) {
37483 reg.showPanel(reg.getPanel(0));
37492 * Returns the nested BorderLayout for this panel
37493 * @return {Roo.BorderLayout}
37495 getLayout : function(){
37496 return this.layout;
37500 * Adds a xtype elements to the layout of the nested panel
37504 xtype : 'ContentPanel',
37511 xtype : 'NestedLayoutPanel',
37517 items : [ ... list of content panels or nested layout panels.. ]
37521 * @param {Object} cfg Xtype definition of item to add.
37523 addxtype : function(cfg) {
37524 return this.layout.addxtype(cfg);
37529 * Ext JS Library 1.1.1
37530 * Copyright(c) 2006-2007, Ext JS, LLC.
37532 * Originally Released Under LGPL - original licence link has changed is not relivant.
37535 * <script type="text/javascript">
37538 * @class Roo.TabPanel
37539 * @extends Roo.util.Observable
37540 * A lightweight tab container.
37544 // basic tabs 1, built from existing content
37545 var tabs = new Roo.TabPanel("tabs1");
37546 tabs.addTab("script", "View Script");
37547 tabs.addTab("markup", "View Markup");
37548 tabs.activate("script");
37550 // more advanced tabs, built from javascript
37551 var jtabs = new Roo.TabPanel("jtabs");
37552 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37554 // set up the UpdateManager
37555 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37556 var updater = tab2.getUpdateManager();
37557 updater.setDefaultUrl("ajax1.htm");
37558 tab2.on('activate', updater.refresh, updater, true);
37560 // Use setUrl for Ajax loading
37561 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37562 tab3.setUrl("ajax2.htm", null, true);
37565 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37568 jtabs.activate("jtabs-1");
37571 * Create a new TabPanel.
37572 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37573 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37575 Roo.bootstrap.panel.Tabs = function(config){
37577 * The container element for this TabPanel.
37578 * @type Roo.Element
37580 this.el = Roo.get(config.el);
37583 if(typeof config == "boolean"){
37584 this.tabPosition = config ? "bottom" : "top";
37586 Roo.apply(this, config);
37590 if(this.tabPosition == "bottom"){
37591 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37592 this.el.addClass("roo-tabs-bottom");
37594 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37595 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37596 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37598 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37600 if(this.tabPosition != "bottom"){
37601 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37602 * @type Roo.Element
37604 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37605 this.el.addClass("roo-tabs-top");
37609 this.bodyEl.setStyle("position", "relative");
37611 this.active = null;
37612 this.activateDelegate = this.activate.createDelegate(this);
37617 * Fires when the active tab changes
37618 * @param {Roo.TabPanel} this
37619 * @param {Roo.TabPanelItem} activePanel The new active tab
37623 * @event beforetabchange
37624 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37625 * @param {Roo.TabPanel} this
37626 * @param {Object} e Set cancel to true on this object to cancel the tab change
37627 * @param {Roo.TabPanelItem} tab The tab being changed to
37629 "beforetabchange" : true
37632 Roo.EventManager.onWindowResize(this.onResize, this);
37633 this.cpad = this.el.getPadding("lr");
37634 this.hiddenCount = 0;
37637 // toolbar on the tabbar support...
37638 if (this.toolbar) {
37639 alert("no toolbar support yet");
37640 this.toolbar = false;
37642 var tcfg = this.toolbar;
37643 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37644 this.toolbar = new Roo.Toolbar(tcfg);
37645 if (Roo.isSafari) {
37646 var tbl = tcfg.container.child('table', true);
37647 tbl.setAttribute('width', '100%');
37655 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37658 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37660 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37662 tabPosition : "top",
37664 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37666 currentTabWidth : 0,
37668 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37672 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37676 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37678 preferredTabWidth : 175,
37680 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37682 resizeTabs : false,
37684 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37686 monitorResize : true,
37688 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37693 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37694 * @param {String} id The id of the div to use <b>or create</b>
37695 * @param {String} text The text for the tab
37696 * @param {String} content (optional) Content to put in the TabPanelItem body
37697 * @param {Boolean} closable (optional) True to create a close icon on the tab
37698 * @return {Roo.TabPanelItem} The created TabPanelItem
37700 addTab : function(id, text, content, closable, tpl)
37702 var item = new Roo.bootstrap.panel.TabItem({
37706 closable : closable,
37709 this.addTabItem(item);
37711 item.setContent(content);
37717 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37718 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37719 * @return {Roo.TabPanelItem}
37721 getTab : function(id){
37722 return this.items[id];
37726 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37727 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37729 hideTab : function(id){
37730 var t = this.items[id];
37733 this.hiddenCount++;
37734 this.autoSizeTabs();
37739 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37740 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37742 unhideTab : function(id){
37743 var t = this.items[id];
37745 t.setHidden(false);
37746 this.hiddenCount--;
37747 this.autoSizeTabs();
37752 * Adds an existing {@link Roo.TabPanelItem}.
37753 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37755 addTabItem : function(item){
37756 this.items[item.id] = item;
37757 this.items.push(item);
37758 // if(this.resizeTabs){
37759 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37760 // this.autoSizeTabs();
37762 // item.autoSize();
37767 * Removes a {@link Roo.TabPanelItem}.
37768 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37770 removeTab : function(id){
37771 var items = this.items;
37772 var tab = items[id];
37773 if(!tab) { return; }
37774 var index = items.indexOf(tab);
37775 if(this.active == tab && items.length > 1){
37776 var newTab = this.getNextAvailable(index);
37781 this.stripEl.dom.removeChild(tab.pnode.dom);
37782 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37783 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37785 items.splice(index, 1);
37786 delete this.items[tab.id];
37787 tab.fireEvent("close", tab);
37788 tab.purgeListeners();
37789 this.autoSizeTabs();
37792 getNextAvailable : function(start){
37793 var items = this.items;
37795 // look for a next tab that will slide over to
37796 // replace the one being removed
37797 while(index < items.length){
37798 var item = items[++index];
37799 if(item && !item.isHidden()){
37803 // if one isn't found select the previous tab (on the left)
37806 var item = items[--index];
37807 if(item && !item.isHidden()){
37815 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37816 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37818 disableTab : function(id){
37819 var tab = this.items[id];
37820 if(tab && this.active != tab){
37826 * Enables a {@link Roo.TabPanelItem} that is disabled.
37827 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37829 enableTab : function(id){
37830 var tab = this.items[id];
37835 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37836 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37837 * @return {Roo.TabPanelItem} The TabPanelItem.
37839 activate : function(id){
37840 var tab = this.items[id];
37844 if(tab == this.active || tab.disabled){
37848 this.fireEvent("beforetabchange", this, e, tab);
37849 if(e.cancel !== true && !tab.disabled){
37851 this.active.hide();
37853 this.active = this.items[id];
37854 this.active.show();
37855 this.fireEvent("tabchange", this, this.active);
37861 * Gets the active {@link Roo.TabPanelItem}.
37862 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37864 getActiveTab : function(){
37865 return this.active;
37869 * Updates the tab body element to fit the height of the container element
37870 * for overflow scrolling
37871 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37873 syncHeight : function(targetHeight){
37874 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37875 var bm = this.bodyEl.getMargins();
37876 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37877 this.bodyEl.setHeight(newHeight);
37881 onResize : function(){
37882 if(this.monitorResize){
37883 this.autoSizeTabs();
37888 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37890 beginUpdate : function(){
37891 this.updating = true;
37895 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37897 endUpdate : function(){
37898 this.updating = false;
37899 this.autoSizeTabs();
37903 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37905 autoSizeTabs : function(){
37906 var count = this.items.length;
37907 var vcount = count - this.hiddenCount;
37908 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37911 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37912 var availWidth = Math.floor(w / vcount);
37913 var b = this.stripBody;
37914 if(b.getWidth() > w){
37915 var tabs = this.items;
37916 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37917 if(availWidth < this.minTabWidth){
37918 /*if(!this.sleft){ // incomplete scrolling code
37919 this.createScrollButtons();
37922 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37925 if(this.currentTabWidth < this.preferredTabWidth){
37926 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37932 * Returns the number of tabs in this TabPanel.
37935 getCount : function(){
37936 return this.items.length;
37940 * Resizes all the tabs to the passed width
37941 * @param {Number} The new width
37943 setTabWidth : function(width){
37944 this.currentTabWidth = width;
37945 for(var i = 0, len = this.items.length; i < len; i++) {
37946 if(!this.items[i].isHidden()) {
37947 this.items[i].setWidth(width);
37953 * Destroys this TabPanel
37954 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37956 destroy : function(removeEl){
37957 Roo.EventManager.removeResizeListener(this.onResize, this);
37958 for(var i = 0, len = this.items.length; i < len; i++){
37959 this.items[i].purgeListeners();
37961 if(removeEl === true){
37962 this.el.update("");
37967 createStrip : function(container)
37969 var strip = document.createElement("nav");
37970 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37971 container.appendChild(strip);
37975 createStripList : function(strip)
37977 // div wrapper for retard IE
37978 // returns the "tr" element.
37979 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37980 //'<div class="x-tabs-strip-wrap">'+
37981 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37982 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37983 return strip.firstChild; //.firstChild.firstChild.firstChild;
37985 createBody : function(container)
37987 var body = document.createElement("div");
37988 Roo.id(body, "tab-body");
37989 //Roo.fly(body).addClass("x-tabs-body");
37990 Roo.fly(body).addClass("tab-content");
37991 container.appendChild(body);
37994 createItemBody :function(bodyEl, id){
37995 var body = Roo.getDom(id);
37997 body = document.createElement("div");
38000 //Roo.fly(body).addClass("x-tabs-item-body");
38001 Roo.fly(body).addClass("tab-pane");
38002 bodyEl.insertBefore(body, bodyEl.firstChild);
38006 createStripElements : function(stripEl, text, closable, tpl)
38008 var td = document.createElement("li"); // was td..
38011 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38014 stripEl.appendChild(td);
38016 td.className = "x-tabs-closable";
38017 if(!this.closeTpl){
38018 this.closeTpl = new Roo.Template(
38019 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38020 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38021 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38024 var el = this.closeTpl.overwrite(td, {"text": text});
38025 var close = el.getElementsByTagName("div")[0];
38026 var inner = el.getElementsByTagName("em")[0];
38027 return {"el": el, "close": close, "inner": inner};
38030 // not sure what this is..
38031 // if(!this.tabTpl){
38032 //this.tabTpl = new Roo.Template(
38033 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38034 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38036 // this.tabTpl = new Roo.Template(
38037 // '<a href="#">' +
38038 // '<span unselectable="on"' +
38039 // (this.disableTooltips ? '' : ' title="{text}"') +
38040 // ' >{text}</span></a>'
38046 var template = tpl || this.tabTpl || false;
38050 template = new Roo.Template(
38052 '<span unselectable="on"' +
38053 (this.disableTooltips ? '' : ' title="{text}"') +
38054 ' >{text}</span></a>'
38058 switch (typeof(template)) {
38062 template = new Roo.Template(template);
38068 var el = template.overwrite(td, {"text": text});
38070 var inner = el.getElementsByTagName("span")[0];
38072 return {"el": el, "inner": inner};
38080 * @class Roo.TabPanelItem
38081 * @extends Roo.util.Observable
38082 * Represents an individual item (tab plus body) in a TabPanel.
38083 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38084 * @param {String} id The id of this TabPanelItem
38085 * @param {String} text The text for the tab of this TabPanelItem
38086 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38088 Roo.bootstrap.panel.TabItem = function(config){
38090 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38091 * @type Roo.TabPanel
38093 this.tabPanel = config.panel;
38095 * The id for this TabPanelItem
38098 this.id = config.id;
38100 this.disabled = false;
38102 this.text = config.text;
38104 this.loaded = false;
38105 this.closable = config.closable;
38108 * The body element for this TabPanelItem.
38109 * @type Roo.Element
38111 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38112 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38113 this.bodyEl.setStyle("display", "block");
38114 this.bodyEl.setStyle("zoom", "1");
38115 //this.hideAction();
38117 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38119 this.el = Roo.get(els.el);
38120 this.inner = Roo.get(els.inner, true);
38121 this.textEl = Roo.get(this.el.dom.firstChild, true);
38122 this.pnode = Roo.get(els.el.parentNode, true);
38123 // this.el.on("mousedown", this.onTabMouseDown, this);
38124 this.el.on("click", this.onTabClick, this);
38126 if(config.closable){
38127 var c = Roo.get(els.close, true);
38128 c.dom.title = this.closeText;
38129 c.addClassOnOver("close-over");
38130 c.on("click", this.closeClick, this);
38136 * Fires when this tab becomes the active tab.
38137 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38138 * @param {Roo.TabPanelItem} this
38142 * @event beforeclose
38143 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38144 * @param {Roo.TabPanelItem} this
38145 * @param {Object} e Set cancel to true on this object to cancel the close.
38147 "beforeclose": true,
38150 * Fires when this tab is closed.
38151 * @param {Roo.TabPanelItem} this
38155 * @event deactivate
38156 * Fires when this tab is no longer the active tab.
38157 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38158 * @param {Roo.TabPanelItem} this
38160 "deactivate" : true
38162 this.hidden = false;
38164 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38167 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38169 purgeListeners : function(){
38170 Roo.util.Observable.prototype.purgeListeners.call(this);
38171 this.el.removeAllListeners();
38174 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38177 this.pnode.addClass("active");
38180 this.tabPanel.stripWrap.repaint();
38182 this.fireEvent("activate", this.tabPanel, this);
38186 * Returns true if this tab is the active tab.
38187 * @return {Boolean}
38189 isActive : function(){
38190 return this.tabPanel.getActiveTab() == this;
38194 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38197 this.pnode.removeClass("active");
38199 this.fireEvent("deactivate", this.tabPanel, this);
38202 hideAction : function(){
38203 this.bodyEl.hide();
38204 this.bodyEl.setStyle("position", "absolute");
38205 this.bodyEl.setLeft("-20000px");
38206 this.bodyEl.setTop("-20000px");
38209 showAction : function(){
38210 this.bodyEl.setStyle("position", "relative");
38211 this.bodyEl.setTop("");
38212 this.bodyEl.setLeft("");
38213 this.bodyEl.show();
38217 * Set the tooltip for the tab.
38218 * @param {String} tooltip The tab's tooltip
38220 setTooltip : function(text){
38221 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38222 this.textEl.dom.qtip = text;
38223 this.textEl.dom.removeAttribute('title');
38225 this.textEl.dom.title = text;
38229 onTabClick : function(e){
38230 e.preventDefault();
38231 this.tabPanel.activate(this.id);
38234 onTabMouseDown : function(e){
38235 e.preventDefault();
38236 this.tabPanel.activate(this.id);
38239 getWidth : function(){
38240 return this.inner.getWidth();
38243 setWidth : function(width){
38244 var iwidth = width - this.pnode.getPadding("lr");
38245 this.inner.setWidth(iwidth);
38246 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38247 this.pnode.setWidth(width);
38251 * Show or hide the tab
38252 * @param {Boolean} hidden True to hide or false to show.
38254 setHidden : function(hidden){
38255 this.hidden = hidden;
38256 this.pnode.setStyle("display", hidden ? "none" : "");
38260 * Returns true if this tab is "hidden"
38261 * @return {Boolean}
38263 isHidden : function(){
38264 return this.hidden;
38268 * Returns the text for this tab
38271 getText : function(){
38275 autoSize : function(){
38276 //this.el.beginMeasure();
38277 this.textEl.setWidth(1);
38279 * #2804 [new] Tabs in Roojs
38280 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38282 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38283 //this.el.endMeasure();
38287 * Sets the text for the tab (Note: this also sets the tooltip text)
38288 * @param {String} text The tab's text and tooltip
38290 setText : function(text){
38292 this.textEl.update(text);
38293 this.setTooltip(text);
38294 //if(!this.tabPanel.resizeTabs){
38295 // this.autoSize();
38299 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38301 activate : function(){
38302 this.tabPanel.activate(this.id);
38306 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38308 disable : function(){
38309 if(this.tabPanel.active != this){
38310 this.disabled = true;
38311 this.pnode.addClass("disabled");
38316 * Enables this TabPanelItem if it was previously disabled.
38318 enable : function(){
38319 this.disabled = false;
38320 this.pnode.removeClass("disabled");
38324 * Sets the content for this TabPanelItem.
38325 * @param {String} content The content
38326 * @param {Boolean} loadScripts true to look for and load scripts
38328 setContent : function(content, loadScripts){
38329 this.bodyEl.update(content, loadScripts);
38333 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38334 * @return {Roo.UpdateManager} The UpdateManager
38336 getUpdateManager : function(){
38337 return this.bodyEl.getUpdateManager();
38341 * Set a URL to be used to load the content for this TabPanelItem.
38342 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38343 * @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)
38344 * @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)
38345 * @return {Roo.UpdateManager} The UpdateManager
38347 setUrl : function(url, params, loadOnce){
38348 if(this.refreshDelegate){
38349 this.un('activate', this.refreshDelegate);
38351 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38352 this.on("activate", this.refreshDelegate);
38353 return this.bodyEl.getUpdateManager();
38357 _handleRefresh : function(url, params, loadOnce){
38358 if(!loadOnce || !this.loaded){
38359 var updater = this.bodyEl.getUpdateManager();
38360 updater.update(url, params, this._setLoaded.createDelegate(this));
38365 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38366 * Will fail silently if the setUrl method has not been called.
38367 * This does not activate the panel, just updates its content.
38369 refresh : function(){
38370 if(this.refreshDelegate){
38371 this.loaded = false;
38372 this.refreshDelegate();
38377 _setLoaded : function(){
38378 this.loaded = true;
38382 closeClick : function(e){
38385 this.fireEvent("beforeclose", this, o);
38386 if(o.cancel !== true){
38387 this.tabPanel.removeTab(this.id);
38391 * The text displayed in the tooltip for the close icon.
38394 closeText : "Close this tab"
38397 * This script refer to:
38398 * Title: International Telephone Input
38399 * Author: Jack O'Connor
38400 * Code version: v12.1.12
38401 * Availability: https://github.com/jackocnr/intl-tel-input.git
38404 Roo.bootstrap.PhoneInputData = function() {
38407 "Afghanistan (افغانستان)",
38412 "Albania (Shqipëri)",
38417 "Algeria (الجزائر)",
38442 "Antigua and Barbuda",
38452 "Armenia (Հայաստան)",
38468 "Austria (Österreich)",
38473 "Azerbaijan (Azərbaycan)",
38483 "Bahrain (البحرين)",
38488 "Bangladesh (বাংলাদেশ)",
38498 "Belarus (Беларусь)",
38503 "Belgium (België)",
38533 "Bosnia and Herzegovina (Босна и Херцеговина)",
38548 "British Indian Ocean Territory",
38553 "British Virgin Islands",
38563 "Bulgaria (България)",
38573 "Burundi (Uburundi)",
38578 "Cambodia (កម្ពុជា)",
38583 "Cameroon (Cameroun)",
38592 ["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"]
38595 "Cape Verde (Kabu Verdi)",
38600 "Caribbean Netherlands",
38611 "Central African Republic (République centrafricaine)",
38631 "Christmas Island",
38637 "Cocos (Keeling) Islands",
38648 "Comoros (جزر القمر)",
38653 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38658 "Congo (Republic) (Congo-Brazzaville)",
38678 "Croatia (Hrvatska)",
38699 "Czech Republic (Česká republika)",
38704 "Denmark (Danmark)",
38719 "Dominican Republic (República Dominicana)",
38723 ["809", "829", "849"]
38741 "Equatorial Guinea (Guinea Ecuatorial)",
38761 "Falkland Islands (Islas Malvinas)",
38766 "Faroe Islands (Føroyar)",
38787 "French Guiana (Guyane française)",
38792 "French Polynesia (Polynésie française)",
38807 "Georgia (საქართველო)",
38812 "Germany (Deutschland)",
38832 "Greenland (Kalaallit Nunaat)",
38869 "Guinea-Bissau (Guiné Bissau)",
38894 "Hungary (Magyarország)",
38899 "Iceland (Ísland)",
38919 "Iraq (العراق)",
38935 "Israel (ישראל)",
38962 "Jordan (الأردن)",
38967 "Kazakhstan (Казахстан)",
38988 "Kuwait (الكويت)",
38993 "Kyrgyzstan (Кыргызстан)",
39003 "Latvia (Latvija)",
39008 "Lebanon (لبنان)",
39023 "Libya (ليبيا)",
39033 "Lithuania (Lietuva)",
39048 "Macedonia (FYROM) (Македонија)",
39053 "Madagascar (Madagasikara)",
39083 "Marshall Islands",
39093 "Mauritania (موريتانيا)",
39098 "Mauritius (Moris)",
39119 "Moldova (Republica Moldova)",
39129 "Mongolia (Монгол)",
39134 "Montenegro (Crna Gora)",
39144 "Morocco (المغرب)",
39150 "Mozambique (Moçambique)",
39155 "Myanmar (Burma) (မြန်မာ)",
39160 "Namibia (Namibië)",
39175 "Netherlands (Nederland)",
39180 "New Caledonia (Nouvelle-Calédonie)",
39215 "North Korea (조선 민주주의 인민 공화국)",
39220 "Northern Mariana Islands",
39236 "Pakistan (پاکستان)",
39246 "Palestine (فلسطين)",
39256 "Papua New Guinea",
39298 "Réunion (La Réunion)",
39304 "Romania (România)",
39320 "Saint Barthélemy",
39331 "Saint Kitts and Nevis",
39341 "Saint Martin (Saint-Martin (partie française))",
39347 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39352 "Saint Vincent and the Grenadines",
39367 "São Tomé and Príncipe (São Tomé e Príncipe)",
39372 "Saudi Arabia (المملكة العربية السعودية)",
39377 "Senegal (Sénégal)",
39407 "Slovakia (Slovensko)",
39412 "Slovenia (Slovenija)",
39422 "Somalia (Soomaaliya)",
39432 "South Korea (대한민국)",
39437 "South Sudan (جنوب السودان)",
39447 "Sri Lanka (ශ්රී ලංකාව)",
39452 "Sudan (السودان)",
39462 "Svalbard and Jan Mayen",
39473 "Sweden (Sverige)",
39478 "Switzerland (Schweiz)",
39483 "Syria (سوريا)",
39528 "Trinidad and Tobago",
39533 "Tunisia (تونس)",
39538 "Turkey (Türkiye)",
39548 "Turks and Caicos Islands",
39558 "U.S. Virgin Islands",
39568 "Ukraine (Україна)",
39573 "United Arab Emirates (الإمارات العربية المتحدة)",
39595 "Uzbekistan (Oʻzbekiston)",
39605 "Vatican City (Città del Vaticano)",
39616 "Vietnam (Việt Nam)",
39621 "Wallis and Futuna (Wallis-et-Futuna)",
39626 "Western Sahara (الصحراء الغربية)",
39632 "Yemen (اليمن)",
39656 * This script refer to:
39657 * Title: International Telephone Input
39658 * Author: Jack O'Connor
39659 * Code version: v12.1.12
39660 * Availability: https://github.com/jackocnr/intl-tel-input.git
39664 * @class Roo.bootstrap.PhoneInput
39665 * @extends Roo.bootstrap.TriggerField
39666 * An input with International dial-code selection
39668 * @cfg {String} defaultDialCode default '+852'
39669 * @cfg {Array} preferedCountries default []
39672 * Create a new PhoneInput.
39673 * @param {Object} config Configuration options
39676 Roo.bootstrap.PhoneInput = function(config) {
39677 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39680 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39682 listWidth: undefined,
39684 selectedClass: 'active',
39686 invalidClass : "has-warning",
39688 validClass: 'has-success',
39690 allowed: '0123456789',
39693 * @cfg {String} defaultDialCode The default dial code when initializing the input
39695 defaultDialCode: '+852',
39698 * @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
39700 preferedCountries: false,
39702 getAutoCreate : function()
39704 var data = Roo.bootstrap.PhoneInputData();
39705 var align = this.labelAlign || this.parentLabelAlign();
39708 this.allCountries = [];
39709 this.dialCodeMapping = [];
39711 for (var i = 0; i < data.length; i++) {
39713 this.allCountries[i] = {
39717 priority: c[3] || 0,
39718 areaCodes: c[4] || null
39720 this.dialCodeMapping[c[2]] = {
39723 priority: c[3] || 0,
39724 areaCodes: c[4] || null
39736 cls : 'form-control tel-input',
39737 autocomplete: 'new-password'
39740 var hiddenInput = {
39743 cls: 'hidden-tel-input'
39747 hiddenInput.name = this.name;
39750 if (this.disabled) {
39751 input.disabled = true;
39754 var flag_container = {
39771 cls: this.hasFeedback ? 'has-feedback' : '',
39777 cls: 'dial-code-holder',
39784 cls: 'roo-select2-container input-group',
39791 if (this.fieldLabel.length) {
39794 tooltip: 'This field is required'
39800 cls: 'control-label',
39806 html: this.fieldLabel
39809 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39815 if(this.indicatorpos == 'right') {
39816 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39823 if(align == 'left') {
39831 if(this.labelWidth > 12){
39832 label.style = "width: " + this.labelWidth + 'px';
39834 if(this.labelWidth < 13 && this.labelmd == 0){
39835 this.labelmd = this.labelWidth;
39837 if(this.labellg > 0){
39838 label.cls += ' col-lg-' + this.labellg;
39839 input.cls += ' col-lg-' + (12 - this.labellg);
39841 if(this.labelmd > 0){
39842 label.cls += ' col-md-' + this.labelmd;
39843 container.cls += ' col-md-' + (12 - this.labelmd);
39845 if(this.labelsm > 0){
39846 label.cls += ' col-sm-' + this.labelsm;
39847 container.cls += ' col-sm-' + (12 - this.labelsm);
39849 if(this.labelxs > 0){
39850 label.cls += ' col-xs-' + this.labelxs;
39851 container.cls += ' col-xs-' + (12 - this.labelxs);
39861 var settings = this;
39863 ['xs','sm','md','lg'].map(function(size){
39864 if (settings[size]) {
39865 cfg.cls += ' col-' + size + '-' + settings[size];
39869 this.store = new Roo.data.Store({
39870 proxy : new Roo.data.MemoryProxy({}),
39871 reader : new Roo.data.JsonReader({
39882 'name' : 'dialCode',
39886 'name' : 'priority',
39890 'name' : 'areaCodes',
39897 if(!this.preferedCountries) {
39898 this.preferedCountries = [
39905 var p = this.preferedCountries.reverse();
39908 for (var i = 0; i < p.length; i++) {
39909 for (var j = 0; j < this.allCountries.length; j++) {
39910 if(this.allCountries[j].iso2 == p[i]) {
39911 var t = this.allCountries[j];
39912 this.allCountries.splice(j,1);
39913 this.allCountries.unshift(t);
39919 this.store.proxy.data = {
39921 data: this.allCountries
39927 initEvents : function()
39930 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39932 this.indicator = this.indicatorEl();
39933 this.flag = this.flagEl();
39934 this.dialCodeHolder = this.dialCodeHolderEl();
39936 this.trigger = this.el.select('div.flag-box',true).first();
39937 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39942 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39943 _this.list.setWidth(lw);
39946 this.list.on('mouseover', this.onViewOver, this);
39947 this.list.on('mousemove', this.onViewMove, this);
39948 this.inputEl().on("keyup", this.onKeyUp, this);
39950 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39952 this.view = new Roo.View(this.list, this.tpl, {
39953 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39956 this.view.on('click', this.onViewClick, this);
39957 this.setValue(this.defaultDialCode);
39960 onTriggerClick : function(e)
39962 Roo.log('trigger click');
39967 if(this.isExpanded()){
39969 this.hasFocus = false;
39971 this.store.load({});
39972 this.hasFocus = true;
39977 isExpanded : function()
39979 return this.list.isVisible();
39982 collapse : function()
39984 if(!this.isExpanded()){
39988 Roo.get(document).un('mousedown', this.collapseIf, this);
39989 Roo.get(document).un('mousewheel', this.collapseIf, this);
39990 this.fireEvent('collapse', this);
39994 expand : function()
39998 if(this.isExpanded() || !this.hasFocus){
40002 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40003 this.list.setWidth(lw);
40006 this.restrictHeight();
40008 Roo.get(document).on('mousedown', this.collapseIf, this);
40009 Roo.get(document).on('mousewheel', this.collapseIf, this);
40011 this.fireEvent('expand', this);
40014 restrictHeight : function()
40016 this.list.alignTo(this.inputEl(), this.listAlign);
40017 this.list.alignTo(this.inputEl(), this.listAlign);
40020 onViewOver : function(e, t)
40022 if(this.inKeyMode){
40025 var item = this.view.findItemFromChild(t);
40028 var index = this.view.indexOf(item);
40029 this.select(index, false);
40034 onViewClick : function(view, doFocus, el, e)
40036 var index = this.view.getSelectedIndexes()[0];
40038 var r = this.store.getAt(index);
40041 this.onSelect(r, index);
40043 if(doFocus !== false && !this.blockFocus){
40044 this.inputEl().focus();
40048 onViewMove : function(e, t)
40050 this.inKeyMode = false;
40053 select : function(index, scrollIntoView)
40055 this.selectedIndex = index;
40056 this.view.select(index);
40057 if(scrollIntoView !== false){
40058 var el = this.view.getNode(index);
40060 this.list.scrollChildIntoView(el, false);
40065 createList : function()
40067 this.list = Roo.get(document.body).createChild({
40069 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40070 style: 'display:none'
40073 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40076 collapseIf : function(e)
40078 var in_combo = e.within(this.el);
40079 var in_list = e.within(this.list);
40080 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40082 if (in_combo || in_list || is_list) {
40088 onSelect : function(record, index)
40090 if(this.fireEvent('beforeselect', this, record, index) !== false){
40092 this.setFlagClass(record.data.iso2);
40093 this.setDialCode(record.data.dialCode);
40094 this.hasFocus = false;
40096 this.fireEvent('select', this, record, index);
40100 flagEl : function()
40102 var flag = this.el.select('div.flag',true).first();
40109 dialCodeHolderEl : function()
40111 var d = this.el.select('input.dial-code-holder',true).first();
40118 setDialCode : function(v)
40120 this.dialCodeHolder.dom.value = '+'+v;
40123 setFlagClass : function(n)
40125 this.flag.dom.className = 'flag '+n;
40128 getValue : function()
40130 var v = this.inputEl().getValue();
40131 if(this.dialCodeHolder) {
40132 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40137 setValue : function(v)
40139 var d = this.getDialCode(v);
40141 //invalid dial code
40142 if(v.length == 0 || !d || d.length == 0) {
40144 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40145 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40151 this.setFlagClass(this.dialCodeMapping[d].iso2);
40152 this.setDialCode(d);
40153 this.inputEl().dom.value = v.replace('+'+d,'');
40154 this.hiddenEl().dom.value = this.getValue();
40159 getDialCode : function(v)
40163 if (v.length == 0) {
40164 return this.dialCodeHolder.dom.value;
40168 if (v.charAt(0) != "+") {
40171 var numericChars = "";
40172 for (var i = 1; i < v.length; i++) {
40173 var c = v.charAt(i);
40176 if (this.dialCodeMapping[numericChars]) {
40177 dialCode = v.substr(1, i);
40179 if (numericChars.length == 4) {
40189 this.setValue(this.defaultDialCode);
40193 hiddenEl : function()
40195 return this.el.select('input.hidden-tel-input',true).first();
40198 onKeyUp : function(e){
40200 var k = e.getKey();
40201 var c = e.getCharCode();
40204 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40205 this.allowed.indexOf(String.fromCharCode(c)) === -1
40210 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40213 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40217 this.setValue(this.getValue());
40222 * @class Roo.bootstrap.MoneyField
40223 * @extends Roo.bootstrap.ComboBox
40224 * Bootstrap MoneyField class
40227 * Create a new MoneyField.
40228 * @param {Object} config Configuration options
40231 Roo.bootstrap.MoneyField = function(config) {
40233 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40237 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40240 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40242 allowDecimals : true,
40244 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40246 decimalSeparator : ".",
40248 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40250 decimalPrecision : 0,
40252 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40254 allowNegative : true,
40256 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40260 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40262 minValue : Number.NEGATIVE_INFINITY,
40264 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40266 maxValue : Number.MAX_VALUE,
40268 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40270 minText : "The minimum value for this field is {0}",
40272 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40274 maxText : "The maximum value for this field is {0}",
40276 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40277 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40279 nanText : "{0} is not a valid number",
40281 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40285 * @cfg {String} defaults currency of the MoneyField
40286 * value should be in lkey
40288 defaultCurrency : false,
40290 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40292 thousandsDelimiter : false,
40302 getAutoCreate : function()
40304 var align = this.labelAlign || this.parentLabelAlign();
40316 cls : 'form-control roo-money-amount-input',
40317 autocomplete: 'new-password'
40320 var hiddenInput = {
40324 cls: 'hidden-number-input'
40328 hiddenInput.name = this.name;
40331 if (this.disabled) {
40332 input.disabled = true;
40335 var clg = 12 - this.inputlg;
40336 var cmd = 12 - this.inputmd;
40337 var csm = 12 - this.inputsm;
40338 var cxs = 12 - this.inputxs;
40342 cls : 'row roo-money-field',
40346 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40350 cls: 'roo-select2-container input-group',
40354 cls : 'form-control roo-money-currency-input',
40355 autocomplete: 'new-password',
40357 name : this.currencyName
40361 cls : 'input-group-addon',
40375 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40379 cls: this.hasFeedback ? 'has-feedback' : '',
40390 if (this.fieldLabel.length) {
40393 tooltip: 'This field is required'
40399 cls: 'control-label',
40405 html: this.fieldLabel
40408 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40414 if(this.indicatorpos == 'right') {
40415 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40422 if(align == 'left') {
40430 if(this.labelWidth > 12){
40431 label.style = "width: " + this.labelWidth + 'px';
40433 if(this.labelWidth < 13 && this.labelmd == 0){
40434 this.labelmd = this.labelWidth;
40436 if(this.labellg > 0){
40437 label.cls += ' col-lg-' + this.labellg;
40438 input.cls += ' col-lg-' + (12 - this.labellg);
40440 if(this.labelmd > 0){
40441 label.cls += ' col-md-' + this.labelmd;
40442 container.cls += ' col-md-' + (12 - this.labelmd);
40444 if(this.labelsm > 0){
40445 label.cls += ' col-sm-' + this.labelsm;
40446 container.cls += ' col-sm-' + (12 - this.labelsm);
40448 if(this.labelxs > 0){
40449 label.cls += ' col-xs-' + this.labelxs;
40450 container.cls += ' col-xs-' + (12 - this.labelxs);
40461 var settings = this;
40463 ['xs','sm','md','lg'].map(function(size){
40464 if (settings[size]) {
40465 cfg.cls += ' col-' + size + '-' + settings[size];
40472 initEvents : function()
40474 this.indicator = this.indicatorEl();
40476 this.initCurrencyEvent();
40478 this.initNumberEvent();
40481 initCurrencyEvent : function()
40484 throw "can not find store for combo";
40487 this.store = Roo.factory(this.store, Roo.data);
40488 this.store.parent = this;
40492 this.triggerEl = this.el.select('.input-group-addon', true).first();
40494 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40499 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40500 _this.list.setWidth(lw);
40503 this.list.on('mouseover', this.onViewOver, this);
40504 this.list.on('mousemove', this.onViewMove, this);
40505 this.list.on('scroll', this.onViewScroll, this);
40508 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40511 this.view = new Roo.View(this.list, this.tpl, {
40512 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40515 this.view.on('click', this.onViewClick, this);
40517 this.store.on('beforeload', this.onBeforeLoad, this);
40518 this.store.on('load', this.onLoad, this);
40519 this.store.on('loadexception', this.onLoadException, this);
40521 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40522 "up" : function(e){
40523 this.inKeyMode = true;
40527 "down" : function(e){
40528 if(!this.isExpanded()){
40529 this.onTriggerClick();
40531 this.inKeyMode = true;
40536 "enter" : function(e){
40539 if(this.fireEvent("specialkey", this, e)){
40540 this.onViewClick(false);
40546 "esc" : function(e){
40550 "tab" : function(e){
40553 if(this.fireEvent("specialkey", this, e)){
40554 this.onViewClick(false);
40562 doRelay : function(foo, bar, hname){
40563 if(hname == 'down' || this.scope.isExpanded()){
40564 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40572 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40576 initNumberEvent : function(e)
40578 this.inputEl().on("keydown" , this.fireKey, this);
40579 this.inputEl().on("focus", this.onFocus, this);
40580 this.inputEl().on("blur", this.onBlur, this);
40582 this.inputEl().relayEvent('keyup', this);
40584 if(this.indicator){
40585 this.indicator.addClass('invisible');
40588 this.originalValue = this.getValue();
40590 if(this.validationEvent == 'keyup'){
40591 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40592 this.inputEl().on('keyup', this.filterValidation, this);
40594 else if(this.validationEvent !== false){
40595 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40598 if(this.selectOnFocus){
40599 this.on("focus", this.preFocus, this);
40602 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40603 this.inputEl().on("keypress", this.filterKeys, this);
40605 this.inputEl().relayEvent('keypress', this);
40608 var allowed = "0123456789";
40610 if(this.allowDecimals){
40611 allowed += this.decimalSeparator;
40614 if(this.allowNegative){
40618 if(this.thousandsDelimiter) {
40622 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40624 var keyPress = function(e){
40626 var k = e.getKey();
40628 var c = e.getCharCode();
40631 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40632 allowed.indexOf(String.fromCharCode(c)) === -1
40638 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40642 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40647 this.inputEl().on("keypress", keyPress, this);
40651 onTriggerClick : function(e)
40658 this.loadNext = false;
40660 if(this.isExpanded()){
40665 this.hasFocus = true;
40667 if(this.triggerAction == 'all') {
40668 this.doQuery(this.allQuery, true);
40672 this.doQuery(this.getRawValue());
40675 getCurrency : function()
40677 var v = this.currencyEl().getValue();
40682 restrictHeight : function()
40684 this.list.alignTo(this.currencyEl(), this.listAlign);
40685 this.list.alignTo(this.currencyEl(), this.listAlign);
40688 onViewClick : function(view, doFocus, el, e)
40690 var index = this.view.getSelectedIndexes()[0];
40692 var r = this.store.getAt(index);
40695 this.onSelect(r, index);
40699 onSelect : function(record, index){
40701 if(this.fireEvent('beforeselect', this, record, index) !== false){
40703 this.setFromCurrencyData(index > -1 ? record.data : false);
40707 this.fireEvent('select', this, record, index);
40711 setFromCurrencyData : function(o)
40715 this.lastCurrency = o;
40717 if (this.currencyField) {
40718 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40720 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40723 this.lastSelectionText = currency;
40725 //setting default currency
40726 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40727 this.setCurrency(this.defaultCurrency);
40731 this.setCurrency(currency);
40734 setFromData : function(o)
40738 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40740 this.setFromCurrencyData(c);
40745 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40747 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40750 this.setValue(value);
40754 setCurrency : function(v)
40756 this.currencyValue = v;
40759 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40764 setValue : function(v)
40766 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40772 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40774 this.inputEl().dom.value = (v == '') ? '' :
40775 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40777 if(!this.allowZero && v === '0') {
40778 this.hiddenEl().dom.value = '';
40779 this.inputEl().dom.value = '';
40786 getRawValue : function()
40788 var v = this.inputEl().getValue();
40793 getValue : function()
40795 return this.fixPrecision(this.parseValue(this.getRawValue()));
40798 parseValue : function(value)
40800 if(this.thousandsDelimiter) {
40802 r = new RegExp(",", "g");
40803 value = value.replace(r, "");
40806 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40807 return isNaN(value) ? '' : value;
40811 fixPrecision : function(value)
40813 if(this.thousandsDelimiter) {
40815 r = new RegExp(",", "g");
40816 value = value.replace(r, "");
40819 var nan = isNaN(value);
40821 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40822 return nan ? '' : value;
40824 return parseFloat(value).toFixed(this.decimalPrecision);
40827 decimalPrecisionFcn : function(v)
40829 return Math.floor(v);
40832 validateValue : function(value)
40834 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40838 var num = this.parseValue(value);
40841 this.markInvalid(String.format(this.nanText, value));
40845 if(num < this.minValue){
40846 this.markInvalid(String.format(this.minText, this.minValue));
40850 if(num > this.maxValue){
40851 this.markInvalid(String.format(this.maxText, this.maxValue));
40858 validate : function()
40860 if(this.disabled || this.allowBlank){
40865 var currency = this.getCurrency();
40867 if(this.validateValue(this.getRawValue()) && currency.length){
40872 this.markInvalid();
40876 getName: function()
40881 beforeBlur : function()
40887 var v = this.parseValue(this.getRawValue());
40894 onBlur : function()
40898 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40899 //this.el.removeClass(this.focusClass);
40902 this.hasFocus = false;
40904 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40908 var v = this.getValue();
40910 if(String(v) !== String(this.startValue)){
40911 this.fireEvent('change', this, v, this.startValue);
40914 this.fireEvent("blur", this);
40917 inputEl : function()
40919 return this.el.select('.roo-money-amount-input', true).first();
40922 currencyEl : function()
40924 return this.el.select('.roo-money-currency-input', true).first();
40927 hiddenEl : function()
40929 return this.el.select('input.hidden-number-input',true).first();