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
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | 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
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
775 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
777 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
778 * @cfg {String} fa (ban|check|...) font awesome icon
779 * @cfg {String} icon (info-sign|check|...) glyphicon name
781 * @cfg {String} html content of column.
784 * Create a new Column
785 * @param {Object} config The config object
788 Roo.bootstrap.Column = function(config){
789 Roo.bootstrap.Column.superclass.constructor.call(this, config);
792 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
804 getAutoCreate : function(){
805 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
813 ['xs','sm','md','lg'].map(function(size){
814 if (settings[size] !== false) {
815 if (!settings[size]) { // 0 = hidden
816 cfg.cls += ' hidden-' + size;
819 cfg.cls += ' col-' + size + '-' + settings[size];
823 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
824 cfg.cls +=' alert alert-' + this.alert;
828 if (this.html.length) {
829 cfg.html = this.html;
832 cfg.html = '<i class="fa fa-'+this.fa + '"></i>' + (cfg.html || '');
835 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
854 * @class Roo.bootstrap.Container
855 * @extends Roo.bootstrap.Component
856 * Bootstrap Container class
857 * @cfg {Boolean} jumbotron is it a jumbotron element
858 * @cfg {String} html content of element
859 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
860 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
861 * @cfg {String} header content of header (for panel)
862 * @cfg {String} footer content of footer (for panel)
863 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
864 * @cfg {String} tag (header|aside|section) type of HTML tag.
865 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
866 * @cfg {String} fa (ban|check|...) font awesome icon
867 * @cfg {String} icon (info-sign|check|...) glyphicon name
871 * Create a new Container
872 * @param {Object} config The config object
875 Roo.bootstrap.Container = function(config){
876 Roo.bootstrap.Container.superclass.constructor.call(this, config);
879 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
893 getChildContainer : function() {
899 if (this.panel.length) {
900 return this.el.select('.panel-body',true).first();
907 getAutoCreate : function(){
910 tag : this.tag || 'div',
914 if (this.jumbotron) {
915 cfg.cls = 'jumbotron';
920 // - this is applied by the parent..
922 // cfg.cls = this.cls + '';
925 if (this.sticky.length) {
927 var bd = Roo.get(document.body);
928 if (!bd.hasClass('bootstrap-sticky')) {
929 bd.addClass('bootstrap-sticky');
930 Roo.select('html',true).setStyle('height', '100%');
933 cfg.cls += 'bootstrap-sticky-' + this.sticky;
937 if (this.well.length) {
941 cfg.cls +=' well well-' +this.well;
948 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
949 cfg.cls +=' alert alert-' + this.alert;
954 if (this.panel.length) {
955 cfg.cls += ' panel panel-' + this.panel;
957 if (this.header.length) {
960 cls : 'panel-heading',
976 if (this.footer.length) {
978 cls : 'panel-footer',
987 body.html = this.html || cfg.html;
988 // prefix with the icons..
990 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
993 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
998 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
999 cfg.cls = 'container';
1005 titleEl : function()
1007 if(!this.el || !this.panel.length || !this.header.length){
1011 return this.el.select('.panel-title',true).first();
1014 setTitle : function(v)
1016 var titleEl = this.titleEl();
1022 titleEl.dom.innerHTML = v;
1025 getTitle : function()
1028 var titleEl = this.titleEl();
1034 return titleEl.dom.innerHTML;
1048 * @class Roo.bootstrap.Img
1049 * @extends Roo.bootstrap.Component
1050 * Bootstrap Img class
1051 * @cfg {Boolean} imgResponsive false | true
1052 * @cfg {String} border rounded | circle | thumbnail
1053 * @cfg {String} src image source
1054 * @cfg {String} alt image alternative text
1055 * @cfg {String} href a tag href
1056 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1059 * Create a new Input
1060 * @param {Object} config The config object
1063 Roo.bootstrap.Img = function(config){
1064 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1070 * The img click event for the img.
1071 * @param {Roo.EventObject} e
1077 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1079 imgResponsive: true,
1085 getAutoCreate : function(){
1089 cls: (this.imgResponsive) ? 'img-responsive' : '',
1093 cfg.html = this.html || cfg.html;
1095 cfg.src = this.src || cfg.src;
1097 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1098 cfg.cls += ' img-' + this.border;
1115 a.target = this.target;
1121 return (this.href) ? a : cfg;
1124 initEvents: function() {
1127 this.el.on('click', this.onClick, this);
1131 onClick : function(e)
1133 Roo.log('img onclick');
1134 this.fireEvent('click', this, e);
1148 * @class Roo.bootstrap.Link
1149 * @extends Roo.bootstrap.Component
1150 * Bootstrap Link Class
1151 * @cfg {String} alt image alternative text
1152 * @cfg {String} href a tag href
1153 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1154 * @cfg {String} html the content of the link.
1155 * @cfg {Boolean} preventDefault (true | false) default false
1159 * Create a new Input
1160 * @param {Object} config The config object
1163 Roo.bootstrap.Link = function(config){
1164 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1170 * The img click event for the img.
1171 * @param {Roo.EventObject} e
1177 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1181 preventDefault: false,
1183 getAutoCreate : function(){
1187 html : this.html || 'html-missing'
1194 cfg.href = this.href || '#';
1196 cfg.target = this.target;
1202 initEvents: function() {
1204 if(!this.href || this.preventDefault){
1205 this.el.on('click', this.onClick, this);
1209 onClick : function(e)
1211 if(this.preventDefault){
1214 //Roo.log('img onclick');
1215 this.fireEvent('click', this, e);
1228 * @class Roo.bootstrap.Header
1229 * @extends Roo.bootstrap.Component
1230 * Bootstrap Header class
1231 * @cfg {String} html content of header
1232 * @cfg {Number} level (1|2|3|4|5|6) default 1
1235 * Create a new Header
1236 * @param {Object} config The config object
1240 Roo.bootstrap.Header = function(config){
1241 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1244 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1252 getAutoCreate : function(){
1255 tag: 'h' + (1 *this.level),
1256 html: this.html || 'fill in html'
1268 * Ext JS Library 1.1.1
1269 * Copyright(c) 2006-2007, Ext JS, LLC.
1271 * Originally Released Under LGPL - original licence link has changed is not relivant.
1274 * <script type="text/javascript">
1278 * @class Roo.bootstrap.MenuMgr
1279 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1282 Roo.bootstrap.MenuMgr = function(){
1283 var menus, active, groups = {}, attached = false, lastShow = new Date();
1285 // private - called when first menu is created
1288 active = new Roo.util.MixedCollection();
1289 Roo.get(document).addKeyListener(27, function(){
1290 if(active.length > 0){
1298 if(active && active.length > 0){
1299 var c = active.clone();
1309 if(active.length < 1){
1310 Roo.get(document).un("mouseup", onMouseDown);
1318 var last = active.last();
1319 lastShow = new Date();
1322 Roo.get(document).on("mouseup", onMouseDown);
1327 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1328 m.parentMenu.activeChild = m;
1329 }else if(last && last.isVisible()){
1330 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1335 function onBeforeHide(m){
1337 m.activeChild.hide();
1339 if(m.autoHideTimer){
1340 clearTimeout(m.autoHideTimer);
1341 delete m.autoHideTimer;
1346 function onBeforeShow(m){
1347 var pm = m.parentMenu;
1348 if(!pm && !m.allowOtherMenus){
1350 }else if(pm && pm.activeChild && active != m){
1351 pm.activeChild.hide();
1356 function onMouseDown(e){
1357 Roo.log("on MouseDown");
1358 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1366 function onBeforeCheck(mi, state){
1368 var g = groups[mi.group];
1369 for(var i = 0, l = g.length; i < l; i++){
1371 g[i].setChecked(false);
1380 * Hides all menus that are currently visible
1382 hideAll : function(){
1387 register : function(menu){
1391 menus[menu.id] = menu;
1392 menu.on("beforehide", onBeforeHide);
1393 menu.on("hide", onHide);
1394 menu.on("beforeshow", onBeforeShow);
1395 menu.on("show", onShow);
1397 if(g && menu.events["checkchange"]){
1401 groups[g].push(menu);
1402 menu.on("checkchange", onCheck);
1407 * Returns a {@link Roo.menu.Menu} object
1408 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1409 * be used to generate and return a new Menu instance.
1411 get : function(menu){
1412 if(typeof menu == "string"){ // menu id
1414 }else if(menu.events){ // menu instance
1417 /*else if(typeof menu.length == 'number'){ // array of menu items?
1418 return new Roo.bootstrap.Menu({items:menu});
1419 }else{ // otherwise, must be a config
1420 return new Roo.bootstrap.Menu(menu);
1427 unregister : function(menu){
1428 delete menus[menu.id];
1429 menu.un("beforehide", onBeforeHide);
1430 menu.un("hide", onHide);
1431 menu.un("beforeshow", onBeforeShow);
1432 menu.un("show", onShow);
1434 if(g && menu.events["checkchange"]){
1435 groups[g].remove(menu);
1436 menu.un("checkchange", onCheck);
1441 registerCheckable : function(menuItem){
1442 var g = menuItem.group;
1447 groups[g].push(menuItem);
1448 menuItem.on("beforecheckchange", onBeforeCheck);
1453 unregisterCheckable : function(menuItem){
1454 var g = menuItem.group;
1456 groups[g].remove(menuItem);
1457 menuItem.un("beforecheckchange", onBeforeCheck);
1469 * @class Roo.bootstrap.Menu
1470 * @extends Roo.bootstrap.Component
1471 * Bootstrap Menu class - container for MenuItems
1472 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1476 * @param {Object} config The config object
1480 Roo.bootstrap.Menu = function(config){
1481 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1482 if (this.registerMenu) {
1483 Roo.bootstrap.MenuMgr.register(this);
1488 * Fires before this menu is displayed
1489 * @param {Roo.menu.Menu} this
1494 * Fires before this menu is hidden
1495 * @param {Roo.menu.Menu} this
1500 * Fires after this menu is displayed
1501 * @param {Roo.menu.Menu} this
1506 * Fires after this menu is hidden
1507 * @param {Roo.menu.Menu} this
1512 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1513 * @param {Roo.menu.Menu} this
1514 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1515 * @param {Roo.EventObject} e
1520 * Fires when the mouse is hovering over this menu
1521 * @param {Roo.menu.Menu} this
1522 * @param {Roo.EventObject} e
1523 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1528 * Fires when the mouse exits this menu
1529 * @param {Roo.menu.Menu} this
1530 * @param {Roo.EventObject} e
1531 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1536 * Fires when a menu item contained in this menu is clicked
1537 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1538 * @param {Roo.EventObject} e
1542 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1545 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1549 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1552 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1554 registerMenu : true,
1556 menuItems :false, // stores the menu items..
1562 getChildContainer : function() {
1566 getAutoCreate : function(){
1568 //if (['right'].indexOf(this.align)!==-1) {
1569 // cfg.cn[1].cls += ' pull-right'
1575 cls : 'dropdown-menu' ,
1576 style : 'z-index:1000'
1580 if (this.type === 'submenu') {
1581 cfg.cls = 'submenu active';
1583 if (this.type === 'treeview') {
1584 cfg.cls = 'treeview-menu';
1589 initEvents : function() {
1591 // Roo.log("ADD event");
1592 // Roo.log(this.triggerEl.dom);
1593 this.triggerEl.on('click', this.onTriggerPress, this);
1594 this.triggerEl.addClass('dropdown-toggle');
1595 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1597 this.el.on("mouseover", this.onMouseOver, this);
1598 this.el.on("mouseout", this.onMouseOut, this);
1602 findTargetItem : function(e){
1603 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1607 //Roo.log(t); Roo.log(t.id);
1609 //Roo.log(this.menuitems);
1610 return this.menuitems.get(t.id);
1612 //return this.items.get(t.menuItemId);
1617 onClick : function(e){
1618 Roo.log("menu.onClick");
1619 var t = this.findTargetItem(e);
1625 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1626 if(t == this.activeItem && t.shouldDeactivate(e)){
1627 this.activeItem.deactivate();
1628 delete this.activeItem;
1632 this.setActiveItem(t, true);
1639 Roo.log('pass click event');
1643 this.fireEvent("click", this, t, e);
1647 onMouseOver : function(e){
1648 var t = this.findTargetItem(e);
1651 // if(t.canActivate && !t.disabled){
1652 // this.setActiveItem(t, true);
1656 this.fireEvent("mouseover", this, e, t);
1658 isVisible : function(){
1659 return !this.hidden;
1661 onMouseOut : function(e){
1662 var t = this.findTargetItem(e);
1665 // if(t == this.activeItem && t.shouldDeactivate(e)){
1666 // this.activeItem.deactivate();
1667 // delete this.activeItem;
1670 this.fireEvent("mouseout", this, e, t);
1675 * Displays this menu relative to another element
1676 * @param {String/HTMLElement/Roo.Element} element The element to align to
1677 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1678 * the element (defaults to this.defaultAlign)
1679 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1681 show : function(el, pos, parentMenu){
1682 this.parentMenu = parentMenu;
1686 this.fireEvent("beforeshow", this);
1687 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1690 * Displays this menu at a specific xy position
1691 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1692 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1694 showAt : function(xy, parentMenu, /* private: */_e){
1695 this.parentMenu = parentMenu;
1700 this.fireEvent("beforeshow", this);
1702 //xy = this.el.adjustForConstraints(xy);
1704 //this.el.setXY(xy);
1706 this.hideMenuItems();
1707 this.hidden = false;
1708 this.triggerEl.addClass('open');
1710 this.fireEvent("show", this);
1716 this.doFocus.defer(50, this);
1720 doFocus : function(){
1722 this.focusEl.focus();
1727 * Hides this menu and optionally all parent menus
1728 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1730 hide : function(deep){
1732 this.hideMenuItems();
1733 if(this.el && this.isVisible()){
1734 this.fireEvent("beforehide", this);
1735 if(this.activeItem){
1736 this.activeItem.deactivate();
1737 this.activeItem = null;
1739 this.triggerEl.removeClass('open');;
1741 this.fireEvent("hide", this);
1743 if(deep === true && this.parentMenu){
1744 this.parentMenu.hide(true);
1748 onTriggerPress : function(e)
1751 Roo.log('trigger press');
1752 //Roo.log(e.getTarget());
1753 // Roo.log(this.triggerEl.dom);
1754 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1757 if (this.isVisible()) {
1761 this.show(this.triggerEl, false, false);
1770 hideMenuItems : function()
1772 //$(backdrop).remove()
1773 Roo.select('.open',true).each(function(aa) {
1775 aa.removeClass('open');
1776 //var parent = getParent($(this))
1777 //var relatedTarget = { relatedTarget: this }
1779 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1780 //if (e.isDefaultPrevented()) return
1781 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1784 addxtypeChild : function (tree, cntr) {
1785 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1787 this.menuitems.add(comp);
1808 * @class Roo.bootstrap.MenuItem
1809 * @extends Roo.bootstrap.Component
1810 * Bootstrap MenuItem class
1811 * @cfg {String} html the menu label
1812 * @cfg {String} href the link
1813 * @cfg {Boolean} preventDefault (true | false) default true
1817 * Create a new MenuItem
1818 * @param {Object} config The config object
1822 Roo.bootstrap.MenuItem = function(config){
1823 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1828 * The raw click event for the entire grid.
1829 * @param {Roo.EventObject} e
1835 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1839 preventDefault: true,
1841 getAutoCreate : function(){
1844 cls: 'dropdown-menu-item',
1853 if (this.parent().type == 'treeview') {
1854 cfg.cls = 'treeview-menu';
1857 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1858 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1862 initEvents: function() {
1864 //this.el.select('a').on('click', this.onClick, this);
1867 onClick : function(e)
1869 Roo.log('item on click ');
1870 //if(this.preventDefault){
1871 // e.preventDefault();
1873 //this.parent().hideMenuItems();
1875 this.fireEvent('click', this, e);
1894 * @class Roo.bootstrap.MenuSeparator
1895 * @extends Roo.bootstrap.Component
1896 * Bootstrap MenuSeparator class
1899 * Create a new MenuItem
1900 * @param {Object} config The config object
1904 Roo.bootstrap.MenuSeparator = function(config){
1905 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1908 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1910 getAutoCreate : function(){
1925 <div class="modal fade">
1926 <div class="modal-dialog">
1927 <div class="modal-content">
1928 <div class="modal-header">
1929 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1930 <h4 class="modal-title">Modal title</h4>
1932 <div class="modal-body">
1933 <p>One fine body…</p>
1935 <div class="modal-footer">
1936 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1937 <button type="button" class="btn btn-primary">Save changes</button>
1939 </div><!-- /.modal-content -->
1940 </div><!-- /.modal-dialog -->
1941 </div><!-- /.modal -->
1951 * @class Roo.bootstrap.Modal
1952 * @extends Roo.bootstrap.Component
1953 * Bootstrap Modal class
1954 * @cfg {String} title Title of dialog
1955 * @cfg {Boolean} specificTitle (true|false) default false
1956 * @cfg {Array} buttons Array of buttons or standard button set..
1957 * @cfg {String} buttonPosition (left|right|center) default right
1960 * Create a new Modal Dialog
1961 * @param {Object} config The config object
1964 Roo.bootstrap.Modal = function(config){
1965 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1970 * The raw btnclick event for the button
1971 * @param {Roo.EventObject} e
1975 this.buttons = this.buttons || [];
1978 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1980 title : 'test dialog',
1987 specificTitle: false,
1989 buttonPosition: 'right',
1991 onRender : function(ct, position)
1993 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1996 var cfg = Roo.apply({}, this.getAutoCreate());
1999 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2001 //if (!cfg.name.length) {
2005 cfg.cls += ' ' + this.cls;
2008 cfg.style = this.style;
2010 this.el = Roo.get(document.body).createChild(cfg, position);
2012 //var type = this.el.dom.type;
2014 if(this.tabIndex !== undefined){
2015 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2020 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2021 this.maskEl.enableDisplayMode("block");
2023 //this.el.addClass("x-dlg-modal");
2025 if (this.buttons.length) {
2026 Roo.each(this.buttons, function(bb) {
2027 b = Roo.apply({}, bb);
2028 b.xns = b.xns || Roo.bootstrap;
2029 b.xtype = b.xtype || 'Button';
2030 if (typeof(b.listeners) == 'undefined') {
2031 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2034 var btn = Roo.factory(b);
2036 btn.onRender(this.el.select('.modal-footer div').first());
2040 // render the children.
2043 if(typeof(this.items) != 'undefined'){
2044 var items = this.items;
2047 for(var i =0;i < items.length;i++) {
2048 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2052 this.items = nitems;
2054 this.body = this.el.select('.modal-body',true).first();
2055 this.close = this.el.select('.modal-header .close', true).first();
2056 this.footer = this.el.select('.modal-footer',true).first();
2058 //this.el.addClass([this.fieldClass, this.cls]);
2061 getAutoCreate : function(){
2066 html : this.html || ''
2071 cls : 'modal-title',
2075 if(this.specificTitle){
2081 style : 'display: none',
2084 cls: "modal-dialog",
2087 cls : "modal-content",
2090 cls : 'modal-header',
2102 cls : 'modal-footer',
2106 cls: 'btn-' + this.buttonPosition
2125 getChildContainer : function() {
2127 return this.el.select('.modal-body',true).first();
2130 getButtonContainer : function() {
2131 return this.el.select('.modal-footer div',true).first();
2134 initEvents : function()
2136 this.el.select('.modal-header .close').on('click', this.hide, this);
2138 // this.addxtype(this);
2142 if (!this.rendered) {
2146 this.el.addClass('on');
2147 this.el.removeClass('fade');
2148 this.el.setStyle('display', 'block');
2149 Roo.get(document.body).addClass("x-body-masked");
2150 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2152 this.el.setStyle('zIndex', '10001');
2153 this.fireEvent('show', this);
2159 Roo.log('Modal hide?!');
2161 Roo.get(document.body).removeClass("x-body-masked");
2162 this.el.removeClass('on');
2163 this.el.addClass('fade');
2164 this.el.setStyle('display', 'none');
2165 this.fireEvent('hide', this);
2168 addButton : function(str, cb)
2172 var b = Roo.apply({}, { html : str } );
2173 b.xns = b.xns || Roo.bootstrap;
2174 b.xtype = b.xtype || 'Button';
2175 if (typeof(b.listeners) == 'undefined') {
2176 b.listeners = { click : cb.createDelegate(this) };
2179 var btn = Roo.factory(b);
2181 btn.onRender(this.el.select('.modal-footer div').first());
2187 setDefaultButton : function(btn)
2189 //this.el.select('.modal-footer').()
2191 resizeTo: function(w,h)
2195 setContentSize : function(w, h)
2199 onButtonClick: function(btn,e)
2202 this.fireEvent('btnclick', btn.name, e);
2204 setTitle: function(str) {
2205 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2211 Roo.apply(Roo.bootstrap.Modal, {
2213 * Button config that displays a single OK button
2222 * Button config that displays Yes and No buttons
2238 * Button config that displays OK and Cancel buttons
2253 * Button config that displays Yes, No and Cancel buttons
2275 * messagebox - can be used as a replace
2279 * @class Roo.MessageBox
2280 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2284 Roo.Msg.alert('Status', 'Changes saved successfully.');
2286 // Prompt for user data:
2287 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2289 // process text value...
2293 // Show a dialog using config options:
2295 title:'Save Changes?',
2296 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2297 buttons: Roo.Msg.YESNOCANCEL,
2304 Roo.bootstrap.MessageBox = function(){
2305 var dlg, opt, mask, waitTimer;
2306 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2307 var buttons, activeTextEl, bwidth;
2311 var handleButton = function(button){
2313 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2317 var handleHide = function(){
2319 dlg.el.removeClass(opt.cls);
2322 // Roo.TaskMgr.stop(waitTimer);
2323 // waitTimer = null;
2328 var updateButtons = function(b){
2331 buttons["ok"].hide();
2332 buttons["cancel"].hide();
2333 buttons["yes"].hide();
2334 buttons["no"].hide();
2335 //dlg.footer.dom.style.display = 'none';
2338 dlg.footer.dom.style.display = '';
2339 for(var k in buttons){
2340 if(typeof buttons[k] != "function"){
2343 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2344 width += buttons[k].el.getWidth()+15;
2354 var handleEsc = function(d, k, e){
2355 if(opt && opt.closable !== false){
2365 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2366 * @return {Roo.BasicDialog} The BasicDialog element
2368 getDialog : function(){
2370 dlg = new Roo.bootstrap.Modal( {
2373 //constraintoviewport:false,
2375 //collapsible : false,
2380 //buttonAlign:"center",
2381 closeClick : function(){
2382 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2385 handleButton("cancel");
2390 dlg.on("hide", handleHide);
2392 //dlg.addKeyListener(27, handleEsc);
2394 this.buttons = buttons;
2395 var bt = this.buttonText;
2396 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2397 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2398 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2399 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2401 bodyEl = dlg.body.createChild({
2403 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2404 '<textarea class="roo-mb-textarea"></textarea>' +
2405 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2407 msgEl = bodyEl.dom.firstChild;
2408 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2409 textboxEl.enableDisplayMode();
2410 textboxEl.addKeyListener([10,13], function(){
2411 if(dlg.isVisible() && opt && opt.buttons){
2414 }else if(opt.buttons.yes){
2415 handleButton("yes");
2419 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2420 textareaEl.enableDisplayMode();
2421 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2422 progressEl.enableDisplayMode();
2423 var pf = progressEl.dom.firstChild;
2425 pp = Roo.get(pf.firstChild);
2426 pp.setHeight(pf.offsetHeight);
2434 * Updates the message box body text
2435 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2436 * the XHTML-compliant non-breaking space character '&#160;')
2437 * @return {Roo.MessageBox} This message box
2439 updateText : function(text){
2440 if(!dlg.isVisible() && !opt.width){
2441 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2443 msgEl.innerHTML = text || ' ';
2445 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2446 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2448 Math.min(opt.width || cw , this.maxWidth),
2449 Math.max(opt.minWidth || this.minWidth, bwidth)
2452 activeTextEl.setWidth(w);
2454 if(dlg.isVisible()){
2455 dlg.fixedcenter = false;
2457 // to big, make it scroll. = But as usual stupid IE does not support
2460 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2461 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2462 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2464 bodyEl.dom.style.height = '';
2465 bodyEl.dom.style.overflowY = '';
2468 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2470 bodyEl.dom.style.overflowX = '';
2473 dlg.setContentSize(w, bodyEl.getHeight());
2474 if(dlg.isVisible()){
2475 dlg.fixedcenter = true;
2481 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2482 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2483 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2484 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2485 * @return {Roo.MessageBox} This message box
2487 updateProgress : function(value, text){
2489 this.updateText(text);
2491 if (pp) { // weird bug on my firefox - for some reason this is not defined
2492 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2498 * Returns true if the message box is currently displayed
2499 * @return {Boolean} True if the message box is visible, else false
2501 isVisible : function(){
2502 return dlg && dlg.isVisible();
2506 * Hides the message box if it is displayed
2509 if(this.isVisible()){
2515 * Displays a new message box, or reinitializes an existing message box, based on the config options
2516 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2517 * The following config object properties are supported:
2519 Property Type Description
2520 ---------- --------------- ------------------------------------------------------------------------------------
2521 animEl String/Element An id or Element from which the message box should animate as it opens and
2522 closes (defaults to undefined)
2523 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2524 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2525 closable Boolean False to hide the top-right close button (defaults to true). Note that
2526 progress and wait dialogs will ignore this property and always hide the
2527 close button as they can only be closed programmatically.
2528 cls String A custom CSS class to apply to the message box element
2529 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2530 displayed (defaults to 75)
2531 fn Function A callback function to execute after closing the dialog. The arguments to the
2532 function will be btn (the name of the button that was clicked, if applicable,
2533 e.g. "ok"), and text (the value of the active text field, if applicable).
2534 Progress and wait dialogs will ignore this option since they do not respond to
2535 user actions and can only be closed programmatically, so any required function
2536 should be called by the same code after it closes the dialog.
2537 icon String A CSS class that provides a background image to be used as an icon for
2538 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2539 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2540 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2541 modal Boolean False to allow user interaction with the page while the message box is
2542 displayed (defaults to true)
2543 msg String A string that will replace the existing message box body text (defaults
2544 to the XHTML-compliant non-breaking space character ' ')
2545 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2546 progress Boolean True to display a progress bar (defaults to false)
2547 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2548 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2549 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2550 title String The title text
2551 value String The string value to set into the active textbox element if displayed
2552 wait Boolean True to display a progress bar (defaults to false)
2553 width Number The width of the dialog in pixels
2560 msg: 'Please enter your address:',
2562 buttons: Roo.MessageBox.OKCANCEL,
2565 animEl: 'addAddressBtn'
2568 * @param {Object} config Configuration options
2569 * @return {Roo.MessageBox} This message box
2571 show : function(options)
2574 // this causes nightmares if you show one dialog after another
2575 // especially on callbacks..
2577 if(this.isVisible()){
2580 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2581 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2582 Roo.log("New Dialog Message:" + options.msg )
2583 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2584 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2587 var d = this.getDialog();
2589 d.setTitle(opt.title || " ");
2590 d.close.setDisplayed(opt.closable !== false);
2591 activeTextEl = textboxEl;
2592 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2597 textareaEl.setHeight(typeof opt.multiline == "number" ?
2598 opt.multiline : this.defaultTextHeight);
2599 activeTextEl = textareaEl;
2608 progressEl.setDisplayed(opt.progress === true);
2609 this.updateProgress(0);
2610 activeTextEl.dom.value = opt.value || "";
2612 dlg.setDefaultButton(activeTextEl);
2614 var bs = opt.buttons;
2618 }else if(bs && bs.yes){
2619 db = buttons["yes"];
2621 dlg.setDefaultButton(db);
2623 bwidth = updateButtons(opt.buttons);
2624 this.updateText(opt.msg);
2626 d.el.addClass(opt.cls);
2628 d.proxyDrag = opt.proxyDrag === true;
2629 d.modal = opt.modal !== false;
2630 d.mask = opt.modal !== false ? mask : false;
2632 // force it to the end of the z-index stack so it gets a cursor in FF
2633 document.body.appendChild(dlg.el.dom);
2634 d.animateTarget = null;
2635 d.show(options.animEl);
2641 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2642 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2643 * and closing the message box when the process is complete.
2644 * @param {String} title The title bar text
2645 * @param {String} msg The message box body text
2646 * @return {Roo.MessageBox} This message box
2648 progress : function(title, msg){
2655 minWidth: this.minProgressWidth,
2662 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2663 * If a callback function is passed it will be called after the user clicks the button, and the
2664 * id of the button that was clicked will be passed as the only parameter to the callback
2665 * (could also be the top-right close button).
2666 * @param {String} title The title bar text
2667 * @param {String} msg The message box body text
2668 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2669 * @param {Object} scope (optional) The scope of the callback function
2670 * @return {Roo.MessageBox} This message box
2672 alert : function(title, msg, fn, scope){
2685 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2686 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2687 * You are responsible for closing the message box when the process is complete.
2688 * @param {String} msg The message box body text
2689 * @param {String} title (optional) The title bar text
2690 * @return {Roo.MessageBox} This message box
2692 wait : function(msg, title){
2703 waitTimer = Roo.TaskMgr.start({
2705 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2713 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2714 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2715 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2716 * @param {String} title The title bar text
2717 * @param {String} msg The message box body text
2718 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2719 * @param {Object} scope (optional) The scope of the callback function
2720 * @return {Roo.MessageBox} This message box
2722 confirm : function(title, msg, fn, scope){
2726 buttons: this.YESNO,
2735 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2736 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2737 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2738 * (could also be the top-right close button) and the text that was entered will be passed as the two
2739 * parameters to the callback.
2740 * @param {String} title The title bar text
2741 * @param {String} msg The message box body text
2742 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2743 * @param {Object} scope (optional) The scope of the callback function
2744 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2745 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2746 * @return {Roo.MessageBox} This message box
2748 prompt : function(title, msg, fn, scope, multiline){
2752 buttons: this.OKCANCEL,
2757 multiline: multiline,
2764 * Button config that displays a single OK button
2769 * Button config that displays Yes and No buttons
2772 YESNO : {yes:true, no:true},
2774 * Button config that displays OK and Cancel buttons
2777 OKCANCEL : {ok:true, cancel:true},
2779 * Button config that displays Yes, No and Cancel buttons
2782 YESNOCANCEL : {yes:true, no:true, cancel:true},
2785 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2788 defaultTextHeight : 75,
2790 * The maximum width in pixels of the message box (defaults to 600)
2795 * The minimum width in pixels of the message box (defaults to 100)
2800 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2801 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2804 minProgressWidth : 250,
2806 * An object containing the default button text strings that can be overriden for localized language support.
2807 * Supported properties are: ok, cancel, yes and no.
2808 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2821 * Shorthand for {@link Roo.MessageBox}
2823 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2824 Roo.Msg = Roo.Msg || Roo.MessageBox;
2833 * @class Roo.bootstrap.Navbar
2834 * @extends Roo.bootstrap.Component
2835 * Bootstrap Navbar class
2838 * Create a new Navbar
2839 * @param {Object} config The config object
2843 Roo.bootstrap.Navbar = function(config){
2844 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2848 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2857 getAutoCreate : function(){
2860 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2864 initEvents :function ()
2866 //Roo.log(this.el.select('.navbar-toggle',true));
2867 this.el.select('.navbar-toggle',true).on('click', function() {
2868 // Roo.log('click');
2869 this.el.select('.navbar-collapse',true).toggleClass('in');
2877 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2879 var size = this.el.getSize();
2880 this.maskEl.setSize(size.width, size.height);
2881 this.maskEl.enableDisplayMode("block");
2890 getChildContainer : function()
2892 if (this.el.select('.collapse').getCount()) {
2893 return this.el.select('.collapse',true).first();
2926 * @class Roo.bootstrap.NavSimplebar
2927 * @extends Roo.bootstrap.Navbar
2928 * Bootstrap Sidebar class
2930 * @cfg {Boolean} inverse is inverted color
2932 * @cfg {String} type (nav | pills | tabs)
2933 * @cfg {Boolean} arrangement stacked | justified
2934 * @cfg {String} align (left | right) alignment
2936 * @cfg {Boolean} main (true|false) main nav bar? default false
2937 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2939 * @cfg {String} tag (header|footer|nav|div) default is nav
2945 * Create a new Sidebar
2946 * @param {Object} config The config object
2950 Roo.bootstrap.NavSimplebar = function(config){
2951 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2954 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2970 getAutoCreate : function(){
2974 tag : this.tag || 'div',
2987 this.type = this.type || 'nav';
2988 if (['tabs','pills'].indexOf(this.type)!==-1) {
2989 cfg.cn[0].cls += ' nav-' + this.type
2993 if (this.type!=='nav') {
2994 Roo.log('nav type must be nav/tabs/pills')
2996 cfg.cn[0].cls += ' navbar-nav'
3002 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3003 cfg.cn[0].cls += ' nav-' + this.arrangement;
3007 if (this.align === 'right') {
3008 cfg.cn[0].cls += ' navbar-right';
3012 cfg.cls += ' navbar-inverse';
3039 * @class Roo.bootstrap.NavHeaderbar
3040 * @extends Roo.bootstrap.NavSimplebar
3041 * Bootstrap Sidebar class
3043 * @cfg {String} brand what is brand
3044 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3045 * @cfg {String} brand_href href of the brand
3046 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3047 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3050 * Create a new Sidebar
3051 * @param {Object} config The config object
3055 Roo.bootstrap.NavHeaderbar = function(config){
3056 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3059 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3067 getAutoCreate : function(){
3070 tag: this.nav || 'nav',
3079 cls: 'navbar-header',
3084 cls: 'navbar-toggle',
3085 'data-toggle': 'collapse',
3090 html: 'Toggle navigation'
3112 cls: 'collapse navbar-collapse',
3116 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3118 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3119 cfg.cls += ' navbar-' + this.position;
3121 // tag can override this..
3123 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3126 if (this.brand !== '') {
3129 href: this.brand_href ? this.brand_href : '#',
3130 cls: 'navbar-brand',
3138 cfg.cls += ' main-nav';
3146 initEvents : function()
3148 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3150 if (this.autohide) {
3155 Roo.get(document).on('scroll',function(e) {
3156 var ns = Roo.get(document).getScroll().top;
3157 var os = prevScroll;
3161 ft.removeClass('slideDown');
3162 ft.addClass('slideUp');
3165 ft.removeClass('slideUp');
3166 ft.addClass('slideDown');
3190 * @class Roo.bootstrap.NavSidebar
3191 * @extends Roo.bootstrap.Navbar
3192 * Bootstrap Sidebar class
3195 * Create a new Sidebar
3196 * @param {Object} config The config object
3200 Roo.bootstrap.NavSidebar = function(config){
3201 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3204 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3206 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3208 getAutoCreate : function(){
3213 cls: 'sidebar sidebar-nav'
3235 * @class Roo.bootstrap.NavGroup
3236 * @extends Roo.bootstrap.Component
3237 * Bootstrap NavGroup class
3238 * @cfg {String} align left | right
3239 * @cfg {Boolean} inverse false | true
3240 * @cfg {String} type (nav|pills|tab) default nav
3241 * @cfg {String} navId - reference Id for navbar.
3245 * Create a new nav group
3246 * @param {Object} config The config object
3249 Roo.bootstrap.NavGroup = function(config){
3250 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3253 Roo.bootstrap.NavGroup.register(this);
3257 * Fires when the active item changes
3258 * @param {Roo.bootstrap.NavGroup} this
3259 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3260 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3267 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3278 getAutoCreate : function()
3280 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3287 if (['tabs','pills'].indexOf(this.type)!==-1) {
3288 cfg.cls += ' nav-' + this.type
3290 if (this.type!=='nav') {
3291 Roo.log('nav type must be nav/tabs/pills')
3293 cfg.cls += ' navbar-nav'
3296 if (this.parent().sidebar) {
3299 cls: 'dashboard-menu sidebar-menu'
3305 if (this.form === true) {
3311 if (this.align === 'right') {
3312 cfg.cls += ' navbar-right';
3314 cfg.cls += ' navbar-left';
3318 if (this.align === 'right') {
3319 cfg.cls += ' navbar-right';
3323 cfg.cls += ' navbar-inverse';
3331 * sets the active Navigation item
3332 * @param {Roo.bootstrap.NavItem} the new current navitem
3334 setActiveItem : function(item)
3337 Roo.each(this.navItems, function(v){
3342 v.setActive(false, true);
3349 item.setActive(true, true);
3350 this.fireEvent('changed', this, item, prev);
3355 * gets the active Navigation item
3356 * @return {Roo.bootstrap.NavItem} the current navitem
3358 getActive : function()
3362 Roo.each(this.navItems, function(v){
3373 indexOfNav : function()
3377 Roo.each(this.navItems, function(v,i){
3388 * adds a Navigation item
3389 * @param {Roo.bootstrap.NavItem} the navitem to add
3391 addItem : function(cfg)
3393 var cn = new Roo.bootstrap.NavItem(cfg);
3395 cn.parentId = this.id;
3396 cn.onRender(this.el, null);
3400 * register a Navigation item
3401 * @param {Roo.bootstrap.NavItem} the navitem to add
3403 register : function(item)
3405 this.navItems.push( item);
3406 item.navId = this.navId;
3411 getNavItem: function(tabId)
3414 Roo.each(this.navItems, function(e) {
3415 if (e.tabId == tabId) {
3425 setActiveNext : function()
3427 var i = this.indexOfNav(this.getActive());
3428 if (i > this.navItems.length) {
3431 this.setActiveItem(this.navItems[i+1]);
3433 setActivePrev : function()
3435 var i = this.indexOfNav(this.getActive());
3439 this.setActiveItem(this.navItems[i-1]);
3441 clearWasActive : function(except) {
3442 Roo.each(this.navItems, function(e) {
3443 if (e.tabId != except.tabId && e.was_active) {
3444 e.was_active = false;
3451 getWasActive : function ()
3454 Roo.each(this.navItems, function(e) {
3469 Roo.apply(Roo.bootstrap.NavGroup, {
3473 * register a Navigation Group
3474 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3476 register : function(navgrp)
3478 this.groups[navgrp.navId] = navgrp;
3482 * fetch a Navigation Group based on the navigation ID
3483 * @param {string} the navgroup to add
3484 * @returns {Roo.bootstrap.NavGroup} the navgroup
3486 get: function(navId) {
3487 if (typeof(this.groups[navId]) == 'undefined') {
3489 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3491 return this.groups[navId] ;
3506 * @class Roo.bootstrap.NavItem
3507 * @extends Roo.bootstrap.Component
3508 * Bootstrap Navbar.NavItem class
3509 * @cfg {String} href link to
3510 * @cfg {String} html content of button
3511 * @cfg {String} badge text inside badge
3512 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3513 * @cfg {String} glyphicon name of glyphicon
3514 * @cfg {String} icon name of font awesome icon
3515 * @cfg {Boolean} active Is item active
3516 * @cfg {Boolean} disabled Is item disabled
3518 * @cfg {Boolean} preventDefault (true | false) default false
3519 * @cfg {String} tabId the tab that this item activates.
3520 * @cfg {String} tagtype (a|span) render as a href or span?
3523 * Create a new Navbar Item
3524 * @param {Object} config The config object
3526 Roo.bootstrap.NavItem = function(config){
3527 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3532 * The raw click event for the entire grid.
3533 * @param {Roo.EventObject} e
3538 * Fires when the active item active state changes
3539 * @param {Roo.bootstrap.NavItem} this
3540 * @param {boolean} state the new state
3548 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3556 preventDefault : false,
3563 getAutoCreate : function(){
3571 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3573 if (this.disabled) {
3574 cfg.cls += ' disabled';
3577 if (this.href || this.html || this.glyphicon || this.icon) {
3581 href : this.href || "#",
3582 html: this.html || ''
3587 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3590 if(this.glyphicon) {
3591 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3596 cfg.cn[0].html += " <span class='caret'></span>";
3600 if (this.badge !== '') {
3602 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3610 initEvents: function() {
3611 // Roo.log('init events?');
3612 // Roo.log(this.el.dom);
3613 if (typeof (this.menu) != 'undefined') {
3614 this.menu.parentType = this.xtype;
3615 this.menu.triggerEl = this.el;
3616 this.addxtype(Roo.apply({}, this.menu));
3620 this.el.select('a',true).on('click', this.onClick, this);
3621 // at this point parent should be available..
3622 this.parent().register(this);
3625 onClick : function(e)
3628 if(this.preventDefault){
3631 if (this.disabled) {
3635 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3636 if (tg && tg.transition) {
3637 Roo.log("waiting for the transitionend");
3641 Roo.log("fire event clicked");
3642 if(this.fireEvent('click', this, e) === false){
3646 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3647 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3648 this.parent().setActiveItem(this);
3653 isActive: function () {
3656 setActive : function(state, fire, is_was_active)
3658 if (this.active && !state & this.navId) {
3659 this.was_active = true;
3660 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3662 nv.clearWasActive(this);
3666 this.active = state;
3669 this.el.removeClass('active');
3670 } else if (!this.el.hasClass('active')) {
3671 this.el.addClass('active');
3674 this.fireEvent('changed', this, state);
3677 // show a panel if it's registered and related..
3679 if (!this.navId || !this.tabId || !state || is_was_active) {
3683 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3687 var pan = tg.getPanelByName(this.tabId);
3691 // if we can not flip to new panel - go back to old nav highlight..
3692 if (false == tg.showPanel(pan)) {
3693 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3695 var onav = nv.getWasActive();
3697 onav.setActive(true, false, true);
3706 // this should not be here...
3707 setDisabled : function(state)
3709 this.disabled = state;
3711 this.el.removeClass('disabled');
3712 } else if (!this.el.hasClass('disabled')) {
3713 this.el.addClass('disabled');
3726 * <span> icon </span>
3727 * <span> text </span>
3728 * <span>badge </span>
3732 * @class Roo.bootstrap.NavSidebarItem
3733 * @extends Roo.bootstrap.NavItem
3734 * Bootstrap Navbar.NavSidebarItem class
3736 * Create a new Navbar Button
3737 * @param {Object} config The config object
3739 Roo.bootstrap.NavSidebarItem = function(config){
3740 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3745 * The raw click event for the entire grid.
3746 * @param {Roo.EventObject} e
3751 * Fires when the active item active state changes
3752 * @param {Roo.bootstrap.NavSidebarItem} this
3753 * @param {boolean} state the new state
3761 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3764 getAutoCreate : function(){
3769 href : this.href || '#',
3781 html : this.html || ''
3786 cfg.cls += ' active';
3790 if (this.glyphicon || this.icon) {
3791 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3792 a.cn.push({ tag : 'i', cls : c }) ;
3797 if (this.badge !== '') {
3798 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3802 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3803 a.cls += 'dropdown-toggle treeview' ;
3827 * @class Roo.bootstrap.Row
3828 * @extends Roo.bootstrap.Component
3829 * Bootstrap Row class (contains columns...)
3833 * @param {Object} config The config object
3836 Roo.bootstrap.Row = function(config){
3837 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3840 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3842 getAutoCreate : function(){
3861 * @class Roo.bootstrap.Element
3862 * @extends Roo.bootstrap.Component
3863 * Bootstrap Element class
3864 * @cfg {String} html contents of the element
3865 * @cfg {String} tag tag of the element
3866 * @cfg {String} cls class of the element
3869 * Create a new Element
3870 * @param {Object} config The config object
3873 Roo.bootstrap.Element = function(config){
3874 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3877 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3884 getAutoCreate : function(){
3909 * @class Roo.bootstrap.Pagination
3910 * @extends Roo.bootstrap.Component
3911 * Bootstrap Pagination class
3912 * @cfg {String} size xs | sm | md | lg
3913 * @cfg {Boolean} inverse false | true
3916 * Create a new Pagination
3917 * @param {Object} config The config object
3920 Roo.bootstrap.Pagination = function(config){
3921 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3924 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3930 getAutoCreate : function(){
3936 cfg.cls += ' inverse';
3942 cfg.cls += " " + this.cls;
3960 * @class Roo.bootstrap.PaginationItem
3961 * @extends Roo.bootstrap.Component
3962 * Bootstrap PaginationItem class
3963 * @cfg {String} html text
3964 * @cfg {String} href the link
3965 * @cfg {Boolean} preventDefault (true | false) default true
3966 * @cfg {Boolean} active (true | false) default false
3970 * Create a new PaginationItem
3971 * @param {Object} config The config object
3975 Roo.bootstrap.PaginationItem = function(config){
3976 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3981 * The raw click event for the entire grid.
3982 * @param {Roo.EventObject} e
3988 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3992 preventDefault: true,
3996 getAutoCreate : function(){
4002 href : this.href ? this.href : '#',
4003 html : this.html ? this.html : ''
4013 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4019 initEvents: function() {
4021 this.el.on('click', this.onClick, this);
4024 onClick : function(e)
4026 Roo.log('PaginationItem on click ');
4027 if(this.preventDefault){
4031 this.fireEvent('click', this, e);
4047 * @class Roo.bootstrap.Slider
4048 * @extends Roo.bootstrap.Component
4049 * Bootstrap Slider class
4052 * Create a new Slider
4053 * @param {Object} config The config object
4056 Roo.bootstrap.Slider = function(config){
4057 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4060 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4062 getAutoCreate : function(){
4066 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4070 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4082 * Ext JS Library 1.1.1
4083 * Copyright(c) 2006-2007, Ext JS, LLC.
4085 * Originally Released Under LGPL - original licence link has changed is not relivant.
4088 * <script type="text/javascript">
4093 * @class Roo.grid.ColumnModel
4094 * @extends Roo.util.Observable
4095 * This is the default implementation of a ColumnModel used by the Grid. It defines
4096 * the columns in the grid.
4099 var colModel = new Roo.grid.ColumnModel([
4100 {header: "Ticker", width: 60, sortable: true, locked: true},
4101 {header: "Company Name", width: 150, sortable: true},
4102 {header: "Market Cap.", width: 100, sortable: true},
4103 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4104 {header: "Employees", width: 100, sortable: true, resizable: false}
4109 * The config options listed for this class are options which may appear in each
4110 * individual column definition.
4111 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4113 * @param {Object} config An Array of column config objects. See this class's
4114 * config objects for details.
4116 Roo.grid.ColumnModel = function(config){
4118 * The config passed into the constructor
4120 this.config = config;
4123 // if no id, create one
4124 // if the column does not have a dataIndex mapping,
4125 // map it to the order it is in the config
4126 for(var i = 0, len = config.length; i < len; i++){
4128 if(typeof c.dataIndex == "undefined"){
4131 if(typeof c.renderer == "string"){
4132 c.renderer = Roo.util.Format[c.renderer];
4134 if(typeof c.id == "undefined"){
4137 if(c.editor && c.editor.xtype){
4138 c.editor = Roo.factory(c.editor, Roo.grid);
4140 if(c.editor && c.editor.isFormField){
4141 c.editor = new Roo.grid.GridEditor(c.editor);
4143 this.lookup[c.id] = c;
4147 * The width of columns which have no width specified (defaults to 100)
4150 this.defaultWidth = 100;
4153 * Default sortable of columns which have no sortable specified (defaults to false)
4156 this.defaultSortable = false;
4160 * @event widthchange
4161 * Fires when the width of a column changes.
4162 * @param {ColumnModel} this
4163 * @param {Number} columnIndex The column index
4164 * @param {Number} newWidth The new width
4166 "widthchange": true,
4168 * @event headerchange
4169 * Fires when the text of a header changes.
4170 * @param {ColumnModel} this
4171 * @param {Number} columnIndex The column index
4172 * @param {Number} newText The new header text
4174 "headerchange": true,
4176 * @event hiddenchange
4177 * Fires when a column is hidden or "unhidden".
4178 * @param {ColumnModel} this
4179 * @param {Number} columnIndex The column index
4180 * @param {Boolean} hidden true if hidden, false otherwise
4182 "hiddenchange": true,
4184 * @event columnmoved
4185 * Fires when a column is moved.
4186 * @param {ColumnModel} this
4187 * @param {Number} oldIndex
4188 * @param {Number} newIndex
4190 "columnmoved" : true,
4192 * @event columlockchange
4193 * Fires when a column's locked state is changed
4194 * @param {ColumnModel} this
4195 * @param {Number} colIndex
4196 * @param {Boolean} locked true if locked
4198 "columnlockchange" : true
4200 Roo.grid.ColumnModel.superclass.constructor.call(this);
4202 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4204 * @cfg {String} header The header text to display in the Grid view.
4207 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4208 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4209 * specified, the column's index is used as an index into the Record's data Array.
4212 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4213 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4216 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4217 * Defaults to the value of the {@link #defaultSortable} property.
4218 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4221 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4224 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4227 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4230 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4233 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4234 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4235 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4236 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4239 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4242 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4246 * Returns the id of the column at the specified index.
4247 * @param {Number} index The column index
4248 * @return {String} the id
4250 getColumnId : function(index){
4251 return this.config[index].id;
4255 * Returns the column for a specified id.
4256 * @param {String} id The column id
4257 * @return {Object} the column
4259 getColumnById : function(id){
4260 return this.lookup[id];
4265 * Returns the column for a specified dataIndex.
4266 * @param {String} dataIndex The column dataIndex
4267 * @return {Object|Boolean} the column or false if not found
4269 getColumnByDataIndex: function(dataIndex){
4270 var index = this.findColumnIndex(dataIndex);
4271 return index > -1 ? this.config[index] : false;
4275 * Returns the index for a specified column id.
4276 * @param {String} id The column id
4277 * @return {Number} the index, or -1 if not found
4279 getIndexById : function(id){
4280 for(var i = 0, len = this.config.length; i < len; i++){
4281 if(this.config[i].id == id){
4289 * Returns the index for a specified column dataIndex.
4290 * @param {String} dataIndex The column dataIndex
4291 * @return {Number} the index, or -1 if not found
4294 findColumnIndex : function(dataIndex){
4295 for(var i = 0, len = this.config.length; i < len; i++){
4296 if(this.config[i].dataIndex == dataIndex){
4304 moveColumn : function(oldIndex, newIndex){
4305 var c = this.config[oldIndex];
4306 this.config.splice(oldIndex, 1);
4307 this.config.splice(newIndex, 0, c);
4308 this.dataMap = null;
4309 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4312 isLocked : function(colIndex){
4313 return this.config[colIndex].locked === true;
4316 setLocked : function(colIndex, value, suppressEvent){
4317 if(this.isLocked(colIndex) == value){
4320 this.config[colIndex].locked = value;
4322 this.fireEvent("columnlockchange", this, colIndex, value);
4326 getTotalLockedWidth : function(){
4328 for(var i = 0; i < this.config.length; i++){
4329 if(this.isLocked(i) && !this.isHidden(i)){
4330 this.totalWidth += this.getColumnWidth(i);
4336 getLockedCount : function(){
4337 for(var i = 0, len = this.config.length; i < len; i++){
4338 if(!this.isLocked(i)){
4345 * Returns the number of columns.
4348 getColumnCount : function(visibleOnly){
4349 if(visibleOnly === true){
4351 for(var i = 0, len = this.config.length; i < len; i++){
4352 if(!this.isHidden(i)){
4358 return this.config.length;
4362 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4363 * @param {Function} fn
4364 * @param {Object} scope (optional)
4365 * @return {Array} result
4367 getColumnsBy : function(fn, scope){
4369 for(var i = 0, len = this.config.length; i < len; i++){
4370 var c = this.config[i];
4371 if(fn.call(scope||this, c, i) === true){
4379 * Returns true if the specified column is sortable.
4380 * @param {Number} col The column index
4383 isSortable : function(col){
4384 if(typeof this.config[col].sortable == "undefined"){
4385 return this.defaultSortable;
4387 return this.config[col].sortable;
4391 * Returns the rendering (formatting) function defined for the column.
4392 * @param {Number} col The column index.
4393 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4395 getRenderer : function(col){
4396 if(!this.config[col].renderer){
4397 return Roo.grid.ColumnModel.defaultRenderer;
4399 return this.config[col].renderer;
4403 * Sets the rendering (formatting) function for a column.
4404 * @param {Number} col The column index
4405 * @param {Function} fn The function to use to process the cell's raw data
4406 * to return HTML markup for the grid view. The render function is called with
4407 * the following parameters:<ul>
4408 * <li>Data value.</li>
4409 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4410 * <li>css A CSS style string to apply to the table cell.</li>
4411 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4412 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4413 * <li>Row index</li>
4414 * <li>Column index</li>
4415 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4417 setRenderer : function(col, fn){
4418 this.config[col].renderer = fn;
4422 * Returns the width for the specified column.
4423 * @param {Number} col The column index
4426 getColumnWidth : function(col){
4427 return this.config[col].width * 1 || this.defaultWidth;
4431 * Sets the width for a column.
4432 * @param {Number} col The column index
4433 * @param {Number} width The new width
4435 setColumnWidth : function(col, width, suppressEvent){
4436 this.config[col].width = width;
4437 this.totalWidth = null;
4439 this.fireEvent("widthchange", this, col, width);
4444 * Returns the total width of all columns.
4445 * @param {Boolean} includeHidden True to include hidden column widths
4448 getTotalWidth : function(includeHidden){
4449 if(!this.totalWidth){
4450 this.totalWidth = 0;
4451 for(var i = 0, len = this.config.length; i < len; i++){
4452 if(includeHidden || !this.isHidden(i)){
4453 this.totalWidth += this.getColumnWidth(i);
4457 return this.totalWidth;
4461 * Returns the header for the specified column.
4462 * @param {Number} col The column index
4465 getColumnHeader : function(col){
4466 return this.config[col].header;
4470 * Sets the header for a column.
4471 * @param {Number} col The column index
4472 * @param {String} header The new header
4474 setColumnHeader : function(col, header){
4475 this.config[col].header = header;
4476 this.fireEvent("headerchange", this, col, header);
4480 * Returns the tooltip for the specified column.
4481 * @param {Number} col The column index
4484 getColumnTooltip : function(col){
4485 return this.config[col].tooltip;
4488 * Sets the tooltip for a column.
4489 * @param {Number} col The column index
4490 * @param {String} tooltip The new tooltip
4492 setColumnTooltip : function(col, tooltip){
4493 this.config[col].tooltip = tooltip;
4497 * Returns the dataIndex for the specified column.
4498 * @param {Number} col The column index
4501 getDataIndex : function(col){
4502 return this.config[col].dataIndex;
4506 * Sets the dataIndex for a column.
4507 * @param {Number} col The column index
4508 * @param {Number} dataIndex The new dataIndex
4510 setDataIndex : function(col, dataIndex){
4511 this.config[col].dataIndex = dataIndex;
4517 * Returns true if the cell is editable.
4518 * @param {Number} colIndex The column index
4519 * @param {Number} rowIndex The row index
4522 isCellEditable : function(colIndex, rowIndex){
4523 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4527 * Returns the editor defined for the cell/column.
4528 * return false or null to disable editing.
4529 * @param {Number} colIndex The column index
4530 * @param {Number} rowIndex The row index
4533 getCellEditor : function(colIndex, rowIndex){
4534 return this.config[colIndex].editor;
4538 * Sets if a column is editable.
4539 * @param {Number} col The column index
4540 * @param {Boolean} editable True if the column is editable
4542 setEditable : function(col, editable){
4543 this.config[col].editable = editable;
4548 * Returns true if the column is hidden.
4549 * @param {Number} colIndex The column index
4552 isHidden : function(colIndex){
4553 return this.config[colIndex].hidden;
4558 * Returns true if the column width cannot be changed
4560 isFixed : function(colIndex){
4561 return this.config[colIndex].fixed;
4565 * Returns true if the column can be resized
4568 isResizable : function(colIndex){
4569 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4572 * Sets if a column is hidden.
4573 * @param {Number} colIndex The column index
4574 * @param {Boolean} hidden True if the column is hidden
4576 setHidden : function(colIndex, hidden){
4577 this.config[colIndex].hidden = hidden;
4578 this.totalWidth = null;
4579 this.fireEvent("hiddenchange", this, colIndex, hidden);
4583 * Sets the editor for a column.
4584 * @param {Number} col The column index
4585 * @param {Object} editor The editor object
4587 setEditor : function(col, editor){
4588 this.config[col].editor = editor;
4592 Roo.grid.ColumnModel.defaultRenderer = function(value){
4593 if(typeof value == "string" && value.length < 1){
4599 // Alias for backwards compatibility
4600 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4603 * Ext JS Library 1.1.1
4604 * Copyright(c) 2006-2007, Ext JS, LLC.
4606 * Originally Released Under LGPL - original licence link has changed is not relivant.
4609 * <script type="text/javascript">
4613 * @class Roo.LoadMask
4614 * A simple utility class for generically masking elements while loading data. If the element being masked has
4615 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4616 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4617 * element's UpdateManager load indicator and will be destroyed after the initial load.
4619 * Create a new LoadMask
4620 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4621 * @param {Object} config The config object
4623 Roo.LoadMask = function(el, config){
4624 this.el = Roo.get(el);
4625 Roo.apply(this, config);
4627 this.store.on('beforeload', this.onBeforeLoad, this);
4628 this.store.on('load', this.onLoad, this);
4629 this.store.on('loadexception', this.onLoadException, this);
4630 this.removeMask = false;
4632 var um = this.el.getUpdateManager();
4633 um.showLoadIndicator = false; // disable the default indicator
4634 um.on('beforeupdate', this.onBeforeLoad, this);
4635 um.on('update', this.onLoad, this);
4636 um.on('failure', this.onLoad, this);
4637 this.removeMask = true;
4641 Roo.LoadMask.prototype = {
4643 * @cfg {Boolean} removeMask
4644 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4645 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4649 * The text to display in a centered loading message box (defaults to 'Loading...')
4653 * @cfg {String} msgCls
4654 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4656 msgCls : 'x-mask-loading',
4659 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4665 * Disables the mask to prevent it from being displayed
4667 disable : function(){
4668 this.disabled = true;
4672 * Enables the mask so that it can be displayed
4674 enable : function(){
4675 this.disabled = false;
4678 onLoadException : function()
4682 if (typeof(arguments[3]) != 'undefined') {
4683 Roo.MessageBox.alert("Error loading",arguments[3]);
4687 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4688 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4697 this.el.unmask(this.removeMask);
4702 this.el.unmask(this.removeMask);
4706 onBeforeLoad : function(){
4708 this.el.mask(this.msg, this.msgCls);
4713 destroy : function(){
4715 this.store.un('beforeload', this.onBeforeLoad, this);
4716 this.store.un('load', this.onLoad, this);
4717 this.store.un('loadexception', this.onLoadException, this);
4719 var um = this.el.getUpdateManager();
4720 um.un('beforeupdate', this.onBeforeLoad, this);
4721 um.un('update', this.onLoad, this);
4722 um.un('failure', this.onLoad, this);
4733 * @class Roo.bootstrap.Table
4734 * @extends Roo.bootstrap.Component
4735 * Bootstrap Table class
4736 * @cfg {String} cls table class
4737 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4738 * @cfg {String} bgcolor Specifies the background color for a table
4739 * @cfg {Number} border Specifies whether the table cells should have borders or not
4740 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4741 * @cfg {Number} cellspacing Specifies the space between cells
4742 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4743 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4744 * @cfg {String} sortable Specifies that the table should be sortable
4745 * @cfg {String} summary Specifies a summary of the content of a table
4746 * @cfg {Number} width Specifies the width of a table
4747 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4749 * @cfg {boolean} striped Should the rows be alternative striped
4750 * @cfg {boolean} bordered Add borders to the table
4751 * @cfg {boolean} hover Add hover highlighting
4752 * @cfg {boolean} condensed Format condensed
4753 * @cfg {boolean} responsive Format condensed
4754 * @cfg {Boolean} loadMask (true|false) default false
4755 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4756 * @cfg {Boolean} thead (true|false) generate thead, default true
4757 * @cfg {Boolean} RowSelection (true|false) default false
4758 * @cfg {Boolean} CellSelection (true|false) default false
4760 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4764 * Create a new Table
4765 * @param {Object} config The config object
4768 Roo.bootstrap.Table = function(config){
4769 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4772 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4773 this.sm = this.selModel;
4774 this.sm.xmodule = this.xmodule || false;
4776 if (this.cm && typeof(this.cm.config) == 'undefined') {
4777 this.colModel = new Roo.grid.ColumnModel(this.cm);
4778 this.cm = this.colModel;
4779 this.cm.xmodule = this.xmodule || false;
4782 this.store= Roo.factory(this.store, Roo.data);
4783 this.ds = this.store;
4784 this.ds.xmodule = this.xmodule || false;
4787 if (this.footer && this.store) {
4788 this.footer.dataSource = this.ds;
4789 this.footer = Roo.factory(this.footer);
4796 * Fires when a cell is clicked
4797 * @param {Roo.bootstrap.Table} this
4798 * @param {Roo.Element} el
4799 * @param {Number} rowIndex
4800 * @param {Number} columnIndex
4801 * @param {Roo.EventObject} e
4805 * @event celldblclick
4806 * Fires when a cell is double clicked
4807 * @param {Roo.bootstrap.Table} this
4808 * @param {Roo.Element} el
4809 * @param {Number} rowIndex
4810 * @param {Number} columnIndex
4811 * @param {Roo.EventObject} e
4813 "celldblclick" : true,
4816 * Fires when a row is clicked
4817 * @param {Roo.bootstrap.Table} this
4818 * @param {Roo.Element} el
4819 * @param {Number} rowIndex
4820 * @param {Roo.EventObject} e
4824 * @event rowdblclick
4825 * Fires when a row is double clicked
4826 * @param {Roo.bootstrap.Table} this
4827 * @param {Roo.Element} el
4828 * @param {Number} rowIndex
4829 * @param {Roo.EventObject} e
4831 "rowdblclick" : true,
4834 * Fires when a mouseover occur
4835 * @param {Roo.bootstrap.Table} this
4836 * @param {Roo.Element} el
4837 * @param {Number} rowIndex
4838 * @param {Number} columnIndex
4839 * @param {Roo.EventObject} e
4844 * Fires when a mouseout occur
4845 * @param {Roo.bootstrap.Table} this
4846 * @param {Roo.Element} el
4847 * @param {Number} rowIndex
4848 * @param {Number} columnIndex
4849 * @param {Roo.EventObject} e
4854 * Fires when a row is rendered, so you can change add a style to it.
4855 * @param {Roo.bootstrap.Table} this
4856 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4863 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4887 RowSelection : false,
4888 CellSelection : false,
4891 // Roo.Element - the tbody
4894 getAutoCreate : function(){
4895 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4904 cfg.cls += ' table-striped';
4908 cfg.cls += ' table-hover';
4910 if (this.bordered) {
4911 cfg.cls += ' table-bordered';
4913 if (this.condensed) {
4914 cfg.cls += ' table-condensed';
4916 if (this.responsive) {
4917 cfg.cls += ' table-responsive';
4921 cfg.cls+= ' ' +this.cls;
4924 // this lot should be simplifed...
4927 cfg.align=this.align;
4930 cfg.bgcolor=this.bgcolor;
4933 cfg.border=this.border;
4935 if (this.cellpadding) {
4936 cfg.cellpadding=this.cellpadding;
4938 if (this.cellspacing) {
4939 cfg.cellspacing=this.cellspacing;
4942 cfg.frame=this.frame;
4945 cfg.rules=this.rules;
4947 if (this.sortable) {
4948 cfg.sortable=this.sortable;
4951 cfg.summary=this.summary;
4954 cfg.width=this.width;
4957 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4960 if(this.store || this.cm){
4962 cfg.cn.push(this.renderHeader());
4965 cfg.cn.push(this.renderBody());
4968 cfg.cn.push(this.renderFooter());
4971 cfg.cls+= ' TableGrid';
4974 return { cn : [ cfg ] };
4977 initEvents : function()
4979 if(!this.store || !this.cm){
4983 //Roo.log('initEvents with ds!!!!');
4985 this.mainBody = this.el.select('tbody', true).first();
4990 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4991 e.on('click', _this.sort, _this);
4994 this.el.on("click", this.onClick, this);
4995 this.el.on("dblclick", this.onDblClick, this);
4997 this.parent().el.setStyle('position', 'relative');
4999 this.footer.parentId = this.id;
5000 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5003 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5005 this.store.on('load', this.onLoad, this);
5006 this.store.on('beforeload', this.onBeforeLoad, this);
5007 this.store.on('update', this.onUpdate, this);
5011 onMouseover : function(e, el)
5013 var cell = Roo.get(el);
5019 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5020 cell = cell.findParent('td', false, true);
5023 var row = cell.findParent('tr', false, true);
5024 var cellIndex = cell.dom.cellIndex;
5025 var rowIndex = row.dom.rowIndex - 1; // start from 0
5027 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5031 onMouseout : function(e, el)
5033 var cell = Roo.get(el);
5039 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5040 cell = cell.findParent('td', false, true);
5043 var row = cell.findParent('tr', false, true);
5044 var cellIndex = cell.dom.cellIndex;
5045 var rowIndex = row.dom.rowIndex - 1; // start from 0
5047 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5051 onClick : function(e, el)
5053 var cell = Roo.get(el);
5055 if(!cell || (!this.CellSelection && !this.RowSelection)){
5060 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5061 cell = cell.findParent('td', false, true);
5064 var row = cell.findParent('tr', false, true);
5065 var cellIndex = cell.dom.cellIndex;
5066 var rowIndex = row.dom.rowIndex - 1;
5068 if(this.CellSelection){
5069 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5072 if(this.RowSelection){
5073 this.fireEvent('rowclick', this, row, rowIndex, e);
5079 onDblClick : function(e,el)
5081 var cell = Roo.get(el);
5083 if(!cell || (!this.CellSelection && !this.RowSelection)){
5087 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5088 cell = cell.findParent('td', false, true);
5091 var row = cell.findParent('tr', false, true);
5092 var cellIndex = cell.dom.cellIndex;
5093 var rowIndex = row.dom.rowIndex - 1;
5095 if(this.CellSelection){
5096 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5099 if(this.RowSelection){
5100 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5104 sort : function(e,el)
5106 var col = Roo.get(el)
5108 if(!col.hasClass('sortable')){
5112 var sort = col.attr('sort');
5115 if(col.hasClass('glyphicon-arrow-up')){
5119 this.store.sortInfo = {field : sort, direction : dir};
5122 Roo.log("calling footer first");
5123 this.footer.onClick('first');
5126 this.store.load({ params : { start : 0 } });
5130 renderHeader : function()
5139 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5141 var config = cm.config[i];
5146 html: cm.getColumnHeader(i)
5149 if(typeof(config.hidden) != 'undefined' && config.hidden){
5150 c.style += ' display:none;';
5153 if(typeof(config.dataIndex) != 'undefined'){
5154 c.sort = config.dataIndex;
5157 if(typeof(config.sortable) != 'undefined' && config.sortable){
5161 if(typeof(config.align) != 'undefined' && config.align.length){
5162 c.style += ' text-align:' + config.align + ';';
5165 if(typeof(config.width) != 'undefined'){
5166 c.style += ' width:' + config.width + 'px;';
5175 renderBody : function()
5185 colspan : this.cm.getColumnCount()
5195 renderFooter : function()
5205 colspan : this.cm.getColumnCount()
5219 Roo.log('ds onload');
5224 var ds = this.store;
5226 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5227 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5229 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5230 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5233 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5234 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5238 var tbody = this.mainBody;
5240 if(ds.getCount() > 0){
5241 ds.data.each(function(d,rowIndex){
5242 var row = this.renderRow(cm, ds, rowIndex);
5244 tbody.createChild(row);
5248 if(row.cellObjects.length){
5249 Roo.each(row.cellObjects, function(r){
5250 _this.renderCellObject(r);
5257 Roo.each(this.el.select('tbody td', true).elements, function(e){
5258 e.on('mouseover', _this.onMouseover, _this);
5261 Roo.each(this.el.select('tbody td', true).elements, function(e){
5262 e.on('mouseout', _this.onMouseout, _this);
5265 //if(this.loadMask){
5266 // this.maskEl.hide();
5271 onUpdate : function(ds,record)
5273 this.refreshRow(record);
5275 onRemove : function(ds, record, index, isUpdate){
5276 if(isUpdate !== true){
5277 this.fireEvent("beforerowremoved", this, index, record);
5279 var bt = this.mainBody.dom;
5281 bt.removeChild(bt.rows[index]);
5284 if(isUpdate !== true){
5285 //this.stripeRows(index);
5286 //this.syncRowHeights(index, index);
5288 this.fireEvent("rowremoved", this, index, record);
5293 refreshRow : function(record){
5294 var ds = this.store, index;
5295 if(typeof record == 'number'){
5297 record = ds.getAt(index);
5299 index = ds.indexOf(record);
5301 this.insertRow(ds, index, true);
5302 this.onRemove(ds, record, index+1, true);
5303 //this.syncRowHeights(index, index);
5305 this.fireEvent("rowupdated", this, index, record);
5308 insertRow : function(dm, rowIndex, isUpdate){
5311 this.fireEvent("beforerowsinserted", this, rowIndex);
5313 //var s = this.getScrollState();
5314 var row = this.renderRow(this.cm, this.store, rowIndex);
5315 // insert before rowIndex..
5316 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5320 if(row.cellObjects.length){
5321 Roo.each(row.cellObjects, function(r){
5322 _this.renderCellObject(r);
5327 this.fireEvent("rowsinserted", this, rowIndex);
5328 //this.syncRowHeights(firstRow, lastRow);
5329 //this.stripeRows(firstRow);
5336 getRowDom : function(rowIndex)
5338 // not sure if I need to check this.. but let's do it anyway..
5339 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5340 this.mainBody.dom.rows[rowIndex] : false
5342 // returns the object tree for a tr..
5345 renderRow : function(cm, ds, rowIndex) {
5347 var d = ds.getAt(rowIndex);
5354 var cellObjects = [];
5356 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5357 var config = cm.config[i];
5359 var renderer = cm.getRenderer(i);
5363 if(typeof(renderer) !== 'undefined'){
5364 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5366 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5367 // and are rendered into the cells after the row is rendered - using the id for the element.
5369 if(typeof(value) === 'object'){
5379 rowIndex : rowIndex,
5384 this.fireEvent('rowclass', this, rowcfg);
5388 cls : rowcfg.rowClass,
5390 html: (typeof(value) === 'object') ? '' : value
5397 if(typeof(config.hidden) != 'undefined' && config.hidden){
5398 td.style += ' display:none;';
5401 if(typeof(config.align) != 'undefined' && config.align.length){
5402 td.style += ' text-align:' + config.align + ';';
5405 if(typeof(config.width) != 'undefined'){
5406 td.style += ' width:' + config.width + 'px;';
5413 row.cellObjects = cellObjects;
5421 onBeforeLoad : function()
5423 //Roo.log('ds onBeforeLoad');
5427 //if(this.loadMask){
5428 // this.maskEl.show();
5434 this.el.select('tbody', true).first().dom.innerHTML = '';
5437 getSelectionModel : function(){
5439 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5441 return this.selModel;
5444 * Render the Roo.bootstrap object from renderder
5446 renderCellObject : function(r)
5450 var t = r.cfg.render(r.container);
5453 Roo.each(r.cfg.cn, function(c){
5455 container: t.getChildContainer(),
5458 _this.renderCellObject(child);
5475 * @class Roo.bootstrap.TableCell
5476 * @extends Roo.bootstrap.Component
5477 * Bootstrap TableCell class
5478 * @cfg {String} html cell contain text
5479 * @cfg {String} cls cell class
5480 * @cfg {String} tag cell tag (td|th) default td
5481 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5482 * @cfg {String} align Aligns the content in a cell
5483 * @cfg {String} axis Categorizes cells
5484 * @cfg {String} bgcolor Specifies the background color of a cell
5485 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5486 * @cfg {Number} colspan Specifies the number of columns a cell should span
5487 * @cfg {String} headers Specifies one or more header cells a cell is related to
5488 * @cfg {Number} height Sets the height of a cell
5489 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5490 * @cfg {Number} rowspan Sets the number of rows a cell should span
5491 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5492 * @cfg {String} valign Vertical aligns the content in a cell
5493 * @cfg {Number} width Specifies the width of a cell
5496 * Create a new TableCell
5497 * @param {Object} config The config object
5500 Roo.bootstrap.TableCell = function(config){
5501 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5504 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5524 getAutoCreate : function(){
5525 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5545 cfg.align=this.align
5551 cfg.bgcolor=this.bgcolor
5554 cfg.charoff=this.charoff
5557 cfg.colspan=this.colspan
5560 cfg.headers=this.headers
5563 cfg.height=this.height
5566 cfg.nowrap=this.nowrap
5569 cfg.rowspan=this.rowspan
5572 cfg.scope=this.scope
5575 cfg.valign=this.valign
5578 cfg.width=this.width
5597 * @class Roo.bootstrap.TableRow
5598 * @extends Roo.bootstrap.Component
5599 * Bootstrap TableRow class
5600 * @cfg {String} cls row class
5601 * @cfg {String} align Aligns the content in a table row
5602 * @cfg {String} bgcolor Specifies a background color for a table row
5603 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5604 * @cfg {String} valign Vertical aligns the content in a table row
5607 * Create a new TableRow
5608 * @param {Object} config The config object
5611 Roo.bootstrap.TableRow = function(config){
5612 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5615 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5623 getAutoCreate : function(){
5624 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5634 cfg.align = this.align;
5637 cfg.bgcolor = this.bgcolor;
5640 cfg.charoff = this.charoff;
5643 cfg.valign = this.valign;
5661 * @class Roo.bootstrap.TableBody
5662 * @extends Roo.bootstrap.Component
5663 * Bootstrap TableBody class
5664 * @cfg {String} cls element class
5665 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5666 * @cfg {String} align Aligns the content inside the element
5667 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5668 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5671 * Create a new TableBody
5672 * @param {Object} config The config object
5675 Roo.bootstrap.TableBody = function(config){
5676 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5679 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5687 getAutoCreate : function(){
5688 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5702 cfg.align = this.align;
5705 cfg.charoff = this.charoff;
5708 cfg.valign = this.valign;
5715 // initEvents : function()
5722 // this.store = Roo.factory(this.store, Roo.data);
5723 // this.store.on('load', this.onLoad, this);
5725 // this.store.load();
5729 // onLoad: function ()
5731 // this.fireEvent('load', this);
5741 * Ext JS Library 1.1.1
5742 * Copyright(c) 2006-2007, Ext JS, LLC.
5744 * Originally Released Under LGPL - original licence link has changed is not relivant.
5747 * <script type="text/javascript">
5750 // as we use this in bootstrap.
5751 Roo.namespace('Roo.form');
5753 * @class Roo.form.Action
5754 * Internal Class used to handle form actions
5756 * @param {Roo.form.BasicForm} el The form element or its id
5757 * @param {Object} config Configuration options
5762 // define the action interface
5763 Roo.form.Action = function(form, options){
5765 this.options = options || {};
5768 * Client Validation Failed
5771 Roo.form.Action.CLIENT_INVALID = 'client';
5773 * Server Validation Failed
5776 Roo.form.Action.SERVER_INVALID = 'server';
5778 * Connect to Server Failed
5781 Roo.form.Action.CONNECT_FAILURE = 'connect';
5783 * Reading Data from Server Failed
5786 Roo.form.Action.LOAD_FAILURE = 'load';
5788 Roo.form.Action.prototype = {
5790 failureType : undefined,
5791 response : undefined,
5795 run : function(options){
5800 success : function(response){
5805 handleResponse : function(response){
5809 // default connection failure
5810 failure : function(response){
5812 this.response = response;
5813 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5814 this.form.afterAction(this, false);
5817 processResponse : function(response){
5818 this.response = response;
5819 if(!response.responseText){
5822 this.result = this.handleResponse(response);
5826 // utility functions used internally
5827 getUrl : function(appendParams){
5828 var url = this.options.url || this.form.url || this.form.el.dom.action;
5830 var p = this.getParams();
5832 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5838 getMethod : function(){
5839 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5842 getParams : function(){
5843 var bp = this.form.baseParams;
5844 var p = this.options.params;
5846 if(typeof p == "object"){
5847 p = Roo.urlEncode(Roo.applyIf(p, bp));
5848 }else if(typeof p == 'string' && bp){
5849 p += '&' + Roo.urlEncode(bp);
5852 p = Roo.urlEncode(bp);
5857 createCallback : function(){
5859 success: this.success,
5860 failure: this.failure,
5862 timeout: (this.form.timeout*1000),
5863 upload: this.form.fileUpload ? this.success : undefined
5868 Roo.form.Action.Submit = function(form, options){
5869 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5872 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5875 haveProgress : false,
5876 uploadComplete : false,
5878 // uploadProgress indicator.
5879 uploadProgress : function()
5881 if (!this.form.progressUrl) {
5885 if (!this.haveProgress) {
5886 Roo.MessageBox.progress("Uploading", "Uploading");
5888 if (this.uploadComplete) {
5889 Roo.MessageBox.hide();
5893 this.haveProgress = true;
5895 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5897 var c = new Roo.data.Connection();
5899 url : this.form.progressUrl,
5904 success : function(req){
5905 //console.log(data);
5909 rdata = Roo.decode(req.responseText)
5911 Roo.log("Invalid data from server..");
5915 if (!rdata || !rdata.success) {
5917 Roo.MessageBox.alert(Roo.encode(rdata));
5920 var data = rdata.data;
5922 if (this.uploadComplete) {
5923 Roo.MessageBox.hide();
5928 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5929 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5932 this.uploadProgress.defer(2000,this);
5935 failure: function(data) {
5936 Roo.log('progress url failed ');
5947 // run get Values on the form, so it syncs any secondary forms.
5948 this.form.getValues();
5950 var o = this.options;
5951 var method = this.getMethod();
5952 var isPost = method == 'POST';
5953 if(o.clientValidation === false || this.form.isValid()){
5955 if (this.form.progressUrl) {
5956 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5957 (new Date() * 1) + '' + Math.random());
5962 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5963 form:this.form.el.dom,
5964 url:this.getUrl(!isPost),
5966 params:isPost ? this.getParams() : null,
5967 isUpload: this.form.fileUpload
5970 this.uploadProgress();
5972 }else if (o.clientValidation !== false){ // client validation failed
5973 this.failureType = Roo.form.Action.CLIENT_INVALID;
5974 this.form.afterAction(this, false);
5978 success : function(response)
5980 this.uploadComplete= true;
5981 if (this.haveProgress) {
5982 Roo.MessageBox.hide();
5986 var result = this.processResponse(response);
5987 if(result === true || result.success){
5988 this.form.afterAction(this, true);
5992 this.form.markInvalid(result.errors);
5993 this.failureType = Roo.form.Action.SERVER_INVALID;
5995 this.form.afterAction(this, false);
5997 failure : function(response)
5999 this.uploadComplete= true;
6000 if (this.haveProgress) {
6001 Roo.MessageBox.hide();
6004 this.response = response;
6005 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6006 this.form.afterAction(this, false);
6009 handleResponse : function(response){
6010 if(this.form.errorReader){
6011 var rs = this.form.errorReader.read(response);
6014 for(var i = 0, len = rs.records.length; i < len; i++) {
6015 var r = rs.records[i];
6019 if(errors.length < 1){
6023 success : rs.success,
6029 ret = Roo.decode(response.responseText);
6033 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6043 Roo.form.Action.Load = function(form, options){
6044 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6045 this.reader = this.form.reader;
6048 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6053 Roo.Ajax.request(Roo.apply(
6054 this.createCallback(), {
6055 method:this.getMethod(),
6056 url:this.getUrl(false),
6057 params:this.getParams()
6061 success : function(response){
6063 var result = this.processResponse(response);
6064 if(result === true || !result.success || !result.data){
6065 this.failureType = Roo.form.Action.LOAD_FAILURE;
6066 this.form.afterAction(this, false);
6069 this.form.clearInvalid();
6070 this.form.setValues(result.data);
6071 this.form.afterAction(this, true);
6074 handleResponse : function(response){
6075 if(this.form.reader){
6076 var rs = this.form.reader.read(response);
6077 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6079 success : rs.success,
6083 return Roo.decode(response.responseText);
6087 Roo.form.Action.ACTION_TYPES = {
6088 'load' : Roo.form.Action.Load,
6089 'submit' : Roo.form.Action.Submit
6098 * @class Roo.bootstrap.Form
6099 * @extends Roo.bootstrap.Component
6100 * Bootstrap Form class
6101 * @cfg {String} method GET | POST (default POST)
6102 * @cfg {String} labelAlign top | left (default top)
6103 * @cfg {String} align left | right - for navbars
6108 * @param {Object} config The config object
6112 Roo.bootstrap.Form = function(config){
6113 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6116 * @event clientvalidation
6117 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6118 * @param {Form} this
6119 * @param {Boolean} valid true if the form has passed client-side validation
6121 clientvalidation: true,
6123 * @event beforeaction
6124 * Fires before any action is performed. Return false to cancel the action.
6125 * @param {Form} this
6126 * @param {Action} action The action to be performed
6130 * @event actionfailed
6131 * Fires when an action fails.
6132 * @param {Form} this
6133 * @param {Action} action The action that failed
6135 actionfailed : true,
6137 * @event actioncomplete
6138 * Fires when an action is completed.
6139 * @param {Form} this
6140 * @param {Action} action The action that completed
6142 actioncomplete : true
6147 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6150 * @cfg {String} method
6151 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6156 * The URL to use for form actions if one isn't supplied in the action options.
6159 * @cfg {Boolean} fileUpload
6160 * Set to true if this form is a file upload.
6164 * @cfg {Object} baseParams
6165 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6169 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6173 * @cfg {Sting} align (left|right) for navbar forms
6178 activeAction : null,
6181 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6182 * element by passing it or its id or mask the form itself by passing in true.
6185 waitMsgTarget : false,
6190 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6191 * element by passing it or its id or mask the form itself by passing in true.
6195 getAutoCreate : function(){
6199 method : this.method || 'POST',
6200 id : this.id || Roo.id(),
6203 if (this.parent().xtype.match(/^Nav/)) {
6204 cfg.cls = 'navbar-form navbar-' + this.align;
6208 if (this.labelAlign == 'left' ) {
6209 cfg.cls += ' form-horizontal';
6215 initEvents : function()
6217 this.el.on('submit', this.onSubmit, this);
6218 // this was added as random key presses on the form where triggering form submit.
6219 this.el.on('keypress', function(e) {
6220 if (e.getCharCode() != 13) {
6223 // we might need to allow it for textareas.. and some other items.
6224 // check e.getTarget().
6226 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6230 Roo.log("keypress blocked");
6238 onSubmit : function(e){
6243 * Returns true if client-side validation on the form is successful.
6246 isValid : function(){
6247 var items = this.getItems();
6249 items.each(function(f){
6258 * Returns true if any fields in this form have changed since their original load.
6261 isDirty : function(){
6263 var items = this.getItems();
6264 items.each(function(f){
6274 * Performs a predefined action (submit or load) or custom actions you define on this form.
6275 * @param {String} actionName The name of the action type
6276 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6277 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6278 * accept other config options):
6280 Property Type Description
6281 ---------------- --------------- ----------------------------------------------------------------------------------
6282 url String The url for the action (defaults to the form's url)
6283 method String The form method to use (defaults to the form's method, or POST if not defined)
6284 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6285 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6286 validate the form on the client (defaults to false)
6288 * @return {BasicForm} this
6290 doAction : function(action, options){
6291 if(typeof action == 'string'){
6292 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6294 if(this.fireEvent('beforeaction', this, action) !== false){
6295 this.beforeAction(action);
6296 action.run.defer(100, action);
6302 beforeAction : function(action){
6303 var o = action.options;
6305 // not really supported yet.. ??
6307 //if(this.waitMsgTarget === true){
6308 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6309 //}else if(this.waitMsgTarget){
6310 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6311 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6313 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6319 afterAction : function(action, success){
6320 this.activeAction = null;
6321 var o = action.options;
6323 //if(this.waitMsgTarget === true){
6325 //}else if(this.waitMsgTarget){
6326 // this.waitMsgTarget.unmask();
6328 // Roo.MessageBox.updateProgress(1);
6329 // Roo.MessageBox.hide();
6336 Roo.callback(o.success, o.scope, [this, action]);
6337 this.fireEvent('actioncomplete', this, action);
6341 // failure condition..
6342 // we have a scenario where updates need confirming.
6343 // eg. if a locking scenario exists..
6344 // we look for { errors : { needs_confirm : true }} in the response.
6346 (typeof(action.result) != 'undefined') &&
6347 (typeof(action.result.errors) != 'undefined') &&
6348 (typeof(action.result.errors.needs_confirm) != 'undefined')
6351 Roo.log("not supported yet");
6354 Roo.MessageBox.confirm(
6355 "Change requires confirmation",
6356 action.result.errorMsg,
6361 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6371 Roo.callback(o.failure, o.scope, [this, action]);
6372 // show an error message if no failed handler is set..
6373 if (!this.hasListener('actionfailed')) {
6374 Roo.log("need to add dialog support");
6376 Roo.MessageBox.alert("Error",
6377 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6378 action.result.errorMsg :
6379 "Saving Failed, please check your entries or try again"
6384 this.fireEvent('actionfailed', this, action);
6389 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6390 * @param {String} id The value to search for
6393 findField : function(id){
6394 var items = this.getItems();
6395 var field = items.get(id);
6397 items.each(function(f){
6398 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6405 return field || null;
6408 * Mark fields in this form invalid in bulk.
6409 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6410 * @return {BasicForm} this
6412 markInvalid : function(errors){
6413 if(errors instanceof Array){
6414 for(var i = 0, len = errors.length; i < len; i++){
6415 var fieldError = errors[i];
6416 var f = this.findField(fieldError.id);
6418 f.markInvalid(fieldError.msg);
6424 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6425 field.markInvalid(errors[id]);
6429 //Roo.each(this.childForms || [], function (f) {
6430 // f.markInvalid(errors);
6437 * Set values for fields in this form in bulk.
6438 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6439 * @return {BasicForm} this
6441 setValues : function(values){
6442 if(values instanceof Array){ // array of objects
6443 for(var i = 0, len = values.length; i < len; i++){
6445 var f = this.findField(v.id);
6447 f.setValue(v.value);
6448 if(this.trackResetOnLoad){
6449 f.originalValue = f.getValue();
6453 }else{ // object hash
6456 if(typeof values[id] != 'function' && (field = this.findField(id))){
6458 if (field.setFromData &&
6460 field.displayField &&
6461 // combos' with local stores can
6462 // be queried via setValue()
6463 // to set their value..
6464 (field.store && !field.store.isLocal)
6468 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6469 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6470 field.setFromData(sd);
6473 field.setValue(values[id]);
6477 if(this.trackResetOnLoad){
6478 field.originalValue = field.getValue();
6484 //Roo.each(this.childForms || [], function (f) {
6485 // f.setValues(values);
6492 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6493 * they are returned as an array.
6494 * @param {Boolean} asString
6497 getValues : function(asString){
6498 //if (this.childForms) {
6499 // copy values from the child forms
6500 // Roo.each(this.childForms, function (f) {
6501 // this.setValues(f.getValues());
6507 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6508 if(asString === true){
6511 return Roo.urlDecode(fs);
6515 * Returns the fields in this form as an object with key/value pairs.
6516 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6519 getFieldValues : function(with_hidden)
6521 var items = this.getItems();
6523 items.each(function(f){
6527 var v = f.getValue();
6528 if (f.inputType =='radio') {
6529 if (typeof(ret[f.getName()]) == 'undefined') {
6530 ret[f.getName()] = ''; // empty..
6533 if (!f.el.dom.checked) {
6541 // not sure if this supported any more..
6542 if ((typeof(v) == 'object') && f.getRawValue) {
6543 v = f.getRawValue() ; // dates..
6545 // combo boxes where name != hiddenName...
6546 if (f.name != f.getName()) {
6547 ret[f.name] = f.getRawValue();
6549 ret[f.getName()] = v;
6556 * Clears all invalid messages in this form.
6557 * @return {BasicForm} this
6559 clearInvalid : function(){
6560 var items = this.getItems();
6562 items.each(function(f){
6573 * @return {BasicForm} this
6576 var items = this.getItems();
6577 items.each(function(f){
6581 Roo.each(this.childForms || [], function (f) {
6588 getItems : function()
6590 var r=new Roo.util.MixedCollection(false, function(o){
6591 return o.id || (o.id = Roo.id());
6593 var iter = function(el) {
6600 Roo.each(el.items,function(e) {
6619 * Ext JS Library 1.1.1
6620 * Copyright(c) 2006-2007, Ext JS, LLC.
6622 * Originally Released Under LGPL - original licence link has changed is not relivant.
6625 * <script type="text/javascript">
6628 * @class Roo.form.VTypes
6629 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6632 Roo.form.VTypes = function(){
6633 // closure these in so they are only created once.
6634 var alpha = /^[a-zA-Z_]+$/;
6635 var alphanum = /^[a-zA-Z0-9_]+$/;
6636 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6637 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6639 // All these messages and functions are configurable
6642 * The function used to validate email addresses
6643 * @param {String} value The email address
6645 'email' : function(v){
6646 return email.test(v);
6649 * The error text to display when the email validation function returns false
6652 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6654 * The keystroke filter mask to be applied on email input
6657 'emailMask' : /[a-z0-9_\.\-@]/i,
6660 * The function used to validate URLs
6661 * @param {String} value The URL
6663 'url' : function(v){
6667 * The error text to display when the url validation function returns false
6670 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6673 * The function used to validate alpha values
6674 * @param {String} value The value
6676 'alpha' : function(v){
6677 return alpha.test(v);
6680 * The error text to display when the alpha validation function returns false
6683 'alphaText' : 'This field should only contain letters and _',
6685 * The keystroke filter mask to be applied on alpha input
6688 'alphaMask' : /[a-z_]/i,
6691 * The function used to validate alphanumeric values
6692 * @param {String} value The value
6694 'alphanum' : function(v){
6695 return alphanum.test(v);
6698 * The error text to display when the alphanumeric validation function returns false
6701 'alphanumText' : 'This field should only contain letters, numbers and _',
6703 * The keystroke filter mask to be applied on alphanumeric input
6706 'alphanumMask' : /[a-z0-9_]/i
6716 * @class Roo.bootstrap.Input
6717 * @extends Roo.bootstrap.Component
6718 * Bootstrap Input class
6719 * @cfg {Boolean} disabled is it disabled
6720 * @cfg {String} fieldLabel - the label associated
6721 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6722 * @cfg {String} name name of the input
6723 * @cfg {string} fieldLabel - the label associated
6724 * @cfg {string} inputType - input / file submit ...
6725 * @cfg {string} placeholder - placeholder to put in text.
6726 * @cfg {string} before - input group add on before
6727 * @cfg {string} after - input group add on after
6728 * @cfg {string} size - (lg|sm) or leave empty..
6729 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6730 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6731 * @cfg {Number} md colspan out of 12 for computer-sized screens
6732 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6733 * @cfg {string} value default value of the input
6734 * @cfg {Number} labelWidth set the width of label (0-12)
6735 * @cfg {String} labelAlign (top|left)
6736 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6737 * @cfg {String} align (left|center|right) Default left
6741 * Create a new Input
6742 * @param {Object} config The config object
6745 Roo.bootstrap.Input = function(config){
6746 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6751 * Fires when this field receives input focus.
6752 * @param {Roo.form.Field} this
6757 * Fires when this field loses input focus.
6758 * @param {Roo.form.Field} this
6763 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6764 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6765 * @param {Roo.form.Field} this
6766 * @param {Roo.EventObject} e The event object
6771 * Fires just before the field blurs if the field value has changed.
6772 * @param {Roo.form.Field} this
6773 * @param {Mixed} newValue The new value
6774 * @param {Mixed} oldValue The original value
6779 * Fires after the field has been marked as invalid.
6780 * @param {Roo.form.Field} this
6781 * @param {String} msg The validation message
6786 * Fires after the field has been validated with no errors.
6787 * @param {Roo.form.Field} this
6792 * Fires after the key up
6793 * @param {Roo.form.Field} this
6794 * @param {Roo.EventObject} e The event Object
6800 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6802 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6803 automatic validation (defaults to "keyup").
6805 validationEvent : "keyup",
6807 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6809 validateOnBlur : true,
6811 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6813 validationDelay : 250,
6815 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6817 focusClass : "x-form-focus", // not needed???
6821 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6823 invalidClass : "has-error",
6826 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6828 selectOnFocus : false,
6831 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6835 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6840 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6842 disableKeyFilter : false,
6845 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6849 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6853 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6855 blankText : "This field is required",
6858 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6862 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6864 maxLength : Number.MAX_VALUE,
6866 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6868 minLengthText : "The minimum length for this field is {0}",
6870 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6872 maxLengthText : "The maximum length for this field is {0}",
6876 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6877 * If available, this function will be called only after the basic validators all return true, and will be passed the
6878 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6882 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6883 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6884 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6888 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6911 formatedValue : false,
6913 parentLabelAlign : function()
6916 while (parent.parent()) {
6917 parent = parent.parent();
6918 if (typeof(parent.labelAlign) !='undefined') {
6919 return parent.labelAlign;
6926 getAutoCreate : function(){
6928 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6934 if(this.inputType != 'hidden'){
6935 cfg.cls = 'form-group' //input-group
6941 type : this.inputType,
6943 cls : 'form-control',
6944 placeholder : this.placeholder || ''
6949 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6952 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6953 input.maxLength = this.maxLength;
6956 if (this.disabled) {
6957 input.disabled=true;
6960 if (this.readOnly) {
6961 input.readonly=true;
6965 input.name = this.name;
6968 input.cls += ' input-' + this.size;
6971 ['xs','sm','md','lg'].map(function(size){
6972 if (settings[size]) {
6973 cfg.cls += ' col-' + size + '-' + settings[size];
6977 var inputblock = input;
6979 if (this.before || this.after) {
6982 cls : 'input-group',
6985 if (this.before && typeof(this.before) == 'string') {
6987 inputblock.cn.push({
6989 cls : 'roo-input-before input-group-addon',
6993 if (this.before && typeof(this.before) == 'object') {
6994 this.before = Roo.factory(this.before);
6995 Roo.log(this.before);
6996 inputblock.cn.push({
6998 cls : 'roo-input-before input-group-' +
6999 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7003 inputblock.cn.push(input);
7005 if (this.after && typeof(this.after) == 'string') {
7006 inputblock.cn.push({
7008 cls : 'roo-input-after input-group-addon',
7012 if (this.after && typeof(this.after) == 'object') {
7013 this.after = Roo.factory(this.after);
7014 Roo.log(this.after);
7015 inputblock.cn.push({
7017 cls : 'roo-input-after input-group-' +
7018 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7023 if (align ==='left' && this.fieldLabel.length) {
7024 Roo.log("left and has label");
7030 cls : 'control-label col-sm-' + this.labelWidth,
7031 html : this.fieldLabel
7035 cls : "col-sm-" + (12 - this.labelWidth),
7042 } else if ( this.fieldLabel.length) {
7048 //cls : 'input-group-addon',
7049 html : this.fieldLabel
7059 Roo.log(" no label && no align");
7068 Roo.log('input-parentType: ' + this.parentType);
7070 if (this.parentType === 'Navbar' && this.parent().bar) {
7071 cfg.cls += ' navbar-form';
7079 * return the real input element.
7081 inputEl: function ()
7083 return this.el.select('input.form-control',true).first();
7085 setDisabled : function(v)
7087 var i = this.inputEl().dom;
7089 i.removeAttribute('disabled');
7093 i.setAttribute('disabled','true');
7095 initEvents : function()
7098 this.inputEl().on("keydown" , this.fireKey, this);
7099 this.inputEl().on("focus", this.onFocus, this);
7100 this.inputEl().on("blur", this.onBlur, this);
7102 this.inputEl().relayEvent('keyup', this);
7104 // reference to original value for reset
7105 this.originalValue = this.getValue();
7106 //Roo.form.TextField.superclass.initEvents.call(this);
7107 if(this.validationEvent == 'keyup'){
7108 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7109 this.inputEl().on('keyup', this.filterValidation, this);
7111 else if(this.validationEvent !== false){
7112 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7115 if(this.selectOnFocus){
7116 this.on("focus", this.preFocus, this);
7119 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7120 this.inputEl().on("keypress", this.filterKeys, this);
7123 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7124 this.el.on("click", this.autoSize, this);
7127 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7128 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7131 if (typeof(this.before) == 'object') {
7132 this.before.render(this.el.select('.roo-input-before',true).first());
7134 if (typeof(this.after) == 'object') {
7135 this.after.render(this.el.select('.roo-input-after',true).first());
7140 filterValidation : function(e){
7141 if(!e.isNavKeyPress()){
7142 this.validationTask.delay(this.validationDelay);
7146 * Validates the field value
7147 * @return {Boolean} True if the value is valid, else false
7149 validate : function(){
7150 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7151 if(this.disabled || this.validateValue(this.getRawValue())){
7152 this.clearInvalid();
7160 * Validates a value according to the field's validation rules and marks the field as invalid
7161 * if the validation fails
7162 * @param {Mixed} value The value to validate
7163 * @return {Boolean} True if the value is valid, else false
7165 validateValue : function(value){
7166 if(value.length < 1) { // if it's blank
7167 if(this.allowBlank){
7168 this.clearInvalid();
7171 this.markInvalid(this.blankText);
7175 if(value.length < this.minLength){
7176 this.markInvalid(String.format(this.minLengthText, this.minLength));
7179 if(value.length > this.maxLength){
7180 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7184 var vt = Roo.form.VTypes;
7185 if(!vt[this.vtype](value, this)){
7186 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7190 if(typeof this.validator == "function"){
7191 var msg = this.validator(value);
7193 this.markInvalid(msg);
7197 if(this.regex && !this.regex.test(value)){
7198 this.markInvalid(this.regexText);
7207 fireKey : function(e){
7208 //Roo.log('field ' + e.getKey());
7209 if(e.isNavKeyPress()){
7210 this.fireEvent("specialkey", this, e);
7213 focus : function (selectText){
7215 this.inputEl().focus();
7216 if(selectText === true){
7217 this.inputEl().dom.select();
7223 onFocus : function(){
7224 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7225 // this.el.addClass(this.focusClass);
7228 this.hasFocus = true;
7229 this.startValue = this.getValue();
7230 this.fireEvent("focus", this);
7234 beforeBlur : Roo.emptyFn,
7238 onBlur : function(){
7240 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7241 //this.el.removeClass(this.focusClass);
7243 this.hasFocus = false;
7244 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7247 var v = this.getValue();
7248 if(String(v) !== String(this.startValue)){
7249 this.fireEvent('change', this, v, this.startValue);
7251 this.fireEvent("blur", this);
7255 * Resets the current field value to the originally loaded value and clears any validation messages
7258 this.setValue(this.originalValue);
7259 this.clearInvalid();
7262 * Returns the name of the field
7263 * @return {Mixed} name The name field
7265 getName: function(){
7269 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7270 * @return {Mixed} value The field value
7272 getValue : function(){
7274 var v = this.inputEl().getValue();
7279 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7280 * @return {Mixed} value The field value
7282 getRawValue : function(){
7283 var v = this.inputEl().getValue();
7289 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7290 * @param {Mixed} value The value to set
7292 setRawValue : function(v){
7293 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7296 selectText : function(start, end){
7297 var v = this.getRawValue();
7299 start = start === undefined ? 0 : start;
7300 end = end === undefined ? v.length : end;
7301 var d = this.inputEl().dom;
7302 if(d.setSelectionRange){
7303 d.setSelectionRange(start, end);
7304 }else if(d.createTextRange){
7305 var range = d.createTextRange();
7306 range.moveStart("character", start);
7307 range.moveEnd("character", v.length-end);
7314 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7315 * @param {Mixed} value The value to set
7317 setValue : function(v){
7320 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7326 processValue : function(value){
7327 if(this.stripCharsRe){
7328 var newValue = value.replace(this.stripCharsRe, '');
7329 if(newValue !== value){
7330 this.setRawValue(newValue);
7337 preFocus : function(){
7339 if(this.selectOnFocus){
7340 this.inputEl().dom.select();
7343 filterKeys : function(e){
7345 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7348 var c = e.getCharCode(), cc = String.fromCharCode(c);
7349 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7352 if(!this.maskRe.test(cc)){
7357 * Clear any invalid styles/messages for this field
7359 clearInvalid : function(){
7361 if(!this.el || this.preventMark){ // not rendered
7364 this.el.removeClass(this.invalidClass);
7366 switch(this.msgTarget){
7368 this.el.dom.qtip = '';
7371 this.el.dom.title = '';
7375 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7380 this.errorIcon.dom.qtip = '';
7381 this.errorIcon.hide();
7382 this.un('resize', this.alignErrorIcon, this);
7386 var t = Roo.getDom(this.msgTarget);
7388 t.style.display = 'none';
7392 this.fireEvent('valid', this);
7395 * Mark this field as invalid
7396 * @param {String} msg The validation message
7398 markInvalid : function(msg){
7399 if(!this.el || this.preventMark){ // not rendered
7402 this.el.addClass(this.invalidClass);
7404 msg = msg || this.invalidText;
7405 switch(this.msgTarget){
7407 this.el.dom.qtip = msg;
7408 this.el.dom.qclass = 'x-form-invalid-tip';
7409 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7410 Roo.QuickTips.enable();
7414 this.el.dom.title = msg;
7418 var elp = this.el.findParent('.x-form-element', 5, true);
7419 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7420 this.errorEl.setWidth(elp.getWidth(true)-20);
7422 this.errorEl.update(msg);
7423 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7426 if(!this.errorIcon){
7427 var elp = this.el.findParent('.x-form-element', 5, true);
7428 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7430 this.alignErrorIcon();
7431 this.errorIcon.dom.qtip = msg;
7432 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7433 this.errorIcon.show();
7434 this.on('resize', this.alignErrorIcon, this);
7437 var t = Roo.getDom(this.msgTarget);
7439 t.style.display = this.msgDisplay;
7443 this.fireEvent('invalid', this, msg);
7446 SafariOnKeyDown : function(event)
7448 // this is a workaround for a password hang bug on chrome/ webkit.
7450 var isSelectAll = false;
7452 if(this.inputEl().dom.selectionEnd > 0){
7453 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7455 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7456 event.preventDefault();
7461 if(isSelectAll){ // backspace and delete key
7463 event.preventDefault();
7464 // this is very hacky as keydown always get's upper case.
7466 var cc = String.fromCharCode(event.getCharCode());
7467 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7471 adjustWidth : function(tag, w){
7472 tag = tag.toLowerCase();
7473 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7474 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7478 if(tag == 'textarea'){
7481 }else if(Roo.isOpera){
7485 if(tag == 'textarea'){
7504 * @class Roo.bootstrap.TextArea
7505 * @extends Roo.bootstrap.Input
7506 * Bootstrap TextArea class
7507 * @cfg {Number} cols Specifies the visible width of a text area
7508 * @cfg {Number} rows Specifies the visible number of lines in a text area
7509 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7510 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7511 * @cfg {string} html text
7514 * Create a new TextArea
7515 * @param {Object} config The config object
7518 Roo.bootstrap.TextArea = function(config){
7519 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7523 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7533 getAutoCreate : function(){
7535 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7546 value : this.value || '',
7547 html: this.html || '',
7548 cls : 'form-control',
7549 placeholder : this.placeholder || ''
7553 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7554 input.maxLength = this.maxLength;
7558 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7562 input.cols = this.cols;
7565 if (this.readOnly) {
7566 input.readonly = true;
7570 input.name = this.name;
7574 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7578 ['xs','sm','md','lg'].map(function(size){
7579 if (settings[size]) {
7580 cfg.cls += ' col-' + size + '-' + settings[size];
7584 var inputblock = input;
7586 if (this.before || this.after) {
7589 cls : 'input-group',
7593 inputblock.cn.push({
7595 cls : 'input-group-addon',
7599 inputblock.cn.push(input);
7601 inputblock.cn.push({
7603 cls : 'input-group-addon',
7610 if (align ==='left' && this.fieldLabel.length) {
7611 Roo.log("left and has label");
7617 cls : 'control-label col-sm-' + this.labelWidth,
7618 html : this.fieldLabel
7622 cls : "col-sm-" + (12 - this.labelWidth),
7629 } else if ( this.fieldLabel.length) {
7635 //cls : 'input-group-addon',
7636 html : this.fieldLabel
7646 Roo.log(" no label && no align");
7656 if (this.disabled) {
7657 input.disabled=true;
7664 * return the real textarea element.
7666 inputEl: function ()
7668 return this.el.select('textarea.form-control',true).first();
7676 * trigger field - base class for combo..
7681 * @class Roo.bootstrap.TriggerField
7682 * @extends Roo.bootstrap.Input
7683 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7684 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7685 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7686 * for which you can provide a custom implementation. For example:
7688 var trigger = new Roo.bootstrap.TriggerField();
7689 trigger.onTriggerClick = myTriggerFn;
7690 trigger.applyTo('my-field');
7693 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7694 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7695 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7696 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7698 * Create a new TriggerField.
7699 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7700 * to the base TextField)
7702 Roo.bootstrap.TriggerField = function(config){
7703 this.mimicing = false;
7704 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7707 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7709 * @cfg {String} triggerClass A CSS class to apply to the trigger
7712 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7716 /** @cfg {Boolean} grow @hide */
7717 /** @cfg {Number} growMin @hide */
7718 /** @cfg {Number} growMax @hide */
7724 autoSize: Roo.emptyFn,
7731 actionMode : 'wrap',
7735 getAutoCreate : function(){
7737 var align = this.labelAlign || this.parentLabelAlign();
7742 cls: 'form-group' //input-group
7749 type : this.inputType,
7750 cls : 'form-control',
7751 autocomplete: 'off',
7752 placeholder : this.placeholder || ''
7756 input.name = this.name;
7759 input.cls += ' input-' + this.size;
7762 if (this.disabled) {
7763 input.disabled=true;
7766 var inputblock = input;
7768 if (this.before || this.after) {
7771 cls : 'input-group',
7775 inputblock.cn.push({
7777 cls : 'input-group-addon',
7781 inputblock.cn.push(input);
7783 inputblock.cn.push({
7785 cls : 'input-group-addon',
7798 cls: 'form-hidden-field'
7806 Roo.log('multiple');
7814 cls: 'form-hidden-field'
7818 cls: 'select2-choices',
7822 cls: 'select2-search-field',
7835 cls: 'select2-container input-group',
7840 // cls: 'typeahead typeahead-long dropdown-menu',
7841 // style: 'display:none'
7846 if(!this.multiple && this.showToggleBtn){
7849 cls : 'input-group-addon btn dropdown-toggle',
7857 cls: 'combobox-clear',
7871 combobox.cls += ' select2-container-multi';
7874 if (align ==='left' && this.fieldLabel.length) {
7876 Roo.log("left and has label");
7882 cls : 'control-label col-sm-' + this.labelWidth,
7883 html : this.fieldLabel
7887 cls : "col-sm-" + (12 - this.labelWidth),
7894 } else if ( this.fieldLabel.length) {
7900 //cls : 'input-group-addon',
7901 html : this.fieldLabel
7911 Roo.log(" no label && no align");
7918 ['xs','sm','md','lg'].map(function(size){
7919 if (settings[size]) {
7920 cfg.cls += ' col-' + size + '-' + settings[size];
7931 onResize : function(w, h){
7932 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7933 // if(typeof w == 'number'){
7934 // var x = w - this.trigger.getWidth();
7935 // this.inputEl().setWidth(this.adjustWidth('input', x));
7936 // this.trigger.setStyle('left', x+'px');
7941 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7944 getResizeEl : function(){
7945 return this.inputEl();
7949 getPositionEl : function(){
7950 return this.inputEl();
7954 alignErrorIcon : function(){
7955 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7959 initEvents : function(){
7963 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7964 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7965 if(!this.multiple && this.showToggleBtn){
7966 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7967 if(this.hideTrigger){
7968 this.trigger.setDisplayed(false);
7970 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7974 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7977 //this.trigger.addClassOnOver('x-form-trigger-over');
7978 //this.trigger.addClassOnClick('x-form-trigger-click');
7981 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7985 createList : function()
7987 this.list = Roo.get(document.body).createChild({
7989 cls: 'typeahead typeahead-long dropdown-menu',
7990 style: 'display:none'
7993 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
7998 initTrigger : function(){
8003 onDestroy : function(){
8005 this.trigger.removeAllListeners();
8006 // this.trigger.remove();
8009 // this.wrap.remove();
8011 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8015 onFocus : function(){
8016 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8019 this.wrap.addClass('x-trigger-wrap-focus');
8020 this.mimicing = true;
8021 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8022 if(this.monitorTab){
8023 this.el.on("keydown", this.checkTab, this);
8030 checkTab : function(e){
8031 if(e.getKey() == e.TAB){
8037 onBlur : function(){
8042 mimicBlur : function(e, t){
8044 if(!this.wrap.contains(t) && this.validateBlur()){
8051 triggerBlur : function(){
8052 this.mimicing = false;
8053 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8054 if(this.monitorTab){
8055 this.el.un("keydown", this.checkTab, this);
8057 //this.wrap.removeClass('x-trigger-wrap-focus');
8058 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8062 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8063 validateBlur : function(e, t){
8068 onDisable : function(){
8069 this.inputEl().dom.disabled = true;
8070 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8072 // this.wrap.addClass('x-item-disabled');
8077 onEnable : function(){
8078 this.inputEl().dom.disabled = false;
8079 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8081 // this.el.removeClass('x-item-disabled');
8086 onShow : function(){
8087 var ae = this.getActionEl();
8090 ae.dom.style.display = '';
8091 ae.dom.style.visibility = 'visible';
8097 onHide : function(){
8098 var ae = this.getActionEl();
8099 ae.dom.style.display = 'none';
8103 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8104 * by an implementing function.
8106 * @param {EventObject} e
8108 onTriggerClick : Roo.emptyFn
8112 * Ext JS Library 1.1.1
8113 * Copyright(c) 2006-2007, Ext JS, LLC.
8115 * Originally Released Under LGPL - original licence link has changed is not relivant.
8118 * <script type="text/javascript">
8123 * @class Roo.data.SortTypes
8125 * Defines the default sorting (casting?) comparison functions used when sorting data.
8127 Roo.data.SortTypes = {
8129 * Default sort that does nothing
8130 * @param {Mixed} s The value being converted
8131 * @return {Mixed} The comparison value
8138 * The regular expression used to strip tags
8142 stripTagsRE : /<\/?[^>]+>/gi,
8145 * Strips all HTML tags to sort on text only
8146 * @param {Mixed} s The value being converted
8147 * @return {String} The comparison value
8149 asText : function(s){
8150 return String(s).replace(this.stripTagsRE, "");
8154 * Strips all HTML tags to sort on text only - Case insensitive
8155 * @param {Mixed} s The value being converted
8156 * @return {String} The comparison value
8158 asUCText : function(s){
8159 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8163 * Case insensitive string
8164 * @param {Mixed} s The value being converted
8165 * @return {String} The comparison value
8167 asUCString : function(s) {
8168 return String(s).toUpperCase();
8173 * @param {Mixed} s The value being converted
8174 * @return {Number} The comparison value
8176 asDate : function(s) {
8180 if(s instanceof Date){
8183 return Date.parse(String(s));
8188 * @param {Mixed} s The value being converted
8189 * @return {Float} The comparison value
8191 asFloat : function(s) {
8192 var val = parseFloat(String(s).replace(/,/g, ""));
8193 if(isNaN(val)) val = 0;
8199 * @param {Mixed} s The value being converted
8200 * @return {Number} The comparison value
8202 asInt : function(s) {
8203 var val = parseInt(String(s).replace(/,/g, ""));
8204 if(isNaN(val)) val = 0;
8209 * Ext JS Library 1.1.1
8210 * Copyright(c) 2006-2007, Ext JS, LLC.
8212 * Originally Released Under LGPL - original licence link has changed is not relivant.
8215 * <script type="text/javascript">
8219 * @class Roo.data.Record
8220 * Instances of this class encapsulate both record <em>definition</em> information, and record
8221 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8222 * to access Records cached in an {@link Roo.data.Store} object.<br>
8224 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8225 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8228 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8230 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8231 * {@link #create}. The parameters are the same.
8232 * @param {Array} data An associative Array of data values keyed by the field name.
8233 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8234 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8235 * not specified an integer id is generated.
8237 Roo.data.Record = function(data, id){
8238 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8243 * Generate a constructor for a specific record layout.
8244 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8245 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8246 * Each field definition object may contain the following properties: <ul>
8247 * <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,
8248 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8249 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8250 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8251 * is being used, then this is a string containing the javascript expression to reference the data relative to
8252 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8253 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8254 * this may be omitted.</p></li>
8255 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8256 * <ul><li>auto (Default, implies no conversion)</li>
8261 * <li>date</li></ul></p></li>
8262 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8263 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8264 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8265 * by the Reader into an object that will be stored in the Record. It is passed the
8266 * following parameters:<ul>
8267 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8269 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8271 * <br>usage:<br><pre><code>
8272 var TopicRecord = Roo.data.Record.create(
8273 {name: 'title', mapping: 'topic_title'},
8274 {name: 'author', mapping: 'username'},
8275 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8276 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8277 {name: 'lastPoster', mapping: 'user2'},
8278 {name: 'excerpt', mapping: 'post_text'}
8281 var myNewRecord = new TopicRecord({
8282 title: 'Do my job please',
8285 lastPost: new Date(),
8286 lastPoster: 'Animal',
8287 excerpt: 'No way dude!'
8289 myStore.add(myNewRecord);
8294 Roo.data.Record.create = function(o){
8296 f.superclass.constructor.apply(this, arguments);
8298 Roo.extend(f, Roo.data.Record);
8299 var p = f.prototype;
8300 p.fields = new Roo.util.MixedCollection(false, function(field){
8303 for(var i = 0, len = o.length; i < len; i++){
8304 p.fields.add(new Roo.data.Field(o[i]));
8306 f.getField = function(name){
8307 return p.fields.get(name);
8312 Roo.data.Record.AUTO_ID = 1000;
8313 Roo.data.Record.EDIT = 'edit';
8314 Roo.data.Record.REJECT = 'reject';
8315 Roo.data.Record.COMMIT = 'commit';
8317 Roo.data.Record.prototype = {
8319 * Readonly flag - true if this record has been modified.
8328 join : function(store){
8333 * Set the named field to the specified value.
8334 * @param {String} name The name of the field to set.
8335 * @param {Object} value The value to set the field to.
8337 set : function(name, value){
8338 if(this.data[name] == value){
8345 if(typeof this.modified[name] == 'undefined'){
8346 this.modified[name] = this.data[name];
8348 this.data[name] = value;
8349 if(!this.editing && this.store){
8350 this.store.afterEdit(this);
8355 * Get the value of the named field.
8356 * @param {String} name The name of the field to get the value of.
8357 * @return {Object} The value of the field.
8359 get : function(name){
8360 return this.data[name];
8364 beginEdit : function(){
8365 this.editing = true;
8370 cancelEdit : function(){
8371 this.editing = false;
8372 delete this.modified;
8376 endEdit : function(){
8377 this.editing = false;
8378 if(this.dirty && this.store){
8379 this.store.afterEdit(this);
8384 * Usually called by the {@link Roo.data.Store} which owns the Record.
8385 * Rejects all changes made to the Record since either creation, or the last commit operation.
8386 * Modified fields are reverted to their original values.
8388 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8389 * of reject operations.
8391 reject : function(){
8392 var m = this.modified;
8394 if(typeof m[n] != "function"){
8395 this.data[n] = m[n];
8399 delete this.modified;
8400 this.editing = false;
8402 this.store.afterReject(this);
8407 * Usually called by the {@link Roo.data.Store} which owns the Record.
8408 * Commits all changes made to the Record since either creation, or the last commit operation.
8410 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8411 * of commit operations.
8413 commit : function(){
8415 delete this.modified;
8416 this.editing = false;
8418 this.store.afterCommit(this);
8423 hasError : function(){
8424 return this.error != null;
8428 clearError : function(){
8433 * Creates a copy of this record.
8434 * @param {String} id (optional) A new record id if you don't want to use this record's id
8437 copy : function(newId) {
8438 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8442 * Ext JS Library 1.1.1
8443 * Copyright(c) 2006-2007, Ext JS, LLC.
8445 * Originally Released Under LGPL - original licence link has changed is not relivant.
8448 * <script type="text/javascript">
8454 * @class Roo.data.Store
8455 * @extends Roo.util.Observable
8456 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8457 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8459 * 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
8460 * has no knowledge of the format of the data returned by the Proxy.<br>
8462 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8463 * instances from the data object. These records are cached and made available through accessor functions.
8465 * Creates a new Store.
8466 * @param {Object} config A config object containing the objects needed for the Store to access data,
8467 * and read the data into Records.
8469 Roo.data.Store = function(config){
8470 this.data = new Roo.util.MixedCollection(false);
8471 this.data.getKey = function(o){
8474 this.baseParams = {};
8481 "multisort" : "_multisort"
8484 if(config && config.data){
8485 this.inlineData = config.data;
8489 Roo.apply(this, config);
8491 if(this.reader){ // reader passed
8492 this.reader = Roo.factory(this.reader, Roo.data);
8493 this.reader.xmodule = this.xmodule || false;
8494 if(!this.recordType){
8495 this.recordType = this.reader.recordType;
8497 if(this.reader.onMetaChange){
8498 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8502 if(this.recordType){
8503 this.fields = this.recordType.prototype.fields;
8509 * @event datachanged
8510 * Fires when the data cache has changed, and a widget which is using this Store
8511 * as a Record cache should refresh its view.
8512 * @param {Store} this
8517 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8518 * @param {Store} this
8519 * @param {Object} meta The JSON metadata
8524 * Fires when Records have been added to the Store
8525 * @param {Store} this
8526 * @param {Roo.data.Record[]} records The array of Records added
8527 * @param {Number} index The index at which the record(s) were added
8532 * Fires when a Record has been removed from the Store
8533 * @param {Store} this
8534 * @param {Roo.data.Record} record The Record that was removed
8535 * @param {Number} index The index at which the record was removed
8540 * Fires when a Record has been updated
8541 * @param {Store} this
8542 * @param {Roo.data.Record} record The Record that was updated
8543 * @param {String} operation The update operation being performed. Value may be one of:
8545 Roo.data.Record.EDIT
8546 Roo.data.Record.REJECT
8547 Roo.data.Record.COMMIT
8553 * Fires when the data cache has been cleared.
8554 * @param {Store} this
8559 * Fires before a request is made for a new data object. If the beforeload handler returns false
8560 * the load action will be canceled.
8561 * @param {Store} this
8562 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8566 * @event beforeloadadd
8567 * Fires after a new set of Records has been loaded.
8568 * @param {Store} this
8569 * @param {Roo.data.Record[]} records The Records that were loaded
8570 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8572 beforeloadadd : true,
8575 * Fires after a new set of Records has been loaded, before they are added to the store.
8576 * @param {Store} this
8577 * @param {Roo.data.Record[]} records The Records that were loaded
8578 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8579 * @params {Object} return from reader
8583 * @event loadexception
8584 * Fires if an exception occurs in the Proxy during loading.
8585 * Called with the signature of the Proxy's "loadexception" event.
8586 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8589 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8590 * @param {Object} load options
8591 * @param {Object} jsonData from your request (normally this contains the Exception)
8593 loadexception : true
8597 this.proxy = Roo.factory(this.proxy, Roo.data);
8598 this.proxy.xmodule = this.xmodule || false;
8599 this.relayEvents(this.proxy, ["loadexception"]);
8601 this.sortToggle = {};
8602 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8604 Roo.data.Store.superclass.constructor.call(this);
8606 if(this.inlineData){
8607 this.loadData(this.inlineData);
8608 delete this.inlineData;
8612 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8614 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8615 * without a remote query - used by combo/forms at present.
8619 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8622 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8625 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8626 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8629 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8630 * on any HTTP request
8633 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8636 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8640 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8641 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8646 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8647 * loaded or when a record is removed. (defaults to false).
8649 pruneModifiedRecords : false,
8655 * Add Records to the Store and fires the add event.
8656 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8658 add : function(records){
8659 records = [].concat(records);
8660 for(var i = 0, len = records.length; i < len; i++){
8661 records[i].join(this);
8663 var index = this.data.length;
8664 this.data.addAll(records);
8665 this.fireEvent("add", this, records, index);
8669 * Remove a Record from the Store and fires the remove event.
8670 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8672 remove : function(record){
8673 var index = this.data.indexOf(record);
8674 this.data.removeAt(index);
8675 if(this.pruneModifiedRecords){
8676 this.modified.remove(record);
8678 this.fireEvent("remove", this, record, index);
8682 * Remove all Records from the Store and fires the clear event.
8684 removeAll : function(){
8686 if(this.pruneModifiedRecords){
8689 this.fireEvent("clear", this);
8693 * Inserts Records to the Store at the given index and fires the add event.
8694 * @param {Number} index The start index at which to insert the passed Records.
8695 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8697 insert : function(index, records){
8698 records = [].concat(records);
8699 for(var i = 0, len = records.length; i < len; i++){
8700 this.data.insert(index, records[i]);
8701 records[i].join(this);
8703 this.fireEvent("add", this, records, index);
8707 * Get the index within the cache of the passed Record.
8708 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8709 * @return {Number} The index of the passed Record. Returns -1 if not found.
8711 indexOf : function(record){
8712 return this.data.indexOf(record);
8716 * Get the index within the cache of the Record with the passed id.
8717 * @param {String} id The id of the Record to find.
8718 * @return {Number} The index of the Record. Returns -1 if not found.
8720 indexOfId : function(id){
8721 return this.data.indexOfKey(id);
8725 * Get the Record with the specified id.
8726 * @param {String} id The id of the Record to find.
8727 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8729 getById : function(id){
8730 return this.data.key(id);
8734 * Get the Record at the specified index.
8735 * @param {Number} index The index of the Record to find.
8736 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8738 getAt : function(index){
8739 return this.data.itemAt(index);
8743 * Returns a range of Records between specified indices.
8744 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8745 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8746 * @return {Roo.data.Record[]} An array of Records
8748 getRange : function(start, end){
8749 return this.data.getRange(start, end);
8753 storeOptions : function(o){
8754 o = Roo.apply({}, o);
8757 this.lastOptions = o;
8761 * Loads the Record cache from the configured Proxy using the configured Reader.
8763 * If using remote paging, then the first load call must specify the <em>start</em>
8764 * and <em>limit</em> properties in the options.params property to establish the initial
8765 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8767 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8768 * and this call will return before the new data has been loaded. Perform any post-processing
8769 * in a callback function, or in a "load" event handler.</strong>
8771 * @param {Object} options An object containing properties which control loading options:<ul>
8772 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8773 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8774 * passed the following arguments:<ul>
8775 * <li>r : Roo.data.Record[]</li>
8776 * <li>options: Options object from the load call</li>
8777 * <li>success: Boolean success indicator</li></ul></li>
8778 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8779 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8782 load : function(options){
8783 options = options || {};
8784 if(this.fireEvent("beforeload", this, options) !== false){
8785 this.storeOptions(options);
8786 var p = Roo.apply(options.params || {}, this.baseParams);
8787 // if meta was not loaded from remote source.. try requesting it.
8788 if (!this.reader.metaFromRemote) {
8791 if(this.sortInfo && this.remoteSort){
8792 var pn = this.paramNames;
8793 p[pn["sort"]] = this.sortInfo.field;
8794 p[pn["dir"]] = this.sortInfo.direction;
8796 if (this.multiSort) {
8797 var pn = this.paramNames;
8798 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8801 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8806 * Reloads the Record cache from the configured Proxy using the configured Reader and
8807 * the options from the last load operation performed.
8808 * @param {Object} options (optional) An object containing properties which may override the options
8809 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8810 * the most recently used options are reused).
8812 reload : function(options){
8813 this.load(Roo.applyIf(options||{}, this.lastOptions));
8817 // Called as a callback by the Reader during a load operation.
8818 loadRecords : function(o, options, success){
8819 if(!o || success === false){
8820 if(success !== false){
8821 this.fireEvent("load", this, [], options, o);
8823 if(options.callback){
8824 options.callback.call(options.scope || this, [], options, false);
8828 // if data returned failure - throw an exception.
8829 if (o.success === false) {
8830 // show a message if no listener is registered.
8831 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8832 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8834 // loadmask wil be hooked into this..
8835 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8838 var r = o.records, t = o.totalRecords || r.length;
8840 this.fireEvent("beforeloadadd", this, r, options, o);
8842 if(!options || options.add !== true){
8843 if(this.pruneModifiedRecords){
8846 for(var i = 0, len = r.length; i < len; i++){
8850 this.data = this.snapshot;
8851 delete this.snapshot;
8854 this.data.addAll(r);
8855 this.totalLength = t;
8857 this.fireEvent("datachanged", this);
8859 this.totalLength = Math.max(t, this.data.length+r.length);
8862 this.fireEvent("load", this, r, options, o);
8863 if(options.callback){
8864 options.callback.call(options.scope || this, r, options, true);
8870 * Loads data from a passed data block. A Reader which understands the format of the data
8871 * must have been configured in the constructor.
8872 * @param {Object} data The data block from which to read the Records. The format of the data expected
8873 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8874 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8876 loadData : function(o, append){
8877 var r = this.reader.readRecords(o);
8878 this.loadRecords(r, {add: append}, true);
8882 * Gets the number of cached records.
8884 * <em>If using paging, this may not be the total size of the dataset. If the data object
8885 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8886 * the data set size</em>
8888 getCount : function(){
8889 return this.data.length || 0;
8893 * Gets the total number of records in the dataset as returned by the server.
8895 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8896 * the dataset size</em>
8898 getTotalCount : function(){
8899 return this.totalLength || 0;
8903 * Returns the sort state of the Store as an object with two properties:
8905 field {String} The name of the field by which the Records are sorted
8906 direction {String} The sort order, "ASC" or "DESC"
8909 getSortState : function(){
8910 return this.sortInfo;
8914 applySort : function(){
8915 if(this.sortInfo && !this.remoteSort){
8916 var s = this.sortInfo, f = s.field;
8917 var st = this.fields.get(f).sortType;
8918 var fn = function(r1, r2){
8919 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8920 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8922 this.data.sort(s.direction, fn);
8923 if(this.snapshot && this.snapshot != this.data){
8924 this.snapshot.sort(s.direction, fn);
8930 * Sets the default sort column and order to be used by the next load operation.
8931 * @param {String} fieldName The name of the field to sort by.
8932 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8934 setDefaultSort : function(field, dir){
8935 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8940 * If remote sorting is used, the sort is performed on the server, and the cache is
8941 * reloaded. If local sorting is used, the cache is sorted internally.
8942 * @param {String} fieldName The name of the field to sort by.
8943 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8945 sort : function(fieldName, dir){
8946 var f = this.fields.get(fieldName);
8948 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8950 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8951 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8956 this.sortToggle[f.name] = dir;
8957 this.sortInfo = {field: f.name, direction: dir};
8958 if(!this.remoteSort){
8960 this.fireEvent("datachanged", this);
8962 this.load(this.lastOptions);
8967 * Calls the specified function for each of the Records in the cache.
8968 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8969 * Returning <em>false</em> aborts and exits the iteration.
8970 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8972 each : function(fn, scope){
8973 this.data.each(fn, scope);
8977 * Gets all records modified since the last commit. Modified records are persisted across load operations
8978 * (e.g., during paging).
8979 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8981 getModifiedRecords : function(){
8982 return this.modified;
8986 createFilterFn : function(property, value, anyMatch){
8987 if(!value.exec){ // not a regex
8988 value = String(value);
8989 if(value.length == 0){
8992 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8995 return value.test(r.data[property]);
9000 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9001 * @param {String} property A field on your records
9002 * @param {Number} start The record index to start at (defaults to 0)
9003 * @param {Number} end The last record index to include (defaults to length - 1)
9004 * @return {Number} The sum
9006 sum : function(property, start, end){
9007 var rs = this.data.items, v = 0;
9009 end = (end || end === 0) ? end : rs.length-1;
9011 for(var i = start; i <= end; i++){
9012 v += (rs[i].data[property] || 0);
9018 * Filter the records by a specified property.
9019 * @param {String} field A field on your records
9020 * @param {String/RegExp} value Either a string that the field
9021 * should start with or a RegExp to test against the field
9022 * @param {Boolean} anyMatch True to match any part not just the beginning
9024 filter : function(property, value, anyMatch){
9025 var fn = this.createFilterFn(property, value, anyMatch);
9026 return fn ? this.filterBy(fn) : this.clearFilter();
9030 * Filter by a function. The specified function will be called with each
9031 * record in this data source. If the function returns true the record is included,
9032 * otherwise it is filtered.
9033 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9034 * @param {Object} scope (optional) The scope of the function (defaults to this)
9036 filterBy : function(fn, scope){
9037 this.snapshot = this.snapshot || this.data;
9038 this.data = this.queryBy(fn, scope||this);
9039 this.fireEvent("datachanged", this);
9043 * Query the records by a specified property.
9044 * @param {String} field A field on your records
9045 * @param {String/RegExp} value Either a string that the field
9046 * should start with or a RegExp to test against the field
9047 * @param {Boolean} anyMatch True to match any part not just the beginning
9048 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9050 query : function(property, value, anyMatch){
9051 var fn = this.createFilterFn(property, value, anyMatch);
9052 return fn ? this.queryBy(fn) : this.data.clone();
9056 * Query by a function. The specified function will be called with each
9057 * record in this data source. If the function returns true the record is included
9059 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9060 * @param {Object} scope (optional) The scope of the function (defaults to this)
9061 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9063 queryBy : function(fn, scope){
9064 var data = this.snapshot || this.data;
9065 return data.filterBy(fn, scope||this);
9069 * Collects unique values for a particular dataIndex from this store.
9070 * @param {String} dataIndex The property to collect
9071 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9072 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9073 * @return {Array} An array of the unique values
9075 collect : function(dataIndex, allowNull, bypassFilter){
9076 var d = (bypassFilter === true && this.snapshot) ?
9077 this.snapshot.items : this.data.items;
9078 var v, sv, r = [], l = {};
9079 for(var i = 0, len = d.length; i < len; i++){
9080 v = d[i].data[dataIndex];
9082 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9091 * Revert to a view of the Record cache with no filtering applied.
9092 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9094 clearFilter : function(suppressEvent){
9095 if(this.snapshot && this.snapshot != this.data){
9096 this.data = this.snapshot;
9097 delete this.snapshot;
9098 if(suppressEvent !== true){
9099 this.fireEvent("datachanged", this);
9105 afterEdit : function(record){
9106 if(this.modified.indexOf(record) == -1){
9107 this.modified.push(record);
9109 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9113 afterReject : function(record){
9114 this.modified.remove(record);
9115 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9119 afterCommit : function(record){
9120 this.modified.remove(record);
9121 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9125 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9126 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9128 commitChanges : function(){
9129 var m = this.modified.slice(0);
9131 for(var i = 0, len = m.length; i < len; i++){
9137 * Cancel outstanding changes on all changed records.
9139 rejectChanges : function(){
9140 var m = this.modified.slice(0);
9142 for(var i = 0, len = m.length; i < len; i++){
9147 onMetaChange : function(meta, rtype, o){
9148 this.recordType = rtype;
9149 this.fields = rtype.prototype.fields;
9150 delete this.snapshot;
9151 this.sortInfo = meta.sortInfo || this.sortInfo;
9153 this.fireEvent('metachange', this, this.reader.meta);
9156 moveIndex : function(data, type)
9158 var index = this.indexOf(data);
9160 var newIndex = index + type;
9164 this.insert(newIndex, data);
9169 * Ext JS Library 1.1.1
9170 * Copyright(c) 2006-2007, Ext JS, LLC.
9172 * Originally Released Under LGPL - original licence link has changed is not relivant.
9175 * <script type="text/javascript">
9179 * @class Roo.data.SimpleStore
9180 * @extends Roo.data.Store
9181 * Small helper class to make creating Stores from Array data easier.
9182 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9183 * @cfg {Array} fields An array of field definition objects, or field name strings.
9184 * @cfg {Array} data The multi-dimensional array of data
9186 * @param {Object} config
9188 Roo.data.SimpleStore = function(config){
9189 Roo.data.SimpleStore.superclass.constructor.call(this, {
9191 reader: new Roo.data.ArrayReader({
9194 Roo.data.Record.create(config.fields)
9196 proxy : new Roo.data.MemoryProxy(config.data)
9200 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9202 * Ext JS Library 1.1.1
9203 * Copyright(c) 2006-2007, Ext JS, LLC.
9205 * Originally Released Under LGPL - original licence link has changed is not relivant.
9208 * <script type="text/javascript">
9213 * @extends Roo.data.Store
9214 * @class Roo.data.JsonStore
9215 * Small helper class to make creating Stores for JSON data easier. <br/>
9217 var store = new Roo.data.JsonStore({
9218 url: 'get-images.php',
9220 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9223 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9224 * JsonReader and HttpProxy (unless inline data is provided).</b>
9225 * @cfg {Array} fields An array of field definition objects, or field name strings.
9227 * @param {Object} config
9229 Roo.data.JsonStore = function(c){
9230 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9231 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9232 reader: new Roo.data.JsonReader(c, c.fields)
9235 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9237 * Ext JS Library 1.1.1
9238 * Copyright(c) 2006-2007, Ext JS, LLC.
9240 * Originally Released Under LGPL - original licence link has changed is not relivant.
9243 * <script type="text/javascript">
9247 Roo.data.Field = function(config){
9248 if(typeof config == "string"){
9249 config = {name: config};
9251 Roo.apply(this, config);
9257 var st = Roo.data.SortTypes;
9258 // named sortTypes are supported, here we look them up
9259 if(typeof this.sortType == "string"){
9260 this.sortType = st[this.sortType];
9263 // set default sortType for strings and dates
9267 this.sortType = st.asUCString;
9270 this.sortType = st.asDate;
9273 this.sortType = st.none;
9278 var stripRe = /[\$,%]/g;
9280 // prebuilt conversion function for this field, instead of
9281 // switching every time we're reading a value
9283 var cv, dateFormat = this.dateFormat;
9288 cv = function(v){ return v; };
9291 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9295 return v !== undefined && v !== null && v !== '' ?
9296 parseInt(String(v).replace(stripRe, ""), 10) : '';
9301 return v !== undefined && v !== null && v !== '' ?
9302 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9307 cv = function(v){ return v === true || v === "true" || v == 1; };
9314 if(v instanceof Date){
9318 if(dateFormat == "timestamp"){
9319 return new Date(v*1000);
9321 return Date.parseDate(v, dateFormat);
9323 var parsed = Date.parse(v);
9324 return parsed ? new Date(parsed) : null;
9333 Roo.data.Field.prototype = {
9341 * Ext JS Library 1.1.1
9342 * Copyright(c) 2006-2007, Ext JS, LLC.
9344 * Originally Released Under LGPL - original licence link has changed is not relivant.
9347 * <script type="text/javascript">
9350 // Base class for reading structured data from a data source. This class is intended to be
9351 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9354 * @class Roo.data.DataReader
9355 * Base class for reading structured data from a data source. This class is intended to be
9356 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9359 Roo.data.DataReader = function(meta, recordType){
9363 this.recordType = recordType instanceof Array ?
9364 Roo.data.Record.create(recordType) : recordType;
9367 Roo.data.DataReader.prototype = {
9369 * Create an empty record
9370 * @param {Object} data (optional) - overlay some values
9371 * @return {Roo.data.Record} record created.
9373 newRow : function(d) {
9375 this.recordType.prototype.fields.each(function(c) {
9377 case 'int' : da[c.name] = 0; break;
9378 case 'date' : da[c.name] = new Date(); break;
9379 case 'float' : da[c.name] = 0.0; break;
9380 case 'boolean' : da[c.name] = false; break;
9381 default : da[c.name] = ""; break;
9385 return new this.recordType(Roo.apply(da, d));
9390 * Ext JS Library 1.1.1
9391 * Copyright(c) 2006-2007, Ext JS, LLC.
9393 * Originally Released Under LGPL - original licence link has changed is not relivant.
9396 * <script type="text/javascript">
9400 * @class Roo.data.DataProxy
9401 * @extends Roo.data.Observable
9402 * This class is an abstract base class for implementations which provide retrieval of
9403 * unformatted data objects.<br>
9405 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9406 * (of the appropriate type which knows how to parse the data object) to provide a block of
9407 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9409 * Custom implementations must implement the load method as described in
9410 * {@link Roo.data.HttpProxy#load}.
9412 Roo.data.DataProxy = function(){
9416 * Fires before a network request is made to retrieve a data object.
9417 * @param {Object} This DataProxy object.
9418 * @param {Object} params The params parameter to the load function.
9423 * Fires before the load method's callback is called.
9424 * @param {Object} This DataProxy object.
9425 * @param {Object} o The data object.
9426 * @param {Object} arg The callback argument object passed to the load function.
9430 * @event loadexception
9431 * Fires if an Exception occurs during data retrieval.
9432 * @param {Object} This DataProxy object.
9433 * @param {Object} o The data object.
9434 * @param {Object} arg The callback argument object passed to the load function.
9435 * @param {Object} e The Exception.
9437 loadexception : true
9439 Roo.data.DataProxy.superclass.constructor.call(this);
9442 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9445 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9449 * Ext JS Library 1.1.1
9450 * Copyright(c) 2006-2007, Ext JS, LLC.
9452 * Originally Released Under LGPL - original licence link has changed is not relivant.
9455 * <script type="text/javascript">
9458 * @class Roo.data.MemoryProxy
9459 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9460 * to the Reader when its load method is called.
9462 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9464 Roo.data.MemoryProxy = function(data){
9468 Roo.data.MemoryProxy.superclass.constructor.call(this);
9472 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9474 * Load data from the requested source (in this case an in-memory
9475 * data object passed to the constructor), read the data object into
9476 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9477 * process that block using the passed callback.
9478 * @param {Object} params This parameter is not used by the MemoryProxy class.
9479 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9480 * object into a block of Roo.data.Records.
9481 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9482 * The function must be passed <ul>
9483 * <li>The Record block object</li>
9484 * <li>The "arg" argument from the load function</li>
9485 * <li>A boolean success indicator</li>
9487 * @param {Object} scope The scope in which to call the callback
9488 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9490 load : function(params, reader, callback, scope, arg){
9491 params = params || {};
9494 result = reader.readRecords(this.data);
9496 this.fireEvent("loadexception", this, arg, null, e);
9497 callback.call(scope, null, arg, false);
9500 callback.call(scope, result, arg, true);
9504 update : function(params, records){
9509 * Ext JS Library 1.1.1
9510 * Copyright(c) 2006-2007, Ext JS, LLC.
9512 * Originally Released Under LGPL - original licence link has changed is not relivant.
9515 * <script type="text/javascript">
9518 * @class Roo.data.HttpProxy
9519 * @extends Roo.data.DataProxy
9520 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9521 * configured to reference a certain URL.<br><br>
9523 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9524 * from which the running page was served.<br><br>
9526 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9528 * Be aware that to enable the browser to parse an XML document, the server must set
9529 * the Content-Type header in the HTTP response to "text/xml".
9531 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9532 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9533 * will be used to make the request.
9535 Roo.data.HttpProxy = function(conn){
9536 Roo.data.HttpProxy.superclass.constructor.call(this);
9537 // is conn a conn config or a real conn?
9539 this.useAjax = !conn || !conn.events;
9543 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9544 // thse are take from connection...
9547 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9550 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9551 * extra parameters to each request made by this object. (defaults to undefined)
9554 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9555 * to each request made by this object. (defaults to undefined)
9558 * @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)
9561 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9564 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9570 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9574 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9575 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9576 * a finer-grained basis than the DataProxy events.
9578 getConnection : function(){
9579 return this.useAjax ? Roo.Ajax : this.conn;
9583 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9584 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9585 * process that block using the passed callback.
9586 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9587 * for the request to the remote server.
9588 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9589 * object into a block of Roo.data.Records.
9590 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9591 * The function must be passed <ul>
9592 * <li>The Record block object</li>
9593 * <li>The "arg" argument from the load function</li>
9594 * <li>A boolean success indicator</li>
9596 * @param {Object} scope The scope in which to call the callback
9597 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9599 load : function(params, reader, callback, scope, arg){
9600 if(this.fireEvent("beforeload", this, params) !== false){
9602 params : params || {},
9604 callback : callback,
9609 callback : this.loadResponse,
9613 Roo.applyIf(o, this.conn);
9614 if(this.activeRequest){
9615 Roo.Ajax.abort(this.activeRequest);
9617 this.activeRequest = Roo.Ajax.request(o);
9619 this.conn.request(o);
9622 callback.call(scope||this, null, arg, false);
9627 loadResponse : function(o, success, response){
9628 delete this.activeRequest;
9630 this.fireEvent("loadexception", this, o, response);
9631 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9636 result = o.reader.read(response);
9638 this.fireEvent("loadexception", this, o, response, e);
9639 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9643 this.fireEvent("load", this, o, o.request.arg);
9644 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9648 update : function(dataSet){
9653 updateResponse : function(dataSet){
9658 * Ext JS Library 1.1.1
9659 * Copyright(c) 2006-2007, Ext JS, LLC.
9661 * Originally Released Under LGPL - original licence link has changed is not relivant.
9664 * <script type="text/javascript">
9668 * @class Roo.data.ScriptTagProxy
9669 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9670 * other than the originating domain of the running page.<br><br>
9672 * <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
9673 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9675 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9676 * source code that is used as the source inside a <script> tag.<br><br>
9678 * In order for the browser to process the returned data, the server must wrap the data object
9679 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9680 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9681 * depending on whether the callback name was passed:
9684 boolean scriptTag = false;
9685 String cb = request.getParameter("callback");
9688 response.setContentType("text/javascript");
9690 response.setContentType("application/x-json");
9692 Writer out = response.getWriter();
9694 out.write(cb + "(");
9696 out.print(dataBlock.toJsonString());
9703 * @param {Object} config A configuration object.
9705 Roo.data.ScriptTagProxy = function(config){
9706 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9707 Roo.apply(this, config);
9708 this.head = document.getElementsByTagName("head")[0];
9711 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9713 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9715 * @cfg {String} url The URL from which to request the data object.
9718 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9722 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9723 * the server the name of the callback function set up by the load call to process the returned data object.
9724 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9725 * javascript output which calls this named function passing the data object as its only parameter.
9727 callbackParam : "callback",
9729 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9730 * name to the request.
9735 * Load data from the configured URL, read the data object into
9736 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9737 * process that block using the passed callback.
9738 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9739 * for the request to the remote server.
9740 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9741 * object into a block of Roo.data.Records.
9742 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9743 * The function must be passed <ul>
9744 * <li>The Record block object</li>
9745 * <li>The "arg" argument from the load function</li>
9746 * <li>A boolean success indicator</li>
9748 * @param {Object} scope The scope in which to call the callback
9749 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9751 load : function(params, reader, callback, scope, arg){
9752 if(this.fireEvent("beforeload", this, params) !== false){
9754 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9757 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9759 url += "&_dc=" + (new Date().getTime());
9761 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9764 cb : "stcCallback"+transId,
9765 scriptId : "stcScript"+transId,
9769 callback : callback,
9775 window[trans.cb] = function(o){
9776 conn.handleResponse(o, trans);
9779 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9781 if(this.autoAbort !== false){
9785 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9787 var script = document.createElement("script");
9788 script.setAttribute("src", url);
9789 script.setAttribute("type", "text/javascript");
9790 script.setAttribute("id", trans.scriptId);
9791 this.head.appendChild(script);
9795 callback.call(scope||this, null, arg, false);
9800 isLoading : function(){
9801 return this.trans ? true : false;
9805 * Abort the current server request.
9808 if(this.isLoading()){
9809 this.destroyTrans(this.trans);
9814 destroyTrans : function(trans, isLoaded){
9815 this.head.removeChild(document.getElementById(trans.scriptId));
9816 clearTimeout(trans.timeoutId);
9818 window[trans.cb] = undefined;
9820 delete window[trans.cb];
9823 // if hasn't been loaded, wait for load to remove it to prevent script error
9824 window[trans.cb] = function(){
9825 window[trans.cb] = undefined;
9827 delete window[trans.cb];
9834 handleResponse : function(o, trans){
9836 this.destroyTrans(trans, true);
9839 result = trans.reader.readRecords(o);
9841 this.fireEvent("loadexception", this, o, trans.arg, e);
9842 trans.callback.call(trans.scope||window, null, trans.arg, false);
9845 this.fireEvent("load", this, o, trans.arg);
9846 trans.callback.call(trans.scope||window, result, trans.arg, true);
9850 handleFailure : function(trans){
9852 this.destroyTrans(trans, false);
9853 this.fireEvent("loadexception", this, null, trans.arg);
9854 trans.callback.call(trans.scope||window, null, trans.arg, false);
9858 * Ext JS Library 1.1.1
9859 * Copyright(c) 2006-2007, Ext JS, LLC.
9861 * Originally Released Under LGPL - original licence link has changed is not relivant.
9864 * <script type="text/javascript">
9868 * @class Roo.data.JsonReader
9869 * @extends Roo.data.DataReader
9870 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9871 * based on mappings in a provided Roo.data.Record constructor.
9873 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9874 * in the reply previously.
9879 var RecordDef = Roo.data.Record.create([
9880 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9881 {name: 'occupation'} // This field will use "occupation" as the mapping.
9883 var myReader = new Roo.data.JsonReader({
9884 totalProperty: "results", // The property which contains the total dataset size (optional)
9885 root: "rows", // The property which contains an Array of row objects
9886 id: "id" // The property within each row object that provides an ID for the record (optional)
9890 * This would consume a JSON file like this:
9892 { 'results': 2, 'rows': [
9893 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9894 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9897 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9898 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9899 * paged from the remote server.
9900 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9901 * @cfg {String} root name of the property which contains the Array of row objects.
9902 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9904 * Create a new JsonReader
9905 * @param {Object} meta Metadata configuration options
9906 * @param {Object} recordType Either an Array of field definition objects,
9907 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9909 Roo.data.JsonReader = function(meta, recordType){
9912 // set some defaults:
9914 totalProperty: 'total',
9915 successProperty : 'success',
9920 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9922 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9925 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9926 * Used by Store query builder to append _requestMeta to params.
9929 metaFromRemote : false,
9931 * This method is only used by a DataProxy which has retrieved data from a remote server.
9932 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9933 * @return {Object} data A data block which is used by an Roo.data.Store object as
9934 * a cache of Roo.data.Records.
9936 read : function(response){
9937 var json = response.responseText;
9939 var o = /* eval:var:o */ eval("("+json+")");
9941 throw {message: "JsonReader.read: Json object not found"};
9947 this.metaFromRemote = true;
9948 this.meta = o.metaData;
9949 this.recordType = Roo.data.Record.create(o.metaData.fields);
9950 this.onMetaChange(this.meta, this.recordType, o);
9952 return this.readRecords(o);
9955 // private function a store will implement
9956 onMetaChange : function(meta, recordType, o){
9963 simpleAccess: function(obj, subsc) {
9970 getJsonAccessor: function(){
9972 return function(expr) {
9974 return(re.test(expr))
9975 ? new Function("obj", "return obj." + expr)
9985 * Create a data block containing Roo.data.Records from an XML document.
9986 * @param {Object} o An object which contains an Array of row objects in the property specified
9987 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9988 * which contains the total size of the dataset.
9989 * @return {Object} data A data block which is used by an Roo.data.Store object as
9990 * a cache of Roo.data.Records.
9992 readRecords : function(o){
9994 * After any data loads, the raw JSON data is available for further custom processing.
9998 var s = this.meta, Record = this.recordType,
9999 f = Record.prototype.fields, fi = f.items, fl = f.length;
10001 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10003 if(s.totalProperty) {
10004 this.getTotal = this.getJsonAccessor(s.totalProperty);
10006 if(s.successProperty) {
10007 this.getSuccess = this.getJsonAccessor(s.successProperty);
10009 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10011 var g = this.getJsonAccessor(s.id);
10012 this.getId = function(rec) {
10014 return (r === undefined || r === "") ? null : r;
10017 this.getId = function(){return null;};
10020 for(var jj = 0; jj < fl; jj++){
10022 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10023 this.ef[jj] = this.getJsonAccessor(map);
10027 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10028 if(s.totalProperty){
10029 var vt = parseInt(this.getTotal(o), 10);
10034 if(s.successProperty){
10035 var vs = this.getSuccess(o);
10036 if(vs === false || vs === 'false'){
10041 for(var i = 0; i < c; i++){
10044 var id = this.getId(n);
10045 for(var j = 0; j < fl; j++){
10047 var v = this.ef[j](n);
10049 Roo.log('missing convert for ' + f.name);
10053 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10055 var record = new Record(values, id);
10057 records[i] = record;
10063 totalRecords : totalRecords
10068 * Ext JS Library 1.1.1
10069 * Copyright(c) 2006-2007, Ext JS, LLC.
10071 * Originally Released Under LGPL - original licence link has changed is not relivant.
10074 * <script type="text/javascript">
10078 * @class Roo.data.ArrayReader
10079 * @extends Roo.data.DataReader
10080 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10081 * Each element of that Array represents a row of data fields. The
10082 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10083 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10087 var RecordDef = Roo.data.Record.create([
10088 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10089 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10091 var myReader = new Roo.data.ArrayReader({
10092 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10096 * This would consume an Array like this:
10098 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10100 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10102 * Create a new JsonReader
10103 * @param {Object} meta Metadata configuration options.
10104 * @param {Object} recordType Either an Array of field definition objects
10105 * as specified to {@link Roo.data.Record#create},
10106 * or an {@link Roo.data.Record} object
10107 * created using {@link Roo.data.Record#create}.
10109 Roo.data.ArrayReader = function(meta, recordType){
10110 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10113 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10115 * Create a data block containing Roo.data.Records from an XML document.
10116 * @param {Object} o An Array of row objects which represents the dataset.
10117 * @return {Object} data A data block which is used by an Roo.data.Store object as
10118 * a cache of Roo.data.Records.
10120 readRecords : function(o){
10121 var sid = this.meta ? this.meta.id : null;
10122 var recordType = this.recordType, fields = recordType.prototype.fields;
10125 for(var i = 0; i < root.length; i++){
10128 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10129 for(var j = 0, jlen = fields.length; j < jlen; j++){
10130 var f = fields.items[j];
10131 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10132 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10134 values[f.name] = v;
10136 var record = new recordType(values, id);
10138 records[records.length] = record;
10142 totalRecords : records.length
10151 * @class Roo.bootstrap.ComboBox
10152 * @extends Roo.bootstrap.TriggerField
10153 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10154 * @cfg {Boolean} append (true|false) default false
10155 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10156 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10157 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10158 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10159 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10161 * Create a new ComboBox.
10162 * @param {Object} config Configuration options
10164 Roo.bootstrap.ComboBox = function(config){
10165 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10169 * Fires when the dropdown list is expanded
10170 * @param {Roo.bootstrap.ComboBox} combo This combo box
10175 * Fires when the dropdown list is collapsed
10176 * @param {Roo.bootstrap.ComboBox} combo This combo box
10180 * @event beforeselect
10181 * Fires before a list item is selected. Return false to cancel the selection.
10182 * @param {Roo.bootstrap.ComboBox} combo This combo box
10183 * @param {Roo.data.Record} record The data record returned from the underlying store
10184 * @param {Number} index The index of the selected item in the dropdown list
10186 'beforeselect' : true,
10189 * Fires when a list item is selected
10190 * @param {Roo.bootstrap.ComboBox} combo This combo box
10191 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10192 * @param {Number} index The index of the selected item in the dropdown list
10196 * @event beforequery
10197 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10198 * The event object passed has these properties:
10199 * @param {Roo.bootstrap.ComboBox} combo This combo box
10200 * @param {String} query The query
10201 * @param {Boolean} forceAll true to force "all" query
10202 * @param {Boolean} cancel true to cancel the query
10203 * @param {Object} e The query event object
10205 'beforequery': true,
10208 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10209 * @param {Roo.bootstrap.ComboBox} combo This combo box
10214 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10215 * @param {Roo.bootstrap.ComboBox} combo This combo box
10216 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10221 * Fires when the remove value from the combobox array
10222 * @param {Roo.bootstrap.ComboBox} combo This combo box
10229 this.tickItems = [];
10231 this.selectedIndex = -1;
10232 if(this.mode == 'local'){
10233 if(config.queryDelay === undefined){
10234 this.queryDelay = 10;
10236 if(config.minChars === undefined){
10242 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10245 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10246 * rendering into an Roo.Editor, defaults to false)
10249 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10250 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10253 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10256 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10257 * the dropdown list (defaults to undefined, with no header element)
10261 * @cfg {String/Roo.Template} tpl The template to use to render the output
10265 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10267 listWidth: undefined,
10269 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10270 * mode = 'remote' or 'text' if mode = 'local')
10272 displayField: undefined,
10274 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10275 * mode = 'remote' or 'value' if mode = 'local').
10276 * Note: use of a valueField requires the user make a selection
10277 * in order for a value to be mapped.
10279 valueField: undefined,
10283 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10284 * field's data value (defaults to the underlying DOM element's name)
10286 hiddenName: undefined,
10288 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10292 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10294 selectedClass: 'active',
10297 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10301 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10302 * anchor positions (defaults to 'tl-bl')
10304 listAlign: 'tl-bl?',
10306 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10310 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10311 * query specified by the allQuery config option (defaults to 'query')
10313 triggerAction: 'query',
10315 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10316 * (defaults to 4, does not apply if editable = false)
10320 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10321 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10325 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10326 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10330 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10331 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10335 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10336 * when editable = true (defaults to false)
10338 selectOnFocus:false,
10340 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10342 queryParam: 'query',
10344 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10345 * when mode = 'remote' (defaults to 'Loading...')
10347 loadingText: 'Loading...',
10349 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10353 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10357 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10358 * traditional select (defaults to true)
10362 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10366 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10370 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10371 * listWidth has a higher value)
10375 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10376 * allow the user to set arbitrary text into the field (defaults to false)
10378 forceSelection:false,
10380 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10381 * if typeAhead = true (defaults to 250)
10383 typeAheadDelay : 250,
10385 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10386 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10388 valueNotFoundText : undefined,
10390 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10392 blockFocus : false,
10395 * @cfg {Boolean} disableClear Disable showing of clear button.
10397 disableClear : false,
10399 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10401 alwaysQuery : false,
10404 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10418 btnPosition : 'right',
10419 triggerList : true,
10420 showToggleBtn : true,
10421 // element that contains real text value.. (when hidden is used..)
10423 getAutoCreate : function()
10430 if(!this.tickable){
10431 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10436 * ComboBox with tickable selections
10439 var align = this.labelAlign || this.parentLabelAlign();
10442 cls : 'form-group roo-combobox-tickable' //input-group
10448 cls : 'tickable-buttons',
10453 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10460 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10467 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10474 Roo.each(buttons.cn, function(c){
10476 c.cls += ' btn-' + _this.size;
10479 if (_this.disabled) {
10490 cls: 'form-hidden-field'
10494 cls: 'select2-choices',
10498 cls: 'select2-search-field',
10510 cls: 'select2-container input-group select2-container-multi',
10515 // cls: 'typeahead typeahead-long dropdown-menu',
10516 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10521 if (align ==='left' && this.fieldLabel.length) {
10523 Roo.log("left and has label");
10529 cls : 'control-label col-sm-' + this.labelWidth,
10530 html : this.fieldLabel
10534 cls : "col-sm-" + (12 - this.labelWidth),
10541 } else if ( this.fieldLabel.length) {
10547 //cls : 'input-group-addon',
10548 html : this.fieldLabel
10558 Roo.log(" no label && no align");
10565 ['xs','sm','md','lg'].map(function(size){
10566 if (settings[size]) {
10567 cfg.cls += ' col-' + size + '-' + settings[size];
10576 initEvents: function()
10580 throw "can not find store for combo";
10582 this.store = Roo.factory(this.store, Roo.data);
10585 this.initTickableEvents();
10589 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10591 if(this.hiddenName){
10593 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10595 this.hiddenField.dom.value =
10596 this.hiddenValue !== undefined ? this.hiddenValue :
10597 this.value !== undefined ? this.value : '';
10599 // prevent input submission
10600 this.el.dom.removeAttribute('name');
10601 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10606 // this.el.dom.setAttribute('autocomplete', 'off');
10609 var cls = 'x-combo-list';
10611 //this.list = new Roo.Layer({
10612 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10618 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10619 _this.list.setWidth(lw);
10622 this.list.on('mouseover', this.onViewOver, this);
10623 this.list.on('mousemove', this.onViewMove, this);
10625 this.list.on('scroll', this.onViewScroll, this);
10628 this.list.swallowEvent('mousewheel');
10629 this.assetHeight = 0;
10632 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10633 this.assetHeight += this.header.getHeight();
10636 this.innerList = this.list.createChild({cls:cls+'-inner'});
10637 this.innerList.on('mouseover', this.onViewOver, this);
10638 this.innerList.on('mousemove', this.onViewMove, this);
10639 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10641 if(this.allowBlank && !this.pageSize && !this.disableClear){
10642 this.footer = this.list.createChild({cls:cls+'-ft'});
10643 this.pageTb = new Roo.Toolbar(this.footer);
10647 this.footer = this.list.createChild({cls:cls+'-ft'});
10648 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10649 {pageSize: this.pageSize});
10653 if (this.pageTb && this.allowBlank && !this.disableClear) {
10655 this.pageTb.add(new Roo.Toolbar.Fill(), {
10656 cls: 'x-btn-icon x-btn-clear',
10658 handler: function()
10661 _this.clearValue();
10662 _this.onSelect(false, -1);
10667 this.assetHeight += this.footer.getHeight();
10672 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10675 this.view = new Roo.View(this.list, this.tpl, {
10676 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10678 //this.view.wrapEl.setDisplayed(false);
10679 this.view.on('click', this.onViewClick, this);
10683 this.store.on('beforeload', this.onBeforeLoad, this);
10684 this.store.on('load', this.onLoad, this);
10685 this.store.on('loadexception', this.onLoadException, this);
10687 if(this.resizable){
10688 this.resizer = new Roo.Resizable(this.list, {
10689 pinned:true, handles:'se'
10691 this.resizer.on('resize', function(r, w, h){
10692 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10693 this.listWidth = w;
10694 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10695 this.restrictHeight();
10697 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10700 if(!this.editable){
10701 this.editable = true;
10702 this.setEditable(false);
10707 if (typeof(this.events.add.listeners) != 'undefined') {
10709 this.addicon = this.wrap.createChild(
10710 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10712 this.addicon.on('click', function(e) {
10713 this.fireEvent('add', this);
10716 if (typeof(this.events.edit.listeners) != 'undefined') {
10718 this.editicon = this.wrap.createChild(
10719 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10720 if (this.addicon) {
10721 this.editicon.setStyle('margin-left', '40px');
10723 this.editicon.on('click', function(e) {
10725 // we fire even if inothing is selected..
10726 this.fireEvent('edit', this, this.lastData );
10732 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10733 "up" : function(e){
10734 this.inKeyMode = true;
10738 "down" : function(e){
10739 if(!this.isExpanded()){
10740 this.onTriggerClick();
10742 this.inKeyMode = true;
10747 "enter" : function(e){
10748 // this.onViewClick();
10752 if(this.fireEvent("specialkey", this, e)){
10753 this.onViewClick(false);
10759 "esc" : function(e){
10763 "tab" : function(e){
10766 if(this.fireEvent("specialkey", this, e)){
10767 this.onViewClick(false);
10775 doRelay : function(foo, bar, hname){
10776 if(hname == 'down' || this.scope.isExpanded()){
10777 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10786 this.queryDelay = Math.max(this.queryDelay || 10,
10787 this.mode == 'local' ? 10 : 250);
10790 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10792 if(this.typeAhead){
10793 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10795 if(this.editable !== false){
10796 this.inputEl().on("keyup", this.onKeyUp, this);
10798 if(this.forceSelection){
10799 this.inputEl().on('blur', this.doForce, this);
10803 this.choices = this.el.select('ul.select2-choices', true).first();
10804 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10808 initTickableEvents: function()
10812 if(this.hiddenName){
10814 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10816 this.hiddenField.dom.value =
10817 this.hiddenValue !== undefined ? this.hiddenValue :
10818 this.value !== undefined ? this.value : '';
10820 // prevent input submission
10821 this.el.dom.removeAttribute('name');
10822 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10827 // this.list = this.el.select('ul.dropdown-menu',true).first();
10829 this.choices = this.el.select('ul.select2-choices', true).first();
10830 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10831 if(this.triggerList){
10832 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10835 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10836 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10838 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10839 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10841 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10842 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10844 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10845 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10846 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10849 this.cancelBtn.hide();
10854 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10855 _this.list.setWidth(lw);
10858 this.list.on('mouseover', this.onViewOver, this);
10859 this.list.on('mousemove', this.onViewMove, this);
10861 this.list.on('scroll', this.onViewScroll, this);
10864 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10867 this.view = new Roo.View(this.list, this.tpl, {
10868 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10871 //this.view.wrapEl.setDisplayed(false);
10872 this.view.on('click', this.onViewClick, this);
10876 this.store.on('beforeload', this.onBeforeLoad, this);
10877 this.store.on('load', this.onLoad, this);
10878 this.store.on('loadexception', this.onLoadException, this);
10880 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10881 // "up" : function(e){
10882 // this.inKeyMode = true;
10883 // this.selectPrev();
10886 // "down" : function(e){
10887 // if(!this.isExpanded()){
10888 // this.onTriggerClick();
10890 // this.inKeyMode = true;
10891 // this.selectNext();
10895 // "enter" : function(e){
10896 //// this.onViewClick();
10898 // this.collapse();
10900 // if(this.fireEvent("specialkey", this, e)){
10901 // this.onViewClick(false);
10907 // "esc" : function(e){
10908 // this.collapse();
10911 // "tab" : function(e){
10912 // this.collapse();
10914 // if(this.fireEvent("specialkey", this, e)){
10915 // this.onViewClick(false);
10923 // doRelay : function(foo, bar, hname){
10924 // if(hname == 'down' || this.scope.isExpanded()){
10925 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10930 // forceKeyDown: true
10934 this.queryDelay = Math.max(this.queryDelay || 10,
10935 this.mode == 'local' ? 10 : 250);
10938 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10940 if(this.typeAhead){
10941 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10945 onDestroy : function(){
10947 this.view.setStore(null);
10948 this.view.el.removeAllListeners();
10949 this.view.el.remove();
10950 this.view.purgeListeners();
10953 this.list.dom.innerHTML = '';
10957 this.store.un('beforeload', this.onBeforeLoad, this);
10958 this.store.un('load', this.onLoad, this);
10959 this.store.un('loadexception', this.onLoadException, this);
10961 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10965 fireKey : function(e){
10966 if(e.isNavKeyPress() && !this.list.isVisible()){
10967 this.fireEvent("specialkey", this, e);
10972 onResize: function(w, h){
10973 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10975 // if(typeof w != 'number'){
10976 // // we do not handle it!?!?
10979 // var tw = this.trigger.getWidth();
10980 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10981 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10983 // this.inputEl().setWidth( this.adjustWidth('input', x));
10985 // //this.trigger.setStyle('left', x+'px');
10987 // if(this.list && this.listWidth === undefined){
10988 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10989 // this.list.setWidth(lw);
10990 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10998 * Allow or prevent the user from directly editing the field text. If false is passed,
10999 * the user will only be able to select from the items defined in the dropdown list. This method
11000 * is the runtime equivalent of setting the 'editable' config option at config time.
11001 * @param {Boolean} value True to allow the user to directly edit the field text
11003 setEditable : function(value){
11004 if(value == this.editable){
11007 this.editable = value;
11009 this.inputEl().dom.setAttribute('readOnly', true);
11010 this.inputEl().on('mousedown', this.onTriggerClick, this);
11011 this.inputEl().addClass('x-combo-noedit');
11013 this.inputEl().dom.setAttribute('readOnly', false);
11014 this.inputEl().un('mousedown', this.onTriggerClick, this);
11015 this.inputEl().removeClass('x-combo-noedit');
11021 onBeforeLoad : function(combo,opts){
11022 if(!this.hasFocus){
11026 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11028 // this.restrictHeight();
11029 this.selectedIndex = -1;
11033 onLoad : function(){
11035 this.hasQuery = false;
11037 if(!this.hasFocus){
11041 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11042 this.loading.hide();
11045 if(this.store.getCount() > 0){
11047 // this.restrictHeight();
11048 if(this.lastQuery == this.allQuery){
11049 if(this.editable && !this.tickable){
11050 this.inputEl().dom.select();
11053 if(!this.selectByValue(this.value, true) && this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || this.store.lastOptions.add != true)){
11054 this.select(0, true);
11057 if(this.autoFocus){
11060 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11061 this.taTask.delay(this.typeAheadDelay);
11065 this.onEmptyResults();
11071 onLoadException : function()
11073 this.hasQuery = false;
11075 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11076 this.loading.hide();
11080 Roo.log(this.store.reader.jsonData);
11081 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11083 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11089 onTypeAhead : function(){
11090 if(this.store.getCount() > 0){
11091 var r = this.store.getAt(0);
11092 var newValue = r.data[this.displayField];
11093 var len = newValue.length;
11094 var selStart = this.getRawValue().length;
11096 if(selStart != len){
11097 this.setRawValue(newValue);
11098 this.selectText(selStart, newValue.length);
11104 onSelect : function(record, index){
11106 if(this.fireEvent('beforeselect', this, record, index) !== false){
11108 this.setFromData(index > -1 ? record.data : false);
11111 this.fireEvent('select', this, record, index);
11116 * Returns the currently selected field value or empty string if no value is set.
11117 * @return {String} value The selected value
11119 getValue : function(){
11122 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11125 if(this.valueField){
11126 return typeof this.value != 'undefined' ? this.value : '';
11128 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11133 * Clears any text/value currently set in the field
11135 clearValue : function(){
11136 if(this.hiddenField){
11137 this.hiddenField.dom.value = '';
11140 this.setRawValue('');
11141 this.lastSelectionText = '';
11146 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11147 * will be displayed in the field. If the value does not match the data value of an existing item,
11148 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11149 * Otherwise the field will be blank (although the value will still be set).
11150 * @param {String} value The value to match
11152 setValue : function(v){
11159 if(this.valueField){
11160 var r = this.findRecord(this.valueField, v);
11162 text = r.data[this.displayField];
11163 }else if(this.valueNotFoundText !== undefined){
11164 text = this.valueNotFoundText;
11167 this.lastSelectionText = text;
11168 if(this.hiddenField){
11169 this.hiddenField.dom.value = v;
11171 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11175 * @property {Object} the last set data for the element
11180 * Sets the value of the field based on a object which is related to the record format for the store.
11181 * @param {Object} value the value to set as. or false on reset?
11183 setFromData : function(o){
11186 if(typeof o.display_name !== 'string'){
11187 for(var i=0;i<o.display_name.length;i++){
11188 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11196 var dv = ''; // display value
11197 var vv = ''; // value value..
11199 if (this.displayField) {
11200 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11202 // this is an error condition!!!
11203 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11206 if(this.valueField){
11207 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11210 if(this.hiddenField){
11211 this.hiddenField.dom.value = vv;
11213 this.lastSelectionText = dv;
11214 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11218 // no hidden field.. - we store the value in 'value', but still display
11219 // display field!!!!
11220 this.lastSelectionText = dv;
11221 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11227 reset : function(){
11228 // overridden so that last data is reset..
11229 this.setValue(this.originalValue);
11230 this.clearInvalid();
11231 this.lastData = false;
11233 this.view.clearSelections();
11237 findRecord : function(prop, value){
11239 if(this.store.getCount() > 0){
11240 this.store.each(function(r){
11241 if(r.data[prop] == value){
11251 getName: function()
11253 // returns hidden if it's set..
11254 if (!this.rendered) {return ''};
11255 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11259 onViewMove : function(e, t){
11260 this.inKeyMode = false;
11264 onViewOver : function(e, t){
11265 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11268 var item = this.view.findItemFromChild(t);
11271 var index = this.view.indexOf(item);
11272 this.select(index, false);
11277 onViewClick : function(view, doFocus, el, e)
11279 var index = this.view.getSelectedIndexes()[0];
11281 var r = this.store.getAt(index);
11285 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11292 Roo.each(this.tickItems, function(v,k){
11294 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11295 _this.tickItems.splice(k, 1);
11305 this.tickItems.push(r.data);
11310 this.onSelect(r, index);
11312 if(doFocus !== false && !this.blockFocus){
11313 this.inputEl().focus();
11318 restrictHeight : function(){
11319 //this.innerList.dom.style.height = '';
11320 //var inner = this.innerList.dom;
11321 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11322 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11323 //this.list.beginUpdate();
11324 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11325 this.list.alignTo(this.inputEl(), this.listAlign);
11326 this.list.alignTo(this.inputEl(), this.listAlign);
11327 //this.list.endUpdate();
11331 onEmptyResults : function(){
11336 * Returns true if the dropdown list is expanded, else false.
11338 isExpanded : function(){
11339 return this.list.isVisible();
11343 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11344 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11345 * @param {String} value The data value of the item to select
11346 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11347 * selected item if it is not currently in view (defaults to true)
11348 * @return {Boolean} True if the value matched an item in the list, else false
11350 selectByValue : function(v, scrollIntoView){
11351 if(v !== undefined && v !== null){
11352 var r = this.findRecord(this.valueField || this.displayField, v);
11354 this.select(this.store.indexOf(r), scrollIntoView);
11362 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11363 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11364 * @param {Number} index The zero-based index of the list item to select
11365 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11366 * selected item if it is not currently in view (defaults to true)
11368 select : function(index, scrollIntoView){
11369 this.selectedIndex = index;
11370 this.view.select(index);
11371 if(scrollIntoView !== false){
11372 var el = this.view.getNode(index);
11373 if(el && !this.multiple && !this.tickable){
11374 this.list.scrollChildIntoView(el, false);
11380 selectNext : function(){
11381 var ct = this.store.getCount();
11383 if(this.selectedIndex == -1){
11385 }else if(this.selectedIndex < ct-1){
11386 this.select(this.selectedIndex+1);
11392 selectPrev : function(){
11393 var ct = this.store.getCount();
11395 if(this.selectedIndex == -1){
11397 }else if(this.selectedIndex != 0){
11398 this.select(this.selectedIndex-1);
11404 onKeyUp : function(e){
11405 if(this.editable !== false && !e.isSpecialKey()){
11406 this.lastKey = e.getKey();
11407 this.dqTask.delay(this.queryDelay);
11412 validateBlur : function(){
11413 return !this.list || !this.list.isVisible();
11417 initQuery : function(){
11418 this.doQuery(this.getRawValue());
11422 doForce : function(){
11423 if(this.inputEl().dom.value.length > 0){
11424 this.inputEl().dom.value =
11425 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11431 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11432 * query allowing the query action to be canceled if needed.
11433 * @param {String} query The SQL query to execute
11434 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11435 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11436 * saved in the current store (defaults to false)
11438 doQuery : function(q, forceAll){
11440 if(q === undefined || q === null){
11445 forceAll: forceAll,
11449 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11454 forceAll = qe.forceAll;
11455 if(forceAll === true || (q.length >= this.minChars)){
11457 this.hasQuery = true;
11459 if(this.lastQuery != q || this.alwaysQuery){
11460 this.lastQuery = q;
11461 if(this.mode == 'local'){
11462 this.selectedIndex = -1;
11464 this.store.clearFilter();
11466 this.store.filter(this.displayField, q);
11470 this.store.baseParams[this.queryParam] = q;
11472 var options = {params : this.getParams(q)};
11475 options.add = true;
11476 options.params.start = this.page * this.pageSize;
11479 this.store.load(options);
11481 * this code will make the page width larger, at the beginning, the list not align correctly,
11482 * we should expand the list on onLoad
11483 * so command out it
11488 this.selectedIndex = -1;
11493 this.loadNext = false;
11497 getParams : function(q){
11499 //p[this.queryParam] = q;
11503 p.limit = this.pageSize;
11509 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11511 collapse : function(){
11512 if(!this.isExpanded()){
11520 this.cancelBtn.hide();
11521 this.trigger.show();
11524 Roo.get(document).un('mousedown', this.collapseIf, this);
11525 Roo.get(document).un('mousewheel', this.collapseIf, this);
11526 if (!this.editable) {
11527 Roo.get(document).un('keydown', this.listKeyPress, this);
11529 this.fireEvent('collapse', this);
11533 collapseIf : function(e){
11534 var in_combo = e.within(this.el);
11535 var in_list = e.within(this.list);
11536 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11538 if (in_combo || in_list || is_list) {
11539 //e.stopPropagation();
11544 this.onTickableFooterButtonClick(e, false, false);
11552 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11554 expand : function(){
11556 if(this.isExpanded() || !this.hasFocus){
11560 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11561 this.list.setWidth(lw);
11566 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11567 this.list.setWidth(lw);
11571 this.restrictHeight();
11575 this.tickItems = Roo.apply([], this.item);
11578 this.cancelBtn.show();
11579 this.trigger.hide();
11583 Roo.get(document).on('mousedown', this.collapseIf, this);
11584 Roo.get(document).on('mousewheel', this.collapseIf, this);
11585 if (!this.editable) {
11586 Roo.get(document).on('keydown', this.listKeyPress, this);
11589 this.fireEvent('expand', this);
11593 // Implements the default empty TriggerField.onTriggerClick function
11594 onTriggerClick : function(e)
11596 Roo.log('trigger click');
11598 if(this.disabled || !this.triggerList){
11603 this.loadNext = false;
11605 if(this.isExpanded()){
11607 if (!this.blockFocus) {
11608 this.inputEl().focus();
11612 this.hasFocus = true;
11613 if(this.triggerAction == 'all') {
11614 this.doQuery(this.allQuery, true);
11616 this.doQuery(this.getRawValue());
11618 if (!this.blockFocus) {
11619 this.inputEl().focus();
11624 onTickableTriggerClick : function(e)
11631 this.loadNext = false;
11632 this.hasFocus = true;
11634 if(this.triggerAction == 'all') {
11635 this.doQuery(this.allQuery, true);
11637 this.doQuery(this.getRawValue());
11641 onSearchFieldClick : function(e)
11643 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11648 this.loadNext = false;
11649 this.hasFocus = true;
11651 if(this.triggerAction == 'all') {
11652 this.doQuery(this.allQuery, true);
11654 this.doQuery(this.getRawValue());
11658 listKeyPress : function(e)
11660 //Roo.log('listkeypress');
11661 // scroll to first matching element based on key pres..
11662 if (e.isSpecialKey()) {
11665 var k = String.fromCharCode(e.getKey()).toUpperCase();
11668 var csel = this.view.getSelectedNodes();
11669 var cselitem = false;
11671 var ix = this.view.indexOf(csel[0]);
11672 cselitem = this.store.getAt(ix);
11673 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11679 this.store.each(function(v) {
11681 // start at existing selection.
11682 if (cselitem.id == v.id) {
11688 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11689 match = this.store.indexOf(v);
11695 if (match === false) {
11696 return true; // no more action?
11699 this.view.select(match);
11700 var sn = Roo.get(this.view.getSelectedNodes()[0])
11701 //sn.scrollIntoView(sn.dom.parentNode, false);
11704 onViewScroll : function(e, t){
11706 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){
11710 this.hasQuery = true;
11712 this.loading = this.list.select('.loading', true).first();
11714 if(this.loading === null){
11715 this.list.createChild({
11717 cls: 'loading select2-more-results select2-active',
11718 html: 'Loading more results...'
11721 this.loading = this.list.select('.loading', true).first();
11723 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11725 this.loading.hide();
11728 this.loading.show();
11733 this.loadNext = true;
11735 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11740 addItem : function(o)
11742 var dv = ''; // display value
11744 if (this.displayField) {
11745 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11747 // this is an error condition!!!
11748 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11755 var choice = this.choices.createChild({
11757 cls: 'select2-search-choice',
11766 cls: 'select2-search-choice-close',
11771 }, this.searchField);
11773 var close = choice.select('a.select2-search-choice-close', true).first()
11775 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11783 this.inputEl().dom.value = '';
11787 onRemoveItem : function(e, _self, o)
11789 e.preventDefault();
11790 var index = this.item.indexOf(o.data) * 1;
11793 Roo.log('not this item?!');
11797 this.item.splice(index, 1);
11802 this.fireEvent('remove', this, e);
11806 syncValue : function()
11808 if(!this.item.length){
11815 Roo.each(this.item, function(i){
11816 if(_this.valueField){
11817 value.push(i[_this.valueField]);
11824 this.value = value.join(',');
11826 if(this.hiddenField){
11827 this.hiddenField.dom.value = this.value;
11831 clearItem : function()
11833 if(!this.multiple){
11839 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11846 inputEl: function ()
11849 return this.searchField;
11851 return this.el.select('input.form-control',true).first();
11855 onTickableFooterButtonClick : function(e, btn, el)
11857 e.preventDefault();
11859 if(btn && btn.name == 'cancel'){
11860 this.tickItems = Roo.apply([], this.item);
11869 Roo.each(this.tickItems, function(o){
11880 * @cfg {Boolean} grow
11884 * @cfg {Number} growMin
11888 * @cfg {Number} growMax
11898 * Ext JS Library 1.1.1
11899 * Copyright(c) 2006-2007, Ext JS, LLC.
11901 * Originally Released Under LGPL - original licence link has changed is not relivant.
11904 * <script type="text/javascript">
11909 * @extends Roo.util.Observable
11910 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11911 * This class also supports single and multi selection modes. <br>
11912 * Create a data model bound view:
11914 var store = new Roo.data.Store(...);
11916 var view = new Roo.View({
11918 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11920 singleSelect: true,
11921 selectedClass: "ydataview-selected",
11925 // listen for node click?
11926 view.on("click", function(vw, index, node, e){
11927 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11931 dataModel.load("foobar.xml");
11933 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11935 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11936 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11938 * Note: old style constructor is still suported (container, template, config)
11941 * Create a new View
11942 * @param {Object} config The config object
11945 Roo.View = function(config, depreciated_tpl, depreciated_config){
11947 this.parent = false;
11949 if (typeof(depreciated_tpl) == 'undefined') {
11950 // new way.. - universal constructor.
11951 Roo.apply(this, config);
11952 this.el = Roo.get(this.el);
11955 this.el = Roo.get(config);
11956 this.tpl = depreciated_tpl;
11957 Roo.apply(this, depreciated_config);
11959 this.wrapEl = this.el.wrap().wrap();
11960 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11963 if(typeof(this.tpl) == "string"){
11964 this.tpl = new Roo.Template(this.tpl);
11966 // support xtype ctors..
11967 this.tpl = new Roo.factory(this.tpl, Roo);
11971 this.tpl.compile();
11976 * @event beforeclick
11977 * Fires before a click is processed. Returns false to cancel the default action.
11978 * @param {Roo.View} this
11979 * @param {Number} index The index of the target node
11980 * @param {HTMLElement} node The target node
11981 * @param {Roo.EventObject} e The raw event object
11983 "beforeclick" : true,
11986 * Fires when a template node is clicked.
11987 * @param {Roo.View} this
11988 * @param {Number} index The index of the target node
11989 * @param {HTMLElement} node The target node
11990 * @param {Roo.EventObject} e The raw event object
11995 * Fires when a template node is double clicked.
11996 * @param {Roo.View} this
11997 * @param {Number} index The index of the target node
11998 * @param {HTMLElement} node The target node
11999 * @param {Roo.EventObject} e The raw event object
12003 * @event contextmenu
12004 * Fires when a template node is right clicked.
12005 * @param {Roo.View} this
12006 * @param {Number} index The index of the target node
12007 * @param {HTMLElement} node The target node
12008 * @param {Roo.EventObject} e The raw event object
12010 "contextmenu" : true,
12012 * @event selectionchange
12013 * Fires when the selected nodes change.
12014 * @param {Roo.View} this
12015 * @param {Array} selections Array of the selected nodes
12017 "selectionchange" : true,
12020 * @event beforeselect
12021 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12022 * @param {Roo.View} this
12023 * @param {HTMLElement} node The node to be selected
12024 * @param {Array} selections Array of currently selected nodes
12026 "beforeselect" : true,
12028 * @event preparedata
12029 * Fires on every row to render, to allow you to change the data.
12030 * @param {Roo.View} this
12031 * @param {Object} data to be rendered (change this)
12033 "preparedata" : true
12041 "click": this.onClick,
12042 "dblclick": this.onDblClick,
12043 "contextmenu": this.onContextMenu,
12047 this.selections = [];
12049 this.cmp = new Roo.CompositeElementLite([]);
12051 this.store = Roo.factory(this.store, Roo.data);
12052 this.setStore(this.store, true);
12055 if ( this.footer && this.footer.xtype) {
12057 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12059 this.footer.dataSource = this.store
12060 this.footer.container = fctr;
12061 this.footer = Roo.factory(this.footer, Roo);
12062 fctr.insertFirst(this.el);
12064 // this is a bit insane - as the paging toolbar seems to detach the el..
12065 // dom.parentNode.parentNode.parentNode
12066 // they get detached?
12070 Roo.View.superclass.constructor.call(this);
12075 Roo.extend(Roo.View, Roo.util.Observable, {
12078 * @cfg {Roo.data.Store} store Data store to load data from.
12083 * @cfg {String|Roo.Element} el The container element.
12088 * @cfg {String|Roo.Template} tpl The template used by this View
12092 * @cfg {String} dataName the named area of the template to use as the data area
12093 * Works with domtemplates roo-name="name"
12097 * @cfg {String} selectedClass The css class to add to selected nodes
12099 selectedClass : "x-view-selected",
12101 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12106 * @cfg {String} text to display on mask (default Loading)
12110 * @cfg {Boolean} multiSelect Allow multiple selection
12112 multiSelect : false,
12114 * @cfg {Boolean} singleSelect Allow single selection
12116 singleSelect: false,
12119 * @cfg {Boolean} toggleSelect - selecting
12121 toggleSelect : false,
12124 * @cfg {Boolean} tickable - selecting
12129 * Returns the element this view is bound to.
12130 * @return {Roo.Element}
12132 getEl : function(){
12133 return this.wrapEl;
12139 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12141 refresh : function(){
12142 Roo.log('refresh');
12145 // if we are using something like 'domtemplate', then
12146 // the what gets used is:
12147 // t.applySubtemplate(NAME, data, wrapping data..)
12148 // the outer template then get' applied with
12149 // the store 'extra data'
12150 // and the body get's added to the
12151 // roo-name="data" node?
12152 // <span class='roo-tpl-{name}'></span> ?????
12156 this.clearSelections();
12157 this.el.update("");
12159 var records = this.store.getRange();
12160 if(records.length < 1) {
12162 // is this valid?? = should it render a template??
12164 this.el.update(this.emptyText);
12168 if (this.dataName) {
12169 this.el.update(t.apply(this.store.meta)); //????
12170 el = this.el.child('.roo-tpl-' + this.dataName);
12173 for(var i = 0, len = records.length; i < len; i++){
12174 var data = this.prepareData(records[i].data, i, records[i]);
12175 this.fireEvent("preparedata", this, data, i, records[i]);
12177 var d = Roo.apply({}, data);
12180 Roo.apply(d, {'roo-id' : Roo.id()});
12184 Roo.each(this.parent.item, function(item){
12185 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12188 Roo.apply(d, {'roo-data-checked' : 'checked'});
12192 html[html.length] = Roo.util.Format.trim(
12194 t.applySubtemplate(this.dataName, d, this.store.meta) :
12201 el.update(html.join(""));
12202 this.nodes = el.dom.childNodes;
12203 this.updateIndexes(0);
12208 * Function to override to reformat the data that is sent to
12209 * the template for each node.
12210 * DEPRICATED - use the preparedata event handler.
12211 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12212 * a JSON object for an UpdateManager bound view).
12214 prepareData : function(data, index, record)
12216 this.fireEvent("preparedata", this, data, index, record);
12220 onUpdate : function(ds, record){
12221 Roo.log('on update');
12222 this.clearSelections();
12223 var index = this.store.indexOf(record);
12224 var n = this.nodes[index];
12225 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12226 n.parentNode.removeChild(n);
12227 this.updateIndexes(index, index);
12233 onAdd : function(ds, records, index)
12235 Roo.log(['on Add', ds, records, index] );
12236 this.clearSelections();
12237 if(this.nodes.length == 0){
12241 var n = this.nodes[index];
12242 for(var i = 0, len = records.length; i < len; i++){
12243 var d = this.prepareData(records[i].data, i, records[i]);
12245 this.tpl.insertBefore(n, d);
12248 this.tpl.append(this.el, d);
12251 this.updateIndexes(index);
12254 onRemove : function(ds, record, index){
12255 Roo.log('onRemove');
12256 this.clearSelections();
12257 var el = this.dataName ?
12258 this.el.child('.roo-tpl-' + this.dataName) :
12261 el.dom.removeChild(this.nodes[index]);
12262 this.updateIndexes(index);
12266 * Refresh an individual node.
12267 * @param {Number} index
12269 refreshNode : function(index){
12270 this.onUpdate(this.store, this.store.getAt(index));
12273 updateIndexes : function(startIndex, endIndex){
12274 var ns = this.nodes;
12275 startIndex = startIndex || 0;
12276 endIndex = endIndex || ns.length - 1;
12277 for(var i = startIndex; i <= endIndex; i++){
12278 ns[i].nodeIndex = i;
12283 * Changes the data store this view uses and refresh the view.
12284 * @param {Store} store
12286 setStore : function(store, initial){
12287 if(!initial && this.store){
12288 this.store.un("datachanged", this.refresh);
12289 this.store.un("add", this.onAdd);
12290 this.store.un("remove", this.onRemove);
12291 this.store.un("update", this.onUpdate);
12292 this.store.un("clear", this.refresh);
12293 this.store.un("beforeload", this.onBeforeLoad);
12294 this.store.un("load", this.onLoad);
12295 this.store.un("loadexception", this.onLoad);
12299 store.on("datachanged", this.refresh, this);
12300 store.on("add", this.onAdd, this);
12301 store.on("remove", this.onRemove, this);
12302 store.on("update", this.onUpdate, this);
12303 store.on("clear", this.refresh, this);
12304 store.on("beforeload", this.onBeforeLoad, this);
12305 store.on("load", this.onLoad, this);
12306 store.on("loadexception", this.onLoad, this);
12314 * onbeforeLoad - masks the loading area.
12317 onBeforeLoad : function(store,opts)
12319 Roo.log('onBeforeLoad');
12321 this.el.update("");
12323 this.el.mask(this.mask ? this.mask : "Loading" );
12325 onLoad : function ()
12332 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12333 * @param {HTMLElement} node
12334 * @return {HTMLElement} The template node
12336 findItemFromChild : function(node){
12337 var el = this.dataName ?
12338 this.el.child('.roo-tpl-' + this.dataName,true) :
12341 if(!node || node.parentNode == el){
12344 var p = node.parentNode;
12345 while(p && p != el){
12346 if(p.parentNode == el){
12355 onClick : function(e){
12356 var item = this.findItemFromChild(e.getTarget());
12358 var index = this.indexOf(item);
12359 if(this.onItemClick(item, index, e) !== false){
12360 this.fireEvent("click", this, index, item, e);
12363 this.clearSelections();
12368 onContextMenu : function(e){
12369 var item = this.findItemFromChild(e.getTarget());
12371 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12376 onDblClick : function(e){
12377 var item = this.findItemFromChild(e.getTarget());
12379 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12383 onItemClick : function(item, index, e)
12385 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12388 if (this.toggleSelect) {
12389 var m = this.isSelected(item) ? 'unselect' : 'select';
12392 _t[m](item, true, false);
12395 if(this.multiSelect || this.singleSelect){
12396 if(this.multiSelect && e.shiftKey && this.lastSelection){
12397 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12399 this.select(item, this.multiSelect && e.ctrlKey);
12400 this.lastSelection = item;
12403 if(!this.tickable){
12404 e.preventDefault();
12412 * Get the number of selected nodes.
12415 getSelectionCount : function(){
12416 return this.selections.length;
12420 * Get the currently selected nodes.
12421 * @return {Array} An array of HTMLElements
12423 getSelectedNodes : function(){
12424 return this.selections;
12428 * Get the indexes of the selected nodes.
12431 getSelectedIndexes : function(){
12432 var indexes = [], s = this.selections;
12433 for(var i = 0, len = s.length; i < len; i++){
12434 indexes.push(s[i].nodeIndex);
12440 * Clear all selections
12441 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12443 clearSelections : function(suppressEvent){
12444 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12445 this.cmp.elements = this.selections;
12446 this.cmp.removeClass(this.selectedClass);
12447 this.selections = [];
12448 if(!suppressEvent){
12449 this.fireEvent("selectionchange", this, this.selections);
12455 * Returns true if the passed node is selected
12456 * @param {HTMLElement/Number} node The node or node index
12457 * @return {Boolean}
12459 isSelected : function(node){
12460 var s = this.selections;
12464 node = this.getNode(node);
12465 return s.indexOf(node) !== -1;
12470 * @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
12471 * @param {Boolean} keepExisting (optional) true to keep existing selections
12472 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12474 select : function(nodeInfo, keepExisting, suppressEvent){
12475 if(nodeInfo instanceof Array){
12477 this.clearSelections(true);
12479 for(var i = 0, len = nodeInfo.length; i < len; i++){
12480 this.select(nodeInfo[i], true, true);
12484 var node = this.getNode(nodeInfo);
12485 if(!node || this.isSelected(node)){
12486 return; // already selected.
12489 this.clearSelections(true);
12491 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12492 Roo.fly(node).addClass(this.selectedClass);
12493 this.selections.push(node);
12494 if(!suppressEvent){
12495 this.fireEvent("selectionchange", this, this.selections);
12503 * @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
12504 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12505 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12507 unselect : function(nodeInfo, keepExisting, suppressEvent)
12509 if(nodeInfo instanceof Array){
12510 Roo.each(this.selections, function(s) {
12511 this.unselect(s, nodeInfo);
12515 var node = this.getNode(nodeInfo);
12516 if(!node || !this.isSelected(node)){
12517 Roo.log("not selected");
12518 return; // not selected.
12522 Roo.each(this.selections, function(s) {
12524 Roo.fly(node).removeClass(this.selectedClass);
12531 this.selections= ns;
12532 this.fireEvent("selectionchange", this, this.selections);
12536 * Gets a template node.
12537 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12538 * @return {HTMLElement} The node or null if it wasn't found
12540 getNode : function(nodeInfo){
12541 if(typeof nodeInfo == "string"){
12542 return document.getElementById(nodeInfo);
12543 }else if(typeof nodeInfo == "number"){
12544 return this.nodes[nodeInfo];
12550 * Gets a range template nodes.
12551 * @param {Number} startIndex
12552 * @param {Number} endIndex
12553 * @return {Array} An array of nodes
12555 getNodes : function(start, end){
12556 var ns = this.nodes;
12557 start = start || 0;
12558 end = typeof end == "undefined" ? ns.length - 1 : end;
12561 for(var i = start; i <= end; i++){
12565 for(var i = start; i >= end; i--){
12573 * Finds the index of the passed node
12574 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12575 * @return {Number} The index of the node or -1
12577 indexOf : function(node){
12578 node = this.getNode(node);
12579 if(typeof node.nodeIndex == "number"){
12580 return node.nodeIndex;
12582 var ns = this.nodes;
12583 for(var i = 0, len = ns.length; i < len; i++){
12594 * based on jquery fullcalendar
12598 Roo.bootstrap = Roo.bootstrap || {};
12600 * @class Roo.bootstrap.Calendar
12601 * @extends Roo.bootstrap.Component
12602 * Bootstrap Calendar class
12603 * @cfg {Boolean} loadMask (true|false) default false
12604 * @cfg {Object} header generate the user specific header of the calendar, default false
12607 * Create a new Container
12608 * @param {Object} config The config object
12613 Roo.bootstrap.Calendar = function(config){
12614 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12618 * Fires when a date is selected
12619 * @param {DatePicker} this
12620 * @param {Date} date The selected date
12624 * @event monthchange
12625 * Fires when the displayed month changes
12626 * @param {DatePicker} this
12627 * @param {Date} date The selected month
12629 'monthchange': true,
12631 * @event evententer
12632 * Fires when mouse over an event
12633 * @param {Calendar} this
12634 * @param {event} Event
12636 'evententer': true,
12638 * @event eventleave
12639 * Fires when the mouse leaves an
12640 * @param {Calendar} this
12643 'eventleave': true,
12645 * @event eventclick
12646 * Fires when the mouse click an
12647 * @param {Calendar} this
12656 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12659 * @cfg {Number} startDay
12660 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12668 getAutoCreate : function(){
12671 var fc_button = function(name, corner, style, content ) {
12672 return Roo.apply({},{
12674 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12676 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12679 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12690 style : 'width:100%',
12697 cls : 'fc-header-left',
12699 fc_button('prev', 'left', 'arrow', '‹' ),
12700 fc_button('next', 'right', 'arrow', '›' ),
12701 { tag: 'span', cls: 'fc-header-space' },
12702 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12710 cls : 'fc-header-center',
12714 cls: 'fc-header-title',
12717 html : 'month / year'
12725 cls : 'fc-header-right',
12727 /* fc_button('month', 'left', '', 'month' ),
12728 fc_button('week', '', '', 'week' ),
12729 fc_button('day', 'right', '', 'day' )
12741 header = this.header;
12744 var cal_heads = function() {
12746 // fixme - handle this.
12748 for (var i =0; i < Date.dayNames.length; i++) {
12749 var d = Date.dayNames[i];
12752 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12753 html : d.substring(0,3)
12757 ret[0].cls += ' fc-first';
12758 ret[6].cls += ' fc-last';
12761 var cal_cell = function(n) {
12764 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12769 cls: 'fc-day-number',
12773 cls: 'fc-day-content',
12777 style: 'position: relative;' // height: 17px;
12789 var cal_rows = function() {
12792 for (var r = 0; r < 6; r++) {
12799 for (var i =0; i < Date.dayNames.length; i++) {
12800 var d = Date.dayNames[i];
12801 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12804 row.cn[0].cls+=' fc-first';
12805 row.cn[0].cn[0].style = 'min-height:90px';
12806 row.cn[6].cls+=' fc-last';
12810 ret[0].cls += ' fc-first';
12811 ret[4].cls += ' fc-prev-last';
12812 ret[5].cls += ' fc-last';
12819 cls: 'fc-border-separate',
12820 style : 'width:100%',
12828 cls : 'fc-first fc-last',
12846 cls : 'fc-content',
12847 style : "position: relative;",
12850 cls : 'fc-view fc-view-month fc-grid',
12851 style : 'position: relative',
12852 unselectable : 'on',
12855 cls : 'fc-event-container',
12856 style : 'position:absolute;z-index:8;top:0;left:0;'
12874 initEvents : function()
12877 throw "can not find store for calendar";
12883 style: "text-align:center",
12887 style: "background-color:white;width:50%;margin:250 auto",
12891 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12902 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12904 var size = this.el.select('.fc-content', true).first().getSize();
12905 this.maskEl.setSize(size.width, size.height);
12906 this.maskEl.enableDisplayMode("block");
12907 if(!this.loadMask){
12908 this.maskEl.hide();
12911 this.store = Roo.factory(this.store, Roo.data);
12912 this.store.on('load', this.onLoad, this);
12913 this.store.on('beforeload', this.onBeforeLoad, this);
12917 this.cells = this.el.select('.fc-day',true);
12918 //Roo.log(this.cells);
12919 this.textNodes = this.el.query('.fc-day-number');
12920 this.cells.addClassOnOver('fc-state-hover');
12922 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12923 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12924 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12925 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12927 this.on('monthchange', this.onMonthChange, this);
12929 this.update(new Date().clearTime());
12932 resize : function() {
12933 var sz = this.el.getSize();
12935 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12936 this.el.select('.fc-day-content div',true).setHeight(34);
12941 showPrevMonth : function(e){
12942 this.update(this.activeDate.add("mo", -1));
12944 showToday : function(e){
12945 this.update(new Date().clearTime());
12948 showNextMonth : function(e){
12949 this.update(this.activeDate.add("mo", 1));
12953 showPrevYear : function(){
12954 this.update(this.activeDate.add("y", -1));
12958 showNextYear : function(){
12959 this.update(this.activeDate.add("y", 1));
12964 update : function(date)
12966 var vd = this.activeDate;
12967 this.activeDate = date;
12968 // if(vd && this.el){
12969 // var t = date.getTime();
12970 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12971 // Roo.log('using add remove');
12973 // this.fireEvent('monthchange', this, date);
12975 // this.cells.removeClass("fc-state-highlight");
12976 // this.cells.each(function(c){
12977 // if(c.dateValue == t){
12978 // c.addClass("fc-state-highlight");
12979 // setTimeout(function(){
12980 // try{c.dom.firstChild.focus();}catch(e){}
12990 var days = date.getDaysInMonth();
12992 var firstOfMonth = date.getFirstDateOfMonth();
12993 var startingPos = firstOfMonth.getDay()-this.startDay;
12995 if(startingPos < this.startDay){
12999 var pm = date.add(Date.MONTH, -1);
13000 var prevStart = pm.getDaysInMonth()-startingPos;
13002 this.cells = this.el.select('.fc-day',true);
13003 this.textNodes = this.el.query('.fc-day-number');
13004 this.cells.addClassOnOver('fc-state-hover');
13006 var cells = this.cells.elements;
13007 var textEls = this.textNodes;
13009 Roo.each(cells, function(cell){
13010 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13013 days += startingPos;
13015 // convert everything to numbers so it's fast
13016 var day = 86400000;
13017 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13020 //Roo.log(prevStart);
13022 var today = new Date().clearTime().getTime();
13023 var sel = date.clearTime().getTime();
13024 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13025 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13026 var ddMatch = this.disabledDatesRE;
13027 var ddText = this.disabledDatesText;
13028 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13029 var ddaysText = this.disabledDaysText;
13030 var format = this.format;
13032 var setCellClass = function(cal, cell){
13036 //Roo.log('set Cell Class');
13038 var t = d.getTime();
13042 cell.dateValue = t;
13044 cell.className += " fc-today";
13045 cell.className += " fc-state-highlight";
13046 cell.title = cal.todayText;
13049 // disable highlight in other month..
13050 //cell.className += " fc-state-highlight";
13055 cell.className = " fc-state-disabled";
13056 cell.title = cal.minText;
13060 cell.className = " fc-state-disabled";
13061 cell.title = cal.maxText;
13065 if(ddays.indexOf(d.getDay()) != -1){
13066 cell.title = ddaysText;
13067 cell.className = " fc-state-disabled";
13070 if(ddMatch && format){
13071 var fvalue = d.dateFormat(format);
13072 if(ddMatch.test(fvalue)){
13073 cell.title = ddText.replace("%0", fvalue);
13074 cell.className = " fc-state-disabled";
13078 if (!cell.initialClassName) {
13079 cell.initialClassName = cell.dom.className;
13082 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13087 for(; i < startingPos; i++) {
13088 textEls[i].innerHTML = (++prevStart);
13089 d.setDate(d.getDate()+1);
13091 cells[i].className = "fc-past fc-other-month";
13092 setCellClass(this, cells[i]);
13097 for(; i < days; i++){
13098 intDay = i - startingPos + 1;
13099 textEls[i].innerHTML = (intDay);
13100 d.setDate(d.getDate()+1);
13102 cells[i].className = ''; // "x-date-active";
13103 setCellClass(this, cells[i]);
13107 for(; i < 42; i++) {
13108 textEls[i].innerHTML = (++extraDays);
13109 d.setDate(d.getDate()+1);
13111 cells[i].className = "fc-future fc-other-month";
13112 setCellClass(this, cells[i]);
13115 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13117 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13119 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13120 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13122 if(totalRows != 6){
13123 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13124 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13127 this.fireEvent('monthchange', this, date);
13131 if(!this.internalRender){
13132 var main = this.el.dom.firstChild;
13133 var w = main.offsetWidth;
13134 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13135 Roo.fly(main).setWidth(w);
13136 this.internalRender = true;
13137 // opera does not respect the auto grow header center column
13138 // then, after it gets a width opera refuses to recalculate
13139 // without a second pass
13140 if(Roo.isOpera && !this.secondPass){
13141 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13142 this.secondPass = true;
13143 this.update.defer(10, this, [date]);
13150 findCell : function(dt) {
13151 dt = dt.clearTime().getTime();
13153 this.cells.each(function(c){
13154 //Roo.log("check " +c.dateValue + '?=' + dt);
13155 if(c.dateValue == dt){
13165 findCells : function(ev) {
13166 var s = ev.start.clone().clearTime().getTime();
13168 var e= ev.end.clone().clearTime().getTime();
13171 this.cells.each(function(c){
13172 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13174 if(c.dateValue > e){
13177 if(c.dateValue < s){
13186 // findBestRow: function(cells)
13190 // for (var i =0 ; i < cells.length;i++) {
13191 // ret = Math.max(cells[i].rows || 0,ret);
13198 addItem : function(ev)
13200 // look for vertical location slot in
13201 var cells = this.findCells(ev);
13203 // ev.row = this.findBestRow(cells);
13205 // work out the location.
13209 for(var i =0; i < cells.length; i++) {
13211 cells[i].row = cells[0].row;
13214 cells[i].row = cells[i].row + 1;
13224 if (crow.start.getY() == cells[i].getY()) {
13226 crow.end = cells[i];
13243 cells[0].events.push(ev);
13245 this.calevents.push(ev);
13248 clearEvents: function() {
13250 if(!this.calevents){
13254 Roo.each(this.cells.elements, function(c){
13260 Roo.each(this.calevents, function(e) {
13261 Roo.each(e.els, function(el) {
13262 el.un('mouseenter' ,this.onEventEnter, this);
13263 el.un('mouseleave' ,this.onEventLeave, this);
13268 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13274 renderEvents: function()
13278 this.cells.each(function(c) {
13287 if(c.row != c.events.length){
13288 r = 4 - (4 - (c.row - c.events.length));
13291 c.events = ev.slice(0, r);
13292 c.more = ev.slice(r);
13294 if(c.more.length && c.more.length == 1){
13295 c.events.push(c.more.pop());
13298 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13302 this.cells.each(function(c) {
13304 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13307 for (var e = 0; e < c.events.length; e++){
13308 var ev = c.events[e];
13309 var rows = ev.rows;
13311 for(var i = 0; i < rows.length; i++) {
13313 // how many rows should it span..
13316 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13317 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13319 unselectable : "on",
13322 cls: 'fc-event-inner',
13326 // cls: 'fc-event-time',
13327 // html : cells.length > 1 ? '' : ev.time
13331 cls: 'fc-event-title',
13332 html : String.format('{0}', ev.title)
13339 cls: 'ui-resizable-handle ui-resizable-e',
13340 html : '  '
13347 cfg.cls += ' fc-event-start';
13349 if ((i+1) == rows.length) {
13350 cfg.cls += ' fc-event-end';
13353 var ctr = _this.el.select('.fc-event-container',true).first();
13354 var cg = ctr.createChild(cfg);
13356 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13357 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13359 var r = (c.more.length) ? 1 : 0;
13360 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13361 cg.setWidth(ebox.right - sbox.x -2);
13363 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13364 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13365 cg.on('click', _this.onEventClick, _this, ev);
13376 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13377 style : 'position: absolute',
13378 unselectable : "on",
13381 cls: 'fc-event-inner',
13385 cls: 'fc-event-title',
13393 cls: 'ui-resizable-handle ui-resizable-e',
13394 html : '  '
13400 var ctr = _this.el.select('.fc-event-container',true).first();
13401 var cg = ctr.createChild(cfg);
13403 var sbox = c.select('.fc-day-content',true).first().getBox();
13404 var ebox = c.select('.fc-day-content',true).first().getBox();
13406 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13407 cg.setWidth(ebox.right - sbox.x -2);
13409 cg.on('click', _this.onMoreEventClick, _this, c.more);
13419 onEventEnter: function (e, el,event,d) {
13420 this.fireEvent('evententer', this, el, event);
13423 onEventLeave: function (e, el,event,d) {
13424 this.fireEvent('eventleave', this, el, event);
13427 onEventClick: function (e, el,event,d) {
13428 this.fireEvent('eventclick', this, el, event);
13431 onMonthChange: function () {
13435 onMoreEventClick: function(e, el, more)
13439 this.calpopover.placement = 'right';
13440 this.calpopover.setTitle('More');
13442 this.calpopover.setContent('');
13444 var ctr = this.calpopover.el.select('.popover-content', true).first();
13446 Roo.each(more, function(m){
13448 cls : 'fc-event-hori fc-event-draggable',
13451 var cg = ctr.createChild(cfg);
13453 cg.on('click', _this.onEventClick, _this, m);
13456 this.calpopover.show(el);
13461 onLoad: function ()
13463 this.calevents = [];
13466 if(this.store.getCount() > 0){
13467 this.store.data.each(function(d){
13470 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13471 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13472 time : d.data.start_time,
13473 title : d.data.title,
13474 description : d.data.description,
13475 venue : d.data.venue
13480 this.renderEvents();
13482 if(this.calevents.length && this.loadMask){
13483 this.maskEl.hide();
13487 onBeforeLoad: function()
13489 this.clearEvents();
13491 this.maskEl.show();
13505 * @class Roo.bootstrap.Popover
13506 * @extends Roo.bootstrap.Component
13507 * Bootstrap Popover class
13508 * @cfg {String} html contents of the popover (or false to use children..)
13509 * @cfg {String} title of popover (or false to hide)
13510 * @cfg {String} placement how it is placed
13511 * @cfg {String} trigger click || hover (or false to trigger manually)
13512 * @cfg {String} over what (parent or false to trigger manually.)
13515 * Create a new Popover
13516 * @param {Object} config The config object
13519 Roo.bootstrap.Popover = function(config){
13520 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13523 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13525 title: 'Fill in a title',
13528 placement : 'right',
13529 trigger : 'hover', // hover
13533 can_build_overlaid : false,
13535 getChildContainer : function()
13537 return this.el.select('.popover-content',true).first();
13540 getAutoCreate : function(){
13541 Roo.log('make popover?');
13543 cls : 'popover roo-dynamic',
13544 style: 'display:block',
13550 cls : 'popover-inner',
13554 cls: 'popover-title',
13558 cls : 'popover-content',
13569 setTitle: function(str)
13571 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13573 setContent: function(str)
13575 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13577 // as it get's added to the bottom of the page.
13578 onRender : function(ct, position)
13580 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13582 var cfg = Roo.apply({}, this.getAutoCreate());
13586 cfg.cls += ' ' + this.cls;
13589 cfg.style = this.style;
13591 Roo.log("adding to ")
13592 this.el = Roo.get(document.body).createChild(cfg, position);
13598 initEvents : function()
13600 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13601 this.el.enableDisplayMode('block');
13603 if (this.over === false) {
13606 if (this.triggers === false) {
13609 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13610 var triggers = this.trigger ? this.trigger.split(' ') : [];
13611 Roo.each(triggers, function(trigger) {
13613 if (trigger == 'click') {
13614 on_el.on('click', this.toggle, this);
13615 } else if (trigger != 'manual') {
13616 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13617 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13619 on_el.on(eventIn ,this.enter, this);
13620 on_el.on(eventOut, this.leave, this);
13631 toggle : function () {
13632 this.hoverState == 'in' ? this.leave() : this.enter();
13635 enter : function () {
13638 clearTimeout(this.timeout);
13640 this.hoverState = 'in'
13642 if (!this.delay || !this.delay.show) {
13647 this.timeout = setTimeout(function () {
13648 if (_t.hoverState == 'in') {
13651 }, this.delay.show)
13653 leave : function() {
13654 clearTimeout(this.timeout);
13656 this.hoverState = 'out'
13658 if (!this.delay || !this.delay.hide) {
13663 this.timeout = setTimeout(function () {
13664 if (_t.hoverState == 'out') {
13667 }, this.delay.hide)
13670 show : function (on_el)
13673 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13676 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13677 if (this.html !== false) {
13678 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13680 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13681 if (!this.title.length) {
13682 this.el.select('.popover-title',true).hide();
13685 var placement = typeof this.placement == 'function' ?
13686 this.placement.call(this, this.el, on_el) :
13689 var autoToken = /\s?auto?\s?/i;
13690 var autoPlace = autoToken.test(placement);
13692 placement = placement.replace(autoToken, '') || 'top';
13696 //this.el.setXY([0,0]);
13698 this.el.dom.style.display='block';
13699 this.el.addClass(placement);
13701 //this.el.appendTo(on_el);
13703 var p = this.getPosition();
13704 var box = this.el.getBox();
13709 var align = Roo.bootstrap.Popover.alignment[placement]
13710 this.el.alignTo(on_el, align[0],align[1]);
13711 //var arrow = this.el.select('.arrow',true).first();
13712 //arrow.set(align[2],
13714 this.el.addClass('in');
13715 this.hoverState = null;
13717 if (this.el.hasClass('fade')) {
13724 this.el.setXY([0,0]);
13725 this.el.removeClass('in');
13732 Roo.bootstrap.Popover.alignment = {
13733 'left' : ['r-l', [-10,0], 'right'],
13734 'right' : ['l-r', [10,0], 'left'],
13735 'bottom' : ['t-b', [0,10], 'top'],
13736 'top' : [ 'b-t', [0,-10], 'bottom']
13747 * @class Roo.bootstrap.Progress
13748 * @extends Roo.bootstrap.Component
13749 * Bootstrap Progress class
13750 * @cfg {Boolean} striped striped of the progress bar
13751 * @cfg {Boolean} active animated of the progress bar
13755 * Create a new Progress
13756 * @param {Object} config The config object
13759 Roo.bootstrap.Progress = function(config){
13760 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13763 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13768 getAutoCreate : function(){
13776 cfg.cls += ' progress-striped';
13780 cfg.cls += ' active';
13799 * @class Roo.bootstrap.ProgressBar
13800 * @extends Roo.bootstrap.Component
13801 * Bootstrap ProgressBar class
13802 * @cfg {Number} aria_valuenow aria-value now
13803 * @cfg {Number} aria_valuemin aria-value min
13804 * @cfg {Number} aria_valuemax aria-value max
13805 * @cfg {String} label label for the progress bar
13806 * @cfg {String} panel (success | info | warning | danger )
13807 * @cfg {String} role role of the progress bar
13808 * @cfg {String} sr_only text
13812 * Create a new ProgressBar
13813 * @param {Object} config The config object
13816 Roo.bootstrap.ProgressBar = function(config){
13817 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13820 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13824 aria_valuemax : 100,
13830 getAutoCreate : function()
13835 cls: 'progress-bar',
13836 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13848 cfg.role = this.role;
13851 if(this.aria_valuenow){
13852 cfg['aria-valuenow'] = this.aria_valuenow;
13855 if(this.aria_valuemin){
13856 cfg['aria-valuemin'] = this.aria_valuemin;
13859 if(this.aria_valuemax){
13860 cfg['aria-valuemax'] = this.aria_valuemax;
13863 if(this.label && !this.sr_only){
13864 cfg.html = this.label;
13868 cfg.cls += ' progress-bar-' + this.panel;
13874 update : function(aria_valuenow)
13876 this.aria_valuenow = aria_valuenow;
13878 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13893 * @class Roo.bootstrap.TabGroup
13894 * @extends Roo.bootstrap.Column
13895 * Bootstrap Column class
13896 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13897 * @cfg {Boolean} carousel true to make the group behave like a carousel
13900 * Create a new TabGroup
13901 * @param {Object} config The config object
13904 Roo.bootstrap.TabGroup = function(config){
13905 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13907 this.navId = Roo.id();
13910 Roo.bootstrap.TabGroup.register(this);
13914 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13917 transition : false,
13919 getAutoCreate : function()
13921 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13923 cfg.cls += ' tab-content';
13925 if (this.carousel) {
13926 cfg.cls += ' carousel slide';
13928 cls : 'carousel-inner'
13935 getChildContainer : function()
13937 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13941 * register a Navigation item
13942 * @param {Roo.bootstrap.NavItem} the navitem to add
13944 register : function(item)
13946 this.tabs.push( item);
13947 item.navId = this.navId; // not really needed..
13951 getActivePanel : function()
13954 Roo.each(this.tabs, function(t) {
13964 getPanelByName : function(n)
13967 Roo.each(this.tabs, function(t) {
13968 if (t.tabId == n) {
13976 indexOfPanel : function(p)
13979 Roo.each(this.tabs, function(t,i) {
13980 if (t.tabId == p.tabId) {
13989 * show a specific panel
13990 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13991 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13993 showPanel : function (pan)
13996 if (typeof(pan) == 'number') {
13997 pan = this.tabs[pan];
13999 if (typeof(pan) == 'string') {
14000 pan = this.getPanelByName(pan);
14002 if (pan.tabId == this.getActivePanel().tabId) {
14005 var cur = this.getActivePanel();
14007 if (false === cur.fireEvent('beforedeactivate')) {
14011 if (this.carousel) {
14012 this.transition = true;
14013 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14014 var lr = dir == 'next' ? 'left' : 'right';
14015 pan.el.addClass(dir); // or prev
14016 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14017 cur.el.addClass(lr); // or right
14018 pan.el.addClass(lr);
14021 cur.el.on('transitionend', function() {
14022 Roo.log("trans end?");
14024 pan.el.removeClass([lr,dir]);
14025 pan.setActive(true);
14027 cur.el.removeClass([lr]);
14028 cur.setActive(false);
14030 _this.transition = false;
14032 }, this, { single: true } );
14036 cur.setActive(false);
14037 pan.setActive(true);
14041 showPanelNext : function()
14043 var i = this.indexOfPanel(this.getActivePanel());
14044 if (i > this.tabs.length) {
14047 this.showPanel(this.tabs[i+1]);
14049 showPanelPrev : function()
14051 var i = this.indexOfPanel(this.getActivePanel());
14055 this.showPanel(this.tabs[i-1]);
14066 Roo.apply(Roo.bootstrap.TabGroup, {
14070 * register a Navigation Group
14071 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14073 register : function(navgrp)
14075 this.groups[navgrp.navId] = navgrp;
14079 * fetch a Navigation Group based on the navigation ID
14080 * if one does not exist , it will get created.
14081 * @param {string} the navgroup to add
14082 * @returns {Roo.bootstrap.NavGroup} the navgroup
14084 get: function(navId) {
14085 if (typeof(this.groups[navId]) == 'undefined') {
14086 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14088 return this.groups[navId] ;
14103 * @class Roo.bootstrap.TabPanel
14104 * @extends Roo.bootstrap.Component
14105 * Bootstrap TabPanel class
14106 * @cfg {Boolean} active panel active
14107 * @cfg {String} html panel content
14108 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14109 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14113 * Create a new TabPanel
14114 * @param {Object} config The config object
14117 Roo.bootstrap.TabPanel = function(config){
14118 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14122 * Fires when the active status changes
14123 * @param {Roo.bootstrap.TabPanel} this
14124 * @param {Boolean} state the new state
14129 * @event beforedeactivate
14130 * Fires before a tab is de-activated - can be used to do validation on a form.
14131 * @param {Roo.bootstrap.TabPanel} this
14132 * @return {Boolean} false if there is an error
14135 'beforedeactivate': true
14138 this.tabId = this.tabId || Roo.id();
14142 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14149 getAutoCreate : function(){
14152 // item is needed for carousel - not sure if it has any effect otherwise
14153 cls: 'tab-pane item',
14154 html: this.html || ''
14158 cfg.cls += ' active';
14162 cfg.tabId = this.tabId;
14169 initEvents: function()
14171 Roo.log('-------- init events on tab panel ---------');
14173 var p = this.parent();
14174 this.navId = this.navId || p.navId;
14176 if (typeof(this.navId) != 'undefined') {
14177 // not really needed.. but just in case.. parent should be a NavGroup.
14178 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14179 Roo.log(['register', tg, this]);
14185 onRender : function(ct, position)
14187 // Roo.log("Call onRender: " + this.xtype);
14189 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14197 setActive: function(state)
14199 Roo.log("panel - set active " + this.tabId + "=" + state);
14201 this.active = state;
14203 this.el.removeClass('active');
14205 } else if (!this.el.hasClass('active')) {
14206 this.el.addClass('active');
14208 this.fireEvent('changed', this, state);
14225 * @class Roo.bootstrap.DateField
14226 * @extends Roo.bootstrap.Input
14227 * Bootstrap DateField class
14228 * @cfg {Number} weekStart default 0
14229 * @cfg {Number} weekStart default 0
14230 * @cfg {Number} viewMode default empty, (months|years)
14231 * @cfg {Number} minViewMode default empty, (months|years)
14232 * @cfg {Number} startDate default -Infinity
14233 * @cfg {Number} endDate default Infinity
14234 * @cfg {Boolean} todayHighlight default false
14235 * @cfg {Boolean} todayBtn default false
14236 * @cfg {Boolean} calendarWeeks default false
14237 * @cfg {Object} daysOfWeekDisabled default empty
14239 * @cfg {Boolean} keyboardNavigation default true
14240 * @cfg {String} language default en
14243 * Create a new DateField
14244 * @param {Object} config The config object
14247 Roo.bootstrap.DateField = function(config){
14248 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14252 * Fires when this field show.
14253 * @param {Roo.bootstrap.DateField} this
14254 * @param {Mixed} date The date value
14259 * Fires when this field hide.
14260 * @param {Roo.bootstrap.DateField} this
14261 * @param {Mixed} date The date value
14266 * Fires when select a date.
14267 * @param {Roo.bootstrap.DateField} this
14268 * @param {Mixed} date The date value
14274 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14277 * @cfg {String} format
14278 * The default date format string which can be overriden for localization support. The format must be
14279 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14283 * @cfg {String} altFormats
14284 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14285 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14287 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14295 todayHighlight : false,
14301 keyboardNavigation: true,
14303 calendarWeeks: false,
14305 startDate: -Infinity,
14309 daysOfWeekDisabled: [],
14313 UTCDate: function()
14315 return new Date(Date.UTC.apply(Date, arguments));
14318 UTCToday: function()
14320 var today = new Date();
14321 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14324 getDate: function() {
14325 var d = this.getUTCDate();
14326 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14329 getUTCDate: function() {
14333 setDate: function(d) {
14334 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14337 setUTCDate: function(d) {
14339 this.setValue(this.formatDate(this.date));
14342 onRender: function(ct, position)
14345 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14347 this.language = this.language || 'en';
14348 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14349 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14351 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14352 this.format = this.format || 'm/d/y';
14353 this.isInline = false;
14354 this.isInput = true;
14355 this.component = this.el.select('.add-on', true).first() || false;
14356 this.component = (this.component && this.component.length === 0) ? false : this.component;
14357 this.hasInput = this.component && this.inputEL().length;
14359 if (typeof(this.minViewMode === 'string')) {
14360 switch (this.minViewMode) {
14362 this.minViewMode = 1;
14365 this.minViewMode = 2;
14368 this.minViewMode = 0;
14373 if (typeof(this.viewMode === 'string')) {
14374 switch (this.viewMode) {
14387 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14389 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14391 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14393 this.picker().on('mousedown', this.onMousedown, this);
14394 this.picker().on('click', this.onClick, this);
14396 this.picker().addClass('datepicker-dropdown');
14398 this.startViewMode = this.viewMode;
14401 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14402 if(!this.calendarWeeks){
14407 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14408 v.attr('colspan', function(i, val){
14409 return parseInt(val) + 1;
14414 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14416 this.setStartDate(this.startDate);
14417 this.setEndDate(this.endDate);
14419 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14426 if(this.isInline) {
14431 picker : function()
14433 return this.pickerEl;
14434 // return this.el.select('.datepicker', true).first();
14437 fillDow: function()
14439 var dowCnt = this.weekStart;
14448 if(this.calendarWeeks){
14456 while (dowCnt < this.weekStart + 7) {
14460 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14464 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14467 fillMonths: function()
14470 var months = this.picker().select('>.datepicker-months td', true).first();
14472 months.dom.innerHTML = '';
14478 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14481 months.createChild(month);
14489 this.date = (typeof(this.date) === 'undefined' || !this.date.length) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14491 if (this.date < this.startDate) {
14492 this.viewDate = new Date(this.startDate);
14493 } else if (this.date > this.endDate) {
14494 this.viewDate = new Date(this.endDate);
14496 this.viewDate = new Date(this.date);
14504 var d = new Date(this.viewDate),
14505 year = d.getUTCFullYear(),
14506 month = d.getUTCMonth(),
14507 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14508 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14509 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14510 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14511 currentDate = this.date && this.date.valueOf(),
14512 today = this.UTCToday();
14514 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14516 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14518 // this.picker.select('>tfoot th.today').
14519 // .text(dates[this.language].today)
14520 // .toggle(this.todayBtn !== false);
14522 this.updateNavArrows();
14525 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14527 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14529 prevMonth.setUTCDate(day);
14531 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14533 var nextMonth = new Date(prevMonth);
14535 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14537 nextMonth = nextMonth.valueOf();
14539 var fillMonths = false;
14541 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14543 while(prevMonth.valueOf() < nextMonth) {
14546 if (prevMonth.getUTCDay() === this.weekStart) {
14548 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14556 if(this.calendarWeeks){
14557 // ISO 8601: First week contains first thursday.
14558 // ISO also states week starts on Monday, but we can be more abstract here.
14560 // Start of current week: based on weekstart/current date
14561 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14562 // Thursday of this week
14563 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14564 // First Thursday of year, year from thursday
14565 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14566 // Calendar week: ms between thursdays, div ms per day, div 7 days
14567 calWeek = (th - yth) / 864e5 / 7 + 1;
14569 fillMonths.cn.push({
14577 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14579 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14582 if (this.todayHighlight &&
14583 prevMonth.getUTCFullYear() == today.getFullYear() &&
14584 prevMonth.getUTCMonth() == today.getMonth() &&
14585 prevMonth.getUTCDate() == today.getDate()) {
14586 clsName += ' today';
14589 if (currentDate && prevMonth.valueOf() === currentDate) {
14590 clsName += ' active';
14593 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14594 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14595 clsName += ' disabled';
14598 fillMonths.cn.push({
14600 cls: 'day ' + clsName,
14601 html: prevMonth.getDate()
14604 prevMonth.setDate(prevMonth.getDate()+1);
14607 var currentYear = this.date && this.date.getUTCFullYear();
14608 var currentMonth = this.date && this.date.getUTCMonth();
14610 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14612 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14613 v.removeClass('active');
14615 if(currentYear === year && k === currentMonth){
14616 v.addClass('active');
14619 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14620 v.addClass('disabled');
14626 year = parseInt(year/10, 10) * 10;
14628 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14630 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14633 for (var i = -1; i < 11; i++) {
14634 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14636 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14644 showMode: function(dir)
14647 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14649 Roo.each(this.picker().select('>div',true).elements, function(v){
14650 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14653 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14658 if(this.isInline) return;
14660 this.picker().removeClass(['bottom', 'top']);
14662 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14664 * place to the top of element!
14668 this.picker().addClass('top');
14669 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14674 this.picker().addClass('bottom');
14676 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14679 parseDate : function(value)
14681 if(!value || value instanceof Date){
14684 var v = Date.parseDate(value, this.format);
14685 if (!v && this.useIso) {
14686 v = Date.parseDate(value, 'Y-m-d');
14688 if(!v && this.altFormats){
14689 if(!this.altFormatsArray){
14690 this.altFormatsArray = this.altFormats.split("|");
14692 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14693 v = Date.parseDate(value, this.altFormatsArray[i]);
14699 formatDate : function(date, fmt)
14701 return (!date || !(date instanceof Date)) ?
14702 date : date.dateFormat(fmt || this.format);
14705 onFocus : function()
14707 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14711 onBlur : function()
14713 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14715 var d = this.inputEl().getValue();
14724 this.picker().show();
14728 this.fireEvent('show', this, this.date);
14733 if(this.isInline) return;
14734 this.picker().hide();
14735 this.viewMode = this.startViewMode;
14738 this.fireEvent('hide', this, this.date);
14742 onMousedown: function(e)
14744 e.stopPropagation();
14745 e.preventDefault();
14750 Roo.bootstrap.DateField.superclass.keyup.call(this);
14754 setValue: function(v)
14756 var d = new Date(v);
14758 if(isNaN(d.getTime())){
14763 v = this.formatDate(d);
14765 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14767 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14771 this.fireEvent('select', this, this.date);
14775 getValue: function()
14777 return this.formatDate(this.date);
14780 fireKey: function(e)
14782 if (!this.picker().isVisible()){
14783 if (e.keyCode == 27) // allow escape to hide and re-show picker
14788 var dateChanged = false,
14790 newDate, newViewDate;
14795 e.preventDefault();
14799 if (!this.keyboardNavigation) break;
14800 dir = e.keyCode == 37 ? -1 : 1;
14803 newDate = this.moveYear(this.date, dir);
14804 newViewDate = this.moveYear(this.viewDate, dir);
14805 } else if (e.shiftKey){
14806 newDate = this.moveMonth(this.date, dir);
14807 newViewDate = this.moveMonth(this.viewDate, dir);
14809 newDate = new Date(this.date);
14810 newDate.setUTCDate(this.date.getUTCDate() + dir);
14811 newViewDate = new Date(this.viewDate);
14812 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14814 if (this.dateWithinRange(newDate)){
14815 this.date = newDate;
14816 this.viewDate = newViewDate;
14817 this.setValue(this.formatDate(this.date));
14819 e.preventDefault();
14820 dateChanged = true;
14825 if (!this.keyboardNavigation) break;
14826 dir = e.keyCode == 38 ? -1 : 1;
14828 newDate = this.moveYear(this.date, dir);
14829 newViewDate = this.moveYear(this.viewDate, dir);
14830 } else if (e.shiftKey){
14831 newDate = this.moveMonth(this.date, dir);
14832 newViewDate = this.moveMonth(this.viewDate, dir);
14834 newDate = new Date(this.date);
14835 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14836 newViewDate = new Date(this.viewDate);
14837 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14839 if (this.dateWithinRange(newDate)){
14840 this.date = newDate;
14841 this.viewDate = newViewDate;
14842 this.setValue(this.formatDate(this.date));
14844 e.preventDefault();
14845 dateChanged = true;
14849 this.setValue(this.formatDate(this.date));
14851 e.preventDefault();
14854 this.setValue(this.formatDate(this.date));
14868 onClick: function(e)
14870 e.stopPropagation();
14871 e.preventDefault();
14873 var target = e.getTarget();
14875 if(target.nodeName.toLowerCase() === 'i'){
14876 target = Roo.get(target).dom.parentNode;
14879 var nodeName = target.nodeName;
14880 var className = target.className;
14881 var html = target.innerHTML;
14883 switch(nodeName.toLowerCase()) {
14885 switch(className) {
14891 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14892 switch(this.viewMode){
14894 this.viewDate = this.moveMonth(this.viewDate, dir);
14898 this.viewDate = this.moveYear(this.viewDate, dir);
14904 var date = new Date();
14905 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14907 this.setValue(this.formatDate(this.date));
14914 if (className.indexOf('disabled') === -1) {
14915 this.viewDate.setUTCDate(1);
14916 if (className.indexOf('month') !== -1) {
14917 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14919 var year = parseInt(html, 10) || 0;
14920 this.viewDate.setUTCFullYear(year);
14929 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14930 var day = parseInt(html, 10) || 1;
14931 var year = this.viewDate.getUTCFullYear(),
14932 month = this.viewDate.getUTCMonth();
14934 if (className.indexOf('old') !== -1) {
14941 } else if (className.indexOf('new') !== -1) {
14949 this.date = this.UTCDate(year, month, day,0,0,0,0);
14950 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14952 this.setValue(this.formatDate(this.date));
14959 setStartDate: function(startDate)
14961 this.startDate = startDate || -Infinity;
14962 if (this.startDate !== -Infinity) {
14963 this.startDate = this.parseDate(this.startDate);
14966 this.updateNavArrows();
14969 setEndDate: function(endDate)
14971 this.endDate = endDate || Infinity;
14972 if (this.endDate !== Infinity) {
14973 this.endDate = this.parseDate(this.endDate);
14976 this.updateNavArrows();
14979 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14981 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14982 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14983 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14985 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14986 return parseInt(d, 10);
14989 this.updateNavArrows();
14992 updateNavArrows: function()
14994 var d = new Date(this.viewDate),
14995 year = d.getUTCFullYear(),
14996 month = d.getUTCMonth();
14998 Roo.each(this.picker().select('.prev', true).elements, function(v){
15000 switch (this.viewMode) {
15003 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15009 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15016 Roo.each(this.picker().select('.next', true).elements, function(v){
15018 switch (this.viewMode) {
15021 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15027 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15035 moveMonth: function(date, dir)
15037 if (!dir) return date;
15038 var new_date = new Date(date.valueOf()),
15039 day = new_date.getUTCDate(),
15040 month = new_date.getUTCMonth(),
15041 mag = Math.abs(dir),
15043 dir = dir > 0 ? 1 : -1;
15046 // If going back one month, make sure month is not current month
15047 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15049 return new_date.getUTCMonth() == month;
15051 // If going forward one month, make sure month is as expected
15052 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15054 return new_date.getUTCMonth() != new_month;
15056 new_month = month + dir;
15057 new_date.setUTCMonth(new_month);
15058 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15059 if (new_month < 0 || new_month > 11)
15060 new_month = (new_month + 12) % 12;
15062 // For magnitudes >1, move one month at a time...
15063 for (var i=0; i<mag; i++)
15064 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15065 new_date = this.moveMonth(new_date, dir);
15066 // ...then reset the day, keeping it in the new month
15067 new_month = new_date.getUTCMonth();
15068 new_date.setUTCDate(day);
15070 return new_month != new_date.getUTCMonth();
15073 // Common date-resetting loop -- if date is beyond end of month, make it
15076 new_date.setUTCDate(--day);
15077 new_date.setUTCMonth(new_month);
15082 moveYear: function(date, dir)
15084 return this.moveMonth(date, dir*12);
15087 dateWithinRange: function(date)
15089 return date >= this.startDate && date <= this.endDate;
15095 this.picker().remove();
15100 Roo.apply(Roo.bootstrap.DateField, {
15111 html: '<i class="fa fa-arrow-left"/>'
15121 html: '<i class="fa fa-arrow-right"/>'
15163 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15164 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15165 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15166 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15167 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15180 navFnc: 'FullYear',
15185 navFnc: 'FullYear',
15190 Roo.apply(Roo.bootstrap.DateField, {
15194 cls: 'datepicker dropdown-menu',
15198 cls: 'datepicker-days',
15202 cls: 'table-condensed',
15204 Roo.bootstrap.DateField.head,
15208 Roo.bootstrap.DateField.footer
15215 cls: 'datepicker-months',
15219 cls: 'table-condensed',
15221 Roo.bootstrap.DateField.head,
15222 Roo.bootstrap.DateField.content,
15223 Roo.bootstrap.DateField.footer
15230 cls: 'datepicker-years',
15234 cls: 'table-condensed',
15236 Roo.bootstrap.DateField.head,
15237 Roo.bootstrap.DateField.content,
15238 Roo.bootstrap.DateField.footer
15257 * @class Roo.bootstrap.TimeField
15258 * @extends Roo.bootstrap.Input
15259 * Bootstrap DateField class
15263 * Create a new TimeField
15264 * @param {Object} config The config object
15267 Roo.bootstrap.TimeField = function(config){
15268 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15272 * Fires when this field show.
15273 * @param {Roo.bootstrap.DateField} this
15274 * @param {Mixed} date The date value
15279 * Fires when this field hide.
15280 * @param {Roo.bootstrap.DateField} this
15281 * @param {Mixed} date The date value
15286 * Fires when select a date.
15287 * @param {Roo.bootstrap.DateField} this
15288 * @param {Mixed} date The date value
15294 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15297 * @cfg {String} format
15298 * The default time format string which can be overriden for localization support. The format must be
15299 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15303 onRender: function(ct, position)
15306 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15308 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15310 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15312 this.pop = this.picker().select('>.datepicker-time',true).first();
15313 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15315 this.picker().on('mousedown', this.onMousedown, this);
15316 this.picker().on('click', this.onClick, this);
15318 this.picker().addClass('datepicker-dropdown');
15323 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15324 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15325 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15326 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15327 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15328 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15332 fireKey: function(e){
15333 if (!this.picker().isVisible()){
15334 if (e.keyCode == 27) // allow escape to hide and re-show picker
15339 e.preventDefault();
15347 this.onTogglePeriod();
15350 this.onIncrementMinutes();
15353 this.onDecrementMinutes();
15362 onClick: function(e) {
15363 e.stopPropagation();
15364 e.preventDefault();
15367 picker : function()
15369 return this.el.select('.datepicker', true).first();
15372 fillTime: function()
15374 var time = this.pop.select('tbody', true).first();
15376 time.dom.innerHTML = '';
15391 cls: 'hours-up glyphicon glyphicon-chevron-up'
15411 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15432 cls: 'timepicker-hour',
15447 cls: 'timepicker-minute',
15462 cls: 'btn btn-primary period',
15484 cls: 'hours-down glyphicon glyphicon-chevron-down'
15504 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15522 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15529 var hours = this.time.getHours();
15530 var minutes = this.time.getMinutes();
15543 hours = hours - 12;
15547 hours = '0' + hours;
15551 minutes = '0' + minutes;
15554 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15555 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15556 this.pop.select('button', true).first().dom.innerHTML = period;
15562 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15564 var cls = ['bottom'];
15566 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15573 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15578 this.picker().addClass(cls.join('-'));
15582 Roo.each(cls, function(c){
15584 _this.picker().setTop(_this.inputEl().getHeight());
15588 _this.picker().setTop(0 - _this.picker().getHeight());
15593 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15597 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15604 onFocus : function()
15606 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15610 onBlur : function()
15612 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15618 this.picker().show();
15623 this.fireEvent('show', this, this.date);
15628 this.picker().hide();
15631 this.fireEvent('hide', this, this.date);
15634 setTime : function()
15637 this.setValue(this.time.format(this.format));
15639 this.fireEvent('select', this, this.date);
15644 onMousedown: function(e){
15645 e.stopPropagation();
15646 e.preventDefault();
15649 onIncrementHours: function()
15651 Roo.log('onIncrementHours');
15652 this.time = this.time.add(Date.HOUR, 1);
15657 onDecrementHours: function()
15659 Roo.log('onDecrementHours');
15660 this.time = this.time.add(Date.HOUR, -1);
15664 onIncrementMinutes: function()
15666 Roo.log('onIncrementMinutes');
15667 this.time = this.time.add(Date.MINUTE, 1);
15671 onDecrementMinutes: function()
15673 Roo.log('onDecrementMinutes');
15674 this.time = this.time.add(Date.MINUTE, -1);
15678 onTogglePeriod: function()
15680 Roo.log('onTogglePeriod');
15681 this.time = this.time.add(Date.HOUR, 12);
15688 Roo.apply(Roo.bootstrap.TimeField, {
15718 cls: 'btn btn-info ok',
15730 Roo.apply(Roo.bootstrap.TimeField, {
15734 cls: 'datepicker dropdown-menu',
15738 cls: 'datepicker-time',
15742 cls: 'table-condensed',
15744 Roo.bootstrap.TimeField.content,
15745 Roo.bootstrap.TimeField.footer
15764 * @class Roo.bootstrap.CheckBox
15765 * @extends Roo.bootstrap.Input
15766 * Bootstrap CheckBox class
15768 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15769 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15770 * @cfg {String} boxLabel The text that appears beside the checkbox
15771 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15772 * @cfg {Boolean} checked initnal the element
15776 * Create a new CheckBox
15777 * @param {Object} config The config object
15780 Roo.bootstrap.CheckBox = function(config){
15781 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15786 * Fires when the element is checked or unchecked.
15787 * @param {Roo.bootstrap.CheckBox} this This input
15788 * @param {Boolean} checked The new checked value
15794 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15796 inputType: 'checkbox',
15803 getAutoCreate : function()
15805 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15811 cfg.cls = 'form-group checkbox' //input-group
15819 type : this.inputType,
15820 value : (!this.checked) ? this.valueOff : this.inputValue,
15821 cls : 'roo-checkbox', //'form-box',
15822 placeholder : this.placeholder || ''
15826 if (this.weight) { // Validity check?
15827 cfg.cls += " checkbox-" + this.weight;
15830 if (this.disabled) {
15831 input.disabled=true;
15835 input.checked = this.checked;
15839 input.name = this.name;
15843 input.cls += ' input-' + this.size;
15847 ['xs','sm','md','lg'].map(function(size){
15848 if (settings[size]) {
15849 cfg.cls += ' col-' + size + '-' + settings[size];
15855 var inputblock = input;
15860 if (this.before || this.after) {
15863 cls : 'input-group',
15867 inputblock.cn.push({
15869 cls : 'input-group-addon',
15873 inputblock.cn.push(input);
15875 inputblock.cn.push({
15877 cls : 'input-group-addon',
15884 if (align ==='left' && this.fieldLabel.length) {
15885 Roo.log("left and has label");
15891 cls : 'control-label col-md-' + this.labelWidth,
15892 html : this.fieldLabel
15896 cls : "col-md-" + (12 - this.labelWidth),
15903 } else if ( this.fieldLabel.length) {
15908 tag: this.boxLabel ? 'span' : 'label',
15910 cls: 'control-label box-input-label',
15911 //cls : 'input-group-addon',
15912 html : this.fieldLabel
15922 Roo.log(" no label && no align");
15923 cfg.cn = [ inputblock ] ;
15932 html: this.boxLabel
15944 * return the real input element.
15946 inputEl: function ()
15948 return this.el.select('input.roo-checkbox',true).first();
15953 return this.el.select('label.control-label',true).first();
15956 initEvents : function()
15958 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15960 this.inputEl().on('click', this.onClick, this);
15964 onClick : function()
15966 this.setChecked(!this.checked);
15969 setChecked : function(state,suppressEvent)
15971 this.checked = state;
15973 this.inputEl().dom.checked = state;
15975 if(suppressEvent !== true){
15976 this.fireEvent('check', this, state);
15979 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15983 setValue : function(v,suppressEvent)
15985 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15999 * @class Roo.bootstrap.Radio
16000 * @extends Roo.bootstrap.CheckBox
16001 * Bootstrap Radio class
16004 * Create a new Radio
16005 * @param {Object} config The config object
16008 Roo.bootstrap.Radio = function(config){
16009 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16013 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16015 inputType: 'radio',
16019 getAutoCreate : function()
16021 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16027 cfg.cls = 'form-group radio' //input-group
16032 type : this.inputType,
16033 value : (!this.checked) ? this.valueOff : this.inputValue,
16035 placeholder : this.placeholder || ''
16038 if (this.weight) { // Validity check?
16039 cfg.cls += " radio-" + this.weight;
16041 if (this.disabled) {
16042 input.disabled=true;
16046 input.checked = this.checked;
16050 input.name = this.name;
16054 input.cls += ' input-' + this.size;
16058 ['xs','sm','md','lg'].map(function(size){
16059 if (settings[size]) {
16060 cfg.cls += ' col-' + size + '-' + settings[size];
16064 var inputblock = input;
16066 if (this.before || this.after) {
16069 cls : 'input-group',
16073 inputblock.cn.push({
16075 cls : 'input-group-addon',
16079 inputblock.cn.push(input);
16081 inputblock.cn.push({
16083 cls : 'input-group-addon',
16090 if (align ==='left' && this.fieldLabel.length) {
16091 Roo.log("left and has label");
16097 cls : 'control-label col-md-' + this.labelWidth,
16098 html : this.fieldLabel
16102 cls : "col-md-" + (12 - this.labelWidth),
16109 } else if ( this.fieldLabel.length) {
16116 cls: 'control-label box-input-label',
16117 //cls : 'input-group-addon',
16118 html : this.fieldLabel
16128 Roo.log(" no label && no align");
16143 html: this.boxLabel
16150 inputEl: function ()
16152 return this.el.select('input.roo-radio',true).first();
16154 onClick : function()
16156 this.setChecked(true);
16159 setChecked : function(state,suppressEvent)
16162 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16163 v.dom.checked = false;
16167 this.checked = state;
16168 this.inputEl().dom.checked = state;
16170 if(suppressEvent !== true){
16171 this.fireEvent('check', this, state);
16174 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16178 getGroupValue : function()
16181 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16182 if(v.dom.checked == true){
16183 value = v.dom.value;
16191 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16192 * @return {Mixed} value The field value
16194 getValue : function(){
16195 return this.getGroupValue();
16201 //<script type="text/javascript">
16204 * Based Ext JS Library 1.1.1
16205 * Copyright(c) 2006-2007, Ext JS, LLC.
16211 * @class Roo.HtmlEditorCore
16212 * @extends Roo.Component
16213 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16215 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16218 Roo.HtmlEditorCore = function(config){
16221 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16224 * @event initialize
16225 * Fires when the editor is fully initialized (including the iframe)
16226 * @param {Roo.HtmlEditorCore} this
16231 * Fires when the editor is first receives the focus. Any insertion must wait
16232 * until after this event.
16233 * @param {Roo.HtmlEditorCore} this
16237 * @event beforesync
16238 * Fires before the textarea is updated with content from the editor iframe. Return false
16239 * to cancel the sync.
16240 * @param {Roo.HtmlEditorCore} this
16241 * @param {String} html
16245 * @event beforepush
16246 * Fires before the iframe editor is updated with content from the textarea. Return false
16247 * to cancel the push.
16248 * @param {Roo.HtmlEditorCore} this
16249 * @param {String} html
16254 * Fires when the textarea is updated with content from the editor iframe.
16255 * @param {Roo.HtmlEditorCore} this
16256 * @param {String} html
16261 * Fires when the iframe editor is updated with content from the textarea.
16262 * @param {Roo.HtmlEditorCore} this
16263 * @param {String} html
16268 * @event editorevent
16269 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16270 * @param {Roo.HtmlEditorCore} this
16278 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16282 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16288 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16293 * @cfg {Number} height (in pixels)
16297 * @cfg {Number} width (in pixels)
16302 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16305 stylesheets: false,
16310 // private properties
16311 validationEvent : false,
16313 initialized : false,
16315 sourceEditMode : false,
16316 onFocus : Roo.emptyFn,
16318 hideMode:'offsets',
16326 * Protected method that will not generally be called directly. It
16327 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16328 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16330 getDocMarkup : function(){
16333 Roo.log(this.stylesheets);
16335 // inherit styels from page...??
16336 if (this.stylesheets === false) {
16338 Roo.get(document.head).select('style').each(function(node) {
16339 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16342 Roo.get(document.head).select('link').each(function(node) {
16343 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16346 } else if (!this.stylesheets.length) {
16348 st = '<style type="text/css">' +
16349 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16352 Roo.each(this.stylesheets, function(s) {
16353 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16358 st += '<style type="text/css">' +
16359 'IMG { cursor: pointer } ' +
16363 return '<html><head>' + st +
16364 //<style type="text/css">' +
16365 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16367 ' </head><body class="roo-htmleditor-body"></body></html>';
16371 onRender : function(ct, position)
16374 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16375 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16378 this.el.dom.style.border = '0 none';
16379 this.el.dom.setAttribute('tabIndex', -1);
16380 this.el.addClass('x-hidden hide');
16384 if(Roo.isIE){ // fix IE 1px bogus margin
16385 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16389 this.frameId = Roo.id();
16393 var iframe = this.owner.wrap.createChild({
16395 cls: 'form-control', // bootstrap..
16397 name: this.frameId,
16398 frameBorder : 'no',
16399 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16404 this.iframe = iframe.dom;
16406 this.assignDocWin();
16408 this.doc.designMode = 'on';
16411 this.doc.write(this.getDocMarkup());
16415 var task = { // must defer to wait for browser to be ready
16417 //console.log("run task?" + this.doc.readyState);
16418 this.assignDocWin();
16419 if(this.doc.body || this.doc.readyState == 'complete'){
16421 this.doc.designMode="on";
16425 Roo.TaskMgr.stop(task);
16426 this.initEditor.defer(10, this);
16433 Roo.TaskMgr.start(task);
16440 onResize : function(w, h)
16442 Roo.log('resize: ' +w + ',' + h );
16443 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16447 if(typeof w == 'number'){
16449 this.iframe.style.width = w + 'px';
16451 if(typeof h == 'number'){
16453 this.iframe.style.height = h + 'px';
16455 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16462 * Toggles the editor between standard and source edit mode.
16463 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16465 toggleSourceEdit : function(sourceEditMode){
16467 this.sourceEditMode = sourceEditMode === true;
16469 if(this.sourceEditMode){
16471 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16474 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16475 //this.iframe.className = '';
16478 //this.setSize(this.owner.wrap.getSize());
16479 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16486 * Protected method that will not generally be called directly. If you need/want
16487 * custom HTML cleanup, this is the method you should override.
16488 * @param {String} html The HTML to be cleaned
16489 * return {String} The cleaned HTML
16491 cleanHtml : function(html){
16492 html = String(html);
16493 if(html.length > 5){
16494 if(Roo.isSafari){ // strip safari nonsense
16495 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16498 if(html == ' '){
16505 * HTML Editor -> Textarea
16506 * Protected method that will not generally be called directly. Syncs the contents
16507 * of the editor iframe with the textarea.
16509 syncValue : function(){
16510 if(this.initialized){
16511 var bd = (this.doc.body || this.doc.documentElement);
16512 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16513 var html = bd.innerHTML;
16515 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16516 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16518 html = '<div style="'+m[0]+'">' + html + '</div>';
16521 html = this.cleanHtml(html);
16522 // fix up the special chars.. normaly like back quotes in word...
16523 // however we do not want to do this with chinese..
16524 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16525 var cc = b.charCodeAt();
16527 (cc >= 0x4E00 && cc < 0xA000 ) ||
16528 (cc >= 0x3400 && cc < 0x4E00 ) ||
16529 (cc >= 0xf900 && cc < 0xfb00 )
16535 if(this.owner.fireEvent('beforesync', this, html) !== false){
16536 this.el.dom.value = html;
16537 this.owner.fireEvent('sync', this, html);
16543 * Protected method that will not generally be called directly. Pushes the value of the textarea
16544 * into the iframe editor.
16546 pushValue : function(){
16547 if(this.initialized){
16548 var v = this.el.dom.value.trim();
16550 // if(v.length < 1){
16554 if(this.owner.fireEvent('beforepush', this, v) !== false){
16555 var d = (this.doc.body || this.doc.documentElement);
16557 this.cleanUpPaste();
16558 this.el.dom.value = d.innerHTML;
16559 this.owner.fireEvent('push', this, v);
16565 deferFocus : function(){
16566 this.focus.defer(10, this);
16570 focus : function(){
16571 if(this.win && !this.sourceEditMode){
16578 assignDocWin: function()
16580 var iframe = this.iframe;
16583 this.doc = iframe.contentWindow.document;
16584 this.win = iframe.contentWindow;
16586 // if (!Roo.get(this.frameId)) {
16589 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16590 // this.win = Roo.get(this.frameId).dom.contentWindow;
16592 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16596 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16597 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16602 initEditor : function(){
16603 //console.log("INIT EDITOR");
16604 this.assignDocWin();
16608 this.doc.designMode="on";
16610 this.doc.write(this.getDocMarkup());
16613 var dbody = (this.doc.body || this.doc.documentElement);
16614 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16615 // this copies styles from the containing element into thsi one..
16616 // not sure why we need all of this..
16617 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16619 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16620 //ss['background-attachment'] = 'fixed'; // w3c
16621 dbody.bgProperties = 'fixed'; // ie
16622 //Roo.DomHelper.applyStyles(dbody, ss);
16623 Roo.EventManager.on(this.doc, {
16624 //'mousedown': this.onEditorEvent,
16625 'mouseup': this.onEditorEvent,
16626 'dblclick': this.onEditorEvent,
16627 'click': this.onEditorEvent,
16628 'keyup': this.onEditorEvent,
16633 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16635 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16636 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16638 this.initialized = true;
16640 this.owner.fireEvent('initialize', this);
16645 onDestroy : function(){
16651 //for (var i =0; i < this.toolbars.length;i++) {
16652 // // fixme - ask toolbars for heights?
16653 // this.toolbars[i].onDestroy();
16656 //this.wrap.dom.innerHTML = '';
16657 //this.wrap.remove();
16662 onFirstFocus : function(){
16664 this.assignDocWin();
16667 this.activated = true;
16670 if(Roo.isGecko){ // prevent silly gecko errors
16672 var s = this.win.getSelection();
16673 if(!s.focusNode || s.focusNode.nodeType != 3){
16674 var r = s.getRangeAt(0);
16675 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16680 this.execCmd('useCSS', true);
16681 this.execCmd('styleWithCSS', false);
16684 this.owner.fireEvent('activate', this);
16688 adjustFont: function(btn){
16689 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16690 //if(Roo.isSafari){ // safari
16693 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16694 if(Roo.isSafari){ // safari
16695 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16696 v = (v < 10) ? 10 : v;
16697 v = (v > 48) ? 48 : v;
16698 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16703 v = Math.max(1, v+adjust);
16705 this.execCmd('FontSize', v );
16708 onEditorEvent : function(e){
16709 this.owner.fireEvent('editorevent', this, e);
16710 // this.updateToolbar();
16711 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16714 insertTag : function(tg)
16716 // could be a bit smarter... -> wrap the current selected tRoo..
16717 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16719 range = this.createRange(this.getSelection());
16720 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16721 wrappingNode.appendChild(range.extractContents());
16722 range.insertNode(wrappingNode);
16729 this.execCmd("formatblock", tg);
16733 insertText : function(txt)
16737 var range = this.createRange();
16738 range.deleteContents();
16739 //alert(Sender.getAttribute('label'));
16741 range.insertNode(this.doc.createTextNode(txt));
16747 * Executes a Midas editor command on the editor document and performs necessary focus and
16748 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16749 * @param {String} cmd The Midas command
16750 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16752 relayCmd : function(cmd, value){
16754 this.execCmd(cmd, value);
16755 this.owner.fireEvent('editorevent', this);
16756 //this.updateToolbar();
16757 this.owner.deferFocus();
16761 * Executes a Midas editor command directly on the editor document.
16762 * For visual commands, you should use {@link #relayCmd} instead.
16763 * <b>This should only be called after the editor is initialized.</b>
16764 * @param {String} cmd The Midas command
16765 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16767 execCmd : function(cmd, value){
16768 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16775 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16777 * @param {String} text | dom node..
16779 insertAtCursor : function(text)
16784 if(!this.activated){
16790 var r = this.doc.selection.createRange();
16801 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16805 // from jquery ui (MIT licenced)
16807 var win = this.win;
16809 if (win.getSelection && win.getSelection().getRangeAt) {
16810 range = win.getSelection().getRangeAt(0);
16811 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16812 range.insertNode(node);
16813 } else if (win.document.selection && win.document.selection.createRange) {
16814 // no firefox support
16815 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16816 win.document.selection.createRange().pasteHTML(txt);
16818 // no firefox support
16819 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16820 this.execCmd('InsertHTML', txt);
16829 mozKeyPress : function(e){
16831 var c = e.getCharCode(), cmd;
16834 c = String.fromCharCode(c).toLowerCase();
16848 this.cleanUpPaste.defer(100, this);
16856 e.preventDefault();
16864 fixKeys : function(){ // load time branching for fastest keydown performance
16866 return function(e){
16867 var k = e.getKey(), r;
16870 r = this.doc.selection.createRange();
16873 r.pasteHTML('    ');
16880 r = this.doc.selection.createRange();
16882 var target = r.parentElement();
16883 if(!target || target.tagName.toLowerCase() != 'li'){
16885 r.pasteHTML('<br />');
16891 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16892 this.cleanUpPaste.defer(100, this);
16898 }else if(Roo.isOpera){
16899 return function(e){
16900 var k = e.getKey();
16904 this.execCmd('InsertHTML','    ');
16907 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16908 this.cleanUpPaste.defer(100, this);
16913 }else if(Roo.isSafari){
16914 return function(e){
16915 var k = e.getKey();
16919 this.execCmd('InsertText','\t');
16923 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16924 this.cleanUpPaste.defer(100, this);
16932 getAllAncestors: function()
16934 var p = this.getSelectedNode();
16937 a.push(p); // push blank onto stack..
16938 p = this.getParentElement();
16942 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16946 a.push(this.doc.body);
16950 lastSelNode : false,
16953 getSelection : function()
16955 this.assignDocWin();
16956 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16959 getSelectedNode: function()
16961 // this may only work on Gecko!!!
16963 // should we cache this!!!!
16968 var range = this.createRange(this.getSelection()).cloneRange();
16971 var parent = range.parentElement();
16973 var testRange = range.duplicate();
16974 testRange.moveToElementText(parent);
16975 if (testRange.inRange(range)) {
16978 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16981 parent = parent.parentElement;
16986 // is ancestor a text element.
16987 var ac = range.commonAncestorContainer;
16988 if (ac.nodeType == 3) {
16989 ac = ac.parentNode;
16992 var ar = ac.childNodes;
16995 var other_nodes = [];
16996 var has_other_nodes = false;
16997 for (var i=0;i<ar.length;i++) {
16998 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17001 // fullly contained node.
17003 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17008 // probably selected..
17009 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17010 other_nodes.push(ar[i]);
17014 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17019 has_other_nodes = true;
17021 if (!nodes.length && other_nodes.length) {
17022 nodes= other_nodes;
17024 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17030 createRange: function(sel)
17032 // this has strange effects when using with
17033 // top toolbar - not sure if it's a great idea.
17034 //this.editor.contentWindow.focus();
17035 if (typeof sel != "undefined") {
17037 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17039 return this.doc.createRange();
17042 return this.doc.createRange();
17045 getParentElement: function()
17048 this.assignDocWin();
17049 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17051 var range = this.createRange(sel);
17054 var p = range.commonAncestorContainer;
17055 while (p.nodeType == 3) { // text node
17066 * Range intersection.. the hard stuff...
17070 * [ -- selected range --- ]
17074 * if end is before start or hits it. fail.
17075 * if start is after end or hits it fail.
17077 * if either hits (but other is outside. - then it's not
17083 // @see http://www.thismuchiknow.co.uk/?p=64.
17084 rangeIntersectsNode : function(range, node)
17086 var nodeRange = node.ownerDocument.createRange();
17088 nodeRange.selectNode(node);
17090 nodeRange.selectNodeContents(node);
17093 var rangeStartRange = range.cloneRange();
17094 rangeStartRange.collapse(true);
17096 var rangeEndRange = range.cloneRange();
17097 rangeEndRange.collapse(false);
17099 var nodeStartRange = nodeRange.cloneRange();
17100 nodeStartRange.collapse(true);
17102 var nodeEndRange = nodeRange.cloneRange();
17103 nodeEndRange.collapse(false);
17105 return rangeStartRange.compareBoundaryPoints(
17106 Range.START_TO_START, nodeEndRange) == -1 &&
17107 rangeEndRange.compareBoundaryPoints(
17108 Range.START_TO_START, nodeStartRange) == 1;
17112 rangeCompareNode : function(range, node)
17114 var nodeRange = node.ownerDocument.createRange();
17116 nodeRange.selectNode(node);
17118 nodeRange.selectNodeContents(node);
17122 range.collapse(true);
17124 nodeRange.collapse(true);
17126 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17127 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17129 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17131 var nodeIsBefore = ss == 1;
17132 var nodeIsAfter = ee == -1;
17134 if (nodeIsBefore && nodeIsAfter)
17136 if (!nodeIsBefore && nodeIsAfter)
17137 return 1; //right trailed.
17139 if (nodeIsBefore && !nodeIsAfter)
17140 return 2; // left trailed.
17145 // private? - in a new class?
17146 cleanUpPaste : function()
17148 // cleans up the whole document..
17149 Roo.log('cleanuppaste');
17151 this.cleanUpChildren(this.doc.body);
17152 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17153 if (clean != this.doc.body.innerHTML) {
17154 this.doc.body.innerHTML = clean;
17159 cleanWordChars : function(input) {// change the chars to hex code
17160 var he = Roo.HtmlEditorCore;
17162 var output = input;
17163 Roo.each(he.swapCodes, function(sw) {
17164 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17166 output = output.replace(swapper, sw[1]);
17173 cleanUpChildren : function (n)
17175 if (!n.childNodes.length) {
17178 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17179 this.cleanUpChild(n.childNodes[i]);
17186 cleanUpChild : function (node)
17189 //console.log(node);
17190 if (node.nodeName == "#text") {
17191 // clean up silly Windows -- stuff?
17194 if (node.nodeName == "#comment") {
17195 node.parentNode.removeChild(node);
17196 // clean up silly Windows -- stuff?
17200 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17202 node.parentNode.removeChild(node);
17207 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17209 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17210 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17212 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17213 // remove_keep_children = true;
17216 if (remove_keep_children) {
17217 this.cleanUpChildren(node);
17218 // inserts everything just before this node...
17219 while (node.childNodes.length) {
17220 var cn = node.childNodes[0];
17221 node.removeChild(cn);
17222 node.parentNode.insertBefore(cn, node);
17224 node.parentNode.removeChild(node);
17228 if (!node.attributes || !node.attributes.length) {
17229 this.cleanUpChildren(node);
17233 function cleanAttr(n,v)
17236 if (v.match(/^\./) || v.match(/^\//)) {
17239 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17242 if (v.match(/^#/)) {
17245 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17246 node.removeAttribute(n);
17250 function cleanStyle(n,v)
17252 if (v.match(/expression/)) { //XSS?? should we even bother..
17253 node.removeAttribute(n);
17256 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17257 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17260 var parts = v.split(/;/);
17263 Roo.each(parts, function(p) {
17264 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17268 var l = p.split(':').shift().replace(/\s+/g,'');
17269 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17271 if ( cblack.indexOf(l) > -1) {
17272 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17273 //node.removeAttribute(n);
17277 // only allow 'c whitelisted system attributes'
17278 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17279 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17280 //node.removeAttribute(n);
17290 if (clean.length) {
17291 node.setAttribute(n, clean.join(';'));
17293 node.removeAttribute(n);
17299 for (var i = node.attributes.length-1; i > -1 ; i--) {
17300 var a = node.attributes[i];
17303 if (a.name.toLowerCase().substr(0,2)=='on') {
17304 node.removeAttribute(a.name);
17307 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17308 node.removeAttribute(a.name);
17311 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17312 cleanAttr(a.name,a.value); // fixme..
17315 if (a.name == 'style') {
17316 cleanStyle(a.name,a.value);
17319 /// clean up MS crap..
17320 // tecnically this should be a list of valid class'es..
17323 if (a.name == 'class') {
17324 if (a.value.match(/^Mso/)) {
17325 node.className = '';
17328 if (a.value.match(/body/)) {
17329 node.className = '';
17340 this.cleanUpChildren(node);
17345 * Clean up MS wordisms...
17347 cleanWord : function(node)
17350 var cleanWordChildren = function()
17352 if (!node.childNodes.length) {
17355 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17356 _t.cleanWord(node.childNodes[i]);
17362 this.cleanWord(this.doc.body);
17365 if (node.nodeName == "#text") {
17366 // clean up silly Windows -- stuff?
17369 if (node.nodeName == "#comment") {
17370 node.parentNode.removeChild(node);
17371 // clean up silly Windows -- stuff?
17375 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17376 node.parentNode.removeChild(node);
17380 // remove - but keep children..
17381 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17382 while (node.childNodes.length) {
17383 var cn = node.childNodes[0];
17384 node.removeChild(cn);
17385 node.parentNode.insertBefore(cn, node);
17387 node.parentNode.removeChild(node);
17388 cleanWordChildren();
17392 if (node.className.length) {
17394 var cn = node.className.split(/\W+/);
17396 Roo.each(cn, function(cls) {
17397 if (cls.match(/Mso[a-zA-Z]+/)) {
17402 node.className = cna.length ? cna.join(' ') : '';
17404 node.removeAttribute("class");
17408 if (node.hasAttribute("lang")) {
17409 node.removeAttribute("lang");
17412 if (node.hasAttribute("style")) {
17414 var styles = node.getAttribute("style").split(";");
17416 Roo.each(styles, function(s) {
17417 if (!s.match(/:/)) {
17420 var kv = s.split(":");
17421 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17424 // what ever is left... we allow.
17427 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17428 if (!nstyle.length) {
17429 node.removeAttribute('style');
17433 cleanWordChildren();
17437 domToHTML : function(currentElement, depth, nopadtext) {
17439 depth = depth || 0;
17440 nopadtext = nopadtext || false;
17442 if (!currentElement) {
17443 return this.domToHTML(this.doc.body);
17446 //Roo.log(currentElement);
17448 var allText = false;
17449 var nodeName = currentElement.nodeName;
17450 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17452 if (nodeName == '#text') {
17453 return currentElement.nodeValue;
17458 if (nodeName != 'BODY') {
17461 // Prints the node tagName, such as <A>, <IMG>, etc
17464 for(i = 0; i < currentElement.attributes.length;i++) {
17466 var aname = currentElement.attributes.item(i).name;
17467 if (!currentElement.attributes.item(i).value.length) {
17470 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17473 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17482 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17485 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17490 // Traverse the tree
17492 var currentElementChild = currentElement.childNodes.item(i);
17493 var allText = true;
17494 var innerHTML = '';
17496 while (currentElementChild) {
17497 // Formatting code (indent the tree so it looks nice on the screen)
17498 var nopad = nopadtext;
17499 if (lastnode == 'SPAN') {
17503 if (currentElementChild.nodeName == '#text') {
17504 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17505 if (!nopad && toadd.length > 80) {
17506 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17508 innerHTML += toadd;
17511 currentElementChild = currentElement.childNodes.item(i);
17517 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17519 // Recursively traverse the tree structure of the child node
17520 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17521 lastnode = currentElementChild.nodeName;
17523 currentElementChild=currentElement.childNodes.item(i);
17529 // The remaining code is mostly for formatting the tree
17530 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17535 ret+= "</"+tagName+">";
17541 // hide stuff that is not compatible
17555 * @event specialkey
17559 * @cfg {String} fieldClass @hide
17562 * @cfg {String} focusClass @hide
17565 * @cfg {String} autoCreate @hide
17568 * @cfg {String} inputType @hide
17571 * @cfg {String} invalidClass @hide
17574 * @cfg {String} invalidText @hide
17577 * @cfg {String} msgFx @hide
17580 * @cfg {String} validateOnBlur @hide
17584 Roo.HtmlEditorCore.white = [
17585 'area', 'br', 'img', 'input', 'hr', 'wbr',
17587 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17588 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17589 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17590 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17591 'table', 'ul', 'xmp',
17593 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17596 'dir', 'menu', 'ol', 'ul', 'dl',
17602 Roo.HtmlEditorCore.black = [
17603 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17605 'base', 'basefont', 'bgsound', 'blink', 'body',
17606 'frame', 'frameset', 'head', 'html', 'ilayer',
17607 'iframe', 'layer', 'link', 'meta', 'object',
17608 'script', 'style' ,'title', 'xml' // clean later..
17610 Roo.HtmlEditorCore.clean = [
17611 'script', 'style', 'title', 'xml'
17613 Roo.HtmlEditorCore.remove = [
17618 Roo.HtmlEditorCore.ablack = [
17622 Roo.HtmlEditorCore.aclean = [
17623 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17627 Roo.HtmlEditorCore.pwhite= [
17628 'http', 'https', 'mailto'
17631 // white listed style attributes.
17632 Roo.HtmlEditorCore.cwhite= [
17633 // 'text-align', /// default is to allow most things..
17639 // black listed style attributes.
17640 Roo.HtmlEditorCore.cblack= [
17641 // 'font-size' -- this can be set by the project
17645 Roo.HtmlEditorCore.swapCodes =[
17664 * @class Roo.bootstrap.HtmlEditor
17665 * @extends Roo.bootstrap.TextArea
17666 * Bootstrap HtmlEditor class
17669 * Create a new HtmlEditor
17670 * @param {Object} config The config object
17673 Roo.bootstrap.HtmlEditor = function(config){
17674 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17675 if (!this.toolbars) {
17676 this.toolbars = [];
17678 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17681 * @event initialize
17682 * Fires when the editor is fully initialized (including the iframe)
17683 * @param {HtmlEditor} this
17688 * Fires when the editor is first receives the focus. Any insertion must wait
17689 * until after this event.
17690 * @param {HtmlEditor} this
17694 * @event beforesync
17695 * Fires before the textarea is updated with content from the editor iframe. Return false
17696 * to cancel the sync.
17697 * @param {HtmlEditor} this
17698 * @param {String} html
17702 * @event beforepush
17703 * Fires before the iframe editor is updated with content from the textarea. Return false
17704 * to cancel the push.
17705 * @param {HtmlEditor} this
17706 * @param {String} html
17711 * Fires when the textarea is updated with content from the editor iframe.
17712 * @param {HtmlEditor} this
17713 * @param {String} html
17718 * Fires when the iframe editor is updated with content from the textarea.
17719 * @param {HtmlEditor} this
17720 * @param {String} html
17724 * @event editmodechange
17725 * Fires when the editor switches edit modes
17726 * @param {HtmlEditor} this
17727 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17729 editmodechange: true,
17731 * @event editorevent
17732 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17733 * @param {HtmlEditor} this
17737 * @event firstfocus
17738 * Fires when on first focus - needed by toolbars..
17739 * @param {HtmlEditor} this
17744 * Auto save the htmlEditor value as a file into Events
17745 * @param {HtmlEditor} this
17749 * @event savedpreview
17750 * preview the saved version of htmlEditor
17751 * @param {HtmlEditor} this
17758 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17762 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17767 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17772 * @cfg {Number} height (in pixels)
17776 * @cfg {Number} width (in pixels)
17781 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17784 stylesheets: false,
17789 // private properties
17790 validationEvent : false,
17792 initialized : false,
17795 onFocus : Roo.emptyFn,
17797 hideMode:'offsets',
17800 tbContainer : false,
17802 toolbarContainer :function() {
17803 return this.wrap.select('.x-html-editor-tb',true).first();
17807 * Protected method that will not generally be called directly. It
17808 * is called when the editor creates its toolbar. Override this method if you need to
17809 * add custom toolbar buttons.
17810 * @param {HtmlEditor} editor
17812 createToolbar : function(){
17814 Roo.log("create toolbars");
17816 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17817 this.toolbars[0].render(this.toolbarContainer());
17821 // if (!editor.toolbars || !editor.toolbars.length) {
17822 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17825 // for (var i =0 ; i < editor.toolbars.length;i++) {
17826 // editor.toolbars[i] = Roo.factory(
17827 // typeof(editor.toolbars[i]) == 'string' ?
17828 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17829 // Roo.bootstrap.HtmlEditor);
17830 // editor.toolbars[i].init(editor);
17836 onRender : function(ct, position)
17838 // Roo.log("Call onRender: " + this.xtype);
17840 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17842 this.wrap = this.inputEl().wrap({
17843 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17846 this.editorcore.onRender(ct, position);
17848 if (this.resizable) {
17849 this.resizeEl = new Roo.Resizable(this.wrap, {
17853 minHeight : this.height,
17854 height: this.height,
17855 handles : this.resizable,
17858 resize : function(r, w, h) {
17859 _t.onResize(w,h); // -something
17865 this.createToolbar(this);
17868 if(!this.width && this.resizable){
17869 this.setSize(this.wrap.getSize());
17871 if (this.resizeEl) {
17872 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17873 // should trigger onReize..
17879 onResize : function(w, h)
17881 Roo.log('resize: ' +w + ',' + h );
17882 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17886 if(this.inputEl() ){
17887 if(typeof w == 'number'){
17888 var aw = w - this.wrap.getFrameWidth('lr');
17889 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17892 if(typeof h == 'number'){
17893 var tbh = -11; // fixme it needs to tool bar size!
17894 for (var i =0; i < this.toolbars.length;i++) {
17895 // fixme - ask toolbars for heights?
17896 tbh += this.toolbars[i].el.getHeight();
17897 //if (this.toolbars[i].footer) {
17898 // tbh += this.toolbars[i].footer.el.getHeight();
17906 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17907 ah -= 5; // knock a few pixes off for look..
17908 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17912 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17913 this.editorcore.onResize(ew,eh);
17918 * Toggles the editor between standard and source edit mode.
17919 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17921 toggleSourceEdit : function(sourceEditMode)
17923 this.editorcore.toggleSourceEdit(sourceEditMode);
17925 if(this.editorcore.sourceEditMode){
17926 Roo.log('editor - showing textarea');
17929 // Roo.log(this.syncValue());
17931 this.inputEl().removeClass(['hide', 'x-hidden']);
17932 this.inputEl().dom.removeAttribute('tabIndex');
17933 this.inputEl().focus();
17935 Roo.log('editor - hiding textarea');
17937 // Roo.log(this.pushValue());
17940 this.inputEl().addClass(['hide', 'x-hidden']);
17941 this.inputEl().dom.setAttribute('tabIndex', -1);
17942 //this.deferFocus();
17945 if(this.resizable){
17946 this.setSize(this.wrap.getSize());
17949 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17952 // private (for BoxComponent)
17953 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17955 // private (for BoxComponent)
17956 getResizeEl : function(){
17960 // private (for BoxComponent)
17961 getPositionEl : function(){
17966 initEvents : function(){
17967 this.originalValue = this.getValue();
17971 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17974 // markInvalid : Roo.emptyFn,
17976 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17979 // clearInvalid : Roo.emptyFn,
17981 setValue : function(v){
17982 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17983 this.editorcore.pushValue();
17988 deferFocus : function(){
17989 this.focus.defer(10, this);
17993 focus : function(){
17994 this.editorcore.focus();
18000 onDestroy : function(){
18006 for (var i =0; i < this.toolbars.length;i++) {
18007 // fixme - ask toolbars for heights?
18008 this.toolbars[i].onDestroy();
18011 this.wrap.dom.innerHTML = '';
18012 this.wrap.remove();
18017 onFirstFocus : function(){
18018 //Roo.log("onFirstFocus");
18019 this.editorcore.onFirstFocus();
18020 for (var i =0; i < this.toolbars.length;i++) {
18021 this.toolbars[i].onFirstFocus();
18027 syncValue : function()
18029 this.editorcore.syncValue();
18032 pushValue : function()
18034 this.editorcore.pushValue();
18038 // hide stuff that is not compatible
18052 * @event specialkey
18056 * @cfg {String} fieldClass @hide
18059 * @cfg {String} focusClass @hide
18062 * @cfg {String} autoCreate @hide
18065 * @cfg {String} inputType @hide
18068 * @cfg {String} invalidClass @hide
18071 * @cfg {String} invalidText @hide
18074 * @cfg {String} msgFx @hide
18077 * @cfg {String} validateOnBlur @hide
18086 Roo.namespace('Roo.bootstrap.htmleditor');
18088 * @class Roo.bootstrap.HtmlEditorToolbar1
18093 new Roo.bootstrap.HtmlEditor({
18096 new Roo.bootstrap.HtmlEditorToolbar1({
18097 disable : { fonts: 1 , format: 1, ..., ... , ...],
18103 * @cfg {Object} disable List of elements to disable..
18104 * @cfg {Array} btns List of additional buttons.
18108 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18111 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18114 Roo.apply(this, config);
18116 // default disabled, based on 'good practice'..
18117 this.disable = this.disable || {};
18118 Roo.applyIf(this.disable, {
18121 specialElements : true
18123 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18125 this.editor = config.editor;
18126 this.editorcore = config.editor.editorcore;
18128 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18130 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18131 // dont call parent... till later.
18133 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18138 editorcore : false,
18143 "h1","h2","h3","h4","h5","h6",
18145 "abbr", "acronym", "address", "cite", "samp", "var",
18149 onRender : function(ct, position)
18151 // Roo.log("Call onRender: " + this.xtype);
18153 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18155 this.el.dom.style.marginBottom = '0';
18157 var editorcore = this.editorcore;
18158 var editor= this.editor;
18161 var btn = function(id,cmd , toggle, handler){
18163 var event = toggle ? 'toggle' : 'click';
18168 xns: Roo.bootstrap,
18171 enableToggle:toggle !== false,
18173 pressed : toggle ? false : null,
18176 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18177 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18186 xns: Roo.bootstrap,
18187 glyphicon : 'font',
18191 xns: Roo.bootstrap,
18195 Roo.each(this.formats, function(f) {
18196 style.menu.items.push({
18198 xns: Roo.bootstrap,
18199 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18204 editorcore.insertTag(this.tagname);
18211 children.push(style);
18214 btn('bold',false,true);
18215 btn('italic',false,true);
18216 btn('align-left', 'justifyleft',true);
18217 btn('align-center', 'justifycenter',true);
18218 btn('align-right' , 'justifyright',true);
18219 btn('link', false, false, function(btn) {
18220 //Roo.log("create link?");
18221 var url = prompt(this.createLinkText, this.defaultLinkValue);
18222 if(url && url != 'http:/'+'/'){
18223 this.editorcore.relayCmd('createlink', url);
18226 btn('list','insertunorderedlist',true);
18227 btn('pencil', false,true, function(btn){
18230 this.toggleSourceEdit(btn.pressed);
18236 xns: Roo.bootstrap,
18241 xns: Roo.bootstrap,
18246 cog.menu.items.push({
18248 xns: Roo.bootstrap,
18249 html : Clean styles,
18254 editorcore.insertTag(this.tagname);
18263 this.xtype = 'NavSimplebar';
18265 for(var i=0;i< children.length;i++) {
18267 this.buttons.add(this.addxtypeChild(children[i]));
18271 editor.on('editorevent', this.updateToolbar, this);
18273 onBtnClick : function(id)
18275 this.editorcore.relayCmd(id);
18276 this.editorcore.focus();
18280 * Protected method that will not generally be called directly. It triggers
18281 * a toolbar update by reading the markup state of the current selection in the editor.
18283 updateToolbar: function(){
18285 if(!this.editorcore.activated){
18286 this.editor.onFirstFocus(); // is this neeed?
18290 var btns = this.buttons;
18291 var doc = this.editorcore.doc;
18292 btns.get('bold').setActive(doc.queryCommandState('bold'));
18293 btns.get('italic').setActive(doc.queryCommandState('italic'));
18294 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18296 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18297 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18298 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18300 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18301 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18304 var ans = this.editorcore.getAllAncestors();
18305 if (this.formatCombo) {
18308 var store = this.formatCombo.store;
18309 this.formatCombo.setValue("");
18310 for (var i =0; i < ans.length;i++) {
18311 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18313 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18321 // hides menus... - so this cant be on a menu...
18322 Roo.bootstrap.MenuMgr.hideAll();
18324 Roo.bootstrap.MenuMgr.hideAll();
18325 //this.editorsyncValue();
18327 onFirstFocus: function() {
18328 this.buttons.each(function(item){
18332 toggleSourceEdit : function(sourceEditMode){
18335 if(sourceEditMode){
18336 Roo.log("disabling buttons");
18337 this.buttons.each( function(item){
18338 if(item.cmd != 'pencil'){
18344 Roo.log("enabling buttons");
18345 if(this.editorcore.initialized){
18346 this.buttons.each( function(item){
18352 Roo.log("calling toggole on editor");
18353 // tell the editor that it's been pressed..
18354 this.editor.toggleSourceEdit(sourceEditMode);
18364 * @class Roo.bootstrap.Table.AbstractSelectionModel
18365 * @extends Roo.util.Observable
18366 * Abstract base class for grid SelectionModels. It provides the interface that should be
18367 * implemented by descendant classes. This class should not be directly instantiated.
18370 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18371 this.locked = false;
18372 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18376 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18377 /** @ignore Called by the grid automatically. Do not call directly. */
18378 init : function(grid){
18384 * Locks the selections.
18387 this.locked = true;
18391 * Unlocks the selections.
18393 unlock : function(){
18394 this.locked = false;
18398 * Returns true if the selections are locked.
18399 * @return {Boolean}
18401 isLocked : function(){
18402 return this.locked;
18406 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18407 * @class Roo.bootstrap.Table.RowSelectionModel
18408 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18409 * It supports multiple selections and keyboard selection/navigation.
18411 * @param {Object} config
18414 Roo.bootstrap.Table.RowSelectionModel = function(config){
18415 Roo.apply(this, config);
18416 this.selections = new Roo.util.MixedCollection(false, function(o){
18421 this.lastActive = false;
18425 * @event selectionchange
18426 * Fires when the selection changes
18427 * @param {SelectionModel} this
18429 "selectionchange" : true,
18431 * @event afterselectionchange
18432 * Fires after the selection changes (eg. by key press or clicking)
18433 * @param {SelectionModel} this
18435 "afterselectionchange" : true,
18437 * @event beforerowselect
18438 * Fires when a row is selected being selected, return false to cancel.
18439 * @param {SelectionModel} this
18440 * @param {Number} rowIndex The selected index
18441 * @param {Boolean} keepExisting False if other selections will be cleared
18443 "beforerowselect" : true,
18446 * Fires when a row is selected.
18447 * @param {SelectionModel} this
18448 * @param {Number} rowIndex The selected index
18449 * @param {Roo.data.Record} r The record
18451 "rowselect" : true,
18453 * @event rowdeselect
18454 * Fires when a row is deselected.
18455 * @param {SelectionModel} this
18456 * @param {Number} rowIndex The selected index
18458 "rowdeselect" : true
18460 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18461 this.locked = false;
18464 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18466 * @cfg {Boolean} singleSelect
18467 * True to allow selection of only one row at a time (defaults to false)
18469 singleSelect : false,
18472 initEvents : function(){
18474 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18475 this.grid.on("mousedown", this.handleMouseDown, this);
18476 }else{ // allow click to work like normal
18477 this.grid.on("rowclick", this.handleDragableRowClick, this);
18480 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18481 "up" : function(e){
18483 this.selectPrevious(e.shiftKey);
18484 }else if(this.last !== false && this.lastActive !== false){
18485 var last = this.last;
18486 this.selectRange(this.last, this.lastActive-1);
18487 this.grid.getView().focusRow(this.lastActive);
18488 if(last !== false){
18492 this.selectFirstRow();
18494 this.fireEvent("afterselectionchange", this);
18496 "down" : function(e){
18498 this.selectNext(e.shiftKey);
18499 }else if(this.last !== false && this.lastActive !== false){
18500 var last = this.last;
18501 this.selectRange(this.last, this.lastActive+1);
18502 this.grid.getView().focusRow(this.lastActive);
18503 if(last !== false){
18507 this.selectFirstRow();
18509 this.fireEvent("afterselectionchange", this);
18514 var view = this.grid.view;
18515 view.on("refresh", this.onRefresh, this);
18516 view.on("rowupdated", this.onRowUpdated, this);
18517 view.on("rowremoved", this.onRemove, this);
18521 onRefresh : function(){
18522 var ds = this.grid.dataSource, i, v = this.grid.view;
18523 var s = this.selections;
18524 s.each(function(r){
18525 if((i = ds.indexOfId(r.id)) != -1){
18534 onRemove : function(v, index, r){
18535 this.selections.remove(r);
18539 onRowUpdated : function(v, index, r){
18540 if(this.isSelected(r)){
18541 v.onRowSelect(index);
18547 * @param {Array} records The records to select
18548 * @param {Boolean} keepExisting (optional) True to keep existing selections
18550 selectRecords : function(records, keepExisting){
18552 this.clearSelections();
18554 var ds = this.grid.dataSource;
18555 for(var i = 0, len = records.length; i < len; i++){
18556 this.selectRow(ds.indexOf(records[i]), true);
18561 * Gets the number of selected rows.
18564 getCount : function(){
18565 return this.selections.length;
18569 * Selects the first row in the grid.
18571 selectFirstRow : function(){
18576 * Select the last row.
18577 * @param {Boolean} keepExisting (optional) True to keep existing selections
18579 selectLastRow : function(keepExisting){
18580 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18584 * Selects the row immediately following the last selected row.
18585 * @param {Boolean} keepExisting (optional) True to keep existing selections
18587 selectNext : function(keepExisting){
18588 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18589 this.selectRow(this.last+1, keepExisting);
18590 this.grid.getView().focusRow(this.last);
18595 * Selects the row that precedes the last selected row.
18596 * @param {Boolean} keepExisting (optional) True to keep existing selections
18598 selectPrevious : function(keepExisting){
18600 this.selectRow(this.last-1, keepExisting);
18601 this.grid.getView().focusRow(this.last);
18606 * Returns the selected records
18607 * @return {Array} Array of selected records
18609 getSelections : function(){
18610 return [].concat(this.selections.items);
18614 * Returns the first selected record.
18617 getSelected : function(){
18618 return this.selections.itemAt(0);
18623 * Clears all selections.
18625 clearSelections : function(fast){
18626 if(this.locked) return;
18628 var ds = this.grid.dataSource;
18629 var s = this.selections;
18630 s.each(function(r){
18631 this.deselectRow(ds.indexOfId(r.id));
18635 this.selections.clear();
18642 * Selects all rows.
18644 selectAll : function(){
18645 if(this.locked) return;
18646 this.selections.clear();
18647 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18648 this.selectRow(i, true);
18653 * Returns True if there is a selection.
18654 * @return {Boolean}
18656 hasSelection : function(){
18657 return this.selections.length > 0;
18661 * Returns True if the specified row is selected.
18662 * @param {Number/Record} record The record or index of the record to check
18663 * @return {Boolean}
18665 isSelected : function(index){
18666 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18667 return (r && this.selections.key(r.id) ? true : false);
18671 * Returns True if the specified record id is selected.
18672 * @param {String} id The id of record to check
18673 * @return {Boolean}
18675 isIdSelected : function(id){
18676 return (this.selections.key(id) ? true : false);
18680 handleMouseDown : function(e, t){
18681 var view = this.grid.getView(), rowIndex;
18682 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18685 if(e.shiftKey && this.last !== false){
18686 var last = this.last;
18687 this.selectRange(last, rowIndex, e.ctrlKey);
18688 this.last = last; // reset the last
18689 view.focusRow(rowIndex);
18691 var isSelected = this.isSelected(rowIndex);
18692 if(e.button !== 0 && isSelected){
18693 view.focusRow(rowIndex);
18694 }else if(e.ctrlKey && isSelected){
18695 this.deselectRow(rowIndex);
18696 }else if(!isSelected){
18697 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18698 view.focusRow(rowIndex);
18701 this.fireEvent("afterselectionchange", this);
18704 handleDragableRowClick : function(grid, rowIndex, e)
18706 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18707 this.selectRow(rowIndex, false);
18708 grid.view.focusRow(rowIndex);
18709 this.fireEvent("afterselectionchange", this);
18714 * Selects multiple rows.
18715 * @param {Array} rows Array of the indexes of the row to select
18716 * @param {Boolean} keepExisting (optional) True to keep existing selections
18718 selectRows : function(rows, keepExisting){
18720 this.clearSelections();
18722 for(var i = 0, len = rows.length; i < len; i++){
18723 this.selectRow(rows[i], true);
18728 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18729 * @param {Number} startRow The index of the first row in the range
18730 * @param {Number} endRow The index of the last row in the range
18731 * @param {Boolean} keepExisting (optional) True to retain existing selections
18733 selectRange : function(startRow, endRow, keepExisting){
18734 if(this.locked) return;
18736 this.clearSelections();
18738 if(startRow <= endRow){
18739 for(var i = startRow; i <= endRow; i++){
18740 this.selectRow(i, true);
18743 for(var i = startRow; i >= endRow; i--){
18744 this.selectRow(i, true);
18750 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18751 * @param {Number} startRow The index of the first row in the range
18752 * @param {Number} endRow The index of the last row in the range
18754 deselectRange : function(startRow, endRow, preventViewNotify){
18755 if(this.locked) return;
18756 for(var i = startRow; i <= endRow; i++){
18757 this.deselectRow(i, preventViewNotify);
18763 * @param {Number} row The index of the row to select
18764 * @param {Boolean} keepExisting (optional) True to keep existing selections
18766 selectRow : function(index, keepExisting, preventViewNotify){
18767 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18768 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18769 if(!keepExisting || this.singleSelect){
18770 this.clearSelections();
18772 var r = this.grid.dataSource.getAt(index);
18773 this.selections.add(r);
18774 this.last = this.lastActive = index;
18775 if(!preventViewNotify){
18776 this.grid.getView().onRowSelect(index);
18778 this.fireEvent("rowselect", this, index, r);
18779 this.fireEvent("selectionchange", this);
18785 * @param {Number} row The index of the row to deselect
18787 deselectRow : function(index, preventViewNotify){
18788 if(this.locked) return;
18789 if(this.last == index){
18792 if(this.lastActive == index){
18793 this.lastActive = false;
18795 var r = this.grid.dataSource.getAt(index);
18796 this.selections.remove(r);
18797 if(!preventViewNotify){
18798 this.grid.getView().onRowDeselect(index);
18800 this.fireEvent("rowdeselect", this, index);
18801 this.fireEvent("selectionchange", this);
18805 restoreLast : function(){
18807 this.last = this._last;
18812 acceptsNav : function(row, col, cm){
18813 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18817 onEditorKey : function(field, e){
18818 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18823 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18825 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18827 }else if(k == e.ENTER && !e.ctrlKey){
18831 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18833 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18835 }else if(k == e.ESC){
18839 g.startEditing(newCell[0], newCell[1]);
18844 * Ext JS Library 1.1.1
18845 * Copyright(c) 2006-2007, Ext JS, LLC.
18847 * Originally Released Under LGPL - original licence link has changed is not relivant.
18850 * <script type="text/javascript">
18854 * @class Roo.bootstrap.PagingToolbar
18856 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18858 * Create a new PagingToolbar
18859 * @param {Object} config The config object
18861 Roo.bootstrap.PagingToolbar = function(config)
18863 // old args format still supported... - xtype is prefered..
18864 // created from xtype...
18865 var ds = config.dataSource;
18866 this.toolbarItems = [];
18867 if (config.items) {
18868 this.toolbarItems = config.items;
18869 // config.items = [];
18872 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18879 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18883 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18885 * @cfg {Roo.data.Store} dataSource
18886 * The underlying data store providing the paged data
18889 * @cfg {String/HTMLElement/Element} container
18890 * container The id or element that will contain the toolbar
18893 * @cfg {Boolean} displayInfo
18894 * True to display the displayMsg (defaults to false)
18897 * @cfg {Number} pageSize
18898 * The number of records to display per page (defaults to 20)
18902 * @cfg {String} displayMsg
18903 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18905 displayMsg : 'Displaying {0} - {1} of {2}',
18907 * @cfg {String} emptyMsg
18908 * The message to display when no records are found (defaults to "No data to display")
18910 emptyMsg : 'No data to display',
18912 * Customizable piece of the default paging text (defaults to "Page")
18915 beforePageText : "Page",
18917 * Customizable piece of the default paging text (defaults to "of %0")
18920 afterPageText : "of {0}",
18922 * Customizable piece of the default paging text (defaults to "First Page")
18925 firstText : "First Page",
18927 * Customizable piece of the default paging text (defaults to "Previous Page")
18930 prevText : "Previous Page",
18932 * Customizable piece of the default paging text (defaults to "Next Page")
18935 nextText : "Next Page",
18937 * Customizable piece of the default paging text (defaults to "Last Page")
18940 lastText : "Last Page",
18942 * Customizable piece of the default paging text (defaults to "Refresh")
18945 refreshText : "Refresh",
18949 onRender : function(ct, position)
18951 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18952 this.navgroup.parentId = this.id;
18953 this.navgroup.onRender(this.el, null);
18954 // add the buttons to the navgroup
18956 if(this.displayInfo){
18957 Roo.log(this.el.select('ul.navbar-nav',true).first());
18958 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18959 this.displayEl = this.el.select('.x-paging-info', true).first();
18960 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18961 // this.displayEl = navel.el.select('span',true).first();
18967 Roo.each(_this.buttons, function(e){
18968 Roo.factory(e).onRender(_this.el, null);
18972 Roo.each(_this.toolbarItems, function(e) {
18973 _this.navgroup.addItem(e);
18976 this.first = this.navgroup.addItem({
18977 tooltip: this.firstText,
18979 icon : 'fa fa-backward',
18981 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18984 this.prev = this.navgroup.addItem({
18985 tooltip: this.prevText,
18987 icon : 'fa fa-step-backward',
18989 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18991 //this.addSeparator();
18994 var field = this.navgroup.addItem( {
18996 cls : 'x-paging-position',
18998 html : this.beforePageText +
18999 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19000 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19003 this.field = field.el.select('input', true).first();
19004 this.field.on("keydown", this.onPagingKeydown, this);
19005 this.field.on("focus", function(){this.dom.select();});
19008 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19009 //this.field.setHeight(18);
19010 //this.addSeparator();
19011 this.next = this.navgroup.addItem({
19012 tooltip: this.nextText,
19014 html : ' <i class="fa fa-step-forward">',
19016 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19018 this.last = this.navgroup.addItem({
19019 tooltip: this.lastText,
19020 icon : 'fa fa-forward',
19023 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19025 //this.addSeparator();
19026 this.loading = this.navgroup.addItem({
19027 tooltip: this.refreshText,
19028 icon: 'fa fa-refresh',
19030 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19036 updateInfo : function(){
19037 if(this.displayEl){
19038 var count = this.ds.getCount();
19039 var msg = count == 0 ?
19043 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19045 this.displayEl.update(msg);
19050 onLoad : function(ds, r, o){
19051 this.cursor = o.params ? o.params.start : 0;
19052 var d = this.getPageData(),
19056 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19057 this.field.dom.value = ap;
19058 this.first.setDisabled(ap == 1);
19059 this.prev.setDisabled(ap == 1);
19060 this.next.setDisabled(ap == ps);
19061 this.last.setDisabled(ap == ps);
19062 this.loading.enable();
19067 getPageData : function(){
19068 var total = this.ds.getTotalCount();
19071 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19072 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19077 onLoadError : function(){
19078 this.loading.enable();
19082 onPagingKeydown : function(e){
19083 var k = e.getKey();
19084 var d = this.getPageData();
19086 var v = this.field.dom.value, pageNum;
19087 if(!v || isNaN(pageNum = parseInt(v, 10))){
19088 this.field.dom.value = d.activePage;
19091 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19092 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19095 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))
19097 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19098 this.field.dom.value = pageNum;
19099 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19102 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19104 var v = this.field.dom.value, pageNum;
19105 var increment = (e.shiftKey) ? 10 : 1;
19106 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19108 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19109 this.field.dom.value = d.activePage;
19112 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19114 this.field.dom.value = parseInt(v, 10) + increment;
19115 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19116 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19123 beforeLoad : function(){
19125 this.loading.disable();
19130 onClick : function(which){
19137 ds.load({params:{start: 0, limit: this.pageSize}});
19140 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19143 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19146 var total = ds.getTotalCount();
19147 var extra = total % this.pageSize;
19148 var lastStart = extra ? (total - extra) : total-this.pageSize;
19149 ds.load({params:{start: lastStart, limit: this.pageSize}});
19152 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19158 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19159 * @param {Roo.data.Store} store The data store to unbind
19161 unbind : function(ds){
19162 ds.un("beforeload", this.beforeLoad, this);
19163 ds.un("load", this.onLoad, this);
19164 ds.un("loadexception", this.onLoadError, this);
19165 ds.un("remove", this.updateInfo, this);
19166 ds.un("add", this.updateInfo, this);
19167 this.ds = undefined;
19171 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19172 * @param {Roo.data.Store} store The data store to bind
19174 bind : function(ds){
19175 ds.on("beforeload", this.beforeLoad, this);
19176 ds.on("load", this.onLoad, this);
19177 ds.on("loadexception", this.onLoadError, this);
19178 ds.on("remove", this.updateInfo, this);
19179 ds.on("add", this.updateInfo, this);
19190 * @class Roo.bootstrap.MessageBar
19191 * @extends Roo.bootstrap.Component
19192 * Bootstrap MessageBar class
19193 * @cfg {String} html contents of the MessageBar
19194 * @cfg {String} weight (info | success | warning | danger) default info
19195 * @cfg {String} beforeClass insert the bar before the given class
19196 * @cfg {Boolean} closable (true | false) default false
19197 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19200 * Create a new Element
19201 * @param {Object} config The config object
19204 Roo.bootstrap.MessageBar = function(config){
19205 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19208 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19214 beforeClass: 'bootstrap-sticky-wrap',
19216 getAutoCreate : function(){
19220 cls: 'alert alert-dismissable alert-' + this.weight,
19225 html: this.html || ''
19231 cfg.cls += ' alert-messages-fixed';
19245 onRender : function(ct, position)
19247 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19250 var cfg = Roo.apply({}, this.getAutoCreate());
19254 cfg.cls += ' ' + this.cls;
19257 cfg.style = this.style;
19259 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19261 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19264 this.el.select('>button.close').on('click', this.hide, this);
19270 if (!this.rendered) {
19276 this.fireEvent('show', this);
19282 if (!this.rendered) {
19288 this.fireEvent('hide', this);
19291 update : function()
19293 // var e = this.el.dom.firstChild;
19295 // if(this.closable){
19296 // e = e.nextSibling;
19299 // e.data = this.html || '';
19301 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19317 * @class Roo.bootstrap.Graph
19318 * @extends Roo.bootstrap.Component
19319 * Bootstrap Graph class
19323 @cfg {String} graphtype bar | vbar | pie
19324 @cfg {number} g_x coodinator | centre x (pie)
19325 @cfg {number} g_y coodinator | centre y (pie)
19326 @cfg {number} g_r radius (pie)
19327 @cfg {number} g_height height of the chart (respected by all elements in the set)
19328 @cfg {number} g_width width of the chart (respected by all elements in the set)
19329 @cfg {Object} title The title of the chart
19332 -opts (object) options for the chart
19334 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19335 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19337 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.
19338 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19340 o stretch (boolean)
19342 -opts (object) options for the pie
19345 o startAngle (number)
19346 o endAngle (number)
19350 * Create a new Input
19351 * @param {Object} config The config object
19354 Roo.bootstrap.Graph = function(config){
19355 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19361 * The img click event for the img.
19362 * @param {Roo.EventObject} e
19368 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19379 //g_colors: this.colors,
19386 getAutoCreate : function(){
19397 onRender : function(ct,position){
19398 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19399 this.raphael = Raphael(this.el.dom);
19401 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19402 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19403 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19404 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19406 r.text(160, 10, "Single Series Chart").attr(txtattr);
19407 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19408 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19409 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19411 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19412 r.barchart(330, 10, 300, 220, data1);
19413 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19414 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19417 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19418 // r.barchart(30, 30, 560, 250, xdata, {
19419 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19420 // axis : "0 0 1 1",
19421 // axisxlabels : xdata
19422 // //yvalues : cols,
19425 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19427 // this.load(null,xdata,{
19428 // axis : "0 0 1 1",
19429 // axisxlabels : xdata
19434 load : function(graphtype,xdata,opts){
19435 this.raphael.clear();
19437 graphtype = this.graphtype;
19442 var r = this.raphael,
19443 fin = function () {
19444 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19446 fout = function () {
19447 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19449 pfin = function() {
19450 this.sector.stop();
19451 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19454 this.label[0].stop();
19455 this.label[0].attr({ r: 7.5 });
19456 this.label[1].attr({ "font-weight": 800 });
19459 pfout = function() {
19460 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19463 this.label[0].animate({ r: 5 }, 500, "bounce");
19464 this.label[1].attr({ "font-weight": 400 });
19470 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19473 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19476 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19477 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19479 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19486 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19491 setTitle: function(o)
19496 initEvents: function() {
19499 this.el.on('click', this.onClick, this);
19503 onClick : function(e)
19505 Roo.log('img onclick');
19506 this.fireEvent('click', this, e);
19518 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19521 * @class Roo.bootstrap.dash.NumberBox
19522 * @extends Roo.bootstrap.Component
19523 * Bootstrap NumberBox class
19524 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19525 * @cfg {String} headline Box headline
19526 * @cfg {String} content Box content
19527 * @cfg {String} icon Box icon
19528 * @cfg {String} footer Footer text
19529 * @cfg {String} fhref Footer href
19532 * Create a new NumberBox
19533 * @param {Object} config The config object
19537 Roo.bootstrap.dash.NumberBox = function(config){
19538 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19542 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19552 getAutoCreate : function(){
19556 cls : 'small-box bg-' + this.bgcolor,
19564 cls : 'roo-headline',
19565 html : this.headline
19569 cls : 'roo-content',
19570 html : this.content
19584 cls : 'ion ' + this.icon
19593 cls : 'small-box-footer',
19594 href : this.fhref || '#',
19598 cfg.cn.push(footer);
19605 onRender : function(ct,position){
19606 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19613 setHeadline: function (value)
19615 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19618 setFooter: function (value, href)
19620 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19623 this.el.select('a.small-box-footer',true).first().attr('href', href);
19628 setContent: function (value)
19630 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19633 initEvents: function()
19647 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19650 * @class Roo.bootstrap.dash.TabBox
19651 * @extends Roo.bootstrap.Component
19652 * Bootstrap TabBox class
19653 * @cfg {String} title Title of the TabBox
19654 * @cfg {String} icon Icon of the TabBox
19655 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19658 * Create a new TabBox
19659 * @param {Object} config The config object
19663 Roo.bootstrap.dash.TabBox = function(config){
19664 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19669 * When a pane is added
19670 * @param {Roo.bootstrap.dash.TabPane} pane
19677 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19683 getChildContainer : function()
19685 return this.el.select('.tab-content', true).first();
19688 getAutoCreate : function(){
19692 cls: 'pull-left header',
19700 cls: 'fa ' + this.icon
19707 cls: 'nav-tabs-custom',
19711 cls: 'nav nav-tabs pull-right',
19718 cls: 'tab-content no-padding',
19726 initEvents : function()
19728 //Roo.log('add add pane handler');
19729 this.on('addpane', this.onAddPane, this);
19732 * Updates the box title
19733 * @param {String} html to set the title to.
19735 setTitle : function(value)
19737 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19739 onAddPane : function(pane)
19741 //Roo.log('addpane');
19743 // tabs are rendere left to right..
19744 if(!this.showtabs){
19748 var ctr = this.el.select('.nav-tabs', true).first();
19751 var existing = ctr.select('.nav-tab',true);
19752 var qty = existing.getCount();;
19755 var tab = ctr.createChild({
19757 cls : 'nav-tab' + (qty ? '' : ' active'),
19765 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19768 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19770 pane.el.addClass('active');
19775 onTabClick : function(ev,un,ob,pane)
19777 //Roo.log('tab - prev default');
19778 ev.preventDefault();
19781 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19782 pane.tab.addClass('active');
19783 //Roo.log(pane.title);
19784 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19785 // technically we should have a deactivate event.. but maybe add later.
19786 // and it should not de-activate the selected tab...
19788 pane.el.addClass('active');
19789 pane.fireEvent('activate');
19804 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19806 * @class Roo.bootstrap.TabPane
19807 * @extends Roo.bootstrap.Component
19808 * Bootstrap TabPane class
19809 * @cfg {Boolean} active (false | true) Default false
19810 * @cfg {String} title title of panel
19814 * Create a new TabPane
19815 * @param {Object} config The config object
19818 Roo.bootstrap.dash.TabPane = function(config){
19819 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19825 * When a pane is activated
19826 * @param {Roo.bootstrap.dash.TabPane} pane
19833 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19838 // the tabBox that this is attached to.
19841 getAutoCreate : function()
19849 cfg.cls += ' active';
19854 initEvents : function()
19856 //Roo.log('trigger add pane handler');
19857 this.parent().fireEvent('addpane', this)
19861 * Updates the tab title
19862 * @param {String} html to set the title to.
19864 setTitle: function(str)
19870 this.tab.select('a', true).first().dom.innerHTML = str;
19887 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19890 * @class Roo.bootstrap.menu.Menu
19891 * @extends Roo.bootstrap.Component
19892 * Bootstrap Menu class - container for Menu
19893 * @cfg {String} html Text of the menu
19894 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19895 * @cfg {String} icon Font awesome icon
19896 * @cfg {String} pos Menu align to (top | bottom) default bottom
19900 * Create a new Menu
19901 * @param {Object} config The config object
19905 Roo.bootstrap.menu.Menu = function(config){
19906 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19910 * @event beforeshow
19911 * Fires before this menu is displayed
19912 * @param {Roo.bootstrap.menu.Menu} this
19916 * @event beforehide
19917 * Fires before this menu is hidden
19918 * @param {Roo.bootstrap.menu.Menu} this
19923 * Fires after this menu is displayed
19924 * @param {Roo.bootstrap.menu.Menu} this
19929 * Fires after this menu is hidden
19930 * @param {Roo.bootstrap.menu.Menu} this
19935 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19936 * @param {Roo.bootstrap.menu.Menu} this
19937 * @param {Roo.EventObject} e
19944 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19948 weight : 'default',
19953 getChildContainer : function() {
19954 if(this.isSubMenu){
19958 return this.el.select('ul.dropdown-menu', true).first();
19961 getAutoCreate : function()
19966 cls : 'roo-menu-text',
19974 cls : 'fa ' + this.icon
19985 cls : 'dropdown-button btn btn-' + this.weight,
19990 cls : 'dropdown-toggle btn btn-' + this.weight,
20000 cls : 'dropdown-menu'
20006 if(this.pos == 'top'){
20007 cfg.cls += ' dropup';
20010 if(this.isSubMenu){
20013 cls : 'dropdown-menu'
20020 onRender : function(ct, position)
20022 this.isSubMenu = ct.hasClass('dropdown-submenu');
20024 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20027 initEvents : function()
20029 if(this.isSubMenu){
20033 this.hidden = true;
20035 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20036 this.triggerEl.on('click', this.onTriggerPress, this);
20038 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20039 this.buttonEl.on('click', this.onClick, this);
20045 if(this.isSubMenu){
20049 return this.el.select('ul.dropdown-menu', true).first();
20052 onClick : function(e)
20054 this.fireEvent("click", this, e);
20057 onTriggerPress : function(e)
20059 if (this.isVisible()) {
20066 isVisible : function(){
20067 return !this.hidden;
20072 this.fireEvent("beforeshow", this);
20074 this.hidden = false;
20075 this.el.addClass('open');
20077 Roo.get(document).on("mouseup", this.onMouseUp, this);
20079 this.fireEvent("show", this);
20086 this.fireEvent("beforehide", this);
20088 this.hidden = true;
20089 this.el.removeClass('open');
20091 Roo.get(document).un("mouseup", this.onMouseUp);
20093 this.fireEvent("hide", this);
20096 onMouseUp : function()
20110 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20113 * @class Roo.bootstrap.menu.Item
20114 * @extends Roo.bootstrap.Component
20115 * Bootstrap MenuItem class
20116 * @cfg {Boolean} submenu (true | false) default false
20117 * @cfg {String} html text of the item
20118 * @cfg {String} href the link
20119 * @cfg {Boolean} disable (true | false) default false
20120 * @cfg {Boolean} preventDefault (true | false) default true
20121 * @cfg {String} icon Font awesome icon
20122 * @cfg {String} pos Submenu align to (left | right) default right
20126 * Create a new Item
20127 * @param {Object} config The config object
20131 Roo.bootstrap.menu.Item = function(config){
20132 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20136 * Fires when the mouse is hovering over this menu
20137 * @param {Roo.bootstrap.menu.Item} this
20138 * @param {Roo.EventObject} e
20143 * Fires when the mouse exits this menu
20144 * @param {Roo.bootstrap.menu.Item} this
20145 * @param {Roo.EventObject} e
20151 * The raw click event for the entire grid.
20152 * @param {Roo.EventObject} e
20158 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20163 preventDefault: true,
20168 getAutoCreate : function()
20173 cls : 'roo-menu-item-text',
20181 cls : 'fa ' + this.icon
20190 href : this.href || '#',
20197 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20201 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20203 if(this.pos == 'left'){
20204 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20211 initEvents : function()
20213 this.el.on('mouseover', this.onMouseOver, this);
20214 this.el.on('mouseout', this.onMouseOut, this);
20216 this.el.select('a', true).first().on('click', this.onClick, this);
20220 onClick : function(e)
20222 if(this.preventDefault){
20223 e.preventDefault();
20226 this.fireEvent("click", this, e);
20229 onMouseOver : function(e)
20231 if(this.submenu && this.pos == 'left'){
20232 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20235 this.fireEvent("mouseover", this, e);
20238 onMouseOut : function(e)
20240 this.fireEvent("mouseout", this, e);
20252 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20255 * @class Roo.bootstrap.menu.Separator
20256 * @extends Roo.bootstrap.Component
20257 * Bootstrap Separator class
20260 * Create a new Separator
20261 * @param {Object} config The config object
20265 Roo.bootstrap.menu.Separator = function(config){
20266 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20269 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20271 getAutoCreate : function(){