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 {Boolean} hidden (true|false) hide the element
778 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
779 * @cfg {String} fa (ban|check|...) font awesome icon
780 * @cfg {String} icon (info-sign|check|...) glyphicon name
782 * @cfg {String} html content of column.
785 * Create a new Column
786 * @param {Object} config The config object
789 Roo.bootstrap.Column = function(config){
790 Roo.bootstrap.Column.superclass.constructor.call(this, config);
793 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
806 getAutoCreate : function(){
807 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
815 ['xs','sm','md','lg'].map(function(size){
816 Roo.log( size + ':' + settings[size]);
817 if (settings[size] === false) {
820 Roo.log(settings[size]);
821 if (!settings[size]) { // 0 = hidden
822 cfg.cls += ' hidden-' + size;
825 cfg.cls += ' col-' + size + '-' + settings[size];
830 cfg.cls += ' hidden';
833 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
834 cfg.cls +=' alert alert-' + this.alert;
838 if (this.html.length) {
839 cfg.html = this.html;
842 cfg.html = '<i class="fa fa-'+this.fa + '"></i>' + (cfg.html || '');
845 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
864 * @class Roo.bootstrap.Container
865 * @extends Roo.bootstrap.Component
866 * Bootstrap Container class
867 * @cfg {Boolean} jumbotron is it a jumbotron element
868 * @cfg {String} html content of element
869 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
870 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
871 * @cfg {String} header content of header (for panel)
872 * @cfg {String} footer content of footer (for panel)
873 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
874 * @cfg {String} tag (header|aside|section) type of HTML tag.
875 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
876 * @cfg {String} fa (ban|check|...) font awesome icon
877 * @cfg {String} icon (info-sign|check|...) glyphicon name
878 * @cfg {Boolean} hidden (true|false) hide the element
882 * Create a new Container
883 * @param {Object} config The config object
886 Roo.bootstrap.Container = function(config){
887 Roo.bootstrap.Container.superclass.constructor.call(this, config);
890 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
904 getChildContainer : function() {
910 if (this.panel.length) {
911 return this.el.select('.panel-body',true).first();
918 getAutoCreate : function(){
921 tag : this.tag || 'div',
925 if (this.jumbotron) {
926 cfg.cls = 'jumbotron';
931 // - this is applied by the parent..
933 // cfg.cls = this.cls + '';
936 if (this.sticky.length) {
938 var bd = Roo.get(document.body);
939 if (!bd.hasClass('bootstrap-sticky')) {
940 bd.addClass('bootstrap-sticky');
941 Roo.select('html',true).setStyle('height', '100%');
944 cfg.cls += 'bootstrap-sticky-' + this.sticky;
948 if (this.well.length) {
952 cfg.cls +=' well well-' +this.well;
961 cfg.cls += ' hidden';
965 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
966 cfg.cls +=' alert alert-' + this.alert;
971 if (this.panel.length) {
972 cfg.cls += ' panel panel-' + this.panel;
974 if (this.header.length) {
977 cls : 'panel-heading',
993 if (this.footer.length) {
995 cls : 'panel-footer',
1004 body.html = this.html || cfg.html;
1005 // prefix with the icons..
1007 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1010 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1015 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1016 cfg.cls = 'container';
1022 titleEl : function()
1024 if(!this.el || !this.panel.length || !this.header.length){
1028 return this.el.select('.panel-title',true).first();
1031 setTitle : function(v)
1033 var titleEl = this.titleEl();
1039 titleEl.dom.innerHTML = v;
1042 getTitle : function()
1045 var titleEl = this.titleEl();
1051 return titleEl.dom.innerHTML;
1065 * @class Roo.bootstrap.Img
1066 * @extends Roo.bootstrap.Component
1067 * Bootstrap Img class
1068 * @cfg {Boolean} imgResponsive false | true
1069 * @cfg {String} border rounded | circle | thumbnail
1070 * @cfg {String} src image source
1071 * @cfg {String} alt image alternative text
1072 * @cfg {String} href a tag href
1073 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1076 * Create a new Input
1077 * @param {Object} config The config object
1080 Roo.bootstrap.Img = function(config){
1081 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1087 * The img click event for the img.
1088 * @param {Roo.EventObject} e
1094 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1096 imgResponsive: true,
1102 getAutoCreate : function(){
1106 cls: (this.imgResponsive) ? 'img-responsive' : '',
1110 cfg.html = this.html || cfg.html;
1112 cfg.src = this.src || cfg.src;
1114 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1115 cfg.cls += ' img-' + this.border;
1132 a.target = this.target;
1138 return (this.href) ? a : cfg;
1141 initEvents: function() {
1144 this.el.on('click', this.onClick, this);
1148 onClick : function(e)
1150 Roo.log('img onclick');
1151 this.fireEvent('click', this, e);
1165 * @class Roo.bootstrap.Link
1166 * @extends Roo.bootstrap.Component
1167 * Bootstrap Link Class
1168 * @cfg {String} alt image alternative text
1169 * @cfg {String} href a tag href
1170 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1171 * @cfg {String} html the content of the link.
1172 * @cfg {Boolean} preventDefault (true | false) default false
1176 * Create a new Input
1177 * @param {Object} config The config object
1180 Roo.bootstrap.Link = function(config){
1181 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1187 * The img click event for the img.
1188 * @param {Roo.EventObject} e
1194 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1198 preventDefault: false,
1200 getAutoCreate : function(){
1204 html : this.html || 'html-missing'
1211 cfg.href = this.href || '#';
1213 cfg.target = this.target;
1219 initEvents: function() {
1221 if(!this.href || this.preventDefault){
1222 this.el.on('click', this.onClick, this);
1226 onClick : function(e)
1228 if(this.preventDefault){
1231 //Roo.log('img onclick');
1232 this.fireEvent('click', this, e);
1245 * @class Roo.bootstrap.Header
1246 * @extends Roo.bootstrap.Component
1247 * Bootstrap Header class
1248 * @cfg {String} html content of header
1249 * @cfg {Number} level (1|2|3|4|5|6) default 1
1252 * Create a new Header
1253 * @param {Object} config The config object
1257 Roo.bootstrap.Header = function(config){
1258 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1261 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1269 getAutoCreate : function(){
1272 tag: 'h' + (1 *this.level),
1273 html: this.html || 'fill in html'
1285 * Ext JS Library 1.1.1
1286 * Copyright(c) 2006-2007, Ext JS, LLC.
1288 * Originally Released Under LGPL - original licence link has changed is not relivant.
1291 * <script type="text/javascript">
1295 * @class Roo.bootstrap.MenuMgr
1296 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1299 Roo.bootstrap.MenuMgr = function(){
1300 var menus, active, groups = {}, attached = false, lastShow = new Date();
1302 // private - called when first menu is created
1305 active = new Roo.util.MixedCollection();
1306 Roo.get(document).addKeyListener(27, function(){
1307 if(active.length > 0){
1315 if(active && active.length > 0){
1316 var c = active.clone();
1326 if(active.length < 1){
1327 Roo.get(document).un("mouseup", onMouseDown);
1335 var last = active.last();
1336 lastShow = new Date();
1339 Roo.get(document).on("mouseup", onMouseDown);
1344 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1345 m.parentMenu.activeChild = m;
1346 }else if(last && last.isVisible()){
1347 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1352 function onBeforeHide(m){
1354 m.activeChild.hide();
1356 if(m.autoHideTimer){
1357 clearTimeout(m.autoHideTimer);
1358 delete m.autoHideTimer;
1363 function onBeforeShow(m){
1364 var pm = m.parentMenu;
1365 if(!pm && !m.allowOtherMenus){
1367 }else if(pm && pm.activeChild && active != m){
1368 pm.activeChild.hide();
1373 function onMouseDown(e){
1374 Roo.log("on MouseDown");
1375 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1383 function onBeforeCheck(mi, state){
1385 var g = groups[mi.group];
1386 for(var i = 0, l = g.length; i < l; i++){
1388 g[i].setChecked(false);
1397 * Hides all menus that are currently visible
1399 hideAll : function(){
1404 register : function(menu){
1408 menus[menu.id] = menu;
1409 menu.on("beforehide", onBeforeHide);
1410 menu.on("hide", onHide);
1411 menu.on("beforeshow", onBeforeShow);
1412 menu.on("show", onShow);
1414 if(g && menu.events["checkchange"]){
1418 groups[g].push(menu);
1419 menu.on("checkchange", onCheck);
1424 * Returns a {@link Roo.menu.Menu} object
1425 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1426 * be used to generate and return a new Menu instance.
1428 get : function(menu){
1429 if(typeof menu == "string"){ // menu id
1431 }else if(menu.events){ // menu instance
1434 /*else if(typeof menu.length == 'number'){ // array of menu items?
1435 return new Roo.bootstrap.Menu({items:menu});
1436 }else{ // otherwise, must be a config
1437 return new Roo.bootstrap.Menu(menu);
1444 unregister : function(menu){
1445 delete menus[menu.id];
1446 menu.un("beforehide", onBeforeHide);
1447 menu.un("hide", onHide);
1448 menu.un("beforeshow", onBeforeShow);
1449 menu.un("show", onShow);
1451 if(g && menu.events["checkchange"]){
1452 groups[g].remove(menu);
1453 menu.un("checkchange", onCheck);
1458 registerCheckable : function(menuItem){
1459 var g = menuItem.group;
1464 groups[g].push(menuItem);
1465 menuItem.on("beforecheckchange", onBeforeCheck);
1470 unregisterCheckable : function(menuItem){
1471 var g = menuItem.group;
1473 groups[g].remove(menuItem);
1474 menuItem.un("beforecheckchange", onBeforeCheck);
1486 * @class Roo.bootstrap.Menu
1487 * @extends Roo.bootstrap.Component
1488 * Bootstrap Menu class - container for MenuItems
1489 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1493 * @param {Object} config The config object
1497 Roo.bootstrap.Menu = function(config){
1498 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1499 if (this.registerMenu) {
1500 Roo.bootstrap.MenuMgr.register(this);
1505 * Fires before this menu is displayed
1506 * @param {Roo.menu.Menu} this
1511 * Fires before this menu is hidden
1512 * @param {Roo.menu.Menu} this
1517 * Fires after this menu is displayed
1518 * @param {Roo.menu.Menu} this
1523 * Fires after this menu is hidden
1524 * @param {Roo.menu.Menu} this
1529 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1530 * @param {Roo.menu.Menu} this
1531 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1532 * @param {Roo.EventObject} e
1537 * Fires when the mouse is hovering over this menu
1538 * @param {Roo.menu.Menu} this
1539 * @param {Roo.EventObject} e
1540 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1545 * Fires when the mouse exits this menu
1546 * @param {Roo.menu.Menu} this
1547 * @param {Roo.EventObject} e
1548 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1553 * Fires when a menu item contained in this menu is clicked
1554 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1555 * @param {Roo.EventObject} e
1559 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1562 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1566 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1569 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1571 registerMenu : true,
1573 menuItems :false, // stores the menu items..
1579 getChildContainer : function() {
1583 getAutoCreate : function(){
1585 //if (['right'].indexOf(this.align)!==-1) {
1586 // cfg.cn[1].cls += ' pull-right'
1592 cls : 'dropdown-menu' ,
1593 style : 'z-index:1000'
1597 if (this.type === 'submenu') {
1598 cfg.cls = 'submenu active';
1600 if (this.type === 'treeview') {
1601 cfg.cls = 'treeview-menu';
1606 initEvents : function() {
1608 // Roo.log("ADD event");
1609 // Roo.log(this.triggerEl.dom);
1610 this.triggerEl.on('click', this.onTriggerPress, this);
1611 this.triggerEl.addClass('dropdown-toggle');
1612 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1614 this.el.on("mouseover", this.onMouseOver, this);
1615 this.el.on("mouseout", this.onMouseOut, this);
1619 findTargetItem : function(e){
1620 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1624 //Roo.log(t); Roo.log(t.id);
1626 //Roo.log(this.menuitems);
1627 return this.menuitems.get(t.id);
1629 //return this.items.get(t.menuItemId);
1634 onClick : function(e){
1635 Roo.log("menu.onClick");
1636 var t = this.findTargetItem(e);
1642 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1643 if(t == this.activeItem && t.shouldDeactivate(e)){
1644 this.activeItem.deactivate();
1645 delete this.activeItem;
1649 this.setActiveItem(t, true);
1656 Roo.log('pass click event');
1660 this.fireEvent("click", this, t, e);
1664 onMouseOver : function(e){
1665 var t = this.findTargetItem(e);
1668 // if(t.canActivate && !t.disabled){
1669 // this.setActiveItem(t, true);
1673 this.fireEvent("mouseover", this, e, t);
1675 isVisible : function(){
1676 return !this.hidden;
1678 onMouseOut : function(e){
1679 var t = this.findTargetItem(e);
1682 // if(t == this.activeItem && t.shouldDeactivate(e)){
1683 // this.activeItem.deactivate();
1684 // delete this.activeItem;
1687 this.fireEvent("mouseout", this, e, t);
1692 * Displays this menu relative to another element
1693 * @param {String/HTMLElement/Roo.Element} element The element to align to
1694 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1695 * the element (defaults to this.defaultAlign)
1696 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1698 show : function(el, pos, parentMenu){
1699 this.parentMenu = parentMenu;
1703 this.fireEvent("beforeshow", this);
1704 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1707 * Displays this menu at a specific xy position
1708 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1709 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1711 showAt : function(xy, parentMenu, /* private: */_e){
1712 this.parentMenu = parentMenu;
1717 this.fireEvent("beforeshow", this);
1719 //xy = this.el.adjustForConstraints(xy);
1721 //this.el.setXY(xy);
1723 this.hideMenuItems();
1724 this.hidden = false;
1725 this.triggerEl.addClass('open');
1727 this.fireEvent("show", this);
1733 this.doFocus.defer(50, this);
1737 doFocus : function(){
1739 this.focusEl.focus();
1744 * Hides this menu and optionally all parent menus
1745 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1747 hide : function(deep){
1749 this.hideMenuItems();
1750 if(this.el && this.isVisible()){
1751 this.fireEvent("beforehide", this);
1752 if(this.activeItem){
1753 this.activeItem.deactivate();
1754 this.activeItem = null;
1756 this.triggerEl.removeClass('open');;
1758 this.fireEvent("hide", this);
1760 if(deep === true && this.parentMenu){
1761 this.parentMenu.hide(true);
1765 onTriggerPress : function(e)
1768 Roo.log('trigger press');
1769 //Roo.log(e.getTarget());
1770 // Roo.log(this.triggerEl.dom);
1771 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1774 if (this.isVisible()) {
1778 this.show(this.triggerEl, false, false);
1787 hideMenuItems : function()
1789 //$(backdrop).remove()
1790 Roo.select('.open',true).each(function(aa) {
1792 aa.removeClass('open');
1793 //var parent = getParent($(this))
1794 //var relatedTarget = { relatedTarget: this }
1796 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1797 //if (e.isDefaultPrevented()) return
1798 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1801 addxtypeChild : function (tree, cntr) {
1802 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1804 this.menuitems.add(comp);
1825 * @class Roo.bootstrap.MenuItem
1826 * @extends Roo.bootstrap.Component
1827 * Bootstrap MenuItem class
1828 * @cfg {String} html the menu label
1829 * @cfg {String} href the link
1830 * @cfg {Boolean} preventDefault (true | false) default true
1834 * Create a new MenuItem
1835 * @param {Object} config The config object
1839 Roo.bootstrap.MenuItem = function(config){
1840 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1845 * The raw click event for the entire grid.
1846 * @param {Roo.EventObject} e
1852 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1856 preventDefault: true,
1858 getAutoCreate : function(){
1861 cls: 'dropdown-menu-item',
1870 if (this.parent().type == 'treeview') {
1871 cfg.cls = 'treeview-menu';
1874 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1875 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1879 initEvents: function() {
1881 //this.el.select('a').on('click', this.onClick, this);
1884 onClick : function(e)
1886 Roo.log('item on click ');
1887 //if(this.preventDefault){
1888 // e.preventDefault();
1890 //this.parent().hideMenuItems();
1892 this.fireEvent('click', this, e);
1911 * @class Roo.bootstrap.MenuSeparator
1912 * @extends Roo.bootstrap.Component
1913 * Bootstrap MenuSeparator class
1916 * Create a new MenuItem
1917 * @param {Object} config The config object
1921 Roo.bootstrap.MenuSeparator = function(config){
1922 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1925 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1927 getAutoCreate : function(){
1942 <div class="modal fade">
1943 <div class="modal-dialog">
1944 <div class="modal-content">
1945 <div class="modal-header">
1946 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1947 <h4 class="modal-title">Modal title</h4>
1949 <div class="modal-body">
1950 <p>One fine body…</p>
1952 <div class="modal-footer">
1953 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1954 <button type="button" class="btn btn-primary">Save changes</button>
1956 </div><!-- /.modal-content -->
1957 </div><!-- /.modal-dialog -->
1958 </div><!-- /.modal -->
1968 * @class Roo.bootstrap.Modal
1969 * @extends Roo.bootstrap.Component
1970 * Bootstrap Modal class
1971 * @cfg {String} title Title of dialog
1972 * @cfg {Boolean} specificTitle (true|false) default false
1973 * @cfg {Array} buttons Array of buttons or standard button set..
1974 * @cfg {String} buttonPosition (left|right|center) default right
1977 * Create a new Modal Dialog
1978 * @param {Object} config The config object
1981 Roo.bootstrap.Modal = function(config){
1982 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1987 * The raw btnclick event for the button
1988 * @param {Roo.EventObject} e
1992 this.buttons = this.buttons || [];
1995 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1997 title : 'test dialog',
2004 specificTitle: false,
2006 buttonPosition: 'right',
2008 onRender : function(ct, position)
2010 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2013 var cfg = Roo.apply({}, this.getAutoCreate());
2016 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2018 //if (!cfg.name.length) {
2022 cfg.cls += ' ' + this.cls;
2025 cfg.style = this.style;
2027 this.el = Roo.get(document.body).createChild(cfg, position);
2029 //var type = this.el.dom.type;
2031 if(this.tabIndex !== undefined){
2032 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2037 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2038 this.maskEl.enableDisplayMode("block");
2040 //this.el.addClass("x-dlg-modal");
2042 if (this.buttons.length) {
2043 Roo.each(this.buttons, function(bb) {
2044 b = Roo.apply({}, bb);
2045 b.xns = b.xns || Roo.bootstrap;
2046 b.xtype = b.xtype || 'Button';
2047 if (typeof(b.listeners) == 'undefined') {
2048 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2051 var btn = Roo.factory(b);
2053 btn.onRender(this.el.select('.modal-footer div').first());
2057 // render the children.
2060 if(typeof(this.items) != 'undefined'){
2061 var items = this.items;
2064 for(var i =0;i < items.length;i++) {
2065 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2069 this.items = nitems;
2071 this.body = this.el.select('.modal-body',true).first();
2072 this.close = this.el.select('.modal-header .close', true).first();
2073 this.footer = this.el.select('.modal-footer',true).first();
2075 //this.el.addClass([this.fieldClass, this.cls]);
2078 getAutoCreate : function(){
2083 html : this.html || ''
2088 cls : 'modal-title',
2092 if(this.specificTitle){
2098 style : 'display: none',
2101 cls: "modal-dialog",
2104 cls : "modal-content",
2107 cls : 'modal-header',
2119 cls : 'modal-footer',
2123 cls: 'btn-' + this.buttonPosition
2142 getChildContainer : function() {
2144 return this.el.select('.modal-body',true).first();
2147 getButtonContainer : function() {
2148 return this.el.select('.modal-footer div',true).first();
2151 initEvents : function()
2153 this.el.select('.modal-header .close').on('click', this.hide, this);
2155 // this.addxtype(this);
2159 if (!this.rendered) {
2163 this.el.addClass('on');
2164 this.el.removeClass('fade');
2165 this.el.setStyle('display', 'block');
2166 Roo.get(document.body).addClass("x-body-masked");
2167 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2169 this.el.setStyle('zIndex', '10001');
2170 this.fireEvent('show', this);
2176 Roo.log('Modal hide?!');
2178 Roo.get(document.body).removeClass("x-body-masked");
2179 this.el.removeClass('on');
2180 this.el.addClass('fade');
2181 this.el.setStyle('display', 'none');
2182 this.fireEvent('hide', this);
2185 addButton : function(str, cb)
2189 var b = Roo.apply({}, { html : str } );
2190 b.xns = b.xns || Roo.bootstrap;
2191 b.xtype = b.xtype || 'Button';
2192 if (typeof(b.listeners) == 'undefined') {
2193 b.listeners = { click : cb.createDelegate(this) };
2196 var btn = Roo.factory(b);
2198 btn.onRender(this.el.select('.modal-footer div').first());
2204 setDefaultButton : function(btn)
2206 //this.el.select('.modal-footer').()
2208 resizeTo: function(w,h)
2212 setContentSize : function(w, h)
2216 onButtonClick: function(btn,e)
2219 this.fireEvent('btnclick', btn.name, e);
2221 setTitle: function(str) {
2222 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2228 Roo.apply(Roo.bootstrap.Modal, {
2230 * Button config that displays a single OK button
2239 * Button config that displays Yes and No buttons
2255 * Button config that displays OK and Cancel buttons
2270 * Button config that displays Yes, No and Cancel buttons
2292 * messagebox - can be used as a replace
2296 * @class Roo.MessageBox
2297 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2301 Roo.Msg.alert('Status', 'Changes saved successfully.');
2303 // Prompt for user data:
2304 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2306 // process text value...
2310 // Show a dialog using config options:
2312 title:'Save Changes?',
2313 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2314 buttons: Roo.Msg.YESNOCANCEL,
2321 Roo.bootstrap.MessageBox = function(){
2322 var dlg, opt, mask, waitTimer;
2323 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2324 var buttons, activeTextEl, bwidth;
2328 var handleButton = function(button){
2330 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2334 var handleHide = function(){
2336 dlg.el.removeClass(opt.cls);
2339 // Roo.TaskMgr.stop(waitTimer);
2340 // waitTimer = null;
2345 var updateButtons = function(b){
2348 buttons["ok"].hide();
2349 buttons["cancel"].hide();
2350 buttons["yes"].hide();
2351 buttons["no"].hide();
2352 //dlg.footer.dom.style.display = 'none';
2355 dlg.footer.dom.style.display = '';
2356 for(var k in buttons){
2357 if(typeof buttons[k] != "function"){
2360 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2361 width += buttons[k].el.getWidth()+15;
2371 var handleEsc = function(d, k, e){
2372 if(opt && opt.closable !== false){
2382 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2383 * @return {Roo.BasicDialog} The BasicDialog element
2385 getDialog : function(){
2387 dlg = new Roo.bootstrap.Modal( {
2390 //constraintoviewport:false,
2392 //collapsible : false,
2397 //buttonAlign:"center",
2398 closeClick : function(){
2399 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2402 handleButton("cancel");
2407 dlg.on("hide", handleHide);
2409 //dlg.addKeyListener(27, handleEsc);
2411 this.buttons = buttons;
2412 var bt = this.buttonText;
2413 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2414 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2415 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2416 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2418 bodyEl = dlg.body.createChild({
2420 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2421 '<textarea class="roo-mb-textarea"></textarea>' +
2422 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2424 msgEl = bodyEl.dom.firstChild;
2425 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2426 textboxEl.enableDisplayMode();
2427 textboxEl.addKeyListener([10,13], function(){
2428 if(dlg.isVisible() && opt && opt.buttons){
2431 }else if(opt.buttons.yes){
2432 handleButton("yes");
2436 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2437 textareaEl.enableDisplayMode();
2438 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2439 progressEl.enableDisplayMode();
2440 var pf = progressEl.dom.firstChild;
2442 pp = Roo.get(pf.firstChild);
2443 pp.setHeight(pf.offsetHeight);
2451 * Updates the message box body text
2452 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2453 * the XHTML-compliant non-breaking space character '&#160;')
2454 * @return {Roo.MessageBox} This message box
2456 updateText : function(text){
2457 if(!dlg.isVisible() && !opt.width){
2458 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2460 msgEl.innerHTML = text || ' ';
2462 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2463 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2465 Math.min(opt.width || cw , this.maxWidth),
2466 Math.max(opt.minWidth || this.minWidth, bwidth)
2469 activeTextEl.setWidth(w);
2471 if(dlg.isVisible()){
2472 dlg.fixedcenter = false;
2474 // to big, make it scroll. = But as usual stupid IE does not support
2477 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2478 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2479 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2481 bodyEl.dom.style.height = '';
2482 bodyEl.dom.style.overflowY = '';
2485 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2487 bodyEl.dom.style.overflowX = '';
2490 dlg.setContentSize(w, bodyEl.getHeight());
2491 if(dlg.isVisible()){
2492 dlg.fixedcenter = true;
2498 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2499 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2500 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2501 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2502 * @return {Roo.MessageBox} This message box
2504 updateProgress : function(value, text){
2506 this.updateText(text);
2508 if (pp) { // weird bug on my firefox - for some reason this is not defined
2509 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2515 * Returns true if the message box is currently displayed
2516 * @return {Boolean} True if the message box is visible, else false
2518 isVisible : function(){
2519 return dlg && dlg.isVisible();
2523 * Hides the message box if it is displayed
2526 if(this.isVisible()){
2532 * Displays a new message box, or reinitializes an existing message box, based on the config options
2533 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2534 * The following config object properties are supported:
2536 Property Type Description
2537 ---------- --------------- ------------------------------------------------------------------------------------
2538 animEl String/Element An id or Element from which the message box should animate as it opens and
2539 closes (defaults to undefined)
2540 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2541 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2542 closable Boolean False to hide the top-right close button (defaults to true). Note that
2543 progress and wait dialogs will ignore this property and always hide the
2544 close button as they can only be closed programmatically.
2545 cls String A custom CSS class to apply to the message box element
2546 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2547 displayed (defaults to 75)
2548 fn Function A callback function to execute after closing the dialog. The arguments to the
2549 function will be btn (the name of the button that was clicked, if applicable,
2550 e.g. "ok"), and text (the value of the active text field, if applicable).
2551 Progress and wait dialogs will ignore this option since they do not respond to
2552 user actions and can only be closed programmatically, so any required function
2553 should be called by the same code after it closes the dialog.
2554 icon String A CSS class that provides a background image to be used as an icon for
2555 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2556 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2557 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2558 modal Boolean False to allow user interaction with the page while the message box is
2559 displayed (defaults to true)
2560 msg String A string that will replace the existing message box body text (defaults
2561 to the XHTML-compliant non-breaking space character ' ')
2562 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2563 progress Boolean True to display a progress bar (defaults to false)
2564 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2565 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2566 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2567 title String The title text
2568 value String The string value to set into the active textbox element if displayed
2569 wait Boolean True to display a progress bar (defaults to false)
2570 width Number The width of the dialog in pixels
2577 msg: 'Please enter your address:',
2579 buttons: Roo.MessageBox.OKCANCEL,
2582 animEl: 'addAddressBtn'
2585 * @param {Object} config Configuration options
2586 * @return {Roo.MessageBox} This message box
2588 show : function(options)
2591 // this causes nightmares if you show one dialog after another
2592 // especially on callbacks..
2594 if(this.isVisible()){
2597 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2598 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2599 Roo.log("New Dialog Message:" + options.msg )
2600 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2601 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2604 var d = this.getDialog();
2606 d.setTitle(opt.title || " ");
2607 d.close.setDisplayed(opt.closable !== false);
2608 activeTextEl = textboxEl;
2609 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2614 textareaEl.setHeight(typeof opt.multiline == "number" ?
2615 opt.multiline : this.defaultTextHeight);
2616 activeTextEl = textareaEl;
2625 progressEl.setDisplayed(opt.progress === true);
2626 this.updateProgress(0);
2627 activeTextEl.dom.value = opt.value || "";
2629 dlg.setDefaultButton(activeTextEl);
2631 var bs = opt.buttons;
2635 }else if(bs && bs.yes){
2636 db = buttons["yes"];
2638 dlg.setDefaultButton(db);
2640 bwidth = updateButtons(opt.buttons);
2641 this.updateText(opt.msg);
2643 d.el.addClass(opt.cls);
2645 d.proxyDrag = opt.proxyDrag === true;
2646 d.modal = opt.modal !== false;
2647 d.mask = opt.modal !== false ? mask : false;
2649 // force it to the end of the z-index stack so it gets a cursor in FF
2650 document.body.appendChild(dlg.el.dom);
2651 d.animateTarget = null;
2652 d.show(options.animEl);
2658 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2659 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2660 * and closing the message box when the process is complete.
2661 * @param {String} title The title bar text
2662 * @param {String} msg The message box body text
2663 * @return {Roo.MessageBox} This message box
2665 progress : function(title, msg){
2672 minWidth: this.minProgressWidth,
2679 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2680 * If a callback function is passed it will be called after the user clicks the button, and the
2681 * id of the button that was clicked will be passed as the only parameter to the callback
2682 * (could also be the top-right close button).
2683 * @param {String} title The title bar text
2684 * @param {String} msg The message box body text
2685 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2686 * @param {Object} scope (optional) The scope of the callback function
2687 * @return {Roo.MessageBox} This message box
2689 alert : function(title, msg, fn, scope){
2702 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2703 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2704 * You are responsible for closing the message box when the process is complete.
2705 * @param {String} msg The message box body text
2706 * @param {String} title (optional) The title bar text
2707 * @return {Roo.MessageBox} This message box
2709 wait : function(msg, title){
2720 waitTimer = Roo.TaskMgr.start({
2722 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2730 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2731 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2732 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2733 * @param {String} title The title bar text
2734 * @param {String} msg The message box body text
2735 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2736 * @param {Object} scope (optional) The scope of the callback function
2737 * @return {Roo.MessageBox} This message box
2739 confirm : function(title, msg, fn, scope){
2743 buttons: this.YESNO,
2752 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2753 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2754 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2755 * (could also be the top-right close button) and the text that was entered will be passed as the two
2756 * parameters to the callback.
2757 * @param {String} title The title bar text
2758 * @param {String} msg The message box body text
2759 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2760 * @param {Object} scope (optional) The scope of the callback function
2761 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2762 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2763 * @return {Roo.MessageBox} This message box
2765 prompt : function(title, msg, fn, scope, multiline){
2769 buttons: this.OKCANCEL,
2774 multiline: multiline,
2781 * Button config that displays a single OK button
2786 * Button config that displays Yes and No buttons
2789 YESNO : {yes:true, no:true},
2791 * Button config that displays OK and Cancel buttons
2794 OKCANCEL : {ok:true, cancel:true},
2796 * Button config that displays Yes, No and Cancel buttons
2799 YESNOCANCEL : {yes:true, no:true, cancel:true},
2802 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2805 defaultTextHeight : 75,
2807 * The maximum width in pixels of the message box (defaults to 600)
2812 * The minimum width in pixels of the message box (defaults to 100)
2817 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2818 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2821 minProgressWidth : 250,
2823 * An object containing the default button text strings that can be overriden for localized language support.
2824 * Supported properties are: ok, cancel, yes and no.
2825 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2838 * Shorthand for {@link Roo.MessageBox}
2840 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2841 Roo.Msg = Roo.Msg || Roo.MessageBox;
2850 * @class Roo.bootstrap.Navbar
2851 * @extends Roo.bootstrap.Component
2852 * Bootstrap Navbar class
2855 * Create a new Navbar
2856 * @param {Object} config The config object
2860 Roo.bootstrap.Navbar = function(config){
2861 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2865 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2874 getAutoCreate : function(){
2877 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2881 initEvents :function ()
2883 //Roo.log(this.el.select('.navbar-toggle',true));
2884 this.el.select('.navbar-toggle',true).on('click', function() {
2885 // Roo.log('click');
2886 this.el.select('.navbar-collapse',true).toggleClass('in');
2894 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2896 var size = this.el.getSize();
2897 this.maskEl.setSize(size.width, size.height);
2898 this.maskEl.enableDisplayMode("block");
2907 getChildContainer : function()
2909 if (this.el.select('.collapse').getCount()) {
2910 return this.el.select('.collapse',true).first();
2943 * @class Roo.bootstrap.NavSimplebar
2944 * @extends Roo.bootstrap.Navbar
2945 * Bootstrap Sidebar class
2947 * @cfg {Boolean} inverse is inverted color
2949 * @cfg {String} type (nav | pills | tabs)
2950 * @cfg {Boolean} arrangement stacked | justified
2951 * @cfg {String} align (left | right) alignment
2953 * @cfg {Boolean} main (true|false) main nav bar? default false
2954 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2956 * @cfg {String} tag (header|footer|nav|div) default is nav
2962 * Create a new Sidebar
2963 * @param {Object} config The config object
2967 Roo.bootstrap.NavSimplebar = function(config){
2968 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2971 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2987 getAutoCreate : function(){
2991 tag : this.tag || 'div',
3004 this.type = this.type || 'nav';
3005 if (['tabs','pills'].indexOf(this.type)!==-1) {
3006 cfg.cn[0].cls += ' nav-' + this.type
3010 if (this.type!=='nav') {
3011 Roo.log('nav type must be nav/tabs/pills')
3013 cfg.cn[0].cls += ' navbar-nav'
3019 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3020 cfg.cn[0].cls += ' nav-' + this.arrangement;
3024 if (this.align === 'right') {
3025 cfg.cn[0].cls += ' navbar-right';
3029 cfg.cls += ' navbar-inverse';
3056 * @class Roo.bootstrap.NavHeaderbar
3057 * @extends Roo.bootstrap.NavSimplebar
3058 * Bootstrap Sidebar class
3060 * @cfg {String} brand what is brand
3061 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3062 * @cfg {String} brand_href href of the brand
3063 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3064 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3067 * Create a new Sidebar
3068 * @param {Object} config The config object
3072 Roo.bootstrap.NavHeaderbar = function(config){
3073 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3076 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3084 getAutoCreate : function(){
3087 tag: this.nav || 'nav',
3096 cls: 'navbar-header',
3101 cls: 'navbar-toggle',
3102 'data-toggle': 'collapse',
3107 html: 'Toggle navigation'
3129 cls: 'collapse navbar-collapse',
3133 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3135 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3136 cfg.cls += ' navbar-' + this.position;
3138 // tag can override this..
3140 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3143 if (this.brand !== '') {
3146 href: this.brand_href ? this.brand_href : '#',
3147 cls: 'navbar-brand',
3155 cfg.cls += ' main-nav';
3163 initEvents : function()
3165 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3167 if (this.autohide) {
3172 Roo.get(document).on('scroll',function(e) {
3173 var ns = Roo.get(document).getScroll().top;
3174 var os = prevScroll;
3178 ft.removeClass('slideDown');
3179 ft.addClass('slideUp');
3182 ft.removeClass('slideUp');
3183 ft.addClass('slideDown');
3207 * @class Roo.bootstrap.NavSidebar
3208 * @extends Roo.bootstrap.Navbar
3209 * Bootstrap Sidebar class
3212 * Create a new Sidebar
3213 * @param {Object} config The config object
3217 Roo.bootstrap.NavSidebar = function(config){
3218 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3221 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3223 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3225 getAutoCreate : function(){
3230 cls: 'sidebar sidebar-nav'
3252 * @class Roo.bootstrap.NavGroup
3253 * @extends Roo.bootstrap.Component
3254 * Bootstrap NavGroup class
3255 * @cfg {String} align left | right
3256 * @cfg {Boolean} inverse false | true
3257 * @cfg {String} type (nav|pills|tab) default nav
3258 * @cfg {String} navId - reference Id for navbar.
3262 * Create a new nav group
3263 * @param {Object} config The config object
3266 Roo.bootstrap.NavGroup = function(config){
3267 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3270 Roo.bootstrap.NavGroup.register(this);
3274 * Fires when the active item changes
3275 * @param {Roo.bootstrap.NavGroup} this
3276 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3277 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3284 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3295 getAutoCreate : function()
3297 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3304 if (['tabs','pills'].indexOf(this.type)!==-1) {
3305 cfg.cls += ' nav-' + this.type
3307 if (this.type!=='nav') {
3308 Roo.log('nav type must be nav/tabs/pills')
3310 cfg.cls += ' navbar-nav'
3313 if (this.parent().sidebar) {
3316 cls: 'dashboard-menu sidebar-menu'
3322 if (this.form === true) {
3328 if (this.align === 'right') {
3329 cfg.cls += ' navbar-right';
3331 cfg.cls += ' navbar-left';
3335 if (this.align === 'right') {
3336 cfg.cls += ' navbar-right';
3340 cfg.cls += ' navbar-inverse';
3348 * sets the active Navigation item
3349 * @param {Roo.bootstrap.NavItem} the new current navitem
3351 setActiveItem : function(item)
3354 Roo.each(this.navItems, function(v){
3359 v.setActive(false, true);
3366 item.setActive(true, true);
3367 this.fireEvent('changed', this, item, prev);
3372 * gets the active Navigation item
3373 * @return {Roo.bootstrap.NavItem} the current navitem
3375 getActive : function()
3379 Roo.each(this.navItems, function(v){
3390 indexOfNav : function()
3394 Roo.each(this.navItems, function(v,i){
3405 * adds a Navigation item
3406 * @param {Roo.bootstrap.NavItem} the navitem to add
3408 addItem : function(cfg)
3410 var cn = new Roo.bootstrap.NavItem(cfg);
3412 cn.parentId = this.id;
3413 cn.onRender(this.el, null);
3417 * register a Navigation item
3418 * @param {Roo.bootstrap.NavItem} the navitem to add
3420 register : function(item)
3422 this.navItems.push( item);
3423 item.navId = this.navId;
3428 getNavItem: function(tabId)
3431 Roo.each(this.navItems, function(e) {
3432 if (e.tabId == tabId) {
3442 setActiveNext : function()
3444 var i = this.indexOfNav(this.getActive());
3445 if (i > this.navItems.length) {
3448 this.setActiveItem(this.navItems[i+1]);
3450 setActivePrev : function()
3452 var i = this.indexOfNav(this.getActive());
3456 this.setActiveItem(this.navItems[i-1]);
3458 clearWasActive : function(except) {
3459 Roo.each(this.navItems, function(e) {
3460 if (e.tabId != except.tabId && e.was_active) {
3461 e.was_active = false;
3468 getWasActive : function ()
3471 Roo.each(this.navItems, function(e) {
3486 Roo.apply(Roo.bootstrap.NavGroup, {
3490 * register a Navigation Group
3491 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3493 register : function(navgrp)
3495 this.groups[navgrp.navId] = navgrp;
3499 * fetch a Navigation Group based on the navigation ID
3500 * @param {string} the navgroup to add
3501 * @returns {Roo.bootstrap.NavGroup} the navgroup
3503 get: function(navId) {
3504 if (typeof(this.groups[navId]) == 'undefined') {
3506 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3508 return this.groups[navId] ;
3523 * @class Roo.bootstrap.NavItem
3524 * @extends Roo.bootstrap.Component
3525 * Bootstrap Navbar.NavItem class
3526 * @cfg {String} href link to
3527 * @cfg {String} html content of button
3528 * @cfg {String} badge text inside badge
3529 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3530 * @cfg {String} glyphicon name of glyphicon
3531 * @cfg {String} icon name of font awesome icon
3532 * @cfg {Boolean} active Is item active
3533 * @cfg {Boolean} disabled Is item disabled
3535 * @cfg {Boolean} preventDefault (true | false) default false
3536 * @cfg {String} tabId the tab that this item activates.
3537 * @cfg {String} tagtype (a|span) render as a href or span?
3540 * Create a new Navbar Item
3541 * @param {Object} config The config object
3543 Roo.bootstrap.NavItem = function(config){
3544 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3549 * The raw click event for the entire grid.
3550 * @param {Roo.EventObject} e
3555 * Fires when the active item active state changes
3556 * @param {Roo.bootstrap.NavItem} this
3557 * @param {boolean} state the new state
3565 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3573 preventDefault : false,
3580 getAutoCreate : function(){
3588 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3590 if (this.disabled) {
3591 cfg.cls += ' disabled';
3594 if (this.href || this.html || this.glyphicon || this.icon) {
3598 href : this.href || "#",
3599 html: this.html || ''
3604 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3607 if(this.glyphicon) {
3608 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3613 cfg.cn[0].html += " <span class='caret'></span>";
3617 if (this.badge !== '') {
3619 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3627 initEvents: function() {
3628 // Roo.log('init events?');
3629 // Roo.log(this.el.dom);
3630 if (typeof (this.menu) != 'undefined') {
3631 this.menu.parentType = this.xtype;
3632 this.menu.triggerEl = this.el;
3633 this.addxtype(Roo.apply({}, this.menu));
3637 this.el.select('a',true).on('click', this.onClick, this);
3638 // at this point parent should be available..
3639 this.parent().register(this);
3642 onClick : function(e)
3645 if(this.preventDefault){
3648 if (this.disabled) {
3652 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3653 if (tg && tg.transition) {
3654 Roo.log("waiting for the transitionend");
3658 Roo.log("fire event clicked");
3659 if(this.fireEvent('click', this, e) === false){
3663 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3664 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3665 this.parent().setActiveItem(this);
3670 isActive: function () {
3673 setActive : function(state, fire, is_was_active)
3675 if (this.active && !state & this.navId) {
3676 this.was_active = true;
3677 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3679 nv.clearWasActive(this);
3683 this.active = state;
3686 this.el.removeClass('active');
3687 } else if (!this.el.hasClass('active')) {
3688 this.el.addClass('active');
3691 this.fireEvent('changed', this, state);
3694 // show a panel if it's registered and related..
3696 if (!this.navId || !this.tabId || !state || is_was_active) {
3700 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3704 var pan = tg.getPanelByName(this.tabId);
3708 // if we can not flip to new panel - go back to old nav highlight..
3709 if (false == tg.showPanel(pan)) {
3710 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3712 var onav = nv.getWasActive();
3714 onav.setActive(true, false, true);
3723 // this should not be here...
3724 setDisabled : function(state)
3726 this.disabled = state;
3728 this.el.removeClass('disabled');
3729 } else if (!this.el.hasClass('disabled')) {
3730 this.el.addClass('disabled');
3743 * <span> icon </span>
3744 * <span> text </span>
3745 * <span>badge </span>
3749 * @class Roo.bootstrap.NavSidebarItem
3750 * @extends Roo.bootstrap.NavItem
3751 * Bootstrap Navbar.NavSidebarItem class
3753 * Create a new Navbar Button
3754 * @param {Object} config The config object
3756 Roo.bootstrap.NavSidebarItem = function(config){
3757 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3762 * The raw click event for the entire grid.
3763 * @param {Roo.EventObject} e
3768 * Fires when the active item active state changes
3769 * @param {Roo.bootstrap.NavSidebarItem} this
3770 * @param {boolean} state the new state
3778 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3781 getAutoCreate : function(){
3786 href : this.href || '#',
3798 html : this.html || ''
3803 cfg.cls += ' active';
3807 if (this.glyphicon || this.icon) {
3808 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3809 a.cn.push({ tag : 'i', cls : c }) ;
3814 if (this.badge !== '') {
3815 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3819 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3820 a.cls += 'dropdown-toggle treeview' ;
3844 * @class Roo.bootstrap.Row
3845 * @extends Roo.bootstrap.Component
3846 * Bootstrap Row class (contains columns...)
3850 * @param {Object} config The config object
3853 Roo.bootstrap.Row = function(config){
3854 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3857 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3859 getAutoCreate : function(){
3878 * @class Roo.bootstrap.Element
3879 * @extends Roo.bootstrap.Component
3880 * Bootstrap Element class
3881 * @cfg {String} html contents of the element
3882 * @cfg {String} tag tag of the element
3883 * @cfg {String} cls class of the element
3886 * Create a new Element
3887 * @param {Object} config The config object
3890 Roo.bootstrap.Element = function(config){
3891 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3894 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3901 getAutoCreate : function(){
3926 * @class Roo.bootstrap.Pagination
3927 * @extends Roo.bootstrap.Component
3928 * Bootstrap Pagination class
3929 * @cfg {String} size xs | sm | md | lg
3930 * @cfg {Boolean} inverse false | true
3933 * Create a new Pagination
3934 * @param {Object} config The config object
3937 Roo.bootstrap.Pagination = function(config){
3938 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3941 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3947 getAutoCreate : function(){
3953 cfg.cls += ' inverse';
3959 cfg.cls += " " + this.cls;
3977 * @class Roo.bootstrap.PaginationItem
3978 * @extends Roo.bootstrap.Component
3979 * Bootstrap PaginationItem class
3980 * @cfg {String} html text
3981 * @cfg {String} href the link
3982 * @cfg {Boolean} preventDefault (true | false) default true
3983 * @cfg {Boolean} active (true | false) default false
3987 * Create a new PaginationItem
3988 * @param {Object} config The config object
3992 Roo.bootstrap.PaginationItem = function(config){
3993 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3998 * The raw click event for the entire grid.
3999 * @param {Roo.EventObject} e
4005 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4009 preventDefault: true,
4013 getAutoCreate : function(){
4019 href : this.href ? this.href : '#',
4020 html : this.html ? this.html : ''
4030 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4036 initEvents: function() {
4038 this.el.on('click', this.onClick, this);
4041 onClick : function(e)
4043 Roo.log('PaginationItem on click ');
4044 if(this.preventDefault){
4048 this.fireEvent('click', this, e);
4064 * @class Roo.bootstrap.Slider
4065 * @extends Roo.bootstrap.Component
4066 * Bootstrap Slider class
4069 * Create a new Slider
4070 * @param {Object} config The config object
4073 Roo.bootstrap.Slider = function(config){
4074 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4077 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4079 getAutoCreate : function(){
4083 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4087 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4099 * Ext JS Library 1.1.1
4100 * Copyright(c) 2006-2007, Ext JS, LLC.
4102 * Originally Released Under LGPL - original licence link has changed is not relivant.
4105 * <script type="text/javascript">
4110 * @class Roo.grid.ColumnModel
4111 * @extends Roo.util.Observable
4112 * This is the default implementation of a ColumnModel used by the Grid. It defines
4113 * the columns in the grid.
4116 var colModel = new Roo.grid.ColumnModel([
4117 {header: "Ticker", width: 60, sortable: true, locked: true},
4118 {header: "Company Name", width: 150, sortable: true},
4119 {header: "Market Cap.", width: 100, sortable: true},
4120 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4121 {header: "Employees", width: 100, sortable: true, resizable: false}
4126 * The config options listed for this class are options which may appear in each
4127 * individual column definition.
4128 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4130 * @param {Object} config An Array of column config objects. See this class's
4131 * config objects for details.
4133 Roo.grid.ColumnModel = function(config){
4135 * The config passed into the constructor
4137 this.config = config;
4140 // if no id, create one
4141 // if the column does not have a dataIndex mapping,
4142 // map it to the order it is in the config
4143 for(var i = 0, len = config.length; i < len; i++){
4145 if(typeof c.dataIndex == "undefined"){
4148 if(typeof c.renderer == "string"){
4149 c.renderer = Roo.util.Format[c.renderer];
4151 if(typeof c.id == "undefined"){
4154 if(c.editor && c.editor.xtype){
4155 c.editor = Roo.factory(c.editor, Roo.grid);
4157 if(c.editor && c.editor.isFormField){
4158 c.editor = new Roo.grid.GridEditor(c.editor);
4160 this.lookup[c.id] = c;
4164 * The width of columns which have no width specified (defaults to 100)
4167 this.defaultWidth = 100;
4170 * Default sortable of columns which have no sortable specified (defaults to false)
4173 this.defaultSortable = false;
4177 * @event widthchange
4178 * Fires when the width of a column changes.
4179 * @param {ColumnModel} this
4180 * @param {Number} columnIndex The column index
4181 * @param {Number} newWidth The new width
4183 "widthchange": true,
4185 * @event headerchange
4186 * Fires when the text of a header changes.
4187 * @param {ColumnModel} this
4188 * @param {Number} columnIndex The column index
4189 * @param {Number} newText The new header text
4191 "headerchange": true,
4193 * @event hiddenchange
4194 * Fires when a column is hidden or "unhidden".
4195 * @param {ColumnModel} this
4196 * @param {Number} columnIndex The column index
4197 * @param {Boolean} hidden true if hidden, false otherwise
4199 "hiddenchange": true,
4201 * @event columnmoved
4202 * Fires when a column is moved.
4203 * @param {ColumnModel} this
4204 * @param {Number} oldIndex
4205 * @param {Number} newIndex
4207 "columnmoved" : true,
4209 * @event columlockchange
4210 * Fires when a column's locked state is changed
4211 * @param {ColumnModel} this
4212 * @param {Number} colIndex
4213 * @param {Boolean} locked true if locked
4215 "columnlockchange" : true
4217 Roo.grid.ColumnModel.superclass.constructor.call(this);
4219 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4221 * @cfg {String} header The header text to display in the Grid view.
4224 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4225 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4226 * specified, the column's index is used as an index into the Record's data Array.
4229 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4230 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4233 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4234 * Defaults to the value of the {@link #defaultSortable} property.
4235 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4238 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4241 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4244 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4247 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4250 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4251 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4252 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4253 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4256 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4259 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4263 * Returns the id of the column at the specified index.
4264 * @param {Number} index The column index
4265 * @return {String} the id
4267 getColumnId : function(index){
4268 return this.config[index].id;
4272 * Returns the column for a specified id.
4273 * @param {String} id The column id
4274 * @return {Object} the column
4276 getColumnById : function(id){
4277 return this.lookup[id];
4282 * Returns the column for a specified dataIndex.
4283 * @param {String} dataIndex The column dataIndex
4284 * @return {Object|Boolean} the column or false if not found
4286 getColumnByDataIndex: function(dataIndex){
4287 var index = this.findColumnIndex(dataIndex);
4288 return index > -1 ? this.config[index] : false;
4292 * Returns the index for a specified column id.
4293 * @param {String} id The column id
4294 * @return {Number} the index, or -1 if not found
4296 getIndexById : function(id){
4297 for(var i = 0, len = this.config.length; i < len; i++){
4298 if(this.config[i].id == id){
4306 * Returns the index for a specified column dataIndex.
4307 * @param {String} dataIndex The column dataIndex
4308 * @return {Number} the index, or -1 if not found
4311 findColumnIndex : function(dataIndex){
4312 for(var i = 0, len = this.config.length; i < len; i++){
4313 if(this.config[i].dataIndex == dataIndex){
4321 moveColumn : function(oldIndex, newIndex){
4322 var c = this.config[oldIndex];
4323 this.config.splice(oldIndex, 1);
4324 this.config.splice(newIndex, 0, c);
4325 this.dataMap = null;
4326 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4329 isLocked : function(colIndex){
4330 return this.config[colIndex].locked === true;
4333 setLocked : function(colIndex, value, suppressEvent){
4334 if(this.isLocked(colIndex) == value){
4337 this.config[colIndex].locked = value;
4339 this.fireEvent("columnlockchange", this, colIndex, value);
4343 getTotalLockedWidth : function(){
4345 for(var i = 0; i < this.config.length; i++){
4346 if(this.isLocked(i) && !this.isHidden(i)){
4347 this.totalWidth += this.getColumnWidth(i);
4353 getLockedCount : function(){
4354 for(var i = 0, len = this.config.length; i < len; i++){
4355 if(!this.isLocked(i)){
4362 * Returns the number of columns.
4365 getColumnCount : function(visibleOnly){
4366 if(visibleOnly === true){
4368 for(var i = 0, len = this.config.length; i < len; i++){
4369 if(!this.isHidden(i)){
4375 return this.config.length;
4379 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4380 * @param {Function} fn
4381 * @param {Object} scope (optional)
4382 * @return {Array} result
4384 getColumnsBy : function(fn, scope){
4386 for(var i = 0, len = this.config.length; i < len; i++){
4387 var c = this.config[i];
4388 if(fn.call(scope||this, c, i) === true){
4396 * Returns true if the specified column is sortable.
4397 * @param {Number} col The column index
4400 isSortable : function(col){
4401 if(typeof this.config[col].sortable == "undefined"){
4402 return this.defaultSortable;
4404 return this.config[col].sortable;
4408 * Returns the rendering (formatting) function defined for the column.
4409 * @param {Number} col The column index.
4410 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4412 getRenderer : function(col){
4413 if(!this.config[col].renderer){
4414 return Roo.grid.ColumnModel.defaultRenderer;
4416 return this.config[col].renderer;
4420 * Sets the rendering (formatting) function for a column.
4421 * @param {Number} col The column index
4422 * @param {Function} fn The function to use to process the cell's raw data
4423 * to return HTML markup for the grid view. The render function is called with
4424 * the following parameters:<ul>
4425 * <li>Data value.</li>
4426 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4427 * <li>css A CSS style string to apply to the table cell.</li>
4428 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4429 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4430 * <li>Row index</li>
4431 * <li>Column index</li>
4432 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4434 setRenderer : function(col, fn){
4435 this.config[col].renderer = fn;
4439 * Returns the width for the specified column.
4440 * @param {Number} col The column index
4443 getColumnWidth : function(col){
4444 return this.config[col].width * 1 || this.defaultWidth;
4448 * Sets the width for a column.
4449 * @param {Number} col The column index
4450 * @param {Number} width The new width
4452 setColumnWidth : function(col, width, suppressEvent){
4453 this.config[col].width = width;
4454 this.totalWidth = null;
4456 this.fireEvent("widthchange", this, col, width);
4461 * Returns the total width of all columns.
4462 * @param {Boolean} includeHidden True to include hidden column widths
4465 getTotalWidth : function(includeHidden){
4466 if(!this.totalWidth){
4467 this.totalWidth = 0;
4468 for(var i = 0, len = this.config.length; i < len; i++){
4469 if(includeHidden || !this.isHidden(i)){
4470 this.totalWidth += this.getColumnWidth(i);
4474 return this.totalWidth;
4478 * Returns the header for the specified column.
4479 * @param {Number} col The column index
4482 getColumnHeader : function(col){
4483 return this.config[col].header;
4487 * Sets the header for a column.
4488 * @param {Number} col The column index
4489 * @param {String} header The new header
4491 setColumnHeader : function(col, header){
4492 this.config[col].header = header;
4493 this.fireEvent("headerchange", this, col, header);
4497 * Returns the tooltip for the specified column.
4498 * @param {Number} col The column index
4501 getColumnTooltip : function(col){
4502 return this.config[col].tooltip;
4505 * Sets the tooltip for a column.
4506 * @param {Number} col The column index
4507 * @param {String} tooltip The new tooltip
4509 setColumnTooltip : function(col, tooltip){
4510 this.config[col].tooltip = tooltip;
4514 * Returns the dataIndex for the specified column.
4515 * @param {Number} col The column index
4518 getDataIndex : function(col){
4519 return this.config[col].dataIndex;
4523 * Sets the dataIndex for a column.
4524 * @param {Number} col The column index
4525 * @param {Number} dataIndex The new dataIndex
4527 setDataIndex : function(col, dataIndex){
4528 this.config[col].dataIndex = dataIndex;
4534 * Returns true if the cell is editable.
4535 * @param {Number} colIndex The column index
4536 * @param {Number} rowIndex The row index
4539 isCellEditable : function(colIndex, rowIndex){
4540 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4544 * Returns the editor defined for the cell/column.
4545 * return false or null to disable editing.
4546 * @param {Number} colIndex The column index
4547 * @param {Number} rowIndex The row index
4550 getCellEditor : function(colIndex, rowIndex){
4551 return this.config[colIndex].editor;
4555 * Sets if a column is editable.
4556 * @param {Number} col The column index
4557 * @param {Boolean} editable True if the column is editable
4559 setEditable : function(col, editable){
4560 this.config[col].editable = editable;
4565 * Returns true if the column is hidden.
4566 * @param {Number} colIndex The column index
4569 isHidden : function(colIndex){
4570 return this.config[colIndex].hidden;
4575 * Returns true if the column width cannot be changed
4577 isFixed : function(colIndex){
4578 return this.config[colIndex].fixed;
4582 * Returns true if the column can be resized
4585 isResizable : function(colIndex){
4586 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4589 * Sets if a column is hidden.
4590 * @param {Number} colIndex The column index
4591 * @param {Boolean} hidden True if the column is hidden
4593 setHidden : function(colIndex, hidden){
4594 this.config[colIndex].hidden = hidden;
4595 this.totalWidth = null;
4596 this.fireEvent("hiddenchange", this, colIndex, hidden);
4600 * Sets the editor for a column.
4601 * @param {Number} col The column index
4602 * @param {Object} editor The editor object
4604 setEditor : function(col, editor){
4605 this.config[col].editor = editor;
4609 Roo.grid.ColumnModel.defaultRenderer = function(value){
4610 if(typeof value == "string" && value.length < 1){
4616 // Alias for backwards compatibility
4617 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4620 * Ext JS Library 1.1.1
4621 * Copyright(c) 2006-2007, Ext JS, LLC.
4623 * Originally Released Under LGPL - original licence link has changed is not relivant.
4626 * <script type="text/javascript">
4630 * @class Roo.LoadMask
4631 * A simple utility class for generically masking elements while loading data. If the element being masked has
4632 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4633 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4634 * element's UpdateManager load indicator and will be destroyed after the initial load.
4636 * Create a new LoadMask
4637 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4638 * @param {Object} config The config object
4640 Roo.LoadMask = function(el, config){
4641 this.el = Roo.get(el);
4642 Roo.apply(this, config);
4644 this.store.on('beforeload', this.onBeforeLoad, this);
4645 this.store.on('load', this.onLoad, this);
4646 this.store.on('loadexception', this.onLoadException, this);
4647 this.removeMask = false;
4649 var um = this.el.getUpdateManager();
4650 um.showLoadIndicator = false; // disable the default indicator
4651 um.on('beforeupdate', this.onBeforeLoad, this);
4652 um.on('update', this.onLoad, this);
4653 um.on('failure', this.onLoad, this);
4654 this.removeMask = true;
4658 Roo.LoadMask.prototype = {
4660 * @cfg {Boolean} removeMask
4661 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4662 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4666 * The text to display in a centered loading message box (defaults to 'Loading...')
4670 * @cfg {String} msgCls
4671 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4673 msgCls : 'x-mask-loading',
4676 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4682 * Disables the mask to prevent it from being displayed
4684 disable : function(){
4685 this.disabled = true;
4689 * Enables the mask so that it can be displayed
4691 enable : function(){
4692 this.disabled = false;
4695 onLoadException : function()
4699 if (typeof(arguments[3]) != 'undefined') {
4700 Roo.MessageBox.alert("Error loading",arguments[3]);
4704 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4705 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4714 this.el.unmask(this.removeMask);
4719 this.el.unmask(this.removeMask);
4723 onBeforeLoad : function(){
4725 this.el.mask(this.msg, this.msgCls);
4730 destroy : function(){
4732 this.store.un('beforeload', this.onBeforeLoad, this);
4733 this.store.un('load', this.onLoad, this);
4734 this.store.un('loadexception', this.onLoadException, this);
4736 var um = this.el.getUpdateManager();
4737 um.un('beforeupdate', this.onBeforeLoad, this);
4738 um.un('update', this.onLoad, this);
4739 um.un('failure', this.onLoad, this);
4750 * @class Roo.bootstrap.Table
4751 * @extends Roo.bootstrap.Component
4752 * Bootstrap Table class
4753 * @cfg {String} cls table class
4754 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4755 * @cfg {String} bgcolor Specifies the background color for a table
4756 * @cfg {Number} border Specifies whether the table cells should have borders or not
4757 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4758 * @cfg {Number} cellspacing Specifies the space between cells
4759 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4760 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4761 * @cfg {String} sortable Specifies that the table should be sortable
4762 * @cfg {String} summary Specifies a summary of the content of a table
4763 * @cfg {Number} width Specifies the width of a table
4764 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4766 * @cfg {boolean} striped Should the rows be alternative striped
4767 * @cfg {boolean} bordered Add borders to the table
4768 * @cfg {boolean} hover Add hover highlighting
4769 * @cfg {boolean} condensed Format condensed
4770 * @cfg {boolean} responsive Format condensed
4771 * @cfg {Boolean} loadMask (true|false) default false
4772 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4773 * @cfg {Boolean} thead (true|false) generate thead, default true
4774 * @cfg {Boolean} RowSelection (true|false) default false
4775 * @cfg {Boolean} CellSelection (true|false) default false
4777 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4781 * Create a new Table
4782 * @param {Object} config The config object
4785 Roo.bootstrap.Table = function(config){
4786 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4789 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4790 this.sm = this.selModel;
4791 this.sm.xmodule = this.xmodule || false;
4793 if (this.cm && typeof(this.cm.config) == 'undefined') {
4794 this.colModel = new Roo.grid.ColumnModel(this.cm);
4795 this.cm = this.colModel;
4796 this.cm.xmodule = this.xmodule || false;
4799 this.store= Roo.factory(this.store, Roo.data);
4800 this.ds = this.store;
4801 this.ds.xmodule = this.xmodule || false;
4804 if (this.footer && this.store) {
4805 this.footer.dataSource = this.ds;
4806 this.footer = Roo.factory(this.footer);
4813 * Fires when a cell is clicked
4814 * @param {Roo.bootstrap.Table} this
4815 * @param {Roo.Element} el
4816 * @param {Number} rowIndex
4817 * @param {Number} columnIndex
4818 * @param {Roo.EventObject} e
4822 * @event celldblclick
4823 * Fires when a cell is double clicked
4824 * @param {Roo.bootstrap.Table} this
4825 * @param {Roo.Element} el
4826 * @param {Number} rowIndex
4827 * @param {Number} columnIndex
4828 * @param {Roo.EventObject} e
4830 "celldblclick" : true,
4833 * Fires when a row is clicked
4834 * @param {Roo.bootstrap.Table} this
4835 * @param {Roo.Element} el
4836 * @param {Number} rowIndex
4837 * @param {Roo.EventObject} e
4841 * @event rowdblclick
4842 * Fires when a row is double clicked
4843 * @param {Roo.bootstrap.Table} this
4844 * @param {Roo.Element} el
4845 * @param {Number} rowIndex
4846 * @param {Roo.EventObject} e
4848 "rowdblclick" : true,
4851 * Fires when a mouseover occur
4852 * @param {Roo.bootstrap.Table} this
4853 * @param {Roo.Element} el
4854 * @param {Number} rowIndex
4855 * @param {Number} columnIndex
4856 * @param {Roo.EventObject} e
4861 * Fires when a mouseout occur
4862 * @param {Roo.bootstrap.Table} this
4863 * @param {Roo.Element} el
4864 * @param {Number} rowIndex
4865 * @param {Number} columnIndex
4866 * @param {Roo.EventObject} e
4871 * Fires when a row is rendered, so you can change add a style to it.
4872 * @param {Roo.bootstrap.Table} this
4873 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4880 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4904 RowSelection : false,
4905 CellSelection : false,
4908 // Roo.Element - the tbody
4911 getAutoCreate : function(){
4912 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4921 cfg.cls += ' table-striped';
4925 cfg.cls += ' table-hover';
4927 if (this.bordered) {
4928 cfg.cls += ' table-bordered';
4930 if (this.condensed) {
4931 cfg.cls += ' table-condensed';
4933 if (this.responsive) {
4934 cfg.cls += ' table-responsive';
4938 cfg.cls+= ' ' +this.cls;
4941 // this lot should be simplifed...
4944 cfg.align=this.align;
4947 cfg.bgcolor=this.bgcolor;
4950 cfg.border=this.border;
4952 if (this.cellpadding) {
4953 cfg.cellpadding=this.cellpadding;
4955 if (this.cellspacing) {
4956 cfg.cellspacing=this.cellspacing;
4959 cfg.frame=this.frame;
4962 cfg.rules=this.rules;
4964 if (this.sortable) {
4965 cfg.sortable=this.sortable;
4968 cfg.summary=this.summary;
4971 cfg.width=this.width;
4974 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4977 if(this.store || this.cm){
4979 cfg.cn.push(this.renderHeader());
4982 cfg.cn.push(this.renderBody());
4985 cfg.cn.push(this.renderFooter());
4988 cfg.cls+= ' TableGrid';
4991 return { cn : [ cfg ] };
4994 initEvents : function()
4996 if(!this.store || !this.cm){
5000 //Roo.log('initEvents with ds!!!!');
5002 this.mainBody = this.el.select('tbody', true).first();
5007 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5008 e.on('click', _this.sort, _this);
5011 this.el.on("click", this.onClick, this);
5012 this.el.on("dblclick", this.onDblClick, this);
5014 this.parent().el.setStyle('position', 'relative');
5016 this.footer.parentId = this.id;
5017 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5020 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5022 this.store.on('load', this.onLoad, this);
5023 this.store.on('beforeload', this.onBeforeLoad, this);
5024 this.store.on('update', this.onUpdate, this);
5028 onMouseover : function(e, el)
5030 var cell = Roo.get(el);
5036 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5037 cell = cell.findParent('td', false, true);
5040 var row = cell.findParent('tr', false, true);
5041 var cellIndex = cell.dom.cellIndex;
5042 var rowIndex = row.dom.rowIndex - 1; // start from 0
5044 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5048 onMouseout : function(e, el)
5050 var cell = Roo.get(el);
5056 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5057 cell = cell.findParent('td', false, true);
5060 var row = cell.findParent('tr', false, true);
5061 var cellIndex = cell.dom.cellIndex;
5062 var rowIndex = row.dom.rowIndex - 1; // start from 0
5064 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5068 onClick : function(e, el)
5070 var cell = Roo.get(el);
5072 if(!cell || (!this.CellSelection && !this.RowSelection)){
5077 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5078 cell = cell.findParent('td', false, true);
5081 var row = cell.findParent('tr', false, true);
5082 var cellIndex = cell.dom.cellIndex;
5083 var rowIndex = row.dom.rowIndex - 1;
5085 if(this.CellSelection){
5086 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5089 if(this.RowSelection){
5090 this.fireEvent('rowclick', this, row, rowIndex, e);
5096 onDblClick : function(e,el)
5098 var cell = Roo.get(el);
5100 if(!cell || (!this.CellSelection && !this.RowSelection)){
5104 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5105 cell = cell.findParent('td', false, true);
5108 var row = cell.findParent('tr', false, true);
5109 var cellIndex = cell.dom.cellIndex;
5110 var rowIndex = row.dom.rowIndex - 1;
5112 if(this.CellSelection){
5113 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5116 if(this.RowSelection){
5117 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5121 sort : function(e,el)
5123 var col = Roo.get(el)
5125 if(!col.hasClass('sortable')){
5129 var sort = col.attr('sort');
5132 if(col.hasClass('glyphicon-arrow-up')){
5136 this.store.sortInfo = {field : sort, direction : dir};
5139 Roo.log("calling footer first");
5140 this.footer.onClick('first');
5143 this.store.load({ params : { start : 0 } });
5147 renderHeader : function()
5156 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5158 var config = cm.config[i];
5163 html: cm.getColumnHeader(i)
5166 if(typeof(config.hidden) != 'undefined' && config.hidden){
5167 c.style += ' display:none;';
5170 if(typeof(config.dataIndex) != 'undefined'){
5171 c.sort = config.dataIndex;
5174 if(typeof(config.sortable) != 'undefined' && config.sortable){
5178 if(typeof(config.align) != 'undefined' && config.align.length){
5179 c.style += ' text-align:' + config.align + ';';
5182 if(typeof(config.width) != 'undefined'){
5183 c.style += ' width:' + config.width + 'px;';
5192 renderBody : function()
5202 colspan : this.cm.getColumnCount()
5212 renderFooter : function()
5222 colspan : this.cm.getColumnCount()
5236 Roo.log('ds onload');
5241 var ds = this.store;
5243 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5244 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5246 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5247 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5250 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5251 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5255 var tbody = this.mainBody;
5257 if(ds.getCount() > 0){
5258 ds.data.each(function(d,rowIndex){
5259 var row = this.renderRow(cm, ds, rowIndex);
5261 tbody.createChild(row);
5265 if(row.cellObjects.length){
5266 Roo.each(row.cellObjects, function(r){
5267 _this.renderCellObject(r);
5274 Roo.each(this.el.select('tbody td', true).elements, function(e){
5275 e.on('mouseover', _this.onMouseover, _this);
5278 Roo.each(this.el.select('tbody td', true).elements, function(e){
5279 e.on('mouseout', _this.onMouseout, _this);
5282 //if(this.loadMask){
5283 // this.maskEl.hide();
5288 onUpdate : function(ds,record)
5290 this.refreshRow(record);
5292 onRemove : function(ds, record, index, isUpdate){
5293 if(isUpdate !== true){
5294 this.fireEvent("beforerowremoved", this, index, record);
5296 var bt = this.mainBody.dom;
5298 bt.removeChild(bt.rows[index]);
5301 if(isUpdate !== true){
5302 //this.stripeRows(index);
5303 //this.syncRowHeights(index, index);
5305 this.fireEvent("rowremoved", this, index, record);
5310 refreshRow : function(record){
5311 var ds = this.store, index;
5312 if(typeof record == 'number'){
5314 record = ds.getAt(index);
5316 index = ds.indexOf(record);
5318 this.insertRow(ds, index, true);
5319 this.onRemove(ds, record, index+1, true);
5320 //this.syncRowHeights(index, index);
5322 this.fireEvent("rowupdated", this, index, record);
5325 insertRow : function(dm, rowIndex, isUpdate){
5328 this.fireEvent("beforerowsinserted", this, rowIndex);
5330 //var s = this.getScrollState();
5331 var row = this.renderRow(this.cm, this.store, rowIndex);
5332 // insert before rowIndex..
5333 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5337 if(row.cellObjects.length){
5338 Roo.each(row.cellObjects, function(r){
5339 _this.renderCellObject(r);
5344 this.fireEvent("rowsinserted", this, rowIndex);
5345 //this.syncRowHeights(firstRow, lastRow);
5346 //this.stripeRows(firstRow);
5353 getRowDom : function(rowIndex)
5355 // not sure if I need to check this.. but let's do it anyway..
5356 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5357 this.mainBody.dom.rows[rowIndex] : false
5359 // returns the object tree for a tr..
5362 renderRow : function(cm, ds, rowIndex) {
5364 var d = ds.getAt(rowIndex);
5371 var cellObjects = [];
5373 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5374 var config = cm.config[i];
5376 var renderer = cm.getRenderer(i);
5380 if(typeof(renderer) !== 'undefined'){
5381 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5383 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5384 // and are rendered into the cells after the row is rendered - using the id for the element.
5386 if(typeof(value) === 'object'){
5396 rowIndex : rowIndex,
5401 this.fireEvent('rowclass', this, rowcfg);
5405 cls : rowcfg.rowClass,
5407 html: (typeof(value) === 'object') ? '' : value
5414 if(typeof(config.hidden) != 'undefined' && config.hidden){
5415 td.style += ' display:none;';
5418 if(typeof(config.align) != 'undefined' && config.align.length){
5419 td.style += ' text-align:' + config.align + ';';
5422 if(typeof(config.width) != 'undefined'){
5423 td.style += ' width:' + config.width + 'px;';
5430 row.cellObjects = cellObjects;
5438 onBeforeLoad : function()
5440 //Roo.log('ds onBeforeLoad');
5444 //if(this.loadMask){
5445 // this.maskEl.show();
5451 this.el.select('tbody', true).first().dom.innerHTML = '';
5454 getSelectionModel : function(){
5456 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5458 return this.selModel;
5461 * Render the Roo.bootstrap object from renderder
5463 renderCellObject : function(r)
5467 var t = r.cfg.render(r.container);
5470 Roo.each(r.cfg.cn, function(c){
5472 container: t.getChildContainer(),
5475 _this.renderCellObject(child);
5492 * @class Roo.bootstrap.TableCell
5493 * @extends Roo.bootstrap.Component
5494 * Bootstrap TableCell class
5495 * @cfg {String} html cell contain text
5496 * @cfg {String} cls cell class
5497 * @cfg {String} tag cell tag (td|th) default td
5498 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5499 * @cfg {String} align Aligns the content in a cell
5500 * @cfg {String} axis Categorizes cells
5501 * @cfg {String} bgcolor Specifies the background color of a cell
5502 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5503 * @cfg {Number} colspan Specifies the number of columns a cell should span
5504 * @cfg {String} headers Specifies one or more header cells a cell is related to
5505 * @cfg {Number} height Sets the height of a cell
5506 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5507 * @cfg {Number} rowspan Sets the number of rows a cell should span
5508 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5509 * @cfg {String} valign Vertical aligns the content in a cell
5510 * @cfg {Number} width Specifies the width of a cell
5513 * Create a new TableCell
5514 * @param {Object} config The config object
5517 Roo.bootstrap.TableCell = function(config){
5518 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5521 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5541 getAutoCreate : function(){
5542 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5562 cfg.align=this.align
5568 cfg.bgcolor=this.bgcolor
5571 cfg.charoff=this.charoff
5574 cfg.colspan=this.colspan
5577 cfg.headers=this.headers
5580 cfg.height=this.height
5583 cfg.nowrap=this.nowrap
5586 cfg.rowspan=this.rowspan
5589 cfg.scope=this.scope
5592 cfg.valign=this.valign
5595 cfg.width=this.width
5614 * @class Roo.bootstrap.TableRow
5615 * @extends Roo.bootstrap.Component
5616 * Bootstrap TableRow class
5617 * @cfg {String} cls row class
5618 * @cfg {String} align Aligns the content in a table row
5619 * @cfg {String} bgcolor Specifies a background color for a table row
5620 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5621 * @cfg {String} valign Vertical aligns the content in a table row
5624 * Create a new TableRow
5625 * @param {Object} config The config object
5628 Roo.bootstrap.TableRow = function(config){
5629 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5632 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5640 getAutoCreate : function(){
5641 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5651 cfg.align = this.align;
5654 cfg.bgcolor = this.bgcolor;
5657 cfg.charoff = this.charoff;
5660 cfg.valign = this.valign;
5678 * @class Roo.bootstrap.TableBody
5679 * @extends Roo.bootstrap.Component
5680 * Bootstrap TableBody class
5681 * @cfg {String} cls element class
5682 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5683 * @cfg {String} align Aligns the content inside the element
5684 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5685 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5688 * Create a new TableBody
5689 * @param {Object} config The config object
5692 Roo.bootstrap.TableBody = function(config){
5693 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5696 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5704 getAutoCreate : function(){
5705 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5719 cfg.align = this.align;
5722 cfg.charoff = this.charoff;
5725 cfg.valign = this.valign;
5732 // initEvents : function()
5739 // this.store = Roo.factory(this.store, Roo.data);
5740 // this.store.on('load', this.onLoad, this);
5742 // this.store.load();
5746 // onLoad: function ()
5748 // this.fireEvent('load', this);
5758 * Ext JS Library 1.1.1
5759 * Copyright(c) 2006-2007, Ext JS, LLC.
5761 * Originally Released Under LGPL - original licence link has changed is not relivant.
5764 * <script type="text/javascript">
5767 // as we use this in bootstrap.
5768 Roo.namespace('Roo.form');
5770 * @class Roo.form.Action
5771 * Internal Class used to handle form actions
5773 * @param {Roo.form.BasicForm} el The form element or its id
5774 * @param {Object} config Configuration options
5779 // define the action interface
5780 Roo.form.Action = function(form, options){
5782 this.options = options || {};
5785 * Client Validation Failed
5788 Roo.form.Action.CLIENT_INVALID = 'client';
5790 * Server Validation Failed
5793 Roo.form.Action.SERVER_INVALID = 'server';
5795 * Connect to Server Failed
5798 Roo.form.Action.CONNECT_FAILURE = 'connect';
5800 * Reading Data from Server Failed
5803 Roo.form.Action.LOAD_FAILURE = 'load';
5805 Roo.form.Action.prototype = {
5807 failureType : undefined,
5808 response : undefined,
5812 run : function(options){
5817 success : function(response){
5822 handleResponse : function(response){
5826 // default connection failure
5827 failure : function(response){
5829 this.response = response;
5830 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5831 this.form.afterAction(this, false);
5834 processResponse : function(response){
5835 this.response = response;
5836 if(!response.responseText){
5839 this.result = this.handleResponse(response);
5843 // utility functions used internally
5844 getUrl : function(appendParams){
5845 var url = this.options.url || this.form.url || this.form.el.dom.action;
5847 var p = this.getParams();
5849 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5855 getMethod : function(){
5856 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5859 getParams : function(){
5860 var bp = this.form.baseParams;
5861 var p = this.options.params;
5863 if(typeof p == "object"){
5864 p = Roo.urlEncode(Roo.applyIf(p, bp));
5865 }else if(typeof p == 'string' && bp){
5866 p += '&' + Roo.urlEncode(bp);
5869 p = Roo.urlEncode(bp);
5874 createCallback : function(){
5876 success: this.success,
5877 failure: this.failure,
5879 timeout: (this.form.timeout*1000),
5880 upload: this.form.fileUpload ? this.success : undefined
5885 Roo.form.Action.Submit = function(form, options){
5886 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5889 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5892 haveProgress : false,
5893 uploadComplete : false,
5895 // uploadProgress indicator.
5896 uploadProgress : function()
5898 if (!this.form.progressUrl) {
5902 if (!this.haveProgress) {
5903 Roo.MessageBox.progress("Uploading", "Uploading");
5905 if (this.uploadComplete) {
5906 Roo.MessageBox.hide();
5910 this.haveProgress = true;
5912 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5914 var c = new Roo.data.Connection();
5916 url : this.form.progressUrl,
5921 success : function(req){
5922 //console.log(data);
5926 rdata = Roo.decode(req.responseText)
5928 Roo.log("Invalid data from server..");
5932 if (!rdata || !rdata.success) {
5934 Roo.MessageBox.alert(Roo.encode(rdata));
5937 var data = rdata.data;
5939 if (this.uploadComplete) {
5940 Roo.MessageBox.hide();
5945 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5946 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5949 this.uploadProgress.defer(2000,this);
5952 failure: function(data) {
5953 Roo.log('progress url failed ');
5964 // run get Values on the form, so it syncs any secondary forms.
5965 this.form.getValues();
5967 var o = this.options;
5968 var method = this.getMethod();
5969 var isPost = method == 'POST';
5970 if(o.clientValidation === false || this.form.isValid()){
5972 if (this.form.progressUrl) {
5973 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5974 (new Date() * 1) + '' + Math.random());
5979 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5980 form:this.form.el.dom,
5981 url:this.getUrl(!isPost),
5983 params:isPost ? this.getParams() : null,
5984 isUpload: this.form.fileUpload
5987 this.uploadProgress();
5989 }else if (o.clientValidation !== false){ // client validation failed
5990 this.failureType = Roo.form.Action.CLIENT_INVALID;
5991 this.form.afterAction(this, false);
5995 success : function(response)
5997 this.uploadComplete= true;
5998 if (this.haveProgress) {
5999 Roo.MessageBox.hide();
6003 var result = this.processResponse(response);
6004 if(result === true || result.success){
6005 this.form.afterAction(this, true);
6009 this.form.markInvalid(result.errors);
6010 this.failureType = Roo.form.Action.SERVER_INVALID;
6012 this.form.afterAction(this, false);
6014 failure : function(response)
6016 this.uploadComplete= true;
6017 if (this.haveProgress) {
6018 Roo.MessageBox.hide();
6021 this.response = response;
6022 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6023 this.form.afterAction(this, false);
6026 handleResponse : function(response){
6027 if(this.form.errorReader){
6028 var rs = this.form.errorReader.read(response);
6031 for(var i = 0, len = rs.records.length; i < len; i++) {
6032 var r = rs.records[i];
6036 if(errors.length < 1){
6040 success : rs.success,
6046 ret = Roo.decode(response.responseText);
6050 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6060 Roo.form.Action.Load = function(form, options){
6061 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6062 this.reader = this.form.reader;
6065 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6070 Roo.Ajax.request(Roo.apply(
6071 this.createCallback(), {
6072 method:this.getMethod(),
6073 url:this.getUrl(false),
6074 params:this.getParams()
6078 success : function(response){
6080 var result = this.processResponse(response);
6081 if(result === true || !result.success || !result.data){
6082 this.failureType = Roo.form.Action.LOAD_FAILURE;
6083 this.form.afterAction(this, false);
6086 this.form.clearInvalid();
6087 this.form.setValues(result.data);
6088 this.form.afterAction(this, true);
6091 handleResponse : function(response){
6092 if(this.form.reader){
6093 var rs = this.form.reader.read(response);
6094 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6096 success : rs.success,
6100 return Roo.decode(response.responseText);
6104 Roo.form.Action.ACTION_TYPES = {
6105 'load' : Roo.form.Action.Load,
6106 'submit' : Roo.form.Action.Submit
6115 * @class Roo.bootstrap.Form
6116 * @extends Roo.bootstrap.Component
6117 * Bootstrap Form class
6118 * @cfg {String} method GET | POST (default POST)
6119 * @cfg {String} labelAlign top | left (default top)
6120 * @cfg {String} align left | right - for navbars
6121 * @cfg {Boolean} loadMask load mask when submit (default true)
6126 * @param {Object} config The config object
6130 Roo.bootstrap.Form = function(config){
6131 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6134 * @event clientvalidation
6135 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6136 * @param {Form} this
6137 * @param {Boolean} valid true if the form has passed client-side validation
6139 clientvalidation: true,
6141 * @event beforeaction
6142 * Fires before any action is performed. Return false to cancel the action.
6143 * @param {Form} this
6144 * @param {Action} action The action to be performed
6148 * @event actionfailed
6149 * Fires when an action fails.
6150 * @param {Form} this
6151 * @param {Action} action The action that failed
6153 actionfailed : true,
6155 * @event actioncomplete
6156 * Fires when an action is completed.
6157 * @param {Form} this
6158 * @param {Action} action The action that completed
6160 actioncomplete : true
6165 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6168 * @cfg {String} method
6169 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6174 * The URL to use for form actions if one isn't supplied in the action options.
6177 * @cfg {Boolean} fileUpload
6178 * Set to true if this form is a file upload.
6182 * @cfg {Object} baseParams
6183 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6187 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6191 * @cfg {Sting} align (left|right) for navbar forms
6196 activeAction : null,
6199 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6200 * element by passing it or its id or mask the form itself by passing in true.
6203 waitMsgTarget : false,
6207 getAutoCreate : function(){
6211 method : this.method || 'POST',
6212 id : this.id || Roo.id(),
6215 if (this.parent().xtype.match(/^Nav/)) {
6216 cfg.cls = 'navbar-form navbar-' + this.align;
6220 if (this.labelAlign == 'left' ) {
6221 cfg.cls += ' form-horizontal';
6227 initEvents : function()
6229 this.el.on('submit', this.onSubmit, this);
6230 // this was added as random key presses on the form where triggering form submit.
6231 this.el.on('keypress', function(e) {
6232 if (e.getCharCode() != 13) {
6235 // we might need to allow it for textareas.. and some other items.
6236 // check e.getTarget().
6238 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6242 Roo.log("keypress blocked");
6250 onSubmit : function(e){
6255 * Returns true if client-side validation on the form is successful.
6258 isValid : function(){
6259 var items = this.getItems();
6261 items.each(function(f){
6270 * Returns true if any fields in this form have changed since their original load.
6273 isDirty : function(){
6275 var items = this.getItems();
6276 items.each(function(f){
6286 * Performs a predefined action (submit or load) or custom actions you define on this form.
6287 * @param {String} actionName The name of the action type
6288 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6289 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6290 * accept other config options):
6292 Property Type Description
6293 ---------------- --------------- ----------------------------------------------------------------------------------
6294 url String The url for the action (defaults to the form's url)
6295 method String The form method to use (defaults to the form's method, or POST if not defined)
6296 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6297 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6298 validate the form on the client (defaults to false)
6300 * @return {BasicForm} this
6302 doAction : function(action, options){
6303 if(typeof action == 'string'){
6304 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6306 if(this.fireEvent('beforeaction', this, action) !== false){
6307 this.beforeAction(action);
6308 action.run.defer(100, action);
6314 beforeAction : function(action){
6315 var o = action.options;
6318 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6320 // not really supported yet.. ??
6322 //if(this.waitMsgTarget === true){
6323 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6324 //}else if(this.waitMsgTarget){
6325 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6326 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6328 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6334 afterAction : function(action, success){
6335 this.activeAction = null;
6336 var o = action.options;
6338 //if(this.waitMsgTarget === true){
6340 //}else if(this.waitMsgTarget){
6341 // this.waitMsgTarget.unmask();
6343 // Roo.MessageBox.updateProgress(1);
6344 // Roo.MessageBox.hide();
6351 Roo.callback(o.success, o.scope, [this, action]);
6352 this.fireEvent('actioncomplete', this, action);
6356 // failure condition..
6357 // we have a scenario where updates need confirming.
6358 // eg. if a locking scenario exists..
6359 // we look for { errors : { needs_confirm : true }} in the response.
6361 (typeof(action.result) != 'undefined') &&
6362 (typeof(action.result.errors) != 'undefined') &&
6363 (typeof(action.result.errors.needs_confirm) != 'undefined')
6366 Roo.log("not supported yet");
6369 Roo.MessageBox.confirm(
6370 "Change requires confirmation",
6371 action.result.errorMsg,
6376 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6386 Roo.callback(o.failure, o.scope, [this, action]);
6387 // show an error message if no failed handler is set..
6388 if (!this.hasListener('actionfailed')) {
6389 Roo.log("need to add dialog support");
6391 Roo.MessageBox.alert("Error",
6392 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6393 action.result.errorMsg :
6394 "Saving Failed, please check your entries or try again"
6399 this.fireEvent('actionfailed', this, action);
6404 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6405 * @param {String} id The value to search for
6408 findField : function(id){
6409 var items = this.getItems();
6410 var field = items.get(id);
6412 items.each(function(f){
6413 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6420 return field || null;
6423 * Mark fields in this form invalid in bulk.
6424 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6425 * @return {BasicForm} this
6427 markInvalid : function(errors){
6428 if(errors instanceof Array){
6429 for(var i = 0, len = errors.length; i < len; i++){
6430 var fieldError = errors[i];
6431 var f = this.findField(fieldError.id);
6433 f.markInvalid(fieldError.msg);
6439 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6440 field.markInvalid(errors[id]);
6444 //Roo.each(this.childForms || [], function (f) {
6445 // f.markInvalid(errors);
6452 * Set values for fields in this form in bulk.
6453 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6454 * @return {BasicForm} this
6456 setValues : function(values){
6457 if(values instanceof Array){ // array of objects
6458 for(var i = 0, len = values.length; i < len; i++){
6460 var f = this.findField(v.id);
6462 f.setValue(v.value);
6463 if(this.trackResetOnLoad){
6464 f.originalValue = f.getValue();
6468 }else{ // object hash
6471 if(typeof values[id] != 'function' && (field = this.findField(id))){
6473 if (field.setFromData &&
6475 field.displayField &&
6476 // combos' with local stores can
6477 // be queried via setValue()
6478 // to set their value..
6479 (field.store && !field.store.isLocal)
6483 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6484 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6485 field.setFromData(sd);
6488 field.setValue(values[id]);
6492 if(this.trackResetOnLoad){
6493 field.originalValue = field.getValue();
6499 //Roo.each(this.childForms || [], function (f) {
6500 // f.setValues(values);
6507 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6508 * they are returned as an array.
6509 * @param {Boolean} asString
6512 getValues : function(asString){
6513 //if (this.childForms) {
6514 // copy values from the child forms
6515 // Roo.each(this.childForms, function (f) {
6516 // this.setValues(f.getValues());
6522 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6523 if(asString === true){
6526 return Roo.urlDecode(fs);
6530 * Returns the fields in this form as an object with key/value pairs.
6531 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6534 getFieldValues : function(with_hidden)
6536 var items = this.getItems();
6538 items.each(function(f){
6542 var v = f.getValue();
6543 if (f.inputType =='radio') {
6544 if (typeof(ret[f.getName()]) == 'undefined') {
6545 ret[f.getName()] = ''; // empty..
6548 if (!f.el.dom.checked) {
6556 // not sure if this supported any more..
6557 if ((typeof(v) == 'object') && f.getRawValue) {
6558 v = f.getRawValue() ; // dates..
6560 // combo boxes where name != hiddenName...
6561 if (f.name != f.getName()) {
6562 ret[f.name] = f.getRawValue();
6564 ret[f.getName()] = v;
6571 * Clears all invalid messages in this form.
6572 * @return {BasicForm} this
6574 clearInvalid : function(){
6575 var items = this.getItems();
6577 items.each(function(f){
6588 * @return {BasicForm} this
6591 var items = this.getItems();
6592 items.each(function(f){
6596 Roo.each(this.childForms || [], function (f) {
6603 getItems : function()
6605 var r=new Roo.util.MixedCollection(false, function(o){
6606 return o.id || (o.id = Roo.id());
6608 var iter = function(el) {
6615 Roo.each(el.items,function(e) {
6634 * Ext JS Library 1.1.1
6635 * Copyright(c) 2006-2007, Ext JS, LLC.
6637 * Originally Released Under LGPL - original licence link has changed is not relivant.
6640 * <script type="text/javascript">
6643 * @class Roo.form.VTypes
6644 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6647 Roo.form.VTypes = function(){
6648 // closure these in so they are only created once.
6649 var alpha = /^[a-zA-Z_]+$/;
6650 var alphanum = /^[a-zA-Z0-9_]+$/;
6651 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6652 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6654 // All these messages and functions are configurable
6657 * The function used to validate email addresses
6658 * @param {String} value The email address
6660 'email' : function(v){
6661 return email.test(v);
6664 * The error text to display when the email validation function returns false
6667 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6669 * The keystroke filter mask to be applied on email input
6672 'emailMask' : /[a-z0-9_\.\-@]/i,
6675 * The function used to validate URLs
6676 * @param {String} value The URL
6678 'url' : function(v){
6682 * The error text to display when the url validation function returns false
6685 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6688 * The function used to validate alpha values
6689 * @param {String} value The value
6691 'alpha' : function(v){
6692 return alpha.test(v);
6695 * The error text to display when the alpha validation function returns false
6698 'alphaText' : 'This field should only contain letters and _',
6700 * The keystroke filter mask to be applied on alpha input
6703 'alphaMask' : /[a-z_]/i,
6706 * The function used to validate alphanumeric values
6707 * @param {String} value The value
6709 'alphanum' : function(v){
6710 return alphanum.test(v);
6713 * The error text to display when the alphanumeric validation function returns false
6716 'alphanumText' : 'This field should only contain letters, numbers and _',
6718 * The keystroke filter mask to be applied on alphanumeric input
6721 'alphanumMask' : /[a-z0-9_]/i
6731 * @class Roo.bootstrap.Input
6732 * @extends Roo.bootstrap.Component
6733 * Bootstrap Input class
6734 * @cfg {Boolean} disabled is it disabled
6735 * @cfg {String} fieldLabel - the label associated
6736 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6737 * @cfg {String} name name of the input
6738 * @cfg {string} fieldLabel - the label associated
6739 * @cfg {string} inputType - input / file submit ...
6740 * @cfg {string} placeholder - placeholder to put in text.
6741 * @cfg {string} before - input group add on before
6742 * @cfg {string} after - input group add on after
6743 * @cfg {string} size - (lg|sm) or leave empty..
6744 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6745 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6746 * @cfg {Number} md colspan out of 12 for computer-sized screens
6747 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6748 * @cfg {string} value default value of the input
6749 * @cfg {Number} labelWidth set the width of label (0-12)
6750 * @cfg {String} labelAlign (top|left)
6751 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6752 * @cfg {String} align (left|center|right) Default left
6756 * Create a new Input
6757 * @param {Object} config The config object
6760 Roo.bootstrap.Input = function(config){
6761 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6766 * Fires when this field receives input focus.
6767 * @param {Roo.form.Field} this
6772 * Fires when this field loses input focus.
6773 * @param {Roo.form.Field} this
6778 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6779 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6780 * @param {Roo.form.Field} this
6781 * @param {Roo.EventObject} e The event object
6786 * Fires just before the field blurs if the field value has changed.
6787 * @param {Roo.form.Field} this
6788 * @param {Mixed} newValue The new value
6789 * @param {Mixed} oldValue The original value
6794 * Fires after the field has been marked as invalid.
6795 * @param {Roo.form.Field} this
6796 * @param {String} msg The validation message
6801 * Fires after the field has been validated with no errors.
6802 * @param {Roo.form.Field} this
6807 * Fires after the key up
6808 * @param {Roo.form.Field} this
6809 * @param {Roo.EventObject} e The event Object
6815 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6817 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6818 automatic validation (defaults to "keyup").
6820 validationEvent : "keyup",
6822 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6824 validateOnBlur : true,
6826 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6828 validationDelay : 250,
6830 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6832 focusClass : "x-form-focus", // not needed???
6836 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6838 invalidClass : "has-error",
6841 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6843 selectOnFocus : false,
6846 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6850 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6855 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6857 disableKeyFilter : false,
6860 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6864 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6868 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6870 blankText : "This field is required",
6873 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6877 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6879 maxLength : Number.MAX_VALUE,
6881 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6883 minLengthText : "The minimum length for this field is {0}",
6885 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6887 maxLengthText : "The maximum length for this field is {0}",
6891 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6892 * If available, this function will be called only after the basic validators all return true, and will be passed the
6893 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6897 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6898 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6899 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6903 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6926 formatedValue : false,
6928 parentLabelAlign : function()
6931 while (parent.parent()) {
6932 parent = parent.parent();
6933 if (typeof(parent.labelAlign) !='undefined') {
6934 return parent.labelAlign;
6941 getAutoCreate : function(){
6943 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6949 if(this.inputType != 'hidden'){
6950 cfg.cls = 'form-group' //input-group
6956 type : this.inputType,
6958 cls : 'form-control',
6959 placeholder : this.placeholder || ''
6964 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6967 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6968 input.maxLength = this.maxLength;
6971 if (this.disabled) {
6972 input.disabled=true;
6975 if (this.readOnly) {
6976 input.readonly=true;
6980 input.name = this.name;
6983 input.cls += ' input-' + this.size;
6986 ['xs','sm','md','lg'].map(function(size){
6987 if (settings[size]) {
6988 cfg.cls += ' col-' + size + '-' + settings[size];
6992 var inputblock = input;
6994 if (this.before || this.after) {
6997 cls : 'input-group',
7000 if (this.before && typeof(this.before) == 'string') {
7002 inputblock.cn.push({
7004 cls : 'roo-input-before input-group-addon',
7008 if (this.before && typeof(this.before) == 'object') {
7009 this.before = Roo.factory(this.before);
7010 Roo.log(this.before);
7011 inputblock.cn.push({
7013 cls : 'roo-input-before input-group-' +
7014 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7018 inputblock.cn.push(input);
7020 if (this.after && typeof(this.after) == 'string') {
7021 inputblock.cn.push({
7023 cls : 'roo-input-after input-group-addon',
7027 if (this.after && typeof(this.after) == 'object') {
7028 this.after = Roo.factory(this.after);
7029 Roo.log(this.after);
7030 inputblock.cn.push({
7032 cls : 'roo-input-after input-group-' +
7033 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7038 if (align ==='left' && this.fieldLabel.length) {
7039 Roo.log("left and has label");
7045 cls : 'control-label col-sm-' + this.labelWidth,
7046 html : this.fieldLabel
7050 cls : "col-sm-" + (12 - this.labelWidth),
7057 } else if ( this.fieldLabel.length) {
7063 //cls : 'input-group-addon',
7064 html : this.fieldLabel
7074 Roo.log(" no label && no align");
7083 Roo.log('input-parentType: ' + this.parentType);
7085 if (this.parentType === 'Navbar' && this.parent().bar) {
7086 cfg.cls += ' navbar-form';
7094 * return the real input element.
7096 inputEl: function ()
7098 return this.el.select('input.form-control',true).first();
7100 setDisabled : function(v)
7102 var i = this.inputEl().dom;
7104 i.removeAttribute('disabled');
7108 i.setAttribute('disabled','true');
7110 initEvents : function()
7113 this.inputEl().on("keydown" , this.fireKey, this);
7114 this.inputEl().on("focus", this.onFocus, this);
7115 this.inputEl().on("blur", this.onBlur, this);
7117 this.inputEl().relayEvent('keyup', this);
7119 // reference to original value for reset
7120 this.originalValue = this.getValue();
7121 //Roo.form.TextField.superclass.initEvents.call(this);
7122 if(this.validationEvent == 'keyup'){
7123 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7124 this.inputEl().on('keyup', this.filterValidation, this);
7126 else if(this.validationEvent !== false){
7127 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7130 if(this.selectOnFocus){
7131 this.on("focus", this.preFocus, this);
7134 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7135 this.inputEl().on("keypress", this.filterKeys, this);
7138 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7139 this.el.on("click", this.autoSize, this);
7142 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7143 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7146 if (typeof(this.before) == 'object') {
7147 this.before.render(this.el.select('.roo-input-before',true).first());
7149 if (typeof(this.after) == 'object') {
7150 this.after.render(this.el.select('.roo-input-after',true).first());
7155 filterValidation : function(e){
7156 if(!e.isNavKeyPress()){
7157 this.validationTask.delay(this.validationDelay);
7161 * Validates the field value
7162 * @return {Boolean} True if the value is valid, else false
7164 validate : function(){
7165 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7166 if(this.disabled || this.validateValue(this.getRawValue())){
7167 this.clearInvalid();
7175 * Validates a value according to the field's validation rules and marks the field as invalid
7176 * if the validation fails
7177 * @param {Mixed} value The value to validate
7178 * @return {Boolean} True if the value is valid, else false
7180 validateValue : function(value){
7181 if(value.length < 1) { // if it's blank
7182 if(this.allowBlank){
7183 this.clearInvalid();
7186 this.markInvalid(this.blankText);
7190 if(value.length < this.minLength){
7191 this.markInvalid(String.format(this.minLengthText, this.minLength));
7194 if(value.length > this.maxLength){
7195 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7199 var vt = Roo.form.VTypes;
7200 if(!vt[this.vtype](value, this)){
7201 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7205 if(typeof this.validator == "function"){
7206 var msg = this.validator(value);
7208 this.markInvalid(msg);
7212 if(this.regex && !this.regex.test(value)){
7213 this.markInvalid(this.regexText);
7222 fireKey : function(e){
7223 //Roo.log('field ' + e.getKey());
7224 if(e.isNavKeyPress()){
7225 this.fireEvent("specialkey", this, e);
7228 focus : function (selectText){
7230 this.inputEl().focus();
7231 if(selectText === true){
7232 this.inputEl().dom.select();
7238 onFocus : function(){
7239 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7240 // this.el.addClass(this.focusClass);
7243 this.hasFocus = true;
7244 this.startValue = this.getValue();
7245 this.fireEvent("focus", this);
7249 beforeBlur : Roo.emptyFn,
7253 onBlur : function(){
7255 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7256 //this.el.removeClass(this.focusClass);
7258 this.hasFocus = false;
7259 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7262 var v = this.getValue();
7263 if(String(v) !== String(this.startValue)){
7264 this.fireEvent('change', this, v, this.startValue);
7266 this.fireEvent("blur", this);
7270 * Resets the current field value to the originally loaded value and clears any validation messages
7273 this.setValue(this.originalValue);
7274 this.clearInvalid();
7277 * Returns the name of the field
7278 * @return {Mixed} name The name field
7280 getName: function(){
7284 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7285 * @return {Mixed} value The field value
7287 getValue : function(){
7289 var v = this.inputEl().getValue();
7294 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7295 * @return {Mixed} value The field value
7297 getRawValue : function(){
7298 var v = this.inputEl().getValue();
7304 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7305 * @param {Mixed} value The value to set
7307 setRawValue : function(v){
7308 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7311 selectText : function(start, end){
7312 var v = this.getRawValue();
7314 start = start === undefined ? 0 : start;
7315 end = end === undefined ? v.length : end;
7316 var d = this.inputEl().dom;
7317 if(d.setSelectionRange){
7318 d.setSelectionRange(start, end);
7319 }else if(d.createTextRange){
7320 var range = d.createTextRange();
7321 range.moveStart("character", start);
7322 range.moveEnd("character", v.length-end);
7329 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7330 * @param {Mixed} value The value to set
7332 setValue : function(v){
7335 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7341 processValue : function(value){
7342 if(this.stripCharsRe){
7343 var newValue = value.replace(this.stripCharsRe, '');
7344 if(newValue !== value){
7345 this.setRawValue(newValue);
7352 preFocus : function(){
7354 if(this.selectOnFocus){
7355 this.inputEl().dom.select();
7358 filterKeys : function(e){
7360 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7363 var c = e.getCharCode(), cc = String.fromCharCode(c);
7364 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7367 if(!this.maskRe.test(cc)){
7372 * Clear any invalid styles/messages for this field
7374 clearInvalid : function(){
7376 if(!this.el || this.preventMark){ // not rendered
7379 this.el.removeClass(this.invalidClass);
7381 switch(this.msgTarget){
7383 this.el.dom.qtip = '';
7386 this.el.dom.title = '';
7390 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7395 this.errorIcon.dom.qtip = '';
7396 this.errorIcon.hide();
7397 this.un('resize', this.alignErrorIcon, this);
7401 var t = Roo.getDom(this.msgTarget);
7403 t.style.display = 'none';
7407 this.fireEvent('valid', this);
7410 * Mark this field as invalid
7411 * @param {String} msg The validation message
7413 markInvalid : function(msg){
7414 if(!this.el || this.preventMark){ // not rendered
7417 this.el.addClass(this.invalidClass);
7419 msg = msg || this.invalidText;
7420 switch(this.msgTarget){
7422 this.el.dom.qtip = msg;
7423 this.el.dom.qclass = 'x-form-invalid-tip';
7424 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7425 Roo.QuickTips.enable();
7429 this.el.dom.title = msg;
7433 var elp = this.el.findParent('.x-form-element', 5, true);
7434 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7435 this.errorEl.setWidth(elp.getWidth(true)-20);
7437 this.errorEl.update(msg);
7438 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7441 if(!this.errorIcon){
7442 var elp = this.el.findParent('.x-form-element', 5, true);
7443 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7445 this.alignErrorIcon();
7446 this.errorIcon.dom.qtip = msg;
7447 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7448 this.errorIcon.show();
7449 this.on('resize', this.alignErrorIcon, this);
7452 var t = Roo.getDom(this.msgTarget);
7454 t.style.display = this.msgDisplay;
7458 this.fireEvent('invalid', this, msg);
7461 SafariOnKeyDown : function(event)
7463 // this is a workaround for a password hang bug on chrome/ webkit.
7465 var isSelectAll = false;
7467 if(this.inputEl().dom.selectionEnd > 0){
7468 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7470 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7471 event.preventDefault();
7476 if(isSelectAll){ // backspace and delete key
7478 event.preventDefault();
7479 // this is very hacky as keydown always get's upper case.
7481 var cc = String.fromCharCode(event.getCharCode());
7482 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7486 adjustWidth : function(tag, w){
7487 tag = tag.toLowerCase();
7488 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7489 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7493 if(tag == 'textarea'){
7496 }else if(Roo.isOpera){
7500 if(tag == 'textarea'){
7519 * @class Roo.bootstrap.TextArea
7520 * @extends Roo.bootstrap.Input
7521 * Bootstrap TextArea class
7522 * @cfg {Number} cols Specifies the visible width of a text area
7523 * @cfg {Number} rows Specifies the visible number of lines in a text area
7524 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7525 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7526 * @cfg {string} html text
7529 * Create a new TextArea
7530 * @param {Object} config The config object
7533 Roo.bootstrap.TextArea = function(config){
7534 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7538 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7548 getAutoCreate : function(){
7550 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7561 value : this.value || '',
7562 html: this.html || '',
7563 cls : 'form-control',
7564 placeholder : this.placeholder || ''
7568 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7569 input.maxLength = this.maxLength;
7573 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7577 input.cols = this.cols;
7580 if (this.readOnly) {
7581 input.readonly = true;
7585 input.name = this.name;
7589 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7593 ['xs','sm','md','lg'].map(function(size){
7594 if (settings[size]) {
7595 cfg.cls += ' col-' + size + '-' + settings[size];
7599 var inputblock = input;
7601 if (this.before || this.after) {
7604 cls : 'input-group',
7608 inputblock.cn.push({
7610 cls : 'input-group-addon',
7614 inputblock.cn.push(input);
7616 inputblock.cn.push({
7618 cls : 'input-group-addon',
7625 if (align ==='left' && this.fieldLabel.length) {
7626 Roo.log("left and has label");
7632 cls : 'control-label col-sm-' + this.labelWidth,
7633 html : this.fieldLabel
7637 cls : "col-sm-" + (12 - this.labelWidth),
7644 } else if ( this.fieldLabel.length) {
7650 //cls : 'input-group-addon',
7651 html : this.fieldLabel
7661 Roo.log(" no label && no align");
7671 if (this.disabled) {
7672 input.disabled=true;
7679 * return the real textarea element.
7681 inputEl: function ()
7683 return this.el.select('textarea.form-control',true).first();
7691 * trigger field - base class for combo..
7696 * @class Roo.bootstrap.TriggerField
7697 * @extends Roo.bootstrap.Input
7698 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7699 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7700 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7701 * for which you can provide a custom implementation. For example:
7703 var trigger = new Roo.bootstrap.TriggerField();
7704 trigger.onTriggerClick = myTriggerFn;
7705 trigger.applyTo('my-field');
7708 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7709 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7710 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7711 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7713 * Create a new TriggerField.
7714 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7715 * to the base TextField)
7717 Roo.bootstrap.TriggerField = function(config){
7718 this.mimicing = false;
7719 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7722 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7724 * @cfg {String} triggerClass A CSS class to apply to the trigger
7727 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7731 /** @cfg {Boolean} grow @hide */
7732 /** @cfg {Number} growMin @hide */
7733 /** @cfg {Number} growMax @hide */
7739 autoSize: Roo.emptyFn,
7746 actionMode : 'wrap',
7750 getAutoCreate : function(){
7752 var align = this.labelAlign || this.parentLabelAlign();
7757 cls: 'form-group' //input-group
7764 type : this.inputType,
7765 cls : 'form-control',
7766 autocomplete: 'off',
7767 placeholder : this.placeholder || ''
7771 input.name = this.name;
7774 input.cls += ' input-' + this.size;
7777 if (this.disabled) {
7778 input.disabled=true;
7781 var inputblock = input;
7783 if (this.before || this.after) {
7786 cls : 'input-group',
7790 inputblock.cn.push({
7792 cls : 'input-group-addon',
7796 inputblock.cn.push(input);
7798 inputblock.cn.push({
7800 cls : 'input-group-addon',
7813 cls: 'form-hidden-field'
7821 Roo.log('multiple');
7829 cls: 'form-hidden-field'
7833 cls: 'select2-choices',
7837 cls: 'select2-search-field',
7850 cls: 'select2-container input-group',
7855 // cls: 'typeahead typeahead-long dropdown-menu',
7856 // style: 'display:none'
7861 if(!this.multiple && this.showToggleBtn){
7864 cls : 'input-group-addon btn dropdown-toggle',
7872 cls: 'combobox-clear',
7886 combobox.cls += ' select2-container-multi';
7889 if (align ==='left' && this.fieldLabel.length) {
7891 Roo.log("left and has label");
7897 cls : 'control-label col-sm-' + this.labelWidth,
7898 html : this.fieldLabel
7902 cls : "col-sm-" + (12 - this.labelWidth),
7909 } else if ( this.fieldLabel.length) {
7915 //cls : 'input-group-addon',
7916 html : this.fieldLabel
7926 Roo.log(" no label && no align");
7933 ['xs','sm','md','lg'].map(function(size){
7934 if (settings[size]) {
7935 cfg.cls += ' col-' + size + '-' + settings[size];
7946 onResize : function(w, h){
7947 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7948 // if(typeof w == 'number'){
7949 // var x = w - this.trigger.getWidth();
7950 // this.inputEl().setWidth(this.adjustWidth('input', x));
7951 // this.trigger.setStyle('left', x+'px');
7956 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7959 getResizeEl : function(){
7960 return this.inputEl();
7964 getPositionEl : function(){
7965 return this.inputEl();
7969 alignErrorIcon : function(){
7970 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7974 initEvents : function(){
7978 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7979 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7980 if(!this.multiple && this.showToggleBtn){
7981 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7982 if(this.hideTrigger){
7983 this.trigger.setDisplayed(false);
7985 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7989 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7992 //this.trigger.addClassOnOver('x-form-trigger-over');
7993 //this.trigger.addClassOnClick('x-form-trigger-click');
7996 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8000 createList : function()
8002 this.list = Roo.get(document.body).createChild({
8004 cls: 'typeahead typeahead-long dropdown-menu',
8005 style: 'display:none'
8008 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8013 initTrigger : function(){
8018 onDestroy : function(){
8020 this.trigger.removeAllListeners();
8021 // this.trigger.remove();
8024 // this.wrap.remove();
8026 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8030 onFocus : function(){
8031 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8034 this.wrap.addClass('x-trigger-wrap-focus');
8035 this.mimicing = true;
8036 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8037 if(this.monitorTab){
8038 this.el.on("keydown", this.checkTab, this);
8045 checkTab : function(e){
8046 if(e.getKey() == e.TAB){
8052 onBlur : function(){
8057 mimicBlur : function(e, t){
8059 if(!this.wrap.contains(t) && this.validateBlur()){
8066 triggerBlur : function(){
8067 this.mimicing = false;
8068 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8069 if(this.monitorTab){
8070 this.el.un("keydown", this.checkTab, this);
8072 //this.wrap.removeClass('x-trigger-wrap-focus');
8073 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8077 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8078 validateBlur : function(e, t){
8083 onDisable : function(){
8084 this.inputEl().dom.disabled = true;
8085 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8087 // this.wrap.addClass('x-item-disabled');
8092 onEnable : function(){
8093 this.inputEl().dom.disabled = false;
8094 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8096 // this.el.removeClass('x-item-disabled');
8101 onShow : function(){
8102 var ae = this.getActionEl();
8105 ae.dom.style.display = '';
8106 ae.dom.style.visibility = 'visible';
8112 onHide : function(){
8113 var ae = this.getActionEl();
8114 ae.dom.style.display = 'none';
8118 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8119 * by an implementing function.
8121 * @param {EventObject} e
8123 onTriggerClick : Roo.emptyFn
8127 * Ext JS Library 1.1.1
8128 * Copyright(c) 2006-2007, Ext JS, LLC.
8130 * Originally Released Under LGPL - original licence link has changed is not relivant.
8133 * <script type="text/javascript">
8138 * @class Roo.data.SortTypes
8140 * Defines the default sorting (casting?) comparison functions used when sorting data.
8142 Roo.data.SortTypes = {
8144 * Default sort that does nothing
8145 * @param {Mixed} s The value being converted
8146 * @return {Mixed} The comparison value
8153 * The regular expression used to strip tags
8157 stripTagsRE : /<\/?[^>]+>/gi,
8160 * Strips all HTML tags to sort on text only
8161 * @param {Mixed} s The value being converted
8162 * @return {String} The comparison value
8164 asText : function(s){
8165 return String(s).replace(this.stripTagsRE, "");
8169 * Strips all HTML tags to sort on text only - Case insensitive
8170 * @param {Mixed} s The value being converted
8171 * @return {String} The comparison value
8173 asUCText : function(s){
8174 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8178 * Case insensitive string
8179 * @param {Mixed} s The value being converted
8180 * @return {String} The comparison value
8182 asUCString : function(s) {
8183 return String(s).toUpperCase();
8188 * @param {Mixed} s The value being converted
8189 * @return {Number} The comparison value
8191 asDate : function(s) {
8195 if(s instanceof Date){
8198 return Date.parse(String(s));
8203 * @param {Mixed} s The value being converted
8204 * @return {Float} The comparison value
8206 asFloat : function(s) {
8207 var val = parseFloat(String(s).replace(/,/g, ""));
8208 if(isNaN(val)) val = 0;
8214 * @param {Mixed} s The value being converted
8215 * @return {Number} The comparison value
8217 asInt : function(s) {
8218 var val = parseInt(String(s).replace(/,/g, ""));
8219 if(isNaN(val)) val = 0;
8224 * Ext JS Library 1.1.1
8225 * Copyright(c) 2006-2007, Ext JS, LLC.
8227 * Originally Released Under LGPL - original licence link has changed is not relivant.
8230 * <script type="text/javascript">
8234 * @class Roo.data.Record
8235 * Instances of this class encapsulate both record <em>definition</em> information, and record
8236 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8237 * to access Records cached in an {@link Roo.data.Store} object.<br>
8239 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8240 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8243 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8245 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8246 * {@link #create}. The parameters are the same.
8247 * @param {Array} data An associative Array of data values keyed by the field name.
8248 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8249 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8250 * not specified an integer id is generated.
8252 Roo.data.Record = function(data, id){
8253 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8258 * Generate a constructor for a specific record layout.
8259 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8260 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8261 * Each field definition object may contain the following properties: <ul>
8262 * <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,
8263 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8264 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8265 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8266 * is being used, then this is a string containing the javascript expression to reference the data relative to
8267 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8268 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8269 * this may be omitted.</p></li>
8270 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8271 * <ul><li>auto (Default, implies no conversion)</li>
8276 * <li>date</li></ul></p></li>
8277 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8278 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8279 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8280 * by the Reader into an object that will be stored in the Record. It is passed the
8281 * following parameters:<ul>
8282 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8284 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8286 * <br>usage:<br><pre><code>
8287 var TopicRecord = Roo.data.Record.create(
8288 {name: 'title', mapping: 'topic_title'},
8289 {name: 'author', mapping: 'username'},
8290 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8291 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8292 {name: 'lastPoster', mapping: 'user2'},
8293 {name: 'excerpt', mapping: 'post_text'}
8296 var myNewRecord = new TopicRecord({
8297 title: 'Do my job please',
8300 lastPost: new Date(),
8301 lastPoster: 'Animal',
8302 excerpt: 'No way dude!'
8304 myStore.add(myNewRecord);
8309 Roo.data.Record.create = function(o){
8311 f.superclass.constructor.apply(this, arguments);
8313 Roo.extend(f, Roo.data.Record);
8314 var p = f.prototype;
8315 p.fields = new Roo.util.MixedCollection(false, function(field){
8318 for(var i = 0, len = o.length; i < len; i++){
8319 p.fields.add(new Roo.data.Field(o[i]));
8321 f.getField = function(name){
8322 return p.fields.get(name);
8327 Roo.data.Record.AUTO_ID = 1000;
8328 Roo.data.Record.EDIT = 'edit';
8329 Roo.data.Record.REJECT = 'reject';
8330 Roo.data.Record.COMMIT = 'commit';
8332 Roo.data.Record.prototype = {
8334 * Readonly flag - true if this record has been modified.
8343 join : function(store){
8348 * Set the named field to the specified value.
8349 * @param {String} name The name of the field to set.
8350 * @param {Object} value The value to set the field to.
8352 set : function(name, value){
8353 if(this.data[name] == value){
8360 if(typeof this.modified[name] == 'undefined'){
8361 this.modified[name] = this.data[name];
8363 this.data[name] = value;
8364 if(!this.editing && this.store){
8365 this.store.afterEdit(this);
8370 * Get the value of the named field.
8371 * @param {String} name The name of the field to get the value of.
8372 * @return {Object} The value of the field.
8374 get : function(name){
8375 return this.data[name];
8379 beginEdit : function(){
8380 this.editing = true;
8385 cancelEdit : function(){
8386 this.editing = false;
8387 delete this.modified;
8391 endEdit : function(){
8392 this.editing = false;
8393 if(this.dirty && this.store){
8394 this.store.afterEdit(this);
8399 * Usually called by the {@link Roo.data.Store} which owns the Record.
8400 * Rejects all changes made to the Record since either creation, or the last commit operation.
8401 * Modified fields are reverted to their original values.
8403 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8404 * of reject operations.
8406 reject : function(){
8407 var m = this.modified;
8409 if(typeof m[n] != "function"){
8410 this.data[n] = m[n];
8414 delete this.modified;
8415 this.editing = false;
8417 this.store.afterReject(this);
8422 * Usually called by the {@link Roo.data.Store} which owns the Record.
8423 * Commits all changes made to the Record since either creation, or the last commit operation.
8425 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8426 * of commit operations.
8428 commit : function(){
8430 delete this.modified;
8431 this.editing = false;
8433 this.store.afterCommit(this);
8438 hasError : function(){
8439 return this.error != null;
8443 clearError : function(){
8448 * Creates a copy of this record.
8449 * @param {String} id (optional) A new record id if you don't want to use this record's id
8452 copy : function(newId) {
8453 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8457 * Ext JS Library 1.1.1
8458 * Copyright(c) 2006-2007, Ext JS, LLC.
8460 * Originally Released Under LGPL - original licence link has changed is not relivant.
8463 * <script type="text/javascript">
8469 * @class Roo.data.Store
8470 * @extends Roo.util.Observable
8471 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8472 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8474 * 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
8475 * has no knowledge of the format of the data returned by the Proxy.<br>
8477 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8478 * instances from the data object. These records are cached and made available through accessor functions.
8480 * Creates a new Store.
8481 * @param {Object} config A config object containing the objects needed for the Store to access data,
8482 * and read the data into Records.
8484 Roo.data.Store = function(config){
8485 this.data = new Roo.util.MixedCollection(false);
8486 this.data.getKey = function(o){
8489 this.baseParams = {};
8496 "multisort" : "_multisort"
8499 if(config && config.data){
8500 this.inlineData = config.data;
8504 Roo.apply(this, config);
8506 if(this.reader){ // reader passed
8507 this.reader = Roo.factory(this.reader, Roo.data);
8508 this.reader.xmodule = this.xmodule || false;
8509 if(!this.recordType){
8510 this.recordType = this.reader.recordType;
8512 if(this.reader.onMetaChange){
8513 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8517 if(this.recordType){
8518 this.fields = this.recordType.prototype.fields;
8524 * @event datachanged
8525 * Fires when the data cache has changed, and a widget which is using this Store
8526 * as a Record cache should refresh its view.
8527 * @param {Store} this
8532 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8533 * @param {Store} this
8534 * @param {Object} meta The JSON metadata
8539 * Fires when Records have been added to the Store
8540 * @param {Store} this
8541 * @param {Roo.data.Record[]} records The array of Records added
8542 * @param {Number} index The index at which the record(s) were added
8547 * Fires when a Record has been removed from the Store
8548 * @param {Store} this
8549 * @param {Roo.data.Record} record The Record that was removed
8550 * @param {Number} index The index at which the record was removed
8555 * Fires when a Record has been updated
8556 * @param {Store} this
8557 * @param {Roo.data.Record} record The Record that was updated
8558 * @param {String} operation The update operation being performed. Value may be one of:
8560 Roo.data.Record.EDIT
8561 Roo.data.Record.REJECT
8562 Roo.data.Record.COMMIT
8568 * Fires when the data cache has been cleared.
8569 * @param {Store} this
8574 * Fires before a request is made for a new data object. If the beforeload handler returns false
8575 * the load action will be canceled.
8576 * @param {Store} this
8577 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8581 * @event beforeloadadd
8582 * Fires after a new set of Records has been loaded.
8583 * @param {Store} this
8584 * @param {Roo.data.Record[]} records The Records that were loaded
8585 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8587 beforeloadadd : true,
8590 * Fires after a new set of Records has been loaded, before they are added to the store.
8591 * @param {Store} this
8592 * @param {Roo.data.Record[]} records The Records that were loaded
8593 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8594 * @params {Object} return from reader
8598 * @event loadexception
8599 * Fires if an exception occurs in the Proxy during loading.
8600 * Called with the signature of the Proxy's "loadexception" event.
8601 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8604 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8605 * @param {Object} load options
8606 * @param {Object} jsonData from your request (normally this contains the Exception)
8608 loadexception : true
8612 this.proxy = Roo.factory(this.proxy, Roo.data);
8613 this.proxy.xmodule = this.xmodule || false;
8614 this.relayEvents(this.proxy, ["loadexception"]);
8616 this.sortToggle = {};
8617 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8619 Roo.data.Store.superclass.constructor.call(this);
8621 if(this.inlineData){
8622 this.loadData(this.inlineData);
8623 delete this.inlineData;
8627 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8629 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8630 * without a remote query - used by combo/forms at present.
8634 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8637 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8640 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8641 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8644 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8645 * on any HTTP request
8648 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8651 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8655 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8656 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8661 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8662 * loaded or when a record is removed. (defaults to false).
8664 pruneModifiedRecords : false,
8670 * Add Records to the Store and fires the add event.
8671 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8673 add : function(records){
8674 records = [].concat(records);
8675 for(var i = 0, len = records.length; i < len; i++){
8676 records[i].join(this);
8678 var index = this.data.length;
8679 this.data.addAll(records);
8680 this.fireEvent("add", this, records, index);
8684 * Remove a Record from the Store and fires the remove event.
8685 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8687 remove : function(record){
8688 var index = this.data.indexOf(record);
8689 this.data.removeAt(index);
8690 if(this.pruneModifiedRecords){
8691 this.modified.remove(record);
8693 this.fireEvent("remove", this, record, index);
8697 * Remove all Records from the Store and fires the clear event.
8699 removeAll : function(){
8701 if(this.pruneModifiedRecords){
8704 this.fireEvent("clear", this);
8708 * Inserts Records to the Store at the given index and fires the add event.
8709 * @param {Number} index The start index at which to insert the passed Records.
8710 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8712 insert : function(index, records){
8713 records = [].concat(records);
8714 for(var i = 0, len = records.length; i < len; i++){
8715 this.data.insert(index, records[i]);
8716 records[i].join(this);
8718 this.fireEvent("add", this, records, index);
8722 * Get the index within the cache of the passed Record.
8723 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8724 * @return {Number} The index of the passed Record. Returns -1 if not found.
8726 indexOf : function(record){
8727 return this.data.indexOf(record);
8731 * Get the index within the cache of the Record with the passed id.
8732 * @param {String} id The id of the Record to find.
8733 * @return {Number} The index of the Record. Returns -1 if not found.
8735 indexOfId : function(id){
8736 return this.data.indexOfKey(id);
8740 * Get the Record with the specified id.
8741 * @param {String} id The id of the Record to find.
8742 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8744 getById : function(id){
8745 return this.data.key(id);
8749 * Get the Record at the specified index.
8750 * @param {Number} index The index of the Record to find.
8751 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8753 getAt : function(index){
8754 return this.data.itemAt(index);
8758 * Returns a range of Records between specified indices.
8759 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8760 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8761 * @return {Roo.data.Record[]} An array of Records
8763 getRange : function(start, end){
8764 return this.data.getRange(start, end);
8768 storeOptions : function(o){
8769 o = Roo.apply({}, o);
8772 this.lastOptions = o;
8776 * Loads the Record cache from the configured Proxy using the configured Reader.
8778 * If using remote paging, then the first load call must specify the <em>start</em>
8779 * and <em>limit</em> properties in the options.params property to establish the initial
8780 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8782 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8783 * and this call will return before the new data has been loaded. Perform any post-processing
8784 * in a callback function, or in a "load" event handler.</strong>
8786 * @param {Object} options An object containing properties which control loading options:<ul>
8787 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8788 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8789 * passed the following arguments:<ul>
8790 * <li>r : Roo.data.Record[]</li>
8791 * <li>options: Options object from the load call</li>
8792 * <li>success: Boolean success indicator</li></ul></li>
8793 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8794 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8797 load : function(options){
8798 options = options || {};
8799 if(this.fireEvent("beforeload", this, options) !== false){
8800 this.storeOptions(options);
8801 var p = Roo.apply(options.params || {}, this.baseParams);
8802 // if meta was not loaded from remote source.. try requesting it.
8803 if (!this.reader.metaFromRemote) {
8806 if(this.sortInfo && this.remoteSort){
8807 var pn = this.paramNames;
8808 p[pn["sort"]] = this.sortInfo.field;
8809 p[pn["dir"]] = this.sortInfo.direction;
8811 if (this.multiSort) {
8812 var pn = this.paramNames;
8813 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8816 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8821 * Reloads the Record cache from the configured Proxy using the configured Reader and
8822 * the options from the last load operation performed.
8823 * @param {Object} options (optional) An object containing properties which may override the options
8824 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8825 * the most recently used options are reused).
8827 reload : function(options){
8828 this.load(Roo.applyIf(options||{}, this.lastOptions));
8832 // Called as a callback by the Reader during a load operation.
8833 loadRecords : function(o, options, success){
8834 if(!o || success === false){
8835 if(success !== false){
8836 this.fireEvent("load", this, [], options, o);
8838 if(options.callback){
8839 options.callback.call(options.scope || this, [], options, false);
8843 // if data returned failure - throw an exception.
8844 if (o.success === false) {
8845 // show a message if no listener is registered.
8846 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8847 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8849 // loadmask wil be hooked into this..
8850 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8853 var r = o.records, t = o.totalRecords || r.length;
8855 this.fireEvent("beforeloadadd", this, r, options, o);
8857 if(!options || options.add !== true){
8858 if(this.pruneModifiedRecords){
8861 for(var i = 0, len = r.length; i < len; i++){
8865 this.data = this.snapshot;
8866 delete this.snapshot;
8869 this.data.addAll(r);
8870 this.totalLength = t;
8872 this.fireEvent("datachanged", this);
8874 this.totalLength = Math.max(t, this.data.length+r.length);
8877 this.fireEvent("load", this, r, options, o);
8878 if(options.callback){
8879 options.callback.call(options.scope || this, r, options, true);
8885 * Loads data from a passed data block. A Reader which understands the format of the data
8886 * must have been configured in the constructor.
8887 * @param {Object} data The data block from which to read the Records. The format of the data expected
8888 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8889 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8891 loadData : function(o, append){
8892 var r = this.reader.readRecords(o);
8893 this.loadRecords(r, {add: append}, true);
8897 * Gets the number of cached records.
8899 * <em>If using paging, this may not be the total size of the dataset. If the data object
8900 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8901 * the data set size</em>
8903 getCount : function(){
8904 return this.data.length || 0;
8908 * Gets the total number of records in the dataset as returned by the server.
8910 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8911 * the dataset size</em>
8913 getTotalCount : function(){
8914 return this.totalLength || 0;
8918 * Returns the sort state of the Store as an object with two properties:
8920 field {String} The name of the field by which the Records are sorted
8921 direction {String} The sort order, "ASC" or "DESC"
8924 getSortState : function(){
8925 return this.sortInfo;
8929 applySort : function(){
8930 if(this.sortInfo && !this.remoteSort){
8931 var s = this.sortInfo, f = s.field;
8932 var st = this.fields.get(f).sortType;
8933 var fn = function(r1, r2){
8934 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8935 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8937 this.data.sort(s.direction, fn);
8938 if(this.snapshot && this.snapshot != this.data){
8939 this.snapshot.sort(s.direction, fn);
8945 * Sets the default sort column and order to be used by the next load operation.
8946 * @param {String} fieldName The name of the field to sort by.
8947 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8949 setDefaultSort : function(field, dir){
8950 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8955 * If remote sorting is used, the sort is performed on the server, and the cache is
8956 * reloaded. If local sorting is used, the cache is sorted internally.
8957 * @param {String} fieldName The name of the field to sort by.
8958 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8960 sort : function(fieldName, dir){
8961 var f = this.fields.get(fieldName);
8963 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8965 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8966 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8971 this.sortToggle[f.name] = dir;
8972 this.sortInfo = {field: f.name, direction: dir};
8973 if(!this.remoteSort){
8975 this.fireEvent("datachanged", this);
8977 this.load(this.lastOptions);
8982 * Calls the specified function for each of the Records in the cache.
8983 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8984 * Returning <em>false</em> aborts and exits the iteration.
8985 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8987 each : function(fn, scope){
8988 this.data.each(fn, scope);
8992 * Gets all records modified since the last commit. Modified records are persisted across load operations
8993 * (e.g., during paging).
8994 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8996 getModifiedRecords : function(){
8997 return this.modified;
9001 createFilterFn : function(property, value, anyMatch){
9002 if(!value.exec){ // not a regex
9003 value = String(value);
9004 if(value.length == 0){
9007 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9010 return value.test(r.data[property]);
9015 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9016 * @param {String} property A field on your records
9017 * @param {Number} start The record index to start at (defaults to 0)
9018 * @param {Number} end The last record index to include (defaults to length - 1)
9019 * @return {Number} The sum
9021 sum : function(property, start, end){
9022 var rs = this.data.items, v = 0;
9024 end = (end || end === 0) ? end : rs.length-1;
9026 for(var i = start; i <= end; i++){
9027 v += (rs[i].data[property] || 0);
9033 * Filter the records by a specified property.
9034 * @param {String} field A field on your records
9035 * @param {String/RegExp} value Either a string that the field
9036 * should start with or a RegExp to test against the field
9037 * @param {Boolean} anyMatch True to match any part not just the beginning
9039 filter : function(property, value, anyMatch){
9040 var fn = this.createFilterFn(property, value, anyMatch);
9041 return fn ? this.filterBy(fn) : this.clearFilter();
9045 * Filter by a function. The specified function will be called with each
9046 * record in this data source. If the function returns true the record is included,
9047 * otherwise it is filtered.
9048 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9049 * @param {Object} scope (optional) The scope of the function (defaults to this)
9051 filterBy : function(fn, scope){
9052 this.snapshot = this.snapshot || this.data;
9053 this.data = this.queryBy(fn, scope||this);
9054 this.fireEvent("datachanged", this);
9058 * Query the records by a specified property.
9059 * @param {String} field A field on your records
9060 * @param {String/RegExp} value Either a string that the field
9061 * should start with or a RegExp to test against the field
9062 * @param {Boolean} anyMatch True to match any part not just the beginning
9063 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9065 query : function(property, value, anyMatch){
9066 var fn = this.createFilterFn(property, value, anyMatch);
9067 return fn ? this.queryBy(fn) : this.data.clone();
9071 * Query by a function. The specified function will be called with each
9072 * record in this data source. If the function returns true the record is included
9074 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9075 * @param {Object} scope (optional) The scope of the function (defaults to this)
9076 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9078 queryBy : function(fn, scope){
9079 var data = this.snapshot || this.data;
9080 return data.filterBy(fn, scope||this);
9084 * Collects unique values for a particular dataIndex from this store.
9085 * @param {String} dataIndex The property to collect
9086 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9087 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9088 * @return {Array} An array of the unique values
9090 collect : function(dataIndex, allowNull, bypassFilter){
9091 var d = (bypassFilter === true && this.snapshot) ?
9092 this.snapshot.items : this.data.items;
9093 var v, sv, r = [], l = {};
9094 for(var i = 0, len = d.length; i < len; i++){
9095 v = d[i].data[dataIndex];
9097 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9106 * Revert to a view of the Record cache with no filtering applied.
9107 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9109 clearFilter : function(suppressEvent){
9110 if(this.snapshot && this.snapshot != this.data){
9111 this.data = this.snapshot;
9112 delete this.snapshot;
9113 if(suppressEvent !== true){
9114 this.fireEvent("datachanged", this);
9120 afterEdit : function(record){
9121 if(this.modified.indexOf(record) == -1){
9122 this.modified.push(record);
9124 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9128 afterReject : function(record){
9129 this.modified.remove(record);
9130 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9134 afterCommit : function(record){
9135 this.modified.remove(record);
9136 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9140 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9141 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9143 commitChanges : function(){
9144 var m = this.modified.slice(0);
9146 for(var i = 0, len = m.length; i < len; i++){
9152 * Cancel outstanding changes on all changed records.
9154 rejectChanges : function(){
9155 var m = this.modified.slice(0);
9157 for(var i = 0, len = m.length; i < len; i++){
9162 onMetaChange : function(meta, rtype, o){
9163 this.recordType = rtype;
9164 this.fields = rtype.prototype.fields;
9165 delete this.snapshot;
9166 this.sortInfo = meta.sortInfo || this.sortInfo;
9168 this.fireEvent('metachange', this, this.reader.meta);
9171 moveIndex : function(data, type)
9173 var index = this.indexOf(data);
9175 var newIndex = index + type;
9179 this.insert(newIndex, data);
9184 * Ext JS Library 1.1.1
9185 * Copyright(c) 2006-2007, Ext JS, LLC.
9187 * Originally Released Under LGPL - original licence link has changed is not relivant.
9190 * <script type="text/javascript">
9194 * @class Roo.data.SimpleStore
9195 * @extends Roo.data.Store
9196 * Small helper class to make creating Stores from Array data easier.
9197 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9198 * @cfg {Array} fields An array of field definition objects, or field name strings.
9199 * @cfg {Array} data The multi-dimensional array of data
9201 * @param {Object} config
9203 Roo.data.SimpleStore = function(config){
9204 Roo.data.SimpleStore.superclass.constructor.call(this, {
9206 reader: new Roo.data.ArrayReader({
9209 Roo.data.Record.create(config.fields)
9211 proxy : new Roo.data.MemoryProxy(config.data)
9215 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9217 * Ext JS Library 1.1.1
9218 * Copyright(c) 2006-2007, Ext JS, LLC.
9220 * Originally Released Under LGPL - original licence link has changed is not relivant.
9223 * <script type="text/javascript">
9228 * @extends Roo.data.Store
9229 * @class Roo.data.JsonStore
9230 * Small helper class to make creating Stores for JSON data easier. <br/>
9232 var store = new Roo.data.JsonStore({
9233 url: 'get-images.php',
9235 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9238 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9239 * JsonReader and HttpProxy (unless inline data is provided).</b>
9240 * @cfg {Array} fields An array of field definition objects, or field name strings.
9242 * @param {Object} config
9244 Roo.data.JsonStore = function(c){
9245 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9246 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9247 reader: new Roo.data.JsonReader(c, c.fields)
9250 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9252 * Ext JS Library 1.1.1
9253 * Copyright(c) 2006-2007, Ext JS, LLC.
9255 * Originally Released Under LGPL - original licence link has changed is not relivant.
9258 * <script type="text/javascript">
9262 Roo.data.Field = function(config){
9263 if(typeof config == "string"){
9264 config = {name: config};
9266 Roo.apply(this, config);
9272 var st = Roo.data.SortTypes;
9273 // named sortTypes are supported, here we look them up
9274 if(typeof this.sortType == "string"){
9275 this.sortType = st[this.sortType];
9278 // set default sortType for strings and dates
9282 this.sortType = st.asUCString;
9285 this.sortType = st.asDate;
9288 this.sortType = st.none;
9293 var stripRe = /[\$,%]/g;
9295 // prebuilt conversion function for this field, instead of
9296 // switching every time we're reading a value
9298 var cv, dateFormat = this.dateFormat;
9303 cv = function(v){ return v; };
9306 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9310 return v !== undefined && v !== null && v !== '' ?
9311 parseInt(String(v).replace(stripRe, ""), 10) : '';
9316 return v !== undefined && v !== null && v !== '' ?
9317 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9322 cv = function(v){ return v === true || v === "true" || v == 1; };
9329 if(v instanceof Date){
9333 if(dateFormat == "timestamp"){
9334 return new Date(v*1000);
9336 return Date.parseDate(v, dateFormat);
9338 var parsed = Date.parse(v);
9339 return parsed ? new Date(parsed) : null;
9348 Roo.data.Field.prototype = {
9356 * Ext JS Library 1.1.1
9357 * Copyright(c) 2006-2007, Ext JS, LLC.
9359 * Originally Released Under LGPL - original licence link has changed is not relivant.
9362 * <script type="text/javascript">
9365 // Base class for reading structured data from a data source. This class is intended to be
9366 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9369 * @class Roo.data.DataReader
9370 * Base class for reading structured data from a data source. This class is intended to be
9371 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9374 Roo.data.DataReader = function(meta, recordType){
9378 this.recordType = recordType instanceof Array ?
9379 Roo.data.Record.create(recordType) : recordType;
9382 Roo.data.DataReader.prototype = {
9384 * Create an empty record
9385 * @param {Object} data (optional) - overlay some values
9386 * @return {Roo.data.Record} record created.
9388 newRow : function(d) {
9390 this.recordType.prototype.fields.each(function(c) {
9392 case 'int' : da[c.name] = 0; break;
9393 case 'date' : da[c.name] = new Date(); break;
9394 case 'float' : da[c.name] = 0.0; break;
9395 case 'boolean' : da[c.name] = false; break;
9396 default : da[c.name] = ""; break;
9400 return new this.recordType(Roo.apply(da, d));
9405 * Ext JS Library 1.1.1
9406 * Copyright(c) 2006-2007, Ext JS, LLC.
9408 * Originally Released Under LGPL - original licence link has changed is not relivant.
9411 * <script type="text/javascript">
9415 * @class Roo.data.DataProxy
9416 * @extends Roo.data.Observable
9417 * This class is an abstract base class for implementations which provide retrieval of
9418 * unformatted data objects.<br>
9420 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9421 * (of the appropriate type which knows how to parse the data object) to provide a block of
9422 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9424 * Custom implementations must implement the load method as described in
9425 * {@link Roo.data.HttpProxy#load}.
9427 Roo.data.DataProxy = function(){
9431 * Fires before a network request is made to retrieve a data object.
9432 * @param {Object} This DataProxy object.
9433 * @param {Object} params The params parameter to the load function.
9438 * Fires before the load method's callback is called.
9439 * @param {Object} This DataProxy object.
9440 * @param {Object} o The data object.
9441 * @param {Object} arg The callback argument object passed to the load function.
9445 * @event loadexception
9446 * Fires if an Exception occurs during data retrieval.
9447 * @param {Object} This DataProxy object.
9448 * @param {Object} o The data object.
9449 * @param {Object} arg The callback argument object passed to the load function.
9450 * @param {Object} e The Exception.
9452 loadexception : true
9454 Roo.data.DataProxy.superclass.constructor.call(this);
9457 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9460 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9464 * Ext JS Library 1.1.1
9465 * Copyright(c) 2006-2007, Ext JS, LLC.
9467 * Originally Released Under LGPL - original licence link has changed is not relivant.
9470 * <script type="text/javascript">
9473 * @class Roo.data.MemoryProxy
9474 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9475 * to the Reader when its load method is called.
9477 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9479 Roo.data.MemoryProxy = function(data){
9483 Roo.data.MemoryProxy.superclass.constructor.call(this);
9487 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9489 * Load data from the requested source (in this case an in-memory
9490 * data object passed to the constructor), read the data object into
9491 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9492 * process that block using the passed callback.
9493 * @param {Object} params This parameter is not used by the MemoryProxy class.
9494 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9495 * object into a block of Roo.data.Records.
9496 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9497 * The function must be passed <ul>
9498 * <li>The Record block object</li>
9499 * <li>The "arg" argument from the load function</li>
9500 * <li>A boolean success indicator</li>
9502 * @param {Object} scope The scope in which to call the callback
9503 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9505 load : function(params, reader, callback, scope, arg){
9506 params = params || {};
9509 result = reader.readRecords(this.data);
9511 this.fireEvent("loadexception", this, arg, null, e);
9512 callback.call(scope, null, arg, false);
9515 callback.call(scope, result, arg, true);
9519 update : function(params, records){
9524 * Ext JS Library 1.1.1
9525 * Copyright(c) 2006-2007, Ext JS, LLC.
9527 * Originally Released Under LGPL - original licence link has changed is not relivant.
9530 * <script type="text/javascript">
9533 * @class Roo.data.HttpProxy
9534 * @extends Roo.data.DataProxy
9535 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9536 * configured to reference a certain URL.<br><br>
9538 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9539 * from which the running page was served.<br><br>
9541 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9543 * Be aware that to enable the browser to parse an XML document, the server must set
9544 * the Content-Type header in the HTTP response to "text/xml".
9546 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9547 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9548 * will be used to make the request.
9550 Roo.data.HttpProxy = function(conn){
9551 Roo.data.HttpProxy.superclass.constructor.call(this);
9552 // is conn a conn config or a real conn?
9554 this.useAjax = !conn || !conn.events;
9558 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9559 // thse are take from connection...
9562 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9565 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9566 * extra parameters to each request made by this object. (defaults to undefined)
9569 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9570 * to each request made by this object. (defaults to undefined)
9573 * @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)
9576 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9579 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9585 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9589 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9590 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9591 * a finer-grained basis than the DataProxy events.
9593 getConnection : function(){
9594 return this.useAjax ? Roo.Ajax : this.conn;
9598 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9599 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9600 * process that block using the passed callback.
9601 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9602 * for the request to the remote server.
9603 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9604 * object into a block of Roo.data.Records.
9605 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9606 * The function must be passed <ul>
9607 * <li>The Record block object</li>
9608 * <li>The "arg" argument from the load function</li>
9609 * <li>A boolean success indicator</li>
9611 * @param {Object} scope The scope in which to call the callback
9612 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9614 load : function(params, reader, callback, scope, arg){
9615 if(this.fireEvent("beforeload", this, params) !== false){
9617 params : params || {},
9619 callback : callback,
9624 callback : this.loadResponse,
9628 Roo.applyIf(o, this.conn);
9629 if(this.activeRequest){
9630 Roo.Ajax.abort(this.activeRequest);
9632 this.activeRequest = Roo.Ajax.request(o);
9634 this.conn.request(o);
9637 callback.call(scope||this, null, arg, false);
9642 loadResponse : function(o, success, response){
9643 delete this.activeRequest;
9645 this.fireEvent("loadexception", this, o, response);
9646 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9651 result = o.reader.read(response);
9653 this.fireEvent("loadexception", this, o, response, e);
9654 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9658 this.fireEvent("load", this, o, o.request.arg);
9659 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9663 update : function(dataSet){
9668 updateResponse : function(dataSet){
9673 * Ext JS Library 1.1.1
9674 * Copyright(c) 2006-2007, Ext JS, LLC.
9676 * Originally Released Under LGPL - original licence link has changed is not relivant.
9679 * <script type="text/javascript">
9683 * @class Roo.data.ScriptTagProxy
9684 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9685 * other than the originating domain of the running page.<br><br>
9687 * <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
9688 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9690 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9691 * source code that is used as the source inside a <script> tag.<br><br>
9693 * In order for the browser to process the returned data, the server must wrap the data object
9694 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9695 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9696 * depending on whether the callback name was passed:
9699 boolean scriptTag = false;
9700 String cb = request.getParameter("callback");
9703 response.setContentType("text/javascript");
9705 response.setContentType("application/x-json");
9707 Writer out = response.getWriter();
9709 out.write(cb + "(");
9711 out.print(dataBlock.toJsonString());
9718 * @param {Object} config A configuration object.
9720 Roo.data.ScriptTagProxy = function(config){
9721 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9722 Roo.apply(this, config);
9723 this.head = document.getElementsByTagName("head")[0];
9726 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9728 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9730 * @cfg {String} url The URL from which to request the data object.
9733 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9737 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9738 * the server the name of the callback function set up by the load call to process the returned data object.
9739 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9740 * javascript output which calls this named function passing the data object as its only parameter.
9742 callbackParam : "callback",
9744 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9745 * name to the request.
9750 * Load data from the configured URL, read the data object into
9751 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9752 * process that block using the passed callback.
9753 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9754 * for the request to the remote server.
9755 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9756 * object into a block of Roo.data.Records.
9757 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9758 * The function must be passed <ul>
9759 * <li>The Record block object</li>
9760 * <li>The "arg" argument from the load function</li>
9761 * <li>A boolean success indicator</li>
9763 * @param {Object} scope The scope in which to call the callback
9764 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9766 load : function(params, reader, callback, scope, arg){
9767 if(this.fireEvent("beforeload", this, params) !== false){
9769 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9772 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9774 url += "&_dc=" + (new Date().getTime());
9776 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9779 cb : "stcCallback"+transId,
9780 scriptId : "stcScript"+transId,
9784 callback : callback,
9790 window[trans.cb] = function(o){
9791 conn.handleResponse(o, trans);
9794 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9796 if(this.autoAbort !== false){
9800 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9802 var script = document.createElement("script");
9803 script.setAttribute("src", url);
9804 script.setAttribute("type", "text/javascript");
9805 script.setAttribute("id", trans.scriptId);
9806 this.head.appendChild(script);
9810 callback.call(scope||this, null, arg, false);
9815 isLoading : function(){
9816 return this.trans ? true : false;
9820 * Abort the current server request.
9823 if(this.isLoading()){
9824 this.destroyTrans(this.trans);
9829 destroyTrans : function(trans, isLoaded){
9830 this.head.removeChild(document.getElementById(trans.scriptId));
9831 clearTimeout(trans.timeoutId);
9833 window[trans.cb] = undefined;
9835 delete window[trans.cb];
9838 // if hasn't been loaded, wait for load to remove it to prevent script error
9839 window[trans.cb] = function(){
9840 window[trans.cb] = undefined;
9842 delete window[trans.cb];
9849 handleResponse : function(o, trans){
9851 this.destroyTrans(trans, true);
9854 result = trans.reader.readRecords(o);
9856 this.fireEvent("loadexception", this, o, trans.arg, e);
9857 trans.callback.call(trans.scope||window, null, trans.arg, false);
9860 this.fireEvent("load", this, o, trans.arg);
9861 trans.callback.call(trans.scope||window, result, trans.arg, true);
9865 handleFailure : function(trans){
9867 this.destroyTrans(trans, false);
9868 this.fireEvent("loadexception", this, null, trans.arg);
9869 trans.callback.call(trans.scope||window, null, trans.arg, false);
9873 * Ext JS Library 1.1.1
9874 * Copyright(c) 2006-2007, Ext JS, LLC.
9876 * Originally Released Under LGPL - original licence link has changed is not relivant.
9879 * <script type="text/javascript">
9883 * @class Roo.data.JsonReader
9884 * @extends Roo.data.DataReader
9885 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9886 * based on mappings in a provided Roo.data.Record constructor.
9888 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9889 * in the reply previously.
9894 var RecordDef = Roo.data.Record.create([
9895 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9896 {name: 'occupation'} // This field will use "occupation" as the mapping.
9898 var myReader = new Roo.data.JsonReader({
9899 totalProperty: "results", // The property which contains the total dataset size (optional)
9900 root: "rows", // The property which contains an Array of row objects
9901 id: "id" // The property within each row object that provides an ID for the record (optional)
9905 * This would consume a JSON file like this:
9907 { 'results': 2, 'rows': [
9908 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9909 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9912 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9913 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9914 * paged from the remote server.
9915 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9916 * @cfg {String} root name of the property which contains the Array of row objects.
9917 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9919 * Create a new JsonReader
9920 * @param {Object} meta Metadata configuration options
9921 * @param {Object} recordType Either an Array of field definition objects,
9922 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9924 Roo.data.JsonReader = function(meta, recordType){
9927 // set some defaults:
9929 totalProperty: 'total',
9930 successProperty : 'success',
9935 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9937 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9940 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9941 * Used by Store query builder to append _requestMeta to params.
9944 metaFromRemote : false,
9946 * This method is only used by a DataProxy which has retrieved data from a remote server.
9947 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9948 * @return {Object} data A data block which is used by an Roo.data.Store object as
9949 * a cache of Roo.data.Records.
9951 read : function(response){
9952 var json = response.responseText;
9954 var o = /* eval:var:o */ eval("("+json+")");
9956 throw {message: "JsonReader.read: Json object not found"};
9962 this.metaFromRemote = true;
9963 this.meta = o.metaData;
9964 this.recordType = Roo.data.Record.create(o.metaData.fields);
9965 this.onMetaChange(this.meta, this.recordType, o);
9967 return this.readRecords(o);
9970 // private function a store will implement
9971 onMetaChange : function(meta, recordType, o){
9978 simpleAccess: function(obj, subsc) {
9985 getJsonAccessor: function(){
9987 return function(expr) {
9989 return(re.test(expr))
9990 ? new Function("obj", "return obj." + expr)
10000 * Create a data block containing Roo.data.Records from an XML document.
10001 * @param {Object} o An object which contains an Array of row objects in the property specified
10002 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10003 * which contains the total size of the dataset.
10004 * @return {Object} data A data block which is used by an Roo.data.Store object as
10005 * a cache of Roo.data.Records.
10007 readRecords : function(o){
10009 * After any data loads, the raw JSON data is available for further custom processing.
10013 var s = this.meta, Record = this.recordType,
10014 f = Record.prototype.fields, fi = f.items, fl = f.length;
10016 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10018 if(s.totalProperty) {
10019 this.getTotal = this.getJsonAccessor(s.totalProperty);
10021 if(s.successProperty) {
10022 this.getSuccess = this.getJsonAccessor(s.successProperty);
10024 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10026 var g = this.getJsonAccessor(s.id);
10027 this.getId = function(rec) {
10029 return (r === undefined || r === "") ? null : r;
10032 this.getId = function(){return null;};
10035 for(var jj = 0; jj < fl; jj++){
10037 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10038 this.ef[jj] = this.getJsonAccessor(map);
10042 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10043 if(s.totalProperty){
10044 var vt = parseInt(this.getTotal(o), 10);
10049 if(s.successProperty){
10050 var vs = this.getSuccess(o);
10051 if(vs === false || vs === 'false'){
10056 for(var i = 0; i < c; i++){
10059 var id = this.getId(n);
10060 for(var j = 0; j < fl; j++){
10062 var v = this.ef[j](n);
10064 Roo.log('missing convert for ' + f.name);
10068 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10070 var record = new Record(values, id);
10072 records[i] = record;
10078 totalRecords : totalRecords
10083 * Ext JS Library 1.1.1
10084 * Copyright(c) 2006-2007, Ext JS, LLC.
10086 * Originally Released Under LGPL - original licence link has changed is not relivant.
10089 * <script type="text/javascript">
10093 * @class Roo.data.ArrayReader
10094 * @extends Roo.data.DataReader
10095 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10096 * Each element of that Array represents a row of data fields. The
10097 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10098 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10102 var RecordDef = Roo.data.Record.create([
10103 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10104 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10106 var myReader = new Roo.data.ArrayReader({
10107 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10111 * This would consume an Array like this:
10113 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10115 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10117 * Create a new JsonReader
10118 * @param {Object} meta Metadata configuration options.
10119 * @param {Object} recordType Either an Array of field definition objects
10120 * as specified to {@link Roo.data.Record#create},
10121 * or an {@link Roo.data.Record} object
10122 * created using {@link Roo.data.Record#create}.
10124 Roo.data.ArrayReader = function(meta, recordType){
10125 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10128 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10130 * Create a data block containing Roo.data.Records from an XML document.
10131 * @param {Object} o An Array of row objects which represents the dataset.
10132 * @return {Object} data A data block which is used by an Roo.data.Store object as
10133 * a cache of Roo.data.Records.
10135 readRecords : function(o){
10136 var sid = this.meta ? this.meta.id : null;
10137 var recordType = this.recordType, fields = recordType.prototype.fields;
10140 for(var i = 0; i < root.length; i++){
10143 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10144 for(var j = 0, jlen = fields.length; j < jlen; j++){
10145 var f = fields.items[j];
10146 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10147 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10149 values[f.name] = v;
10151 var record = new recordType(values, id);
10153 records[records.length] = record;
10157 totalRecords : records.length
10166 * @class Roo.bootstrap.ComboBox
10167 * @extends Roo.bootstrap.TriggerField
10168 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10169 * @cfg {Boolean} append (true|false) default false
10170 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10171 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10172 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10173 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10174 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10176 * Create a new ComboBox.
10177 * @param {Object} config Configuration options
10179 Roo.bootstrap.ComboBox = function(config){
10180 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10184 * Fires when the dropdown list is expanded
10185 * @param {Roo.bootstrap.ComboBox} combo This combo box
10190 * Fires when the dropdown list is collapsed
10191 * @param {Roo.bootstrap.ComboBox} combo This combo box
10195 * @event beforeselect
10196 * Fires before a list item is selected. Return false to cancel the selection.
10197 * @param {Roo.bootstrap.ComboBox} combo This combo box
10198 * @param {Roo.data.Record} record The data record returned from the underlying store
10199 * @param {Number} index The index of the selected item in the dropdown list
10201 'beforeselect' : true,
10204 * Fires when a list item is selected
10205 * @param {Roo.bootstrap.ComboBox} combo This combo box
10206 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10207 * @param {Number} index The index of the selected item in the dropdown list
10211 * @event beforequery
10212 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10213 * The event object passed has these properties:
10214 * @param {Roo.bootstrap.ComboBox} combo This combo box
10215 * @param {String} query The query
10216 * @param {Boolean} forceAll true to force "all" query
10217 * @param {Boolean} cancel true to cancel the query
10218 * @param {Object} e The query event object
10220 'beforequery': true,
10223 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10224 * @param {Roo.bootstrap.ComboBox} combo This combo box
10229 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10230 * @param {Roo.bootstrap.ComboBox} combo This combo box
10231 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10236 * Fires when the remove value from the combobox array
10237 * @param {Roo.bootstrap.ComboBox} combo This combo box
10244 this.tickItems = [];
10246 this.selectedIndex = -1;
10247 if(this.mode == 'local'){
10248 if(config.queryDelay === undefined){
10249 this.queryDelay = 10;
10251 if(config.minChars === undefined){
10257 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10260 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10261 * rendering into an Roo.Editor, defaults to false)
10264 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10265 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10268 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10271 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10272 * the dropdown list (defaults to undefined, with no header element)
10276 * @cfg {String/Roo.Template} tpl The template to use to render the output
10280 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10282 listWidth: undefined,
10284 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10285 * mode = 'remote' or 'text' if mode = 'local')
10287 displayField: undefined,
10289 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10290 * mode = 'remote' or 'value' if mode = 'local').
10291 * Note: use of a valueField requires the user make a selection
10292 * in order for a value to be mapped.
10294 valueField: undefined,
10298 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10299 * field's data value (defaults to the underlying DOM element's name)
10301 hiddenName: undefined,
10303 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10307 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10309 selectedClass: 'active',
10312 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10316 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10317 * anchor positions (defaults to 'tl-bl')
10319 listAlign: 'tl-bl?',
10321 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10325 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10326 * query specified by the allQuery config option (defaults to 'query')
10328 triggerAction: 'query',
10330 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10331 * (defaults to 4, does not apply if editable = false)
10335 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10336 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10340 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10341 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10345 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10346 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10350 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10351 * when editable = true (defaults to false)
10353 selectOnFocus:false,
10355 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10357 queryParam: 'query',
10359 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10360 * when mode = 'remote' (defaults to 'Loading...')
10362 loadingText: 'Loading...',
10364 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10368 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10372 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10373 * traditional select (defaults to true)
10377 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10381 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10385 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10386 * listWidth has a higher value)
10390 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10391 * allow the user to set arbitrary text into the field (defaults to false)
10393 forceSelection:false,
10395 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10396 * if typeAhead = true (defaults to 250)
10398 typeAheadDelay : 250,
10400 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10401 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10403 valueNotFoundText : undefined,
10405 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10407 blockFocus : false,
10410 * @cfg {Boolean} disableClear Disable showing of clear button.
10412 disableClear : false,
10414 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10416 alwaysQuery : false,
10419 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10433 btnPosition : 'right',
10434 triggerList : true,
10435 showToggleBtn : true,
10436 // element that contains real text value.. (when hidden is used..)
10438 getAutoCreate : function()
10445 if(!this.tickable){
10446 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10451 * ComboBox with tickable selections
10454 var align = this.labelAlign || this.parentLabelAlign();
10457 cls : 'form-group roo-combobox-tickable' //input-group
10463 cls : 'tickable-buttons',
10468 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10475 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10482 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10489 Roo.each(buttons.cn, function(c){
10491 c.cls += ' btn-' + _this.size;
10494 if (_this.disabled) {
10505 cls: 'form-hidden-field'
10509 cls: 'select2-choices',
10513 cls: 'select2-search-field',
10525 cls: 'select2-container input-group select2-container-multi',
10530 // cls: 'typeahead typeahead-long dropdown-menu',
10531 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10536 if (align ==='left' && this.fieldLabel.length) {
10538 Roo.log("left and has label");
10544 cls : 'control-label col-sm-' + this.labelWidth,
10545 html : this.fieldLabel
10549 cls : "col-sm-" + (12 - this.labelWidth),
10556 } else if ( this.fieldLabel.length) {
10562 //cls : 'input-group-addon',
10563 html : this.fieldLabel
10573 Roo.log(" no label && no align");
10580 ['xs','sm','md','lg'].map(function(size){
10581 if (settings[size]) {
10582 cfg.cls += ' col-' + size + '-' + settings[size];
10591 initEvents: function()
10595 throw "can not find store for combo";
10597 this.store = Roo.factory(this.store, Roo.data);
10600 this.initTickableEvents();
10604 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10606 if(this.hiddenName){
10608 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10610 this.hiddenField.dom.value =
10611 this.hiddenValue !== undefined ? this.hiddenValue :
10612 this.value !== undefined ? this.value : '';
10614 // prevent input submission
10615 this.el.dom.removeAttribute('name');
10616 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10621 // this.el.dom.setAttribute('autocomplete', 'off');
10624 var cls = 'x-combo-list';
10626 //this.list = new Roo.Layer({
10627 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10633 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10634 _this.list.setWidth(lw);
10637 this.list.on('mouseover', this.onViewOver, this);
10638 this.list.on('mousemove', this.onViewMove, this);
10640 this.list.on('scroll', this.onViewScroll, this);
10643 this.list.swallowEvent('mousewheel');
10644 this.assetHeight = 0;
10647 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10648 this.assetHeight += this.header.getHeight();
10651 this.innerList = this.list.createChild({cls:cls+'-inner'});
10652 this.innerList.on('mouseover', this.onViewOver, this);
10653 this.innerList.on('mousemove', this.onViewMove, this);
10654 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10656 if(this.allowBlank && !this.pageSize && !this.disableClear){
10657 this.footer = this.list.createChild({cls:cls+'-ft'});
10658 this.pageTb = new Roo.Toolbar(this.footer);
10662 this.footer = this.list.createChild({cls:cls+'-ft'});
10663 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10664 {pageSize: this.pageSize});
10668 if (this.pageTb && this.allowBlank && !this.disableClear) {
10670 this.pageTb.add(new Roo.Toolbar.Fill(), {
10671 cls: 'x-btn-icon x-btn-clear',
10673 handler: function()
10676 _this.clearValue();
10677 _this.onSelect(false, -1);
10682 this.assetHeight += this.footer.getHeight();
10687 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10690 this.view = new Roo.View(this.list, this.tpl, {
10691 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10693 //this.view.wrapEl.setDisplayed(false);
10694 this.view.on('click', this.onViewClick, this);
10698 this.store.on('beforeload', this.onBeforeLoad, this);
10699 this.store.on('load', this.onLoad, this);
10700 this.store.on('loadexception', this.onLoadException, this);
10702 if(this.resizable){
10703 this.resizer = new Roo.Resizable(this.list, {
10704 pinned:true, handles:'se'
10706 this.resizer.on('resize', function(r, w, h){
10707 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10708 this.listWidth = w;
10709 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10710 this.restrictHeight();
10712 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10715 if(!this.editable){
10716 this.editable = true;
10717 this.setEditable(false);
10722 if (typeof(this.events.add.listeners) != 'undefined') {
10724 this.addicon = this.wrap.createChild(
10725 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10727 this.addicon.on('click', function(e) {
10728 this.fireEvent('add', this);
10731 if (typeof(this.events.edit.listeners) != 'undefined') {
10733 this.editicon = this.wrap.createChild(
10734 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10735 if (this.addicon) {
10736 this.editicon.setStyle('margin-left', '40px');
10738 this.editicon.on('click', function(e) {
10740 // we fire even if inothing is selected..
10741 this.fireEvent('edit', this, this.lastData );
10747 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10748 "up" : function(e){
10749 this.inKeyMode = true;
10753 "down" : function(e){
10754 if(!this.isExpanded()){
10755 this.onTriggerClick();
10757 this.inKeyMode = true;
10762 "enter" : function(e){
10763 // this.onViewClick();
10767 if(this.fireEvent("specialkey", this, e)){
10768 this.onViewClick(false);
10774 "esc" : function(e){
10778 "tab" : function(e){
10781 if(this.fireEvent("specialkey", this, e)){
10782 this.onViewClick(false);
10790 doRelay : function(foo, bar, hname){
10791 if(hname == 'down' || this.scope.isExpanded()){
10792 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10801 this.queryDelay = Math.max(this.queryDelay || 10,
10802 this.mode == 'local' ? 10 : 250);
10805 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10807 if(this.typeAhead){
10808 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10810 if(this.editable !== false){
10811 this.inputEl().on("keyup", this.onKeyUp, this);
10813 if(this.forceSelection){
10814 this.inputEl().on('blur', this.doForce, this);
10818 this.choices = this.el.select('ul.select2-choices', true).first();
10819 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10823 initTickableEvents: function()
10827 if(this.hiddenName){
10829 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10831 this.hiddenField.dom.value =
10832 this.hiddenValue !== undefined ? this.hiddenValue :
10833 this.value !== undefined ? this.value : '';
10835 // prevent input submission
10836 this.el.dom.removeAttribute('name');
10837 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10842 // this.list = this.el.select('ul.dropdown-menu',true).first();
10844 this.choices = this.el.select('ul.select2-choices', true).first();
10845 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10846 if(this.triggerList){
10847 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10850 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10851 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10853 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10854 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10856 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10857 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10859 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10860 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10861 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10864 this.cancelBtn.hide();
10869 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10870 _this.list.setWidth(lw);
10873 this.list.on('mouseover', this.onViewOver, this);
10874 this.list.on('mousemove', this.onViewMove, this);
10876 this.list.on('scroll', this.onViewScroll, this);
10879 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>';
10882 this.view = new Roo.View(this.list, this.tpl, {
10883 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10886 //this.view.wrapEl.setDisplayed(false);
10887 this.view.on('click', this.onViewClick, this);
10891 this.store.on('beforeload', this.onBeforeLoad, this);
10892 this.store.on('load', this.onLoad, this);
10893 this.store.on('loadexception', this.onLoadException, this);
10895 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10896 // "up" : function(e){
10897 // this.inKeyMode = true;
10898 // this.selectPrev();
10901 // "down" : function(e){
10902 // if(!this.isExpanded()){
10903 // this.onTriggerClick();
10905 // this.inKeyMode = true;
10906 // this.selectNext();
10910 // "enter" : function(e){
10911 //// this.onViewClick();
10913 // this.collapse();
10915 // if(this.fireEvent("specialkey", this, e)){
10916 // this.onViewClick(false);
10922 // "esc" : function(e){
10923 // this.collapse();
10926 // "tab" : function(e){
10927 // this.collapse();
10929 // if(this.fireEvent("specialkey", this, e)){
10930 // this.onViewClick(false);
10938 // doRelay : function(foo, bar, hname){
10939 // if(hname == 'down' || this.scope.isExpanded()){
10940 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10945 // forceKeyDown: true
10949 this.queryDelay = Math.max(this.queryDelay || 10,
10950 this.mode == 'local' ? 10 : 250);
10953 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10955 if(this.typeAhead){
10956 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10960 onDestroy : function(){
10962 this.view.setStore(null);
10963 this.view.el.removeAllListeners();
10964 this.view.el.remove();
10965 this.view.purgeListeners();
10968 this.list.dom.innerHTML = '';
10972 this.store.un('beforeload', this.onBeforeLoad, this);
10973 this.store.un('load', this.onLoad, this);
10974 this.store.un('loadexception', this.onLoadException, this);
10976 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10980 fireKey : function(e){
10981 if(e.isNavKeyPress() && !this.list.isVisible()){
10982 this.fireEvent("specialkey", this, e);
10987 onResize: function(w, h){
10988 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10990 // if(typeof w != 'number'){
10991 // // we do not handle it!?!?
10994 // var tw = this.trigger.getWidth();
10995 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10996 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10998 // this.inputEl().setWidth( this.adjustWidth('input', x));
11000 // //this.trigger.setStyle('left', x+'px');
11002 // if(this.list && this.listWidth === undefined){
11003 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11004 // this.list.setWidth(lw);
11005 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11013 * Allow or prevent the user from directly editing the field text. If false is passed,
11014 * the user will only be able to select from the items defined in the dropdown list. This method
11015 * is the runtime equivalent of setting the 'editable' config option at config time.
11016 * @param {Boolean} value True to allow the user to directly edit the field text
11018 setEditable : function(value){
11019 if(value == this.editable){
11022 this.editable = value;
11024 this.inputEl().dom.setAttribute('readOnly', true);
11025 this.inputEl().on('mousedown', this.onTriggerClick, this);
11026 this.inputEl().addClass('x-combo-noedit');
11028 this.inputEl().dom.setAttribute('readOnly', false);
11029 this.inputEl().un('mousedown', this.onTriggerClick, this);
11030 this.inputEl().removeClass('x-combo-noedit');
11036 onBeforeLoad : function(combo,opts){
11037 if(!this.hasFocus){
11041 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11043 // this.restrictHeight();
11044 this.selectedIndex = -1;
11048 onLoad : function(){
11050 this.hasQuery = false;
11052 if(!this.hasFocus){
11056 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11057 this.loading.hide();
11060 if(this.store.getCount() > 0){
11062 // this.restrictHeight();
11063 if(this.lastQuery == this.allQuery){
11064 if(this.editable && !this.tickable){
11065 this.inputEl().dom.select();
11069 !this.selectByValue(this.value, true) &&
11070 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11071 this.store.lastOptions.add != true)
11073 this.select(0, true);
11076 if(this.autoFocus){
11079 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11080 this.taTask.delay(this.typeAheadDelay);
11084 this.onEmptyResults();
11090 onLoadException : function()
11092 this.hasQuery = false;
11094 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11095 this.loading.hide();
11099 Roo.log(this.store.reader.jsonData);
11100 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11102 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11108 onTypeAhead : function(){
11109 if(this.store.getCount() > 0){
11110 var r = this.store.getAt(0);
11111 var newValue = r.data[this.displayField];
11112 var len = newValue.length;
11113 var selStart = this.getRawValue().length;
11115 if(selStart != len){
11116 this.setRawValue(newValue);
11117 this.selectText(selStart, newValue.length);
11123 onSelect : function(record, index){
11125 if(this.fireEvent('beforeselect', this, record, index) !== false){
11127 this.setFromData(index > -1 ? record.data : false);
11130 this.fireEvent('select', this, record, index);
11135 * Returns the currently selected field value or empty string if no value is set.
11136 * @return {String} value The selected value
11138 getValue : function(){
11141 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11144 if(this.valueField){
11145 return typeof this.value != 'undefined' ? this.value : '';
11147 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11152 * Clears any text/value currently set in the field
11154 clearValue : function(){
11155 if(this.hiddenField){
11156 this.hiddenField.dom.value = '';
11159 this.setRawValue('');
11160 this.lastSelectionText = '';
11165 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11166 * will be displayed in the field. If the value does not match the data value of an existing item,
11167 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11168 * Otherwise the field will be blank (although the value will still be set).
11169 * @param {String} value The value to match
11171 setValue : function(v){
11178 if(this.valueField){
11179 var r = this.findRecord(this.valueField, v);
11181 text = r.data[this.displayField];
11182 }else if(this.valueNotFoundText !== undefined){
11183 text = this.valueNotFoundText;
11186 this.lastSelectionText = text;
11187 if(this.hiddenField){
11188 this.hiddenField.dom.value = v;
11190 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11194 * @property {Object} the last set data for the element
11199 * Sets the value of the field based on a object which is related to the record format for the store.
11200 * @param {Object} value the value to set as. or false on reset?
11202 setFromData : function(o){
11205 if(typeof o.display_name !== 'string'){
11206 for(var i=0;i<o.display_name.length;i++){
11207 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11215 var dv = ''; // display value
11216 var vv = ''; // value value..
11218 if (this.displayField) {
11219 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11221 // this is an error condition!!!
11222 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11225 if(this.valueField){
11226 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11229 if(this.hiddenField){
11230 this.hiddenField.dom.value = vv;
11232 this.lastSelectionText = dv;
11233 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11237 // no hidden field.. - we store the value in 'value', but still display
11238 // display field!!!!
11239 this.lastSelectionText = dv;
11240 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11246 reset : function(){
11247 // overridden so that last data is reset..
11248 this.setValue(this.originalValue);
11249 this.clearInvalid();
11250 this.lastData = false;
11252 this.view.clearSelections();
11256 findRecord : function(prop, value){
11258 if(this.store.getCount() > 0){
11259 this.store.each(function(r){
11260 if(r.data[prop] == value){
11270 getName: function()
11272 // returns hidden if it's set..
11273 if (!this.rendered) {return ''};
11274 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11278 onViewMove : function(e, t){
11279 this.inKeyMode = false;
11283 onViewOver : function(e, t){
11284 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11287 var item = this.view.findItemFromChild(t);
11290 var index = this.view.indexOf(item);
11291 this.select(index, false);
11296 onViewClick : function(view, doFocus, el, e)
11298 var index = this.view.getSelectedIndexes()[0];
11300 var r = this.store.getAt(index);
11304 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11311 Roo.each(this.tickItems, function(v,k){
11313 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11314 _this.tickItems.splice(k, 1);
11324 this.tickItems.push(r.data);
11329 this.onSelect(r, index);
11331 if(doFocus !== false && !this.blockFocus){
11332 this.inputEl().focus();
11337 restrictHeight : function(){
11338 //this.innerList.dom.style.height = '';
11339 //var inner = this.innerList.dom;
11340 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11341 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11342 //this.list.beginUpdate();
11343 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11344 this.list.alignTo(this.inputEl(), this.listAlign);
11345 this.list.alignTo(this.inputEl(), this.listAlign);
11346 //this.list.endUpdate();
11350 onEmptyResults : function(){
11355 * Returns true if the dropdown list is expanded, else false.
11357 isExpanded : function(){
11358 return this.list.isVisible();
11362 * Select an item in the dropdown list by its data value. 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 {String} value The data value of the 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)
11367 * @return {Boolean} True if the value matched an item in the list, else false
11369 selectByValue : function(v, scrollIntoView){
11370 if(v !== undefined && v !== null){
11371 var r = this.findRecord(this.valueField || this.displayField, v);
11373 this.select(this.store.indexOf(r), scrollIntoView);
11381 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11382 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11383 * @param {Number} index The zero-based index of the list item to select
11384 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11385 * selected item if it is not currently in view (defaults to true)
11387 select : function(index, scrollIntoView){
11388 this.selectedIndex = index;
11389 this.view.select(index);
11390 if(scrollIntoView !== false){
11391 var el = this.view.getNode(index);
11392 if(el && !this.multiple && !this.tickable){
11393 this.list.scrollChildIntoView(el, false);
11399 selectNext : function(){
11400 var ct = this.store.getCount();
11402 if(this.selectedIndex == -1){
11404 }else if(this.selectedIndex < ct-1){
11405 this.select(this.selectedIndex+1);
11411 selectPrev : function(){
11412 var ct = this.store.getCount();
11414 if(this.selectedIndex == -1){
11416 }else if(this.selectedIndex != 0){
11417 this.select(this.selectedIndex-1);
11423 onKeyUp : function(e){
11424 if(this.editable !== false && !e.isSpecialKey()){
11425 this.lastKey = e.getKey();
11426 this.dqTask.delay(this.queryDelay);
11431 validateBlur : function(){
11432 return !this.list || !this.list.isVisible();
11436 initQuery : function(){
11437 this.doQuery(this.getRawValue());
11441 doForce : function(){
11442 if(this.inputEl().dom.value.length > 0){
11443 this.inputEl().dom.value =
11444 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11450 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11451 * query allowing the query action to be canceled if needed.
11452 * @param {String} query The SQL query to execute
11453 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11454 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11455 * saved in the current store (defaults to false)
11457 doQuery : function(q, forceAll){
11459 if(q === undefined || q === null){
11464 forceAll: forceAll,
11468 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11473 forceAll = qe.forceAll;
11474 if(forceAll === true || (q.length >= this.minChars)){
11476 this.hasQuery = true;
11478 if(this.lastQuery != q || this.alwaysQuery){
11479 this.lastQuery = q;
11480 if(this.mode == 'local'){
11481 this.selectedIndex = -1;
11483 this.store.clearFilter();
11485 this.store.filter(this.displayField, q);
11489 this.store.baseParams[this.queryParam] = q;
11491 var options = {params : this.getParams(q)};
11494 options.add = true;
11495 options.params.start = this.page * this.pageSize;
11498 this.store.load(options);
11500 * this code will make the page width larger, at the beginning, the list not align correctly,
11501 * we should expand the list on onLoad
11502 * so command out it
11507 this.selectedIndex = -1;
11512 this.loadNext = false;
11516 getParams : function(q){
11518 //p[this.queryParam] = q;
11522 p.limit = this.pageSize;
11528 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11530 collapse : function(){
11531 if(!this.isExpanded()){
11539 this.cancelBtn.hide();
11540 this.trigger.show();
11543 Roo.get(document).un('mousedown', this.collapseIf, this);
11544 Roo.get(document).un('mousewheel', this.collapseIf, this);
11545 if (!this.editable) {
11546 Roo.get(document).un('keydown', this.listKeyPress, this);
11548 this.fireEvent('collapse', this);
11552 collapseIf : function(e){
11553 var in_combo = e.within(this.el);
11554 var in_list = e.within(this.list);
11555 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11557 if (in_combo || in_list || is_list) {
11558 //e.stopPropagation();
11563 this.onTickableFooterButtonClick(e, false, false);
11571 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11573 expand : function(){
11575 if(this.isExpanded() || !this.hasFocus){
11579 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11580 this.list.setWidth(lw);
11585 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11586 this.list.setWidth(lw);
11590 this.restrictHeight();
11594 this.tickItems = Roo.apply([], this.item);
11597 this.cancelBtn.show();
11598 this.trigger.hide();
11602 Roo.get(document).on('mousedown', this.collapseIf, this);
11603 Roo.get(document).on('mousewheel', this.collapseIf, this);
11604 if (!this.editable) {
11605 Roo.get(document).on('keydown', this.listKeyPress, this);
11608 this.fireEvent('expand', this);
11612 // Implements the default empty TriggerField.onTriggerClick function
11613 onTriggerClick : function(e)
11615 Roo.log('trigger click');
11617 if(this.disabled || !this.triggerList){
11622 this.loadNext = false;
11624 if(this.isExpanded()){
11626 if (!this.blockFocus) {
11627 this.inputEl().focus();
11631 this.hasFocus = true;
11632 if(this.triggerAction == 'all') {
11633 this.doQuery(this.allQuery, true);
11635 this.doQuery(this.getRawValue());
11637 if (!this.blockFocus) {
11638 this.inputEl().focus();
11643 onTickableTriggerClick : function(e)
11650 this.loadNext = false;
11651 this.hasFocus = true;
11653 if(this.triggerAction == 'all') {
11654 this.doQuery(this.allQuery, true);
11656 this.doQuery(this.getRawValue());
11660 onSearchFieldClick : function(e)
11662 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11667 this.loadNext = false;
11668 this.hasFocus = true;
11670 if(this.triggerAction == 'all') {
11671 this.doQuery(this.allQuery, true);
11673 this.doQuery(this.getRawValue());
11677 listKeyPress : function(e)
11679 //Roo.log('listkeypress');
11680 // scroll to first matching element based on key pres..
11681 if (e.isSpecialKey()) {
11684 var k = String.fromCharCode(e.getKey()).toUpperCase();
11687 var csel = this.view.getSelectedNodes();
11688 var cselitem = false;
11690 var ix = this.view.indexOf(csel[0]);
11691 cselitem = this.store.getAt(ix);
11692 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11698 this.store.each(function(v) {
11700 // start at existing selection.
11701 if (cselitem.id == v.id) {
11707 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11708 match = this.store.indexOf(v);
11714 if (match === false) {
11715 return true; // no more action?
11718 this.view.select(match);
11719 var sn = Roo.get(this.view.getSelectedNodes()[0])
11720 //sn.scrollIntoView(sn.dom.parentNode, false);
11723 onViewScroll : function(e, t){
11725 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){
11729 this.hasQuery = true;
11731 this.loading = this.list.select('.loading', true).first();
11733 if(this.loading === null){
11734 this.list.createChild({
11736 cls: 'loading select2-more-results select2-active',
11737 html: 'Loading more results...'
11740 this.loading = this.list.select('.loading', true).first();
11742 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11744 this.loading.hide();
11747 this.loading.show();
11752 this.loadNext = true;
11754 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11759 addItem : function(o)
11761 var dv = ''; // display value
11763 if (this.displayField) {
11764 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11766 // this is an error condition!!!
11767 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11774 var choice = this.choices.createChild({
11776 cls: 'select2-search-choice',
11785 cls: 'select2-search-choice-close',
11790 }, this.searchField);
11792 var close = choice.select('a.select2-search-choice-close', true).first()
11794 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11802 this.inputEl().dom.value = '';
11806 onRemoveItem : function(e, _self, o)
11808 e.preventDefault();
11809 var index = this.item.indexOf(o.data) * 1;
11812 Roo.log('not this item?!');
11816 this.item.splice(index, 1);
11821 this.fireEvent('remove', this, e);
11825 syncValue : function()
11827 if(!this.item.length){
11834 Roo.each(this.item, function(i){
11835 if(_this.valueField){
11836 value.push(i[_this.valueField]);
11843 this.value = value.join(',');
11845 if(this.hiddenField){
11846 this.hiddenField.dom.value = this.value;
11850 clearItem : function()
11852 if(!this.multiple){
11858 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11865 inputEl: function ()
11868 return this.searchField;
11870 return this.el.select('input.form-control',true).first();
11874 onTickableFooterButtonClick : function(e, btn, el)
11876 e.preventDefault();
11878 if(btn && btn.name == 'cancel'){
11879 this.tickItems = Roo.apply([], this.item);
11888 Roo.each(this.tickItems, function(o){
11899 * @cfg {Boolean} grow
11903 * @cfg {Number} growMin
11907 * @cfg {Number} growMax
11917 * Ext JS Library 1.1.1
11918 * Copyright(c) 2006-2007, Ext JS, LLC.
11920 * Originally Released Under LGPL - original licence link has changed is not relivant.
11923 * <script type="text/javascript">
11928 * @extends Roo.util.Observable
11929 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11930 * This class also supports single and multi selection modes. <br>
11931 * Create a data model bound view:
11933 var store = new Roo.data.Store(...);
11935 var view = new Roo.View({
11937 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11939 singleSelect: true,
11940 selectedClass: "ydataview-selected",
11944 // listen for node click?
11945 view.on("click", function(vw, index, node, e){
11946 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11950 dataModel.load("foobar.xml");
11952 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11954 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11955 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11957 * Note: old style constructor is still suported (container, template, config)
11960 * Create a new View
11961 * @param {Object} config The config object
11964 Roo.View = function(config, depreciated_tpl, depreciated_config){
11966 this.parent = false;
11968 if (typeof(depreciated_tpl) == 'undefined') {
11969 // new way.. - universal constructor.
11970 Roo.apply(this, config);
11971 this.el = Roo.get(this.el);
11974 this.el = Roo.get(config);
11975 this.tpl = depreciated_tpl;
11976 Roo.apply(this, depreciated_config);
11978 this.wrapEl = this.el.wrap().wrap();
11979 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11982 if(typeof(this.tpl) == "string"){
11983 this.tpl = new Roo.Template(this.tpl);
11985 // support xtype ctors..
11986 this.tpl = new Roo.factory(this.tpl, Roo);
11990 this.tpl.compile();
11995 * @event beforeclick
11996 * Fires before a click is processed. Returns false to cancel the default action.
11997 * @param {Roo.View} this
11998 * @param {Number} index The index of the target node
11999 * @param {HTMLElement} node The target node
12000 * @param {Roo.EventObject} e The raw event object
12002 "beforeclick" : true,
12005 * Fires when a template node is clicked.
12006 * @param {Roo.View} this
12007 * @param {Number} index The index of the target node
12008 * @param {HTMLElement} node The target node
12009 * @param {Roo.EventObject} e The raw event object
12014 * Fires when a template node is double clicked.
12015 * @param {Roo.View} this
12016 * @param {Number} index The index of the target node
12017 * @param {HTMLElement} node The target node
12018 * @param {Roo.EventObject} e The raw event object
12022 * @event contextmenu
12023 * Fires when a template node is right clicked.
12024 * @param {Roo.View} this
12025 * @param {Number} index The index of the target node
12026 * @param {HTMLElement} node The target node
12027 * @param {Roo.EventObject} e The raw event object
12029 "contextmenu" : true,
12031 * @event selectionchange
12032 * Fires when the selected nodes change.
12033 * @param {Roo.View} this
12034 * @param {Array} selections Array of the selected nodes
12036 "selectionchange" : true,
12039 * @event beforeselect
12040 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12041 * @param {Roo.View} this
12042 * @param {HTMLElement} node The node to be selected
12043 * @param {Array} selections Array of currently selected nodes
12045 "beforeselect" : true,
12047 * @event preparedata
12048 * Fires on every row to render, to allow you to change the data.
12049 * @param {Roo.View} this
12050 * @param {Object} data to be rendered (change this)
12052 "preparedata" : true
12060 "click": this.onClick,
12061 "dblclick": this.onDblClick,
12062 "contextmenu": this.onContextMenu,
12066 this.selections = [];
12068 this.cmp = new Roo.CompositeElementLite([]);
12070 this.store = Roo.factory(this.store, Roo.data);
12071 this.setStore(this.store, true);
12074 if ( this.footer && this.footer.xtype) {
12076 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12078 this.footer.dataSource = this.store
12079 this.footer.container = fctr;
12080 this.footer = Roo.factory(this.footer, Roo);
12081 fctr.insertFirst(this.el);
12083 // this is a bit insane - as the paging toolbar seems to detach the el..
12084 // dom.parentNode.parentNode.parentNode
12085 // they get detached?
12089 Roo.View.superclass.constructor.call(this);
12094 Roo.extend(Roo.View, Roo.util.Observable, {
12097 * @cfg {Roo.data.Store} store Data store to load data from.
12102 * @cfg {String|Roo.Element} el The container element.
12107 * @cfg {String|Roo.Template} tpl The template used by this View
12111 * @cfg {String} dataName the named area of the template to use as the data area
12112 * Works with domtemplates roo-name="name"
12116 * @cfg {String} selectedClass The css class to add to selected nodes
12118 selectedClass : "x-view-selected",
12120 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12125 * @cfg {String} text to display on mask (default Loading)
12129 * @cfg {Boolean} multiSelect Allow multiple selection
12131 multiSelect : false,
12133 * @cfg {Boolean} singleSelect Allow single selection
12135 singleSelect: false,
12138 * @cfg {Boolean} toggleSelect - selecting
12140 toggleSelect : false,
12143 * @cfg {Boolean} tickable - selecting
12148 * Returns the element this view is bound to.
12149 * @return {Roo.Element}
12151 getEl : function(){
12152 return this.wrapEl;
12158 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12160 refresh : function(){
12161 Roo.log('refresh');
12164 // if we are using something like 'domtemplate', then
12165 // the what gets used is:
12166 // t.applySubtemplate(NAME, data, wrapping data..)
12167 // the outer template then get' applied with
12168 // the store 'extra data'
12169 // and the body get's added to the
12170 // roo-name="data" node?
12171 // <span class='roo-tpl-{name}'></span> ?????
12175 this.clearSelections();
12176 this.el.update("");
12178 var records = this.store.getRange();
12179 if(records.length < 1) {
12181 // is this valid?? = should it render a template??
12183 this.el.update(this.emptyText);
12187 if (this.dataName) {
12188 this.el.update(t.apply(this.store.meta)); //????
12189 el = this.el.child('.roo-tpl-' + this.dataName);
12192 for(var i = 0, len = records.length; i < len; i++){
12193 var data = this.prepareData(records[i].data, i, records[i]);
12194 this.fireEvent("preparedata", this, data, i, records[i]);
12196 var d = Roo.apply({}, data);
12199 Roo.apply(d, {'roo-id' : Roo.id()});
12203 Roo.each(this.parent.item, function(item){
12204 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12207 Roo.apply(d, {'roo-data-checked' : 'checked'});
12211 html[html.length] = Roo.util.Format.trim(
12213 t.applySubtemplate(this.dataName, d, this.store.meta) :
12220 el.update(html.join(""));
12221 this.nodes = el.dom.childNodes;
12222 this.updateIndexes(0);
12227 * Function to override to reformat the data that is sent to
12228 * the template for each node.
12229 * DEPRICATED - use the preparedata event handler.
12230 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12231 * a JSON object for an UpdateManager bound view).
12233 prepareData : function(data, index, record)
12235 this.fireEvent("preparedata", this, data, index, record);
12239 onUpdate : function(ds, record){
12240 Roo.log('on update');
12241 this.clearSelections();
12242 var index = this.store.indexOf(record);
12243 var n = this.nodes[index];
12244 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12245 n.parentNode.removeChild(n);
12246 this.updateIndexes(index, index);
12252 onAdd : function(ds, records, index)
12254 Roo.log(['on Add', ds, records, index] );
12255 this.clearSelections();
12256 if(this.nodes.length == 0){
12260 var n = this.nodes[index];
12261 for(var i = 0, len = records.length; i < len; i++){
12262 var d = this.prepareData(records[i].data, i, records[i]);
12264 this.tpl.insertBefore(n, d);
12267 this.tpl.append(this.el, d);
12270 this.updateIndexes(index);
12273 onRemove : function(ds, record, index){
12274 Roo.log('onRemove');
12275 this.clearSelections();
12276 var el = this.dataName ?
12277 this.el.child('.roo-tpl-' + this.dataName) :
12280 el.dom.removeChild(this.nodes[index]);
12281 this.updateIndexes(index);
12285 * Refresh an individual node.
12286 * @param {Number} index
12288 refreshNode : function(index){
12289 this.onUpdate(this.store, this.store.getAt(index));
12292 updateIndexes : function(startIndex, endIndex){
12293 var ns = this.nodes;
12294 startIndex = startIndex || 0;
12295 endIndex = endIndex || ns.length - 1;
12296 for(var i = startIndex; i <= endIndex; i++){
12297 ns[i].nodeIndex = i;
12302 * Changes the data store this view uses and refresh the view.
12303 * @param {Store} store
12305 setStore : function(store, initial){
12306 if(!initial && this.store){
12307 this.store.un("datachanged", this.refresh);
12308 this.store.un("add", this.onAdd);
12309 this.store.un("remove", this.onRemove);
12310 this.store.un("update", this.onUpdate);
12311 this.store.un("clear", this.refresh);
12312 this.store.un("beforeload", this.onBeforeLoad);
12313 this.store.un("load", this.onLoad);
12314 this.store.un("loadexception", this.onLoad);
12318 store.on("datachanged", this.refresh, this);
12319 store.on("add", this.onAdd, this);
12320 store.on("remove", this.onRemove, this);
12321 store.on("update", this.onUpdate, this);
12322 store.on("clear", this.refresh, this);
12323 store.on("beforeload", this.onBeforeLoad, this);
12324 store.on("load", this.onLoad, this);
12325 store.on("loadexception", this.onLoad, this);
12333 * onbeforeLoad - masks the loading area.
12336 onBeforeLoad : function(store,opts)
12338 Roo.log('onBeforeLoad');
12340 this.el.update("");
12342 this.el.mask(this.mask ? this.mask : "Loading" );
12344 onLoad : function ()
12351 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12352 * @param {HTMLElement} node
12353 * @return {HTMLElement} The template node
12355 findItemFromChild : function(node){
12356 var el = this.dataName ?
12357 this.el.child('.roo-tpl-' + this.dataName,true) :
12360 if(!node || node.parentNode == el){
12363 var p = node.parentNode;
12364 while(p && p != el){
12365 if(p.parentNode == el){
12374 onClick : function(e){
12375 var item = this.findItemFromChild(e.getTarget());
12377 var index = this.indexOf(item);
12378 if(this.onItemClick(item, index, e) !== false){
12379 this.fireEvent("click", this, index, item, e);
12382 this.clearSelections();
12387 onContextMenu : function(e){
12388 var item = this.findItemFromChild(e.getTarget());
12390 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12395 onDblClick : function(e){
12396 var item = this.findItemFromChild(e.getTarget());
12398 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12402 onItemClick : function(item, index, e)
12404 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12407 if (this.toggleSelect) {
12408 var m = this.isSelected(item) ? 'unselect' : 'select';
12411 _t[m](item, true, false);
12414 if(this.multiSelect || this.singleSelect){
12415 if(this.multiSelect && e.shiftKey && this.lastSelection){
12416 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12418 this.select(item, this.multiSelect && e.ctrlKey);
12419 this.lastSelection = item;
12422 if(!this.tickable){
12423 e.preventDefault();
12431 * Get the number of selected nodes.
12434 getSelectionCount : function(){
12435 return this.selections.length;
12439 * Get the currently selected nodes.
12440 * @return {Array} An array of HTMLElements
12442 getSelectedNodes : function(){
12443 return this.selections;
12447 * Get the indexes of the selected nodes.
12450 getSelectedIndexes : function(){
12451 var indexes = [], s = this.selections;
12452 for(var i = 0, len = s.length; i < len; i++){
12453 indexes.push(s[i].nodeIndex);
12459 * Clear all selections
12460 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12462 clearSelections : function(suppressEvent){
12463 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12464 this.cmp.elements = this.selections;
12465 this.cmp.removeClass(this.selectedClass);
12466 this.selections = [];
12467 if(!suppressEvent){
12468 this.fireEvent("selectionchange", this, this.selections);
12474 * Returns true if the passed node is selected
12475 * @param {HTMLElement/Number} node The node or node index
12476 * @return {Boolean}
12478 isSelected : function(node){
12479 var s = this.selections;
12483 node = this.getNode(node);
12484 return s.indexOf(node) !== -1;
12489 * @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
12490 * @param {Boolean} keepExisting (optional) true to keep existing selections
12491 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12493 select : function(nodeInfo, keepExisting, suppressEvent){
12494 if(nodeInfo instanceof Array){
12496 this.clearSelections(true);
12498 for(var i = 0, len = nodeInfo.length; i < len; i++){
12499 this.select(nodeInfo[i], true, true);
12503 var node = this.getNode(nodeInfo);
12504 if(!node || this.isSelected(node)){
12505 return; // already selected.
12508 this.clearSelections(true);
12510 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12511 Roo.fly(node).addClass(this.selectedClass);
12512 this.selections.push(node);
12513 if(!suppressEvent){
12514 this.fireEvent("selectionchange", this, this.selections);
12522 * @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
12523 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12524 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12526 unselect : function(nodeInfo, keepExisting, suppressEvent)
12528 if(nodeInfo instanceof Array){
12529 Roo.each(this.selections, function(s) {
12530 this.unselect(s, nodeInfo);
12534 var node = this.getNode(nodeInfo);
12535 if(!node || !this.isSelected(node)){
12536 Roo.log("not selected");
12537 return; // not selected.
12541 Roo.each(this.selections, function(s) {
12543 Roo.fly(node).removeClass(this.selectedClass);
12550 this.selections= ns;
12551 this.fireEvent("selectionchange", this, this.selections);
12555 * Gets a template node.
12556 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12557 * @return {HTMLElement} The node or null if it wasn't found
12559 getNode : function(nodeInfo){
12560 if(typeof nodeInfo == "string"){
12561 return document.getElementById(nodeInfo);
12562 }else if(typeof nodeInfo == "number"){
12563 return this.nodes[nodeInfo];
12569 * Gets a range template nodes.
12570 * @param {Number} startIndex
12571 * @param {Number} endIndex
12572 * @return {Array} An array of nodes
12574 getNodes : function(start, end){
12575 var ns = this.nodes;
12576 start = start || 0;
12577 end = typeof end == "undefined" ? ns.length - 1 : end;
12580 for(var i = start; i <= end; i++){
12584 for(var i = start; i >= end; i--){
12592 * Finds the index of the passed node
12593 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12594 * @return {Number} The index of the node or -1
12596 indexOf : function(node){
12597 node = this.getNode(node);
12598 if(typeof node.nodeIndex == "number"){
12599 return node.nodeIndex;
12601 var ns = this.nodes;
12602 for(var i = 0, len = ns.length; i < len; i++){
12613 * based on jquery fullcalendar
12617 Roo.bootstrap = Roo.bootstrap || {};
12619 * @class Roo.bootstrap.Calendar
12620 * @extends Roo.bootstrap.Component
12621 * Bootstrap Calendar class
12622 * @cfg {Boolean} loadMask (true|false) default false
12623 * @cfg {Object} header generate the user specific header of the calendar, default false
12626 * Create a new Container
12627 * @param {Object} config The config object
12632 Roo.bootstrap.Calendar = function(config){
12633 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12637 * Fires when a date is selected
12638 * @param {DatePicker} this
12639 * @param {Date} date The selected date
12643 * @event monthchange
12644 * Fires when the displayed month changes
12645 * @param {DatePicker} this
12646 * @param {Date} date The selected month
12648 'monthchange': true,
12650 * @event evententer
12651 * Fires when mouse over an event
12652 * @param {Calendar} this
12653 * @param {event} Event
12655 'evententer': true,
12657 * @event eventleave
12658 * Fires when the mouse leaves an
12659 * @param {Calendar} this
12662 'eventleave': true,
12664 * @event eventclick
12665 * Fires when the mouse click an
12666 * @param {Calendar} this
12675 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12678 * @cfg {Number} startDay
12679 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12687 getAutoCreate : function(){
12690 var fc_button = function(name, corner, style, content ) {
12691 return Roo.apply({},{
12693 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12695 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12698 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12709 style : 'width:100%',
12716 cls : 'fc-header-left',
12718 fc_button('prev', 'left', 'arrow', '‹' ),
12719 fc_button('next', 'right', 'arrow', '›' ),
12720 { tag: 'span', cls: 'fc-header-space' },
12721 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12729 cls : 'fc-header-center',
12733 cls: 'fc-header-title',
12736 html : 'month / year'
12744 cls : 'fc-header-right',
12746 /* fc_button('month', 'left', '', 'month' ),
12747 fc_button('week', '', '', 'week' ),
12748 fc_button('day', 'right', '', 'day' )
12760 header = this.header;
12763 var cal_heads = function() {
12765 // fixme - handle this.
12767 for (var i =0; i < Date.dayNames.length; i++) {
12768 var d = Date.dayNames[i];
12771 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12772 html : d.substring(0,3)
12776 ret[0].cls += ' fc-first';
12777 ret[6].cls += ' fc-last';
12780 var cal_cell = function(n) {
12783 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12788 cls: 'fc-day-number',
12792 cls: 'fc-day-content',
12796 style: 'position: relative;' // height: 17px;
12808 var cal_rows = function() {
12811 for (var r = 0; r < 6; r++) {
12818 for (var i =0; i < Date.dayNames.length; i++) {
12819 var d = Date.dayNames[i];
12820 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12823 row.cn[0].cls+=' fc-first';
12824 row.cn[0].cn[0].style = 'min-height:90px';
12825 row.cn[6].cls+=' fc-last';
12829 ret[0].cls += ' fc-first';
12830 ret[4].cls += ' fc-prev-last';
12831 ret[5].cls += ' fc-last';
12838 cls: 'fc-border-separate',
12839 style : 'width:100%',
12847 cls : 'fc-first fc-last',
12865 cls : 'fc-content',
12866 style : "position: relative;",
12869 cls : 'fc-view fc-view-month fc-grid',
12870 style : 'position: relative',
12871 unselectable : 'on',
12874 cls : 'fc-event-container',
12875 style : 'position:absolute;z-index:8;top:0;left:0;'
12893 initEvents : function()
12896 throw "can not find store for calendar";
12902 style: "text-align:center",
12906 style: "background-color:white;width:50%;margin:250 auto",
12910 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12921 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12923 var size = this.el.select('.fc-content', true).first().getSize();
12924 this.maskEl.setSize(size.width, size.height);
12925 this.maskEl.enableDisplayMode("block");
12926 if(!this.loadMask){
12927 this.maskEl.hide();
12930 this.store = Roo.factory(this.store, Roo.data);
12931 this.store.on('load', this.onLoad, this);
12932 this.store.on('beforeload', this.onBeforeLoad, this);
12936 this.cells = this.el.select('.fc-day',true);
12937 //Roo.log(this.cells);
12938 this.textNodes = this.el.query('.fc-day-number');
12939 this.cells.addClassOnOver('fc-state-hover');
12941 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12942 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12943 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12944 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12946 this.on('monthchange', this.onMonthChange, this);
12948 this.update(new Date().clearTime());
12951 resize : function() {
12952 var sz = this.el.getSize();
12954 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12955 this.el.select('.fc-day-content div',true).setHeight(34);
12960 showPrevMonth : function(e){
12961 this.update(this.activeDate.add("mo", -1));
12963 showToday : function(e){
12964 this.update(new Date().clearTime());
12967 showNextMonth : function(e){
12968 this.update(this.activeDate.add("mo", 1));
12972 showPrevYear : function(){
12973 this.update(this.activeDate.add("y", -1));
12977 showNextYear : function(){
12978 this.update(this.activeDate.add("y", 1));
12983 update : function(date)
12985 var vd = this.activeDate;
12986 this.activeDate = date;
12987 // if(vd && this.el){
12988 // var t = date.getTime();
12989 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12990 // Roo.log('using add remove');
12992 // this.fireEvent('monthchange', this, date);
12994 // this.cells.removeClass("fc-state-highlight");
12995 // this.cells.each(function(c){
12996 // if(c.dateValue == t){
12997 // c.addClass("fc-state-highlight");
12998 // setTimeout(function(){
12999 // try{c.dom.firstChild.focus();}catch(e){}
13009 var days = date.getDaysInMonth();
13011 var firstOfMonth = date.getFirstDateOfMonth();
13012 var startingPos = firstOfMonth.getDay()-this.startDay;
13014 if(startingPos < this.startDay){
13018 var pm = date.add(Date.MONTH, -1);
13019 var prevStart = pm.getDaysInMonth()-startingPos;
13021 this.cells = this.el.select('.fc-day',true);
13022 this.textNodes = this.el.query('.fc-day-number');
13023 this.cells.addClassOnOver('fc-state-hover');
13025 var cells = this.cells.elements;
13026 var textEls = this.textNodes;
13028 Roo.each(cells, function(cell){
13029 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13032 days += startingPos;
13034 // convert everything to numbers so it's fast
13035 var day = 86400000;
13036 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13039 //Roo.log(prevStart);
13041 var today = new Date().clearTime().getTime();
13042 var sel = date.clearTime().getTime();
13043 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13044 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13045 var ddMatch = this.disabledDatesRE;
13046 var ddText = this.disabledDatesText;
13047 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13048 var ddaysText = this.disabledDaysText;
13049 var format = this.format;
13051 var setCellClass = function(cal, cell){
13055 //Roo.log('set Cell Class');
13057 var t = d.getTime();
13061 cell.dateValue = t;
13063 cell.className += " fc-today";
13064 cell.className += " fc-state-highlight";
13065 cell.title = cal.todayText;
13068 // disable highlight in other month..
13069 //cell.className += " fc-state-highlight";
13074 cell.className = " fc-state-disabled";
13075 cell.title = cal.minText;
13079 cell.className = " fc-state-disabled";
13080 cell.title = cal.maxText;
13084 if(ddays.indexOf(d.getDay()) != -1){
13085 cell.title = ddaysText;
13086 cell.className = " fc-state-disabled";
13089 if(ddMatch && format){
13090 var fvalue = d.dateFormat(format);
13091 if(ddMatch.test(fvalue)){
13092 cell.title = ddText.replace("%0", fvalue);
13093 cell.className = " fc-state-disabled";
13097 if (!cell.initialClassName) {
13098 cell.initialClassName = cell.dom.className;
13101 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13106 for(; i < startingPos; i++) {
13107 textEls[i].innerHTML = (++prevStart);
13108 d.setDate(d.getDate()+1);
13110 cells[i].className = "fc-past fc-other-month";
13111 setCellClass(this, cells[i]);
13116 for(; i < days; i++){
13117 intDay = i - startingPos + 1;
13118 textEls[i].innerHTML = (intDay);
13119 d.setDate(d.getDate()+1);
13121 cells[i].className = ''; // "x-date-active";
13122 setCellClass(this, cells[i]);
13126 for(; i < 42; i++) {
13127 textEls[i].innerHTML = (++extraDays);
13128 d.setDate(d.getDate()+1);
13130 cells[i].className = "fc-future fc-other-month";
13131 setCellClass(this, cells[i]);
13134 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13136 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13138 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13139 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13141 if(totalRows != 6){
13142 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13143 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13146 this.fireEvent('monthchange', this, date);
13150 if(!this.internalRender){
13151 var main = this.el.dom.firstChild;
13152 var w = main.offsetWidth;
13153 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13154 Roo.fly(main).setWidth(w);
13155 this.internalRender = true;
13156 // opera does not respect the auto grow header center column
13157 // then, after it gets a width opera refuses to recalculate
13158 // without a second pass
13159 if(Roo.isOpera && !this.secondPass){
13160 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13161 this.secondPass = true;
13162 this.update.defer(10, this, [date]);
13169 findCell : function(dt) {
13170 dt = dt.clearTime().getTime();
13172 this.cells.each(function(c){
13173 //Roo.log("check " +c.dateValue + '?=' + dt);
13174 if(c.dateValue == dt){
13184 findCells : function(ev) {
13185 var s = ev.start.clone().clearTime().getTime();
13187 var e= ev.end.clone().clearTime().getTime();
13190 this.cells.each(function(c){
13191 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13193 if(c.dateValue > e){
13196 if(c.dateValue < s){
13205 // findBestRow: function(cells)
13209 // for (var i =0 ; i < cells.length;i++) {
13210 // ret = Math.max(cells[i].rows || 0,ret);
13217 addItem : function(ev)
13219 // look for vertical location slot in
13220 var cells = this.findCells(ev);
13222 // ev.row = this.findBestRow(cells);
13224 // work out the location.
13228 for(var i =0; i < cells.length; i++) {
13230 cells[i].row = cells[0].row;
13233 cells[i].row = cells[i].row + 1;
13243 if (crow.start.getY() == cells[i].getY()) {
13245 crow.end = cells[i];
13262 cells[0].events.push(ev);
13264 this.calevents.push(ev);
13267 clearEvents: function() {
13269 if(!this.calevents){
13273 Roo.each(this.cells.elements, function(c){
13279 Roo.each(this.calevents, function(e) {
13280 Roo.each(e.els, function(el) {
13281 el.un('mouseenter' ,this.onEventEnter, this);
13282 el.un('mouseleave' ,this.onEventLeave, this);
13287 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13293 renderEvents: function()
13297 this.cells.each(function(c) {
13306 if(c.row != c.events.length){
13307 r = 4 - (4 - (c.row - c.events.length));
13310 c.events = ev.slice(0, r);
13311 c.more = ev.slice(r);
13313 if(c.more.length && c.more.length == 1){
13314 c.events.push(c.more.pop());
13317 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13321 this.cells.each(function(c) {
13323 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13326 for (var e = 0; e < c.events.length; e++){
13327 var ev = c.events[e];
13328 var rows = ev.rows;
13330 for(var i = 0; i < rows.length; i++) {
13332 // how many rows should it span..
13335 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13336 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13338 unselectable : "on",
13341 cls: 'fc-event-inner',
13345 // cls: 'fc-event-time',
13346 // html : cells.length > 1 ? '' : ev.time
13350 cls: 'fc-event-title',
13351 html : String.format('{0}', ev.title)
13358 cls: 'ui-resizable-handle ui-resizable-e',
13359 html : '  '
13366 cfg.cls += ' fc-event-start';
13368 if ((i+1) == rows.length) {
13369 cfg.cls += ' fc-event-end';
13372 var ctr = _this.el.select('.fc-event-container',true).first();
13373 var cg = ctr.createChild(cfg);
13375 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13376 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13378 var r = (c.more.length) ? 1 : 0;
13379 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13380 cg.setWidth(ebox.right - sbox.x -2);
13382 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13383 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13384 cg.on('click', _this.onEventClick, _this, ev);
13395 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13396 style : 'position: absolute',
13397 unselectable : "on",
13400 cls: 'fc-event-inner',
13404 cls: 'fc-event-title',
13412 cls: 'ui-resizable-handle ui-resizable-e',
13413 html : '  '
13419 var ctr = _this.el.select('.fc-event-container',true).first();
13420 var cg = ctr.createChild(cfg);
13422 var sbox = c.select('.fc-day-content',true).first().getBox();
13423 var ebox = c.select('.fc-day-content',true).first().getBox();
13425 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13426 cg.setWidth(ebox.right - sbox.x -2);
13428 cg.on('click', _this.onMoreEventClick, _this, c.more);
13438 onEventEnter: function (e, el,event,d) {
13439 this.fireEvent('evententer', this, el, event);
13442 onEventLeave: function (e, el,event,d) {
13443 this.fireEvent('eventleave', this, el, event);
13446 onEventClick: function (e, el,event,d) {
13447 this.fireEvent('eventclick', this, el, event);
13450 onMonthChange: function () {
13454 onMoreEventClick: function(e, el, more)
13458 this.calpopover.placement = 'right';
13459 this.calpopover.setTitle('More');
13461 this.calpopover.setContent('');
13463 var ctr = this.calpopover.el.select('.popover-content', true).first();
13465 Roo.each(more, function(m){
13467 cls : 'fc-event-hori fc-event-draggable',
13470 var cg = ctr.createChild(cfg);
13472 cg.on('click', _this.onEventClick, _this, m);
13475 this.calpopover.show(el);
13480 onLoad: function ()
13482 this.calevents = [];
13485 if(this.store.getCount() > 0){
13486 this.store.data.each(function(d){
13489 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13490 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13491 time : d.data.start_time,
13492 title : d.data.title,
13493 description : d.data.description,
13494 venue : d.data.venue
13499 this.renderEvents();
13501 if(this.calevents.length && this.loadMask){
13502 this.maskEl.hide();
13506 onBeforeLoad: function()
13508 this.clearEvents();
13510 this.maskEl.show();
13524 * @class Roo.bootstrap.Popover
13525 * @extends Roo.bootstrap.Component
13526 * Bootstrap Popover class
13527 * @cfg {String} html contents of the popover (or false to use children..)
13528 * @cfg {String} title of popover (or false to hide)
13529 * @cfg {String} placement how it is placed
13530 * @cfg {String} trigger click || hover (or false to trigger manually)
13531 * @cfg {String} over what (parent or false to trigger manually.)
13534 * Create a new Popover
13535 * @param {Object} config The config object
13538 Roo.bootstrap.Popover = function(config){
13539 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13542 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13544 title: 'Fill in a title',
13547 placement : 'right',
13548 trigger : 'hover', // hover
13552 can_build_overlaid : false,
13554 getChildContainer : function()
13556 return this.el.select('.popover-content',true).first();
13559 getAutoCreate : function(){
13560 Roo.log('make popover?');
13562 cls : 'popover roo-dynamic',
13563 style: 'display:block',
13569 cls : 'popover-inner',
13573 cls: 'popover-title',
13577 cls : 'popover-content',
13588 setTitle: function(str)
13590 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13592 setContent: function(str)
13594 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13596 // as it get's added to the bottom of the page.
13597 onRender : function(ct, position)
13599 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13601 var cfg = Roo.apply({}, this.getAutoCreate());
13605 cfg.cls += ' ' + this.cls;
13608 cfg.style = this.style;
13610 Roo.log("adding to ")
13611 this.el = Roo.get(document.body).createChild(cfg, position);
13617 initEvents : function()
13619 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13620 this.el.enableDisplayMode('block');
13622 if (this.over === false) {
13625 if (this.triggers === false) {
13628 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13629 var triggers = this.trigger ? this.trigger.split(' ') : [];
13630 Roo.each(triggers, function(trigger) {
13632 if (trigger == 'click') {
13633 on_el.on('click', this.toggle, this);
13634 } else if (trigger != 'manual') {
13635 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13636 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13638 on_el.on(eventIn ,this.enter, this);
13639 on_el.on(eventOut, this.leave, this);
13650 toggle : function () {
13651 this.hoverState == 'in' ? this.leave() : this.enter();
13654 enter : function () {
13657 clearTimeout(this.timeout);
13659 this.hoverState = 'in'
13661 if (!this.delay || !this.delay.show) {
13666 this.timeout = setTimeout(function () {
13667 if (_t.hoverState == 'in') {
13670 }, this.delay.show)
13672 leave : function() {
13673 clearTimeout(this.timeout);
13675 this.hoverState = 'out'
13677 if (!this.delay || !this.delay.hide) {
13682 this.timeout = setTimeout(function () {
13683 if (_t.hoverState == 'out') {
13686 }, this.delay.hide)
13689 show : function (on_el)
13692 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13695 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13696 if (this.html !== false) {
13697 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13699 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13700 if (!this.title.length) {
13701 this.el.select('.popover-title',true).hide();
13704 var placement = typeof this.placement == 'function' ?
13705 this.placement.call(this, this.el, on_el) :
13708 var autoToken = /\s?auto?\s?/i;
13709 var autoPlace = autoToken.test(placement);
13711 placement = placement.replace(autoToken, '') || 'top';
13715 //this.el.setXY([0,0]);
13717 this.el.dom.style.display='block';
13718 this.el.addClass(placement);
13720 //this.el.appendTo(on_el);
13722 var p = this.getPosition();
13723 var box = this.el.getBox();
13728 var align = Roo.bootstrap.Popover.alignment[placement]
13729 this.el.alignTo(on_el, align[0],align[1]);
13730 //var arrow = this.el.select('.arrow',true).first();
13731 //arrow.set(align[2],
13733 this.el.addClass('in');
13734 this.hoverState = null;
13736 if (this.el.hasClass('fade')) {
13743 this.el.setXY([0,0]);
13744 this.el.removeClass('in');
13751 Roo.bootstrap.Popover.alignment = {
13752 'left' : ['r-l', [-10,0], 'right'],
13753 'right' : ['l-r', [10,0], 'left'],
13754 'bottom' : ['t-b', [0,10], 'top'],
13755 'top' : [ 'b-t', [0,-10], 'bottom']
13766 * @class Roo.bootstrap.Progress
13767 * @extends Roo.bootstrap.Component
13768 * Bootstrap Progress class
13769 * @cfg {Boolean} striped striped of the progress bar
13770 * @cfg {Boolean} active animated of the progress bar
13774 * Create a new Progress
13775 * @param {Object} config The config object
13778 Roo.bootstrap.Progress = function(config){
13779 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13782 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13787 getAutoCreate : function(){
13795 cfg.cls += ' progress-striped';
13799 cfg.cls += ' active';
13818 * @class Roo.bootstrap.ProgressBar
13819 * @extends Roo.bootstrap.Component
13820 * Bootstrap ProgressBar class
13821 * @cfg {Number} aria_valuenow aria-value now
13822 * @cfg {Number} aria_valuemin aria-value min
13823 * @cfg {Number} aria_valuemax aria-value max
13824 * @cfg {String} label label for the progress bar
13825 * @cfg {String} panel (success | info | warning | danger )
13826 * @cfg {String} role role of the progress bar
13827 * @cfg {String} sr_only text
13831 * Create a new ProgressBar
13832 * @param {Object} config The config object
13835 Roo.bootstrap.ProgressBar = function(config){
13836 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13839 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13843 aria_valuemax : 100,
13849 getAutoCreate : function()
13854 cls: 'progress-bar',
13855 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13867 cfg.role = this.role;
13870 if(this.aria_valuenow){
13871 cfg['aria-valuenow'] = this.aria_valuenow;
13874 if(this.aria_valuemin){
13875 cfg['aria-valuemin'] = this.aria_valuemin;
13878 if(this.aria_valuemax){
13879 cfg['aria-valuemax'] = this.aria_valuemax;
13882 if(this.label && !this.sr_only){
13883 cfg.html = this.label;
13887 cfg.cls += ' progress-bar-' + this.panel;
13893 update : function(aria_valuenow)
13895 this.aria_valuenow = aria_valuenow;
13897 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13912 * @class Roo.bootstrap.TabGroup
13913 * @extends Roo.bootstrap.Column
13914 * Bootstrap Column class
13915 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13916 * @cfg {Boolean} carousel true to make the group behave like a carousel
13919 * Create a new TabGroup
13920 * @param {Object} config The config object
13923 Roo.bootstrap.TabGroup = function(config){
13924 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13926 this.navId = Roo.id();
13929 Roo.bootstrap.TabGroup.register(this);
13933 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13936 transition : false,
13938 getAutoCreate : function()
13940 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13942 cfg.cls += ' tab-content';
13944 if (this.carousel) {
13945 cfg.cls += ' carousel slide';
13947 cls : 'carousel-inner'
13954 getChildContainer : function()
13956 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13960 * register a Navigation item
13961 * @param {Roo.bootstrap.NavItem} the navitem to add
13963 register : function(item)
13965 this.tabs.push( item);
13966 item.navId = this.navId; // not really needed..
13970 getActivePanel : function()
13973 Roo.each(this.tabs, function(t) {
13983 getPanelByName : function(n)
13986 Roo.each(this.tabs, function(t) {
13987 if (t.tabId == n) {
13995 indexOfPanel : function(p)
13998 Roo.each(this.tabs, function(t,i) {
13999 if (t.tabId == p.tabId) {
14008 * show a specific panel
14009 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14010 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14012 showPanel : function (pan)
14015 if (typeof(pan) == 'number') {
14016 pan = this.tabs[pan];
14018 if (typeof(pan) == 'string') {
14019 pan = this.getPanelByName(pan);
14021 if (pan.tabId == this.getActivePanel().tabId) {
14024 var cur = this.getActivePanel();
14026 if (false === cur.fireEvent('beforedeactivate')) {
14030 if (this.carousel) {
14031 this.transition = true;
14032 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14033 var lr = dir == 'next' ? 'left' : 'right';
14034 pan.el.addClass(dir); // or prev
14035 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14036 cur.el.addClass(lr); // or right
14037 pan.el.addClass(lr);
14040 cur.el.on('transitionend', function() {
14041 Roo.log("trans end?");
14043 pan.el.removeClass([lr,dir]);
14044 pan.setActive(true);
14046 cur.el.removeClass([lr]);
14047 cur.setActive(false);
14049 _this.transition = false;
14051 }, this, { single: true } );
14055 cur.setActive(false);
14056 pan.setActive(true);
14060 showPanelNext : function()
14062 var i = this.indexOfPanel(this.getActivePanel());
14063 if (i > this.tabs.length) {
14066 this.showPanel(this.tabs[i+1]);
14068 showPanelPrev : function()
14070 var i = this.indexOfPanel(this.getActivePanel());
14074 this.showPanel(this.tabs[i-1]);
14085 Roo.apply(Roo.bootstrap.TabGroup, {
14089 * register a Navigation Group
14090 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14092 register : function(navgrp)
14094 this.groups[navgrp.navId] = navgrp;
14098 * fetch a Navigation Group based on the navigation ID
14099 * if one does not exist , it will get created.
14100 * @param {string} the navgroup to add
14101 * @returns {Roo.bootstrap.NavGroup} the navgroup
14103 get: function(navId) {
14104 if (typeof(this.groups[navId]) == 'undefined') {
14105 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14107 return this.groups[navId] ;
14122 * @class Roo.bootstrap.TabPanel
14123 * @extends Roo.bootstrap.Component
14124 * Bootstrap TabPanel class
14125 * @cfg {Boolean} active panel active
14126 * @cfg {String} html panel content
14127 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14128 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14132 * Create a new TabPanel
14133 * @param {Object} config The config object
14136 Roo.bootstrap.TabPanel = function(config){
14137 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14141 * Fires when the active status changes
14142 * @param {Roo.bootstrap.TabPanel} this
14143 * @param {Boolean} state the new state
14148 * @event beforedeactivate
14149 * Fires before a tab is de-activated - can be used to do validation on a form.
14150 * @param {Roo.bootstrap.TabPanel} this
14151 * @return {Boolean} false if there is an error
14154 'beforedeactivate': true
14157 this.tabId = this.tabId || Roo.id();
14161 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14168 getAutoCreate : function(){
14171 // item is needed for carousel - not sure if it has any effect otherwise
14172 cls: 'tab-pane item',
14173 html: this.html || ''
14177 cfg.cls += ' active';
14181 cfg.tabId = this.tabId;
14188 initEvents: function()
14190 Roo.log('-------- init events on tab panel ---------');
14192 var p = this.parent();
14193 this.navId = this.navId || p.navId;
14195 if (typeof(this.navId) != 'undefined') {
14196 // not really needed.. but just in case.. parent should be a NavGroup.
14197 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14198 Roo.log(['register', tg, this]);
14204 onRender : function(ct, position)
14206 // Roo.log("Call onRender: " + this.xtype);
14208 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14216 setActive: function(state)
14218 Roo.log("panel - set active " + this.tabId + "=" + state);
14220 this.active = state;
14222 this.el.removeClass('active');
14224 } else if (!this.el.hasClass('active')) {
14225 this.el.addClass('active');
14227 this.fireEvent('changed', this, state);
14244 * @class Roo.bootstrap.DateField
14245 * @extends Roo.bootstrap.Input
14246 * Bootstrap DateField class
14247 * @cfg {Number} weekStart default 0
14248 * @cfg {Number} weekStart default 0
14249 * @cfg {Number} viewMode default empty, (months|years)
14250 * @cfg {Number} minViewMode default empty, (months|years)
14251 * @cfg {Number} startDate default -Infinity
14252 * @cfg {Number} endDate default Infinity
14253 * @cfg {Boolean} todayHighlight default false
14254 * @cfg {Boolean} todayBtn default false
14255 * @cfg {Boolean} calendarWeeks default false
14256 * @cfg {Object} daysOfWeekDisabled default empty
14258 * @cfg {Boolean} keyboardNavigation default true
14259 * @cfg {String} language default en
14262 * Create a new DateField
14263 * @param {Object} config The config object
14266 Roo.bootstrap.DateField = function(config){
14267 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14271 * Fires when this field show.
14272 * @param {Roo.bootstrap.DateField} this
14273 * @param {Mixed} date The date value
14278 * Fires when this field hide.
14279 * @param {Roo.bootstrap.DateField} this
14280 * @param {Mixed} date The date value
14285 * Fires when select a date.
14286 * @param {Roo.bootstrap.DateField} this
14287 * @param {Mixed} date The date value
14293 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14296 * @cfg {String} format
14297 * The default date format string which can be overriden for localization support. The format must be
14298 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14302 * @cfg {String} altFormats
14303 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14304 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14306 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14314 todayHighlight : false,
14320 keyboardNavigation: true,
14322 calendarWeeks: false,
14324 startDate: -Infinity,
14328 daysOfWeekDisabled: [],
14332 UTCDate: function()
14334 return new Date(Date.UTC.apply(Date, arguments));
14337 UTCToday: function()
14339 var today = new Date();
14340 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14343 getDate: function() {
14344 var d = this.getUTCDate();
14345 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14348 getUTCDate: function() {
14352 setDate: function(d) {
14353 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14356 setUTCDate: function(d) {
14358 this.setValue(this.formatDate(this.date));
14361 onRender: function(ct, position)
14364 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14366 this.language = this.language || 'en';
14367 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14368 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14370 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14371 this.format = this.format || 'm/d/y';
14372 this.isInline = false;
14373 this.isInput = true;
14374 this.component = this.el.select('.add-on', true).first() || false;
14375 this.component = (this.component && this.component.length === 0) ? false : this.component;
14376 this.hasInput = this.component && this.inputEL().length;
14378 if (typeof(this.minViewMode === 'string')) {
14379 switch (this.minViewMode) {
14381 this.minViewMode = 1;
14384 this.minViewMode = 2;
14387 this.minViewMode = 0;
14392 if (typeof(this.viewMode === 'string')) {
14393 switch (this.viewMode) {
14406 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14408 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14410 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14412 this.picker().on('mousedown', this.onMousedown, this);
14413 this.picker().on('click', this.onClick, this);
14415 this.picker().addClass('datepicker-dropdown');
14417 this.startViewMode = this.viewMode;
14420 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14421 if(!this.calendarWeeks){
14426 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14427 v.attr('colspan', function(i, val){
14428 return parseInt(val) + 1;
14433 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14435 this.setStartDate(this.startDate);
14436 this.setEndDate(this.endDate);
14438 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14445 if(this.isInline) {
14450 picker : function()
14452 return this.pickerEl;
14453 // return this.el.select('.datepicker', true).first();
14456 fillDow: function()
14458 var dowCnt = this.weekStart;
14467 if(this.calendarWeeks){
14475 while (dowCnt < this.weekStart + 7) {
14479 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14483 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14486 fillMonths: function()
14489 var months = this.picker().select('>.datepicker-months td', true).first();
14491 months.dom.innerHTML = '';
14497 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14500 months.createChild(month);
14508 this.date = (typeof(this.date) === 'undefined' || !this.date.length) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14510 if (this.date < this.startDate) {
14511 this.viewDate = new Date(this.startDate);
14512 } else if (this.date > this.endDate) {
14513 this.viewDate = new Date(this.endDate);
14515 this.viewDate = new Date(this.date);
14523 var d = new Date(this.viewDate),
14524 year = d.getUTCFullYear(),
14525 month = d.getUTCMonth(),
14526 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14527 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14528 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14529 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14530 currentDate = this.date && this.date.valueOf(),
14531 today = this.UTCToday();
14533 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14535 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14537 // this.picker.select('>tfoot th.today').
14538 // .text(dates[this.language].today)
14539 // .toggle(this.todayBtn !== false);
14541 this.updateNavArrows();
14544 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14546 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14548 prevMonth.setUTCDate(day);
14550 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14552 var nextMonth = new Date(prevMonth);
14554 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14556 nextMonth = nextMonth.valueOf();
14558 var fillMonths = false;
14560 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14562 while(prevMonth.valueOf() < nextMonth) {
14565 if (prevMonth.getUTCDay() === this.weekStart) {
14567 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14575 if(this.calendarWeeks){
14576 // ISO 8601: First week contains first thursday.
14577 // ISO also states week starts on Monday, but we can be more abstract here.
14579 // Start of current week: based on weekstart/current date
14580 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14581 // Thursday of this week
14582 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14583 // First Thursday of year, year from thursday
14584 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14585 // Calendar week: ms between thursdays, div ms per day, div 7 days
14586 calWeek = (th - yth) / 864e5 / 7 + 1;
14588 fillMonths.cn.push({
14596 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14598 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14601 if (this.todayHighlight &&
14602 prevMonth.getUTCFullYear() == today.getFullYear() &&
14603 prevMonth.getUTCMonth() == today.getMonth() &&
14604 prevMonth.getUTCDate() == today.getDate()) {
14605 clsName += ' today';
14608 if (currentDate && prevMonth.valueOf() === currentDate) {
14609 clsName += ' active';
14612 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14613 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14614 clsName += ' disabled';
14617 fillMonths.cn.push({
14619 cls: 'day ' + clsName,
14620 html: prevMonth.getDate()
14623 prevMonth.setDate(prevMonth.getDate()+1);
14626 var currentYear = this.date && this.date.getUTCFullYear();
14627 var currentMonth = this.date && this.date.getUTCMonth();
14629 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14631 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14632 v.removeClass('active');
14634 if(currentYear === year && k === currentMonth){
14635 v.addClass('active');
14638 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14639 v.addClass('disabled');
14645 year = parseInt(year/10, 10) * 10;
14647 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14649 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14652 for (var i = -1; i < 11; i++) {
14653 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14655 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14663 showMode: function(dir)
14666 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14668 Roo.each(this.picker().select('>div',true).elements, function(v){
14669 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14672 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14677 if(this.isInline) return;
14679 this.picker().removeClass(['bottom', 'top']);
14681 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14683 * place to the top of element!
14687 this.picker().addClass('top');
14688 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14693 this.picker().addClass('bottom');
14695 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14698 parseDate : function(value)
14700 if(!value || value instanceof Date){
14703 var v = Date.parseDate(value, this.format);
14704 if (!v && this.useIso) {
14705 v = Date.parseDate(value, 'Y-m-d');
14707 if(!v && this.altFormats){
14708 if(!this.altFormatsArray){
14709 this.altFormatsArray = this.altFormats.split("|");
14711 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14712 v = Date.parseDate(value, this.altFormatsArray[i]);
14718 formatDate : function(date, fmt)
14720 return (!date || !(date instanceof Date)) ?
14721 date : date.dateFormat(fmt || this.format);
14724 onFocus : function()
14726 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14730 onBlur : function()
14732 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14734 var d = this.inputEl().getValue();
14743 this.picker().show();
14747 this.fireEvent('show', this, this.date);
14752 if(this.isInline) return;
14753 this.picker().hide();
14754 this.viewMode = this.startViewMode;
14757 this.fireEvent('hide', this, this.date);
14761 onMousedown: function(e)
14763 e.stopPropagation();
14764 e.preventDefault();
14769 Roo.bootstrap.DateField.superclass.keyup.call(this);
14773 setValue: function(v)
14775 var d = new Date(v);
14777 if(isNaN(d.getTime())){
14779 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14783 v = this.formatDate(d);
14785 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14787 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14791 this.fireEvent('select', this, this.date);
14795 getValue: function()
14797 return this.formatDate(this.date);
14800 fireKey: function(e)
14802 if (!this.picker().isVisible()){
14803 if (e.keyCode == 27) // allow escape to hide and re-show picker
14808 var dateChanged = false,
14810 newDate, newViewDate;
14815 e.preventDefault();
14819 if (!this.keyboardNavigation) break;
14820 dir = e.keyCode == 37 ? -1 : 1;
14823 newDate = this.moveYear(this.date, dir);
14824 newViewDate = this.moveYear(this.viewDate, dir);
14825 } else if (e.shiftKey){
14826 newDate = this.moveMonth(this.date, dir);
14827 newViewDate = this.moveMonth(this.viewDate, dir);
14829 newDate = new Date(this.date);
14830 newDate.setUTCDate(this.date.getUTCDate() + dir);
14831 newViewDate = new Date(this.viewDate);
14832 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14834 if (this.dateWithinRange(newDate)){
14835 this.date = newDate;
14836 this.viewDate = newViewDate;
14837 this.setValue(this.formatDate(this.date));
14839 e.preventDefault();
14840 dateChanged = true;
14845 if (!this.keyboardNavigation) break;
14846 dir = e.keyCode == 38 ? -1 : 1;
14848 newDate = this.moveYear(this.date, dir);
14849 newViewDate = this.moveYear(this.viewDate, dir);
14850 } else if (e.shiftKey){
14851 newDate = this.moveMonth(this.date, dir);
14852 newViewDate = this.moveMonth(this.viewDate, dir);
14854 newDate = new Date(this.date);
14855 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14856 newViewDate = new Date(this.viewDate);
14857 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14859 if (this.dateWithinRange(newDate)){
14860 this.date = newDate;
14861 this.viewDate = newViewDate;
14862 this.setValue(this.formatDate(this.date));
14864 e.preventDefault();
14865 dateChanged = true;
14869 this.setValue(this.formatDate(this.date));
14871 e.preventDefault();
14874 this.setValue(this.formatDate(this.date));
14888 onClick: function(e)
14890 e.stopPropagation();
14891 e.preventDefault();
14893 var target = e.getTarget();
14895 if(target.nodeName.toLowerCase() === 'i'){
14896 target = Roo.get(target).dom.parentNode;
14899 var nodeName = target.nodeName;
14900 var className = target.className;
14901 var html = target.innerHTML;
14903 switch(nodeName.toLowerCase()) {
14905 switch(className) {
14911 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14912 switch(this.viewMode){
14914 this.viewDate = this.moveMonth(this.viewDate, dir);
14918 this.viewDate = this.moveYear(this.viewDate, dir);
14924 var date = new Date();
14925 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14927 this.setValue(this.formatDate(this.date));
14934 if (className.indexOf('disabled') === -1) {
14935 this.viewDate.setUTCDate(1);
14936 if (className.indexOf('month') !== -1) {
14937 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14939 var year = parseInt(html, 10) || 0;
14940 this.viewDate.setUTCFullYear(year);
14949 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14950 var day = parseInt(html, 10) || 1;
14951 var year = this.viewDate.getUTCFullYear(),
14952 month = this.viewDate.getUTCMonth();
14954 if (className.indexOf('old') !== -1) {
14961 } else if (className.indexOf('new') !== -1) {
14969 this.date = this.UTCDate(year, month, day,0,0,0,0);
14970 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14972 this.setValue(this.formatDate(this.date));
14979 setStartDate: function(startDate)
14981 this.startDate = startDate || -Infinity;
14982 if (this.startDate !== -Infinity) {
14983 this.startDate = this.parseDate(this.startDate);
14986 this.updateNavArrows();
14989 setEndDate: function(endDate)
14991 this.endDate = endDate || Infinity;
14992 if (this.endDate !== Infinity) {
14993 this.endDate = this.parseDate(this.endDate);
14996 this.updateNavArrows();
14999 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15001 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15002 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15003 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15005 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15006 return parseInt(d, 10);
15009 this.updateNavArrows();
15012 updateNavArrows: function()
15014 var d = new Date(this.viewDate),
15015 year = d.getUTCFullYear(),
15016 month = d.getUTCMonth();
15018 Roo.each(this.picker().select('.prev', true).elements, function(v){
15020 switch (this.viewMode) {
15023 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15029 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15036 Roo.each(this.picker().select('.next', true).elements, function(v){
15038 switch (this.viewMode) {
15041 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15047 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15055 moveMonth: function(date, dir)
15057 if (!dir) return date;
15058 var new_date = new Date(date.valueOf()),
15059 day = new_date.getUTCDate(),
15060 month = new_date.getUTCMonth(),
15061 mag = Math.abs(dir),
15063 dir = dir > 0 ? 1 : -1;
15066 // If going back one month, make sure month is not current month
15067 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15069 return new_date.getUTCMonth() == month;
15071 // If going forward one month, make sure month is as expected
15072 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15074 return new_date.getUTCMonth() != new_month;
15076 new_month = month + dir;
15077 new_date.setUTCMonth(new_month);
15078 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15079 if (new_month < 0 || new_month > 11)
15080 new_month = (new_month + 12) % 12;
15082 // For magnitudes >1, move one month at a time...
15083 for (var i=0; i<mag; i++)
15084 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15085 new_date = this.moveMonth(new_date, dir);
15086 // ...then reset the day, keeping it in the new month
15087 new_month = new_date.getUTCMonth();
15088 new_date.setUTCDate(day);
15090 return new_month != new_date.getUTCMonth();
15093 // Common date-resetting loop -- if date is beyond end of month, make it
15096 new_date.setUTCDate(--day);
15097 new_date.setUTCMonth(new_month);
15102 moveYear: function(date, dir)
15104 return this.moveMonth(date, dir*12);
15107 dateWithinRange: function(date)
15109 return date >= this.startDate && date <= this.endDate;
15115 this.picker().remove();
15120 Roo.apply(Roo.bootstrap.DateField, {
15131 html: '<i class="fa fa-arrow-left"/>'
15141 html: '<i class="fa fa-arrow-right"/>'
15183 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15184 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15185 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15186 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15187 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15200 navFnc: 'FullYear',
15205 navFnc: 'FullYear',
15210 Roo.apply(Roo.bootstrap.DateField, {
15214 cls: 'datepicker dropdown-menu',
15218 cls: 'datepicker-days',
15222 cls: 'table-condensed',
15224 Roo.bootstrap.DateField.head,
15228 Roo.bootstrap.DateField.footer
15235 cls: 'datepicker-months',
15239 cls: 'table-condensed',
15241 Roo.bootstrap.DateField.head,
15242 Roo.bootstrap.DateField.content,
15243 Roo.bootstrap.DateField.footer
15250 cls: 'datepicker-years',
15254 cls: 'table-condensed',
15256 Roo.bootstrap.DateField.head,
15257 Roo.bootstrap.DateField.content,
15258 Roo.bootstrap.DateField.footer
15277 * @class Roo.bootstrap.TimeField
15278 * @extends Roo.bootstrap.Input
15279 * Bootstrap DateField class
15283 * Create a new TimeField
15284 * @param {Object} config The config object
15287 Roo.bootstrap.TimeField = function(config){
15288 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15292 * Fires when this field show.
15293 * @param {Roo.bootstrap.DateField} this
15294 * @param {Mixed} date The date value
15299 * Fires when this field hide.
15300 * @param {Roo.bootstrap.DateField} this
15301 * @param {Mixed} date The date value
15306 * Fires when select a date.
15307 * @param {Roo.bootstrap.DateField} this
15308 * @param {Mixed} date The date value
15314 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15317 * @cfg {String} format
15318 * The default time format string which can be overriden for localization support. The format must be
15319 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15323 onRender: function(ct, position)
15326 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15328 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15330 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15332 this.pop = this.picker().select('>.datepicker-time',true).first();
15333 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15335 this.picker().on('mousedown', this.onMousedown, this);
15336 this.picker().on('click', this.onClick, this);
15338 this.picker().addClass('datepicker-dropdown');
15343 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15344 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15345 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15346 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15347 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15348 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15352 fireKey: function(e){
15353 if (!this.picker().isVisible()){
15354 if (e.keyCode == 27) // allow escape to hide and re-show picker
15359 e.preventDefault();
15367 this.onTogglePeriod();
15370 this.onIncrementMinutes();
15373 this.onDecrementMinutes();
15382 onClick: function(e) {
15383 e.stopPropagation();
15384 e.preventDefault();
15387 picker : function()
15389 return this.el.select('.datepicker', true).first();
15392 fillTime: function()
15394 var time = this.pop.select('tbody', true).first();
15396 time.dom.innerHTML = '';
15411 cls: 'hours-up glyphicon glyphicon-chevron-up'
15431 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15452 cls: 'timepicker-hour',
15467 cls: 'timepicker-minute',
15482 cls: 'btn btn-primary period',
15504 cls: 'hours-down glyphicon glyphicon-chevron-down'
15524 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15542 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15549 var hours = this.time.getHours();
15550 var minutes = this.time.getMinutes();
15563 hours = hours - 12;
15567 hours = '0' + hours;
15571 minutes = '0' + minutes;
15574 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15575 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15576 this.pop.select('button', true).first().dom.innerHTML = period;
15582 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15584 var cls = ['bottom'];
15586 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15593 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15598 this.picker().addClass(cls.join('-'));
15602 Roo.each(cls, function(c){
15604 _this.picker().setTop(_this.inputEl().getHeight());
15608 _this.picker().setTop(0 - _this.picker().getHeight());
15613 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15617 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15624 onFocus : function()
15626 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15630 onBlur : function()
15632 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15638 this.picker().show();
15643 this.fireEvent('show', this, this.date);
15648 this.picker().hide();
15651 this.fireEvent('hide', this, this.date);
15654 setTime : function()
15657 this.setValue(this.time.format(this.format));
15659 this.fireEvent('select', this, this.date);
15664 onMousedown: function(e){
15665 e.stopPropagation();
15666 e.preventDefault();
15669 onIncrementHours: function()
15671 Roo.log('onIncrementHours');
15672 this.time = this.time.add(Date.HOUR, 1);
15677 onDecrementHours: function()
15679 Roo.log('onDecrementHours');
15680 this.time = this.time.add(Date.HOUR, -1);
15684 onIncrementMinutes: function()
15686 Roo.log('onIncrementMinutes');
15687 this.time = this.time.add(Date.MINUTE, 1);
15691 onDecrementMinutes: function()
15693 Roo.log('onDecrementMinutes');
15694 this.time = this.time.add(Date.MINUTE, -1);
15698 onTogglePeriod: function()
15700 Roo.log('onTogglePeriod');
15701 this.time = this.time.add(Date.HOUR, 12);
15708 Roo.apply(Roo.bootstrap.TimeField, {
15738 cls: 'btn btn-info ok',
15750 Roo.apply(Roo.bootstrap.TimeField, {
15754 cls: 'datepicker dropdown-menu',
15758 cls: 'datepicker-time',
15762 cls: 'table-condensed',
15764 Roo.bootstrap.TimeField.content,
15765 Roo.bootstrap.TimeField.footer
15784 * @class Roo.bootstrap.CheckBox
15785 * @extends Roo.bootstrap.Input
15786 * Bootstrap CheckBox class
15788 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15789 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15790 * @cfg {String} boxLabel The text that appears beside the checkbox
15791 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15792 * @cfg {Boolean} checked initnal the element
15796 * Create a new CheckBox
15797 * @param {Object} config The config object
15800 Roo.bootstrap.CheckBox = function(config){
15801 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15806 * Fires when the element is checked or unchecked.
15807 * @param {Roo.bootstrap.CheckBox} this This input
15808 * @param {Boolean} checked The new checked value
15814 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15816 inputType: 'checkbox',
15823 getAutoCreate : function()
15825 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15831 cfg.cls = 'form-group checkbox' //input-group
15839 type : this.inputType,
15840 value : (!this.checked) ? this.valueOff : this.inputValue,
15841 cls : 'roo-checkbox', //'form-box',
15842 placeholder : this.placeholder || ''
15846 if (this.weight) { // Validity check?
15847 cfg.cls += " checkbox-" + this.weight;
15850 if (this.disabled) {
15851 input.disabled=true;
15855 input.checked = this.checked;
15859 input.name = this.name;
15863 input.cls += ' input-' + this.size;
15867 ['xs','sm','md','lg'].map(function(size){
15868 if (settings[size]) {
15869 cfg.cls += ' col-' + size + '-' + settings[size];
15875 var inputblock = input;
15880 if (this.before || this.after) {
15883 cls : 'input-group',
15887 inputblock.cn.push({
15889 cls : 'input-group-addon',
15893 inputblock.cn.push(input);
15895 inputblock.cn.push({
15897 cls : 'input-group-addon',
15904 if (align ==='left' && this.fieldLabel.length) {
15905 Roo.log("left and has label");
15911 cls : 'control-label col-md-' + this.labelWidth,
15912 html : this.fieldLabel
15916 cls : "col-md-" + (12 - this.labelWidth),
15923 } else if ( this.fieldLabel.length) {
15928 tag: this.boxLabel ? 'span' : 'label',
15930 cls: 'control-label box-input-label',
15931 //cls : 'input-group-addon',
15932 html : this.fieldLabel
15942 Roo.log(" no label && no align");
15943 cfg.cn = [ inputblock ] ;
15952 html: this.boxLabel
15964 * return the real input element.
15966 inputEl: function ()
15968 return this.el.select('input.roo-checkbox',true).first();
15973 return this.el.select('label.control-label',true).first();
15976 initEvents : function()
15978 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15980 this.inputEl().on('click', this.onClick, this);
15984 onClick : function()
15986 this.setChecked(!this.checked);
15989 setChecked : function(state,suppressEvent)
15991 this.checked = state;
15993 this.inputEl().dom.checked = state;
15995 if(suppressEvent !== true){
15996 this.fireEvent('check', this, state);
15999 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16003 setValue : function(v,suppressEvent)
16005 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16019 * @class Roo.bootstrap.Radio
16020 * @extends Roo.bootstrap.CheckBox
16021 * Bootstrap Radio class
16024 * Create a new Radio
16025 * @param {Object} config The config object
16028 Roo.bootstrap.Radio = function(config){
16029 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16033 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16035 inputType: 'radio',
16039 getAutoCreate : function()
16041 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16047 cfg.cls = 'form-group radio' //input-group
16052 type : this.inputType,
16053 value : (!this.checked) ? this.valueOff : this.inputValue,
16055 placeholder : this.placeholder || ''
16058 if (this.weight) { // Validity check?
16059 cfg.cls += " radio-" + this.weight;
16061 if (this.disabled) {
16062 input.disabled=true;
16066 input.checked = this.checked;
16070 input.name = this.name;
16074 input.cls += ' input-' + this.size;
16078 ['xs','sm','md','lg'].map(function(size){
16079 if (settings[size]) {
16080 cfg.cls += ' col-' + size + '-' + settings[size];
16084 var inputblock = input;
16086 if (this.before || this.after) {
16089 cls : 'input-group',
16093 inputblock.cn.push({
16095 cls : 'input-group-addon',
16099 inputblock.cn.push(input);
16101 inputblock.cn.push({
16103 cls : 'input-group-addon',
16110 if (align ==='left' && this.fieldLabel.length) {
16111 Roo.log("left and has label");
16117 cls : 'control-label col-md-' + this.labelWidth,
16118 html : this.fieldLabel
16122 cls : "col-md-" + (12 - this.labelWidth),
16129 } else if ( this.fieldLabel.length) {
16136 cls: 'control-label box-input-label',
16137 //cls : 'input-group-addon',
16138 html : this.fieldLabel
16148 Roo.log(" no label && no align");
16163 html: this.boxLabel
16170 inputEl: function ()
16172 return this.el.select('input.roo-radio',true).first();
16174 onClick : function()
16176 this.setChecked(true);
16179 setChecked : function(state,suppressEvent)
16182 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16183 v.dom.checked = false;
16187 this.checked = state;
16188 this.inputEl().dom.checked = state;
16190 if(suppressEvent !== true){
16191 this.fireEvent('check', this, state);
16194 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16198 getGroupValue : function()
16201 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16202 if(v.dom.checked == true){
16203 value = v.dom.value;
16211 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16212 * @return {Mixed} value The field value
16214 getValue : function(){
16215 return this.getGroupValue();
16221 //<script type="text/javascript">
16224 * Based Ext JS Library 1.1.1
16225 * Copyright(c) 2006-2007, Ext JS, LLC.
16231 * @class Roo.HtmlEditorCore
16232 * @extends Roo.Component
16233 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16235 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16238 Roo.HtmlEditorCore = function(config){
16241 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16244 * @event initialize
16245 * Fires when the editor is fully initialized (including the iframe)
16246 * @param {Roo.HtmlEditorCore} this
16251 * Fires when the editor is first receives the focus. Any insertion must wait
16252 * until after this event.
16253 * @param {Roo.HtmlEditorCore} this
16257 * @event beforesync
16258 * Fires before the textarea is updated with content from the editor iframe. Return false
16259 * to cancel the sync.
16260 * @param {Roo.HtmlEditorCore} this
16261 * @param {String} html
16265 * @event beforepush
16266 * Fires before the iframe editor is updated with content from the textarea. Return false
16267 * to cancel the push.
16268 * @param {Roo.HtmlEditorCore} this
16269 * @param {String} html
16274 * Fires when the textarea is updated with content from the editor iframe.
16275 * @param {Roo.HtmlEditorCore} this
16276 * @param {String} html
16281 * Fires when the iframe editor is updated with content from the textarea.
16282 * @param {Roo.HtmlEditorCore} this
16283 * @param {String} html
16288 * @event editorevent
16289 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16290 * @param {Roo.HtmlEditorCore} this
16298 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16302 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16308 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16313 * @cfg {Number} height (in pixels)
16317 * @cfg {Number} width (in pixels)
16322 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16325 stylesheets: false,
16330 // private properties
16331 validationEvent : false,
16333 initialized : false,
16335 sourceEditMode : false,
16336 onFocus : Roo.emptyFn,
16338 hideMode:'offsets',
16346 * Protected method that will not generally be called directly. It
16347 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16348 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16350 getDocMarkup : function(){
16353 Roo.log(this.stylesheets);
16355 // inherit styels from page...??
16356 if (this.stylesheets === false) {
16358 Roo.get(document.head).select('style').each(function(node) {
16359 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16362 Roo.get(document.head).select('link').each(function(node) {
16363 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16366 } else if (!this.stylesheets.length) {
16368 st = '<style type="text/css">' +
16369 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16372 Roo.each(this.stylesheets, function(s) {
16373 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16378 st += '<style type="text/css">' +
16379 'IMG { cursor: pointer } ' +
16383 return '<html><head>' + st +
16384 //<style type="text/css">' +
16385 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16387 ' </head><body class="roo-htmleditor-body"></body></html>';
16391 onRender : function(ct, position)
16394 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16395 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16398 this.el.dom.style.border = '0 none';
16399 this.el.dom.setAttribute('tabIndex', -1);
16400 this.el.addClass('x-hidden hide');
16404 if(Roo.isIE){ // fix IE 1px bogus margin
16405 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16409 this.frameId = Roo.id();
16413 var iframe = this.owner.wrap.createChild({
16415 cls: 'form-control', // bootstrap..
16417 name: this.frameId,
16418 frameBorder : 'no',
16419 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16424 this.iframe = iframe.dom;
16426 this.assignDocWin();
16428 this.doc.designMode = 'on';
16431 this.doc.write(this.getDocMarkup());
16435 var task = { // must defer to wait for browser to be ready
16437 //console.log("run task?" + this.doc.readyState);
16438 this.assignDocWin();
16439 if(this.doc.body || this.doc.readyState == 'complete'){
16441 this.doc.designMode="on";
16445 Roo.TaskMgr.stop(task);
16446 this.initEditor.defer(10, this);
16453 Roo.TaskMgr.start(task);
16460 onResize : function(w, h)
16462 Roo.log('resize: ' +w + ',' + h );
16463 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16467 if(typeof w == 'number'){
16469 this.iframe.style.width = w + 'px';
16471 if(typeof h == 'number'){
16473 this.iframe.style.height = h + 'px';
16475 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16482 * Toggles the editor between standard and source edit mode.
16483 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16485 toggleSourceEdit : function(sourceEditMode){
16487 this.sourceEditMode = sourceEditMode === true;
16489 if(this.sourceEditMode){
16491 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16494 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16495 //this.iframe.className = '';
16498 //this.setSize(this.owner.wrap.getSize());
16499 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16506 * Protected method that will not generally be called directly. If you need/want
16507 * custom HTML cleanup, this is the method you should override.
16508 * @param {String} html The HTML to be cleaned
16509 * return {String} The cleaned HTML
16511 cleanHtml : function(html){
16512 html = String(html);
16513 if(html.length > 5){
16514 if(Roo.isSafari){ // strip safari nonsense
16515 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16518 if(html == ' '){
16525 * HTML Editor -> Textarea
16526 * Protected method that will not generally be called directly. Syncs the contents
16527 * of the editor iframe with the textarea.
16529 syncValue : function(){
16530 if(this.initialized){
16531 var bd = (this.doc.body || this.doc.documentElement);
16532 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16533 var html = bd.innerHTML;
16535 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16536 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16538 html = '<div style="'+m[0]+'">' + html + '</div>';
16541 html = this.cleanHtml(html);
16542 // fix up the special chars.. normaly like back quotes in word...
16543 // however we do not want to do this with chinese..
16544 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16545 var cc = b.charCodeAt();
16547 (cc >= 0x4E00 && cc < 0xA000 ) ||
16548 (cc >= 0x3400 && cc < 0x4E00 ) ||
16549 (cc >= 0xf900 && cc < 0xfb00 )
16555 if(this.owner.fireEvent('beforesync', this, html) !== false){
16556 this.el.dom.value = html;
16557 this.owner.fireEvent('sync', this, html);
16563 * Protected method that will not generally be called directly. Pushes the value of the textarea
16564 * into the iframe editor.
16566 pushValue : function(){
16567 if(this.initialized){
16568 var v = this.el.dom.value.trim();
16570 // if(v.length < 1){
16574 if(this.owner.fireEvent('beforepush', this, v) !== false){
16575 var d = (this.doc.body || this.doc.documentElement);
16577 this.cleanUpPaste();
16578 this.el.dom.value = d.innerHTML;
16579 this.owner.fireEvent('push', this, v);
16585 deferFocus : function(){
16586 this.focus.defer(10, this);
16590 focus : function(){
16591 if(this.win && !this.sourceEditMode){
16598 assignDocWin: function()
16600 var iframe = this.iframe;
16603 this.doc = iframe.contentWindow.document;
16604 this.win = iframe.contentWindow;
16606 // if (!Roo.get(this.frameId)) {
16609 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16610 // this.win = Roo.get(this.frameId).dom.contentWindow;
16612 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16616 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16617 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16622 initEditor : function(){
16623 //console.log("INIT EDITOR");
16624 this.assignDocWin();
16628 this.doc.designMode="on";
16630 this.doc.write(this.getDocMarkup());
16633 var dbody = (this.doc.body || this.doc.documentElement);
16634 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16635 // this copies styles from the containing element into thsi one..
16636 // not sure why we need all of this..
16637 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16639 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16640 //ss['background-attachment'] = 'fixed'; // w3c
16641 dbody.bgProperties = 'fixed'; // ie
16642 //Roo.DomHelper.applyStyles(dbody, ss);
16643 Roo.EventManager.on(this.doc, {
16644 //'mousedown': this.onEditorEvent,
16645 'mouseup': this.onEditorEvent,
16646 'dblclick': this.onEditorEvent,
16647 'click': this.onEditorEvent,
16648 'keyup': this.onEditorEvent,
16653 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16655 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16656 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16658 this.initialized = true;
16660 this.owner.fireEvent('initialize', this);
16665 onDestroy : function(){
16671 //for (var i =0; i < this.toolbars.length;i++) {
16672 // // fixme - ask toolbars for heights?
16673 // this.toolbars[i].onDestroy();
16676 //this.wrap.dom.innerHTML = '';
16677 //this.wrap.remove();
16682 onFirstFocus : function(){
16684 this.assignDocWin();
16687 this.activated = true;
16690 if(Roo.isGecko){ // prevent silly gecko errors
16692 var s = this.win.getSelection();
16693 if(!s.focusNode || s.focusNode.nodeType != 3){
16694 var r = s.getRangeAt(0);
16695 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16700 this.execCmd('useCSS', true);
16701 this.execCmd('styleWithCSS', false);
16704 this.owner.fireEvent('activate', this);
16708 adjustFont: function(btn){
16709 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16710 //if(Roo.isSafari){ // safari
16713 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16714 if(Roo.isSafari){ // safari
16715 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16716 v = (v < 10) ? 10 : v;
16717 v = (v > 48) ? 48 : v;
16718 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16723 v = Math.max(1, v+adjust);
16725 this.execCmd('FontSize', v );
16728 onEditorEvent : function(e){
16729 this.owner.fireEvent('editorevent', this, e);
16730 // this.updateToolbar();
16731 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16734 insertTag : function(tg)
16736 // could be a bit smarter... -> wrap the current selected tRoo..
16737 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16739 range = this.createRange(this.getSelection());
16740 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16741 wrappingNode.appendChild(range.extractContents());
16742 range.insertNode(wrappingNode);
16749 this.execCmd("formatblock", tg);
16753 insertText : function(txt)
16757 var range = this.createRange();
16758 range.deleteContents();
16759 //alert(Sender.getAttribute('label'));
16761 range.insertNode(this.doc.createTextNode(txt));
16767 * Executes a Midas editor command on the editor document and performs necessary focus and
16768 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16769 * @param {String} cmd The Midas command
16770 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16772 relayCmd : function(cmd, value){
16774 this.execCmd(cmd, value);
16775 this.owner.fireEvent('editorevent', this);
16776 //this.updateToolbar();
16777 this.owner.deferFocus();
16781 * Executes a Midas editor command directly on the editor document.
16782 * For visual commands, you should use {@link #relayCmd} instead.
16783 * <b>This should only be called after the editor is initialized.</b>
16784 * @param {String} cmd The Midas command
16785 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16787 execCmd : function(cmd, value){
16788 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16795 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16797 * @param {String} text | dom node..
16799 insertAtCursor : function(text)
16804 if(!this.activated){
16810 var r = this.doc.selection.createRange();
16821 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16825 // from jquery ui (MIT licenced)
16827 var win = this.win;
16829 if (win.getSelection && win.getSelection().getRangeAt) {
16830 range = win.getSelection().getRangeAt(0);
16831 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16832 range.insertNode(node);
16833 } else if (win.document.selection && win.document.selection.createRange) {
16834 // no firefox support
16835 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16836 win.document.selection.createRange().pasteHTML(txt);
16838 // no firefox support
16839 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16840 this.execCmd('InsertHTML', txt);
16849 mozKeyPress : function(e){
16851 var c = e.getCharCode(), cmd;
16854 c = String.fromCharCode(c).toLowerCase();
16868 this.cleanUpPaste.defer(100, this);
16876 e.preventDefault();
16884 fixKeys : function(){ // load time branching for fastest keydown performance
16886 return function(e){
16887 var k = e.getKey(), r;
16890 r = this.doc.selection.createRange();
16893 r.pasteHTML('    ');
16900 r = this.doc.selection.createRange();
16902 var target = r.parentElement();
16903 if(!target || target.tagName.toLowerCase() != 'li'){
16905 r.pasteHTML('<br />');
16911 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16912 this.cleanUpPaste.defer(100, this);
16918 }else if(Roo.isOpera){
16919 return function(e){
16920 var k = e.getKey();
16924 this.execCmd('InsertHTML','    ');
16927 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16928 this.cleanUpPaste.defer(100, this);
16933 }else if(Roo.isSafari){
16934 return function(e){
16935 var k = e.getKey();
16939 this.execCmd('InsertText','\t');
16943 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16944 this.cleanUpPaste.defer(100, this);
16952 getAllAncestors: function()
16954 var p = this.getSelectedNode();
16957 a.push(p); // push blank onto stack..
16958 p = this.getParentElement();
16962 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16966 a.push(this.doc.body);
16970 lastSelNode : false,
16973 getSelection : function()
16975 this.assignDocWin();
16976 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16979 getSelectedNode: function()
16981 // this may only work on Gecko!!!
16983 // should we cache this!!!!
16988 var range = this.createRange(this.getSelection()).cloneRange();
16991 var parent = range.parentElement();
16993 var testRange = range.duplicate();
16994 testRange.moveToElementText(parent);
16995 if (testRange.inRange(range)) {
16998 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17001 parent = parent.parentElement;
17006 // is ancestor a text element.
17007 var ac = range.commonAncestorContainer;
17008 if (ac.nodeType == 3) {
17009 ac = ac.parentNode;
17012 var ar = ac.childNodes;
17015 var other_nodes = [];
17016 var has_other_nodes = false;
17017 for (var i=0;i<ar.length;i++) {
17018 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17021 // fullly contained node.
17023 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17028 // probably selected..
17029 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17030 other_nodes.push(ar[i]);
17034 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17039 has_other_nodes = true;
17041 if (!nodes.length && other_nodes.length) {
17042 nodes= other_nodes;
17044 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17050 createRange: function(sel)
17052 // this has strange effects when using with
17053 // top toolbar - not sure if it's a great idea.
17054 //this.editor.contentWindow.focus();
17055 if (typeof sel != "undefined") {
17057 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17059 return this.doc.createRange();
17062 return this.doc.createRange();
17065 getParentElement: function()
17068 this.assignDocWin();
17069 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17071 var range = this.createRange(sel);
17074 var p = range.commonAncestorContainer;
17075 while (p.nodeType == 3) { // text node
17086 * Range intersection.. the hard stuff...
17090 * [ -- selected range --- ]
17094 * if end is before start or hits it. fail.
17095 * if start is after end or hits it fail.
17097 * if either hits (but other is outside. - then it's not
17103 // @see http://www.thismuchiknow.co.uk/?p=64.
17104 rangeIntersectsNode : function(range, node)
17106 var nodeRange = node.ownerDocument.createRange();
17108 nodeRange.selectNode(node);
17110 nodeRange.selectNodeContents(node);
17113 var rangeStartRange = range.cloneRange();
17114 rangeStartRange.collapse(true);
17116 var rangeEndRange = range.cloneRange();
17117 rangeEndRange.collapse(false);
17119 var nodeStartRange = nodeRange.cloneRange();
17120 nodeStartRange.collapse(true);
17122 var nodeEndRange = nodeRange.cloneRange();
17123 nodeEndRange.collapse(false);
17125 return rangeStartRange.compareBoundaryPoints(
17126 Range.START_TO_START, nodeEndRange) == -1 &&
17127 rangeEndRange.compareBoundaryPoints(
17128 Range.START_TO_START, nodeStartRange) == 1;
17132 rangeCompareNode : function(range, node)
17134 var nodeRange = node.ownerDocument.createRange();
17136 nodeRange.selectNode(node);
17138 nodeRange.selectNodeContents(node);
17142 range.collapse(true);
17144 nodeRange.collapse(true);
17146 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17147 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17149 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17151 var nodeIsBefore = ss == 1;
17152 var nodeIsAfter = ee == -1;
17154 if (nodeIsBefore && nodeIsAfter)
17156 if (!nodeIsBefore && nodeIsAfter)
17157 return 1; //right trailed.
17159 if (nodeIsBefore && !nodeIsAfter)
17160 return 2; // left trailed.
17165 // private? - in a new class?
17166 cleanUpPaste : function()
17168 // cleans up the whole document..
17169 Roo.log('cleanuppaste');
17171 this.cleanUpChildren(this.doc.body);
17172 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17173 if (clean != this.doc.body.innerHTML) {
17174 this.doc.body.innerHTML = clean;
17179 cleanWordChars : function(input) {// change the chars to hex code
17180 var he = Roo.HtmlEditorCore;
17182 var output = input;
17183 Roo.each(he.swapCodes, function(sw) {
17184 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17186 output = output.replace(swapper, sw[1]);
17193 cleanUpChildren : function (n)
17195 if (!n.childNodes.length) {
17198 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17199 this.cleanUpChild(n.childNodes[i]);
17206 cleanUpChild : function (node)
17209 //console.log(node);
17210 if (node.nodeName == "#text") {
17211 // clean up silly Windows -- stuff?
17214 if (node.nodeName == "#comment") {
17215 node.parentNode.removeChild(node);
17216 // clean up silly Windows -- stuff?
17220 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17222 node.parentNode.removeChild(node);
17227 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17229 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17230 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17232 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17233 // remove_keep_children = true;
17236 if (remove_keep_children) {
17237 this.cleanUpChildren(node);
17238 // inserts everything just before this node...
17239 while (node.childNodes.length) {
17240 var cn = node.childNodes[0];
17241 node.removeChild(cn);
17242 node.parentNode.insertBefore(cn, node);
17244 node.parentNode.removeChild(node);
17248 if (!node.attributes || !node.attributes.length) {
17249 this.cleanUpChildren(node);
17253 function cleanAttr(n,v)
17256 if (v.match(/^\./) || v.match(/^\//)) {
17259 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17262 if (v.match(/^#/)) {
17265 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17266 node.removeAttribute(n);
17270 function cleanStyle(n,v)
17272 if (v.match(/expression/)) { //XSS?? should we even bother..
17273 node.removeAttribute(n);
17276 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17277 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17280 var parts = v.split(/;/);
17283 Roo.each(parts, function(p) {
17284 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17288 var l = p.split(':').shift().replace(/\s+/g,'');
17289 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17291 if ( cblack.indexOf(l) > -1) {
17292 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17293 //node.removeAttribute(n);
17297 // only allow 'c whitelisted system attributes'
17298 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17299 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17300 //node.removeAttribute(n);
17310 if (clean.length) {
17311 node.setAttribute(n, clean.join(';'));
17313 node.removeAttribute(n);
17319 for (var i = node.attributes.length-1; i > -1 ; i--) {
17320 var a = node.attributes[i];
17323 if (a.name.toLowerCase().substr(0,2)=='on') {
17324 node.removeAttribute(a.name);
17327 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17328 node.removeAttribute(a.name);
17331 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17332 cleanAttr(a.name,a.value); // fixme..
17335 if (a.name == 'style') {
17336 cleanStyle(a.name,a.value);
17339 /// clean up MS crap..
17340 // tecnically this should be a list of valid class'es..
17343 if (a.name == 'class') {
17344 if (a.value.match(/^Mso/)) {
17345 node.className = '';
17348 if (a.value.match(/body/)) {
17349 node.className = '';
17360 this.cleanUpChildren(node);
17365 * Clean up MS wordisms...
17367 cleanWord : function(node)
17370 var cleanWordChildren = function()
17372 if (!node.childNodes.length) {
17375 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17376 _t.cleanWord(node.childNodes[i]);
17382 this.cleanWord(this.doc.body);
17385 if (node.nodeName == "#text") {
17386 // clean up silly Windows -- stuff?
17389 if (node.nodeName == "#comment") {
17390 node.parentNode.removeChild(node);
17391 // clean up silly Windows -- stuff?
17395 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17396 node.parentNode.removeChild(node);
17400 // remove - but keep children..
17401 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17402 while (node.childNodes.length) {
17403 var cn = node.childNodes[0];
17404 node.removeChild(cn);
17405 node.parentNode.insertBefore(cn, node);
17407 node.parentNode.removeChild(node);
17408 cleanWordChildren();
17412 if (node.className.length) {
17414 var cn = node.className.split(/\W+/);
17416 Roo.each(cn, function(cls) {
17417 if (cls.match(/Mso[a-zA-Z]+/)) {
17422 node.className = cna.length ? cna.join(' ') : '';
17424 node.removeAttribute("class");
17428 if (node.hasAttribute("lang")) {
17429 node.removeAttribute("lang");
17432 if (node.hasAttribute("style")) {
17434 var styles = node.getAttribute("style").split(";");
17436 Roo.each(styles, function(s) {
17437 if (!s.match(/:/)) {
17440 var kv = s.split(":");
17441 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17444 // what ever is left... we allow.
17447 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17448 if (!nstyle.length) {
17449 node.removeAttribute('style');
17453 cleanWordChildren();
17457 domToHTML : function(currentElement, depth, nopadtext) {
17459 depth = depth || 0;
17460 nopadtext = nopadtext || false;
17462 if (!currentElement) {
17463 return this.domToHTML(this.doc.body);
17466 //Roo.log(currentElement);
17468 var allText = false;
17469 var nodeName = currentElement.nodeName;
17470 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17472 if (nodeName == '#text') {
17473 return currentElement.nodeValue;
17478 if (nodeName != 'BODY') {
17481 // Prints the node tagName, such as <A>, <IMG>, etc
17484 for(i = 0; i < currentElement.attributes.length;i++) {
17486 var aname = currentElement.attributes.item(i).name;
17487 if (!currentElement.attributes.item(i).value.length) {
17490 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17493 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17502 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17505 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17510 // Traverse the tree
17512 var currentElementChild = currentElement.childNodes.item(i);
17513 var allText = true;
17514 var innerHTML = '';
17516 while (currentElementChild) {
17517 // Formatting code (indent the tree so it looks nice on the screen)
17518 var nopad = nopadtext;
17519 if (lastnode == 'SPAN') {
17523 if (currentElementChild.nodeName == '#text') {
17524 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17525 if (!nopad && toadd.length > 80) {
17526 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17528 innerHTML += toadd;
17531 currentElementChild = currentElement.childNodes.item(i);
17537 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17539 // Recursively traverse the tree structure of the child node
17540 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17541 lastnode = currentElementChild.nodeName;
17543 currentElementChild=currentElement.childNodes.item(i);
17549 // The remaining code is mostly for formatting the tree
17550 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17555 ret+= "</"+tagName+">";
17561 // hide stuff that is not compatible
17575 * @event specialkey
17579 * @cfg {String} fieldClass @hide
17582 * @cfg {String} focusClass @hide
17585 * @cfg {String} autoCreate @hide
17588 * @cfg {String} inputType @hide
17591 * @cfg {String} invalidClass @hide
17594 * @cfg {String} invalidText @hide
17597 * @cfg {String} msgFx @hide
17600 * @cfg {String} validateOnBlur @hide
17604 Roo.HtmlEditorCore.white = [
17605 'area', 'br', 'img', 'input', 'hr', 'wbr',
17607 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17608 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17609 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17610 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17611 'table', 'ul', 'xmp',
17613 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17616 'dir', 'menu', 'ol', 'ul', 'dl',
17622 Roo.HtmlEditorCore.black = [
17623 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17625 'base', 'basefont', 'bgsound', 'blink', 'body',
17626 'frame', 'frameset', 'head', 'html', 'ilayer',
17627 'iframe', 'layer', 'link', 'meta', 'object',
17628 'script', 'style' ,'title', 'xml' // clean later..
17630 Roo.HtmlEditorCore.clean = [
17631 'script', 'style', 'title', 'xml'
17633 Roo.HtmlEditorCore.remove = [
17638 Roo.HtmlEditorCore.ablack = [
17642 Roo.HtmlEditorCore.aclean = [
17643 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17647 Roo.HtmlEditorCore.pwhite= [
17648 'http', 'https', 'mailto'
17651 // white listed style attributes.
17652 Roo.HtmlEditorCore.cwhite= [
17653 // 'text-align', /// default is to allow most things..
17659 // black listed style attributes.
17660 Roo.HtmlEditorCore.cblack= [
17661 // 'font-size' -- this can be set by the project
17665 Roo.HtmlEditorCore.swapCodes =[
17684 * @class Roo.bootstrap.HtmlEditor
17685 * @extends Roo.bootstrap.TextArea
17686 * Bootstrap HtmlEditor class
17689 * Create a new HtmlEditor
17690 * @param {Object} config The config object
17693 Roo.bootstrap.HtmlEditor = function(config){
17694 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17695 if (!this.toolbars) {
17696 this.toolbars = [];
17698 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17701 * @event initialize
17702 * Fires when the editor is fully initialized (including the iframe)
17703 * @param {HtmlEditor} this
17708 * Fires when the editor is first receives the focus. Any insertion must wait
17709 * until after this event.
17710 * @param {HtmlEditor} this
17714 * @event beforesync
17715 * Fires before the textarea is updated with content from the editor iframe. Return false
17716 * to cancel the sync.
17717 * @param {HtmlEditor} this
17718 * @param {String} html
17722 * @event beforepush
17723 * Fires before the iframe editor is updated with content from the textarea. Return false
17724 * to cancel the push.
17725 * @param {HtmlEditor} this
17726 * @param {String} html
17731 * Fires when the textarea is updated with content from the editor iframe.
17732 * @param {HtmlEditor} this
17733 * @param {String} html
17738 * Fires when the iframe editor is updated with content from the textarea.
17739 * @param {HtmlEditor} this
17740 * @param {String} html
17744 * @event editmodechange
17745 * Fires when the editor switches edit modes
17746 * @param {HtmlEditor} this
17747 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17749 editmodechange: true,
17751 * @event editorevent
17752 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17753 * @param {HtmlEditor} this
17757 * @event firstfocus
17758 * Fires when on first focus - needed by toolbars..
17759 * @param {HtmlEditor} this
17764 * Auto save the htmlEditor value as a file into Events
17765 * @param {HtmlEditor} this
17769 * @event savedpreview
17770 * preview the saved version of htmlEditor
17771 * @param {HtmlEditor} this
17778 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17782 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17787 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17792 * @cfg {Number} height (in pixels)
17796 * @cfg {Number} width (in pixels)
17801 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17804 stylesheets: false,
17809 // private properties
17810 validationEvent : false,
17812 initialized : false,
17815 onFocus : Roo.emptyFn,
17817 hideMode:'offsets',
17820 tbContainer : false,
17822 toolbarContainer :function() {
17823 return this.wrap.select('.x-html-editor-tb',true).first();
17827 * Protected method that will not generally be called directly. It
17828 * is called when the editor creates its toolbar. Override this method if you need to
17829 * add custom toolbar buttons.
17830 * @param {HtmlEditor} editor
17832 createToolbar : function(){
17834 Roo.log("create toolbars");
17836 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17837 this.toolbars[0].render(this.toolbarContainer());
17841 // if (!editor.toolbars || !editor.toolbars.length) {
17842 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17845 // for (var i =0 ; i < editor.toolbars.length;i++) {
17846 // editor.toolbars[i] = Roo.factory(
17847 // typeof(editor.toolbars[i]) == 'string' ?
17848 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17849 // Roo.bootstrap.HtmlEditor);
17850 // editor.toolbars[i].init(editor);
17856 onRender : function(ct, position)
17858 // Roo.log("Call onRender: " + this.xtype);
17860 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17862 this.wrap = this.inputEl().wrap({
17863 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17866 this.editorcore.onRender(ct, position);
17868 if (this.resizable) {
17869 this.resizeEl = new Roo.Resizable(this.wrap, {
17873 minHeight : this.height,
17874 height: this.height,
17875 handles : this.resizable,
17878 resize : function(r, w, h) {
17879 _t.onResize(w,h); // -something
17885 this.createToolbar(this);
17888 if(!this.width && this.resizable){
17889 this.setSize(this.wrap.getSize());
17891 if (this.resizeEl) {
17892 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17893 // should trigger onReize..
17899 onResize : function(w, h)
17901 Roo.log('resize: ' +w + ',' + h );
17902 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17906 if(this.inputEl() ){
17907 if(typeof w == 'number'){
17908 var aw = w - this.wrap.getFrameWidth('lr');
17909 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17912 if(typeof h == 'number'){
17913 var tbh = -11; // fixme it needs to tool bar size!
17914 for (var i =0; i < this.toolbars.length;i++) {
17915 // fixme - ask toolbars for heights?
17916 tbh += this.toolbars[i].el.getHeight();
17917 //if (this.toolbars[i].footer) {
17918 // tbh += this.toolbars[i].footer.el.getHeight();
17926 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17927 ah -= 5; // knock a few pixes off for look..
17928 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17932 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17933 this.editorcore.onResize(ew,eh);
17938 * Toggles the editor between standard and source edit mode.
17939 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17941 toggleSourceEdit : function(sourceEditMode)
17943 this.editorcore.toggleSourceEdit(sourceEditMode);
17945 if(this.editorcore.sourceEditMode){
17946 Roo.log('editor - showing textarea');
17949 // Roo.log(this.syncValue());
17951 this.inputEl().removeClass(['hide', 'x-hidden']);
17952 this.inputEl().dom.removeAttribute('tabIndex');
17953 this.inputEl().focus();
17955 Roo.log('editor - hiding textarea');
17957 // Roo.log(this.pushValue());
17960 this.inputEl().addClass(['hide', 'x-hidden']);
17961 this.inputEl().dom.setAttribute('tabIndex', -1);
17962 //this.deferFocus();
17965 if(this.resizable){
17966 this.setSize(this.wrap.getSize());
17969 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17972 // private (for BoxComponent)
17973 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17975 // private (for BoxComponent)
17976 getResizeEl : function(){
17980 // private (for BoxComponent)
17981 getPositionEl : function(){
17986 initEvents : function(){
17987 this.originalValue = this.getValue();
17991 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17994 // markInvalid : Roo.emptyFn,
17996 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17999 // clearInvalid : Roo.emptyFn,
18001 setValue : function(v){
18002 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18003 this.editorcore.pushValue();
18008 deferFocus : function(){
18009 this.focus.defer(10, this);
18013 focus : function(){
18014 this.editorcore.focus();
18020 onDestroy : function(){
18026 for (var i =0; i < this.toolbars.length;i++) {
18027 // fixme - ask toolbars for heights?
18028 this.toolbars[i].onDestroy();
18031 this.wrap.dom.innerHTML = '';
18032 this.wrap.remove();
18037 onFirstFocus : function(){
18038 //Roo.log("onFirstFocus");
18039 this.editorcore.onFirstFocus();
18040 for (var i =0; i < this.toolbars.length;i++) {
18041 this.toolbars[i].onFirstFocus();
18047 syncValue : function()
18049 this.editorcore.syncValue();
18052 pushValue : function()
18054 this.editorcore.pushValue();
18058 // hide stuff that is not compatible
18072 * @event specialkey
18076 * @cfg {String} fieldClass @hide
18079 * @cfg {String} focusClass @hide
18082 * @cfg {String} autoCreate @hide
18085 * @cfg {String} inputType @hide
18088 * @cfg {String} invalidClass @hide
18091 * @cfg {String} invalidText @hide
18094 * @cfg {String} msgFx @hide
18097 * @cfg {String} validateOnBlur @hide
18106 Roo.namespace('Roo.bootstrap.htmleditor');
18108 * @class Roo.bootstrap.HtmlEditorToolbar1
18113 new Roo.bootstrap.HtmlEditor({
18116 new Roo.bootstrap.HtmlEditorToolbar1({
18117 disable : { fonts: 1 , format: 1, ..., ... , ...],
18123 * @cfg {Object} disable List of elements to disable..
18124 * @cfg {Array} btns List of additional buttons.
18128 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18131 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18134 Roo.apply(this, config);
18136 // default disabled, based on 'good practice'..
18137 this.disable = this.disable || {};
18138 Roo.applyIf(this.disable, {
18141 specialElements : true
18143 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18145 this.editor = config.editor;
18146 this.editorcore = config.editor.editorcore;
18148 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18150 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18151 // dont call parent... till later.
18153 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18158 editorcore : false,
18163 "h1","h2","h3","h4","h5","h6",
18165 "abbr", "acronym", "address", "cite", "samp", "var",
18169 onRender : function(ct, position)
18171 // Roo.log("Call onRender: " + this.xtype);
18173 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18175 this.el.dom.style.marginBottom = '0';
18177 var editorcore = this.editorcore;
18178 var editor= this.editor;
18181 var btn = function(id,cmd , toggle, handler){
18183 var event = toggle ? 'toggle' : 'click';
18188 xns: Roo.bootstrap,
18191 enableToggle:toggle !== false,
18193 pressed : toggle ? false : null,
18196 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18197 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18206 xns: Roo.bootstrap,
18207 glyphicon : 'font',
18211 xns: Roo.bootstrap,
18215 Roo.each(this.formats, function(f) {
18216 style.menu.items.push({
18218 xns: Roo.bootstrap,
18219 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18224 editorcore.insertTag(this.tagname);
18231 children.push(style);
18234 btn('bold',false,true);
18235 btn('italic',false,true);
18236 btn('align-left', 'justifyleft',true);
18237 btn('align-center', 'justifycenter',true);
18238 btn('align-right' , 'justifyright',true);
18239 btn('link', false, false, function(btn) {
18240 //Roo.log("create link?");
18241 var url = prompt(this.createLinkText, this.defaultLinkValue);
18242 if(url && url != 'http:/'+'/'){
18243 this.editorcore.relayCmd('createlink', url);
18246 btn('list','insertunorderedlist',true);
18247 btn('pencil', false,true, function(btn){
18250 this.toggleSourceEdit(btn.pressed);
18256 xns: Roo.bootstrap,
18261 xns: Roo.bootstrap,
18266 cog.menu.items.push({
18268 xns: Roo.bootstrap,
18269 html : Clean styles,
18274 editorcore.insertTag(this.tagname);
18283 this.xtype = 'NavSimplebar';
18285 for(var i=0;i< children.length;i++) {
18287 this.buttons.add(this.addxtypeChild(children[i]));
18291 editor.on('editorevent', this.updateToolbar, this);
18293 onBtnClick : function(id)
18295 this.editorcore.relayCmd(id);
18296 this.editorcore.focus();
18300 * Protected method that will not generally be called directly. It triggers
18301 * a toolbar update by reading the markup state of the current selection in the editor.
18303 updateToolbar: function(){
18305 if(!this.editorcore.activated){
18306 this.editor.onFirstFocus(); // is this neeed?
18310 var btns = this.buttons;
18311 var doc = this.editorcore.doc;
18312 btns.get('bold').setActive(doc.queryCommandState('bold'));
18313 btns.get('italic').setActive(doc.queryCommandState('italic'));
18314 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18316 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18317 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18318 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18320 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18321 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18324 var ans = this.editorcore.getAllAncestors();
18325 if (this.formatCombo) {
18328 var store = this.formatCombo.store;
18329 this.formatCombo.setValue("");
18330 for (var i =0; i < ans.length;i++) {
18331 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18333 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18341 // hides menus... - so this cant be on a menu...
18342 Roo.bootstrap.MenuMgr.hideAll();
18344 Roo.bootstrap.MenuMgr.hideAll();
18345 //this.editorsyncValue();
18347 onFirstFocus: function() {
18348 this.buttons.each(function(item){
18352 toggleSourceEdit : function(sourceEditMode){
18355 if(sourceEditMode){
18356 Roo.log("disabling buttons");
18357 this.buttons.each( function(item){
18358 if(item.cmd != 'pencil'){
18364 Roo.log("enabling buttons");
18365 if(this.editorcore.initialized){
18366 this.buttons.each( function(item){
18372 Roo.log("calling toggole on editor");
18373 // tell the editor that it's been pressed..
18374 this.editor.toggleSourceEdit(sourceEditMode);
18384 * @class Roo.bootstrap.Table.AbstractSelectionModel
18385 * @extends Roo.util.Observable
18386 * Abstract base class for grid SelectionModels. It provides the interface that should be
18387 * implemented by descendant classes. This class should not be directly instantiated.
18390 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18391 this.locked = false;
18392 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18396 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18397 /** @ignore Called by the grid automatically. Do not call directly. */
18398 init : function(grid){
18404 * Locks the selections.
18407 this.locked = true;
18411 * Unlocks the selections.
18413 unlock : function(){
18414 this.locked = false;
18418 * Returns true if the selections are locked.
18419 * @return {Boolean}
18421 isLocked : function(){
18422 return this.locked;
18426 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18427 * @class Roo.bootstrap.Table.RowSelectionModel
18428 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18429 * It supports multiple selections and keyboard selection/navigation.
18431 * @param {Object} config
18434 Roo.bootstrap.Table.RowSelectionModel = function(config){
18435 Roo.apply(this, config);
18436 this.selections = new Roo.util.MixedCollection(false, function(o){
18441 this.lastActive = false;
18445 * @event selectionchange
18446 * Fires when the selection changes
18447 * @param {SelectionModel} this
18449 "selectionchange" : true,
18451 * @event afterselectionchange
18452 * Fires after the selection changes (eg. by key press or clicking)
18453 * @param {SelectionModel} this
18455 "afterselectionchange" : true,
18457 * @event beforerowselect
18458 * Fires when a row is selected being selected, return false to cancel.
18459 * @param {SelectionModel} this
18460 * @param {Number} rowIndex The selected index
18461 * @param {Boolean} keepExisting False if other selections will be cleared
18463 "beforerowselect" : true,
18466 * Fires when a row is selected.
18467 * @param {SelectionModel} this
18468 * @param {Number} rowIndex The selected index
18469 * @param {Roo.data.Record} r The record
18471 "rowselect" : true,
18473 * @event rowdeselect
18474 * Fires when a row is deselected.
18475 * @param {SelectionModel} this
18476 * @param {Number} rowIndex The selected index
18478 "rowdeselect" : true
18480 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18481 this.locked = false;
18484 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18486 * @cfg {Boolean} singleSelect
18487 * True to allow selection of only one row at a time (defaults to false)
18489 singleSelect : false,
18492 initEvents : function(){
18494 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18495 this.grid.on("mousedown", this.handleMouseDown, this);
18496 }else{ // allow click to work like normal
18497 this.grid.on("rowclick", this.handleDragableRowClick, this);
18500 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18501 "up" : function(e){
18503 this.selectPrevious(e.shiftKey);
18504 }else if(this.last !== false && this.lastActive !== false){
18505 var last = this.last;
18506 this.selectRange(this.last, this.lastActive-1);
18507 this.grid.getView().focusRow(this.lastActive);
18508 if(last !== false){
18512 this.selectFirstRow();
18514 this.fireEvent("afterselectionchange", this);
18516 "down" : function(e){
18518 this.selectNext(e.shiftKey);
18519 }else if(this.last !== false && this.lastActive !== false){
18520 var last = this.last;
18521 this.selectRange(this.last, this.lastActive+1);
18522 this.grid.getView().focusRow(this.lastActive);
18523 if(last !== false){
18527 this.selectFirstRow();
18529 this.fireEvent("afterselectionchange", this);
18534 var view = this.grid.view;
18535 view.on("refresh", this.onRefresh, this);
18536 view.on("rowupdated", this.onRowUpdated, this);
18537 view.on("rowremoved", this.onRemove, this);
18541 onRefresh : function(){
18542 var ds = this.grid.dataSource, i, v = this.grid.view;
18543 var s = this.selections;
18544 s.each(function(r){
18545 if((i = ds.indexOfId(r.id)) != -1){
18554 onRemove : function(v, index, r){
18555 this.selections.remove(r);
18559 onRowUpdated : function(v, index, r){
18560 if(this.isSelected(r)){
18561 v.onRowSelect(index);
18567 * @param {Array} records The records to select
18568 * @param {Boolean} keepExisting (optional) True to keep existing selections
18570 selectRecords : function(records, keepExisting){
18572 this.clearSelections();
18574 var ds = this.grid.dataSource;
18575 for(var i = 0, len = records.length; i < len; i++){
18576 this.selectRow(ds.indexOf(records[i]), true);
18581 * Gets the number of selected rows.
18584 getCount : function(){
18585 return this.selections.length;
18589 * Selects the first row in the grid.
18591 selectFirstRow : function(){
18596 * Select the last row.
18597 * @param {Boolean} keepExisting (optional) True to keep existing selections
18599 selectLastRow : function(keepExisting){
18600 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18604 * Selects the row immediately following the last selected row.
18605 * @param {Boolean} keepExisting (optional) True to keep existing selections
18607 selectNext : function(keepExisting){
18608 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18609 this.selectRow(this.last+1, keepExisting);
18610 this.grid.getView().focusRow(this.last);
18615 * Selects the row that precedes the last selected row.
18616 * @param {Boolean} keepExisting (optional) True to keep existing selections
18618 selectPrevious : function(keepExisting){
18620 this.selectRow(this.last-1, keepExisting);
18621 this.grid.getView().focusRow(this.last);
18626 * Returns the selected records
18627 * @return {Array} Array of selected records
18629 getSelections : function(){
18630 return [].concat(this.selections.items);
18634 * Returns the first selected record.
18637 getSelected : function(){
18638 return this.selections.itemAt(0);
18643 * Clears all selections.
18645 clearSelections : function(fast){
18646 if(this.locked) return;
18648 var ds = this.grid.dataSource;
18649 var s = this.selections;
18650 s.each(function(r){
18651 this.deselectRow(ds.indexOfId(r.id));
18655 this.selections.clear();
18662 * Selects all rows.
18664 selectAll : function(){
18665 if(this.locked) return;
18666 this.selections.clear();
18667 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18668 this.selectRow(i, true);
18673 * Returns True if there is a selection.
18674 * @return {Boolean}
18676 hasSelection : function(){
18677 return this.selections.length > 0;
18681 * Returns True if the specified row is selected.
18682 * @param {Number/Record} record The record or index of the record to check
18683 * @return {Boolean}
18685 isSelected : function(index){
18686 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18687 return (r && this.selections.key(r.id) ? true : false);
18691 * Returns True if the specified record id is selected.
18692 * @param {String} id The id of record to check
18693 * @return {Boolean}
18695 isIdSelected : function(id){
18696 return (this.selections.key(id) ? true : false);
18700 handleMouseDown : function(e, t){
18701 var view = this.grid.getView(), rowIndex;
18702 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18705 if(e.shiftKey && this.last !== false){
18706 var last = this.last;
18707 this.selectRange(last, rowIndex, e.ctrlKey);
18708 this.last = last; // reset the last
18709 view.focusRow(rowIndex);
18711 var isSelected = this.isSelected(rowIndex);
18712 if(e.button !== 0 && isSelected){
18713 view.focusRow(rowIndex);
18714 }else if(e.ctrlKey && isSelected){
18715 this.deselectRow(rowIndex);
18716 }else if(!isSelected){
18717 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18718 view.focusRow(rowIndex);
18721 this.fireEvent("afterselectionchange", this);
18724 handleDragableRowClick : function(grid, rowIndex, e)
18726 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18727 this.selectRow(rowIndex, false);
18728 grid.view.focusRow(rowIndex);
18729 this.fireEvent("afterselectionchange", this);
18734 * Selects multiple rows.
18735 * @param {Array} rows Array of the indexes of the row to select
18736 * @param {Boolean} keepExisting (optional) True to keep existing selections
18738 selectRows : function(rows, keepExisting){
18740 this.clearSelections();
18742 for(var i = 0, len = rows.length; i < len; i++){
18743 this.selectRow(rows[i], true);
18748 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18749 * @param {Number} startRow The index of the first row in the range
18750 * @param {Number} endRow The index of the last row in the range
18751 * @param {Boolean} keepExisting (optional) True to retain existing selections
18753 selectRange : function(startRow, endRow, keepExisting){
18754 if(this.locked) return;
18756 this.clearSelections();
18758 if(startRow <= endRow){
18759 for(var i = startRow; i <= endRow; i++){
18760 this.selectRow(i, true);
18763 for(var i = startRow; i >= endRow; i--){
18764 this.selectRow(i, true);
18770 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18771 * @param {Number} startRow The index of the first row in the range
18772 * @param {Number} endRow The index of the last row in the range
18774 deselectRange : function(startRow, endRow, preventViewNotify){
18775 if(this.locked) return;
18776 for(var i = startRow; i <= endRow; i++){
18777 this.deselectRow(i, preventViewNotify);
18783 * @param {Number} row The index of the row to select
18784 * @param {Boolean} keepExisting (optional) True to keep existing selections
18786 selectRow : function(index, keepExisting, preventViewNotify){
18787 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18788 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18789 if(!keepExisting || this.singleSelect){
18790 this.clearSelections();
18792 var r = this.grid.dataSource.getAt(index);
18793 this.selections.add(r);
18794 this.last = this.lastActive = index;
18795 if(!preventViewNotify){
18796 this.grid.getView().onRowSelect(index);
18798 this.fireEvent("rowselect", this, index, r);
18799 this.fireEvent("selectionchange", this);
18805 * @param {Number} row The index of the row to deselect
18807 deselectRow : function(index, preventViewNotify){
18808 if(this.locked) return;
18809 if(this.last == index){
18812 if(this.lastActive == index){
18813 this.lastActive = false;
18815 var r = this.grid.dataSource.getAt(index);
18816 this.selections.remove(r);
18817 if(!preventViewNotify){
18818 this.grid.getView().onRowDeselect(index);
18820 this.fireEvent("rowdeselect", this, index);
18821 this.fireEvent("selectionchange", this);
18825 restoreLast : function(){
18827 this.last = this._last;
18832 acceptsNav : function(row, col, cm){
18833 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18837 onEditorKey : function(field, e){
18838 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18843 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18845 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18847 }else if(k == e.ENTER && !e.ctrlKey){
18851 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18853 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18855 }else if(k == e.ESC){
18859 g.startEditing(newCell[0], newCell[1]);
18864 * Ext JS Library 1.1.1
18865 * Copyright(c) 2006-2007, Ext JS, LLC.
18867 * Originally Released Under LGPL - original licence link has changed is not relivant.
18870 * <script type="text/javascript">
18874 * @class Roo.bootstrap.PagingToolbar
18876 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18878 * Create a new PagingToolbar
18879 * @param {Object} config The config object
18881 Roo.bootstrap.PagingToolbar = function(config)
18883 // old args format still supported... - xtype is prefered..
18884 // created from xtype...
18885 var ds = config.dataSource;
18886 this.toolbarItems = [];
18887 if (config.items) {
18888 this.toolbarItems = config.items;
18889 // config.items = [];
18892 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18899 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18903 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18905 * @cfg {Roo.data.Store} dataSource
18906 * The underlying data store providing the paged data
18909 * @cfg {String/HTMLElement/Element} container
18910 * container The id or element that will contain the toolbar
18913 * @cfg {Boolean} displayInfo
18914 * True to display the displayMsg (defaults to false)
18917 * @cfg {Number} pageSize
18918 * The number of records to display per page (defaults to 20)
18922 * @cfg {String} displayMsg
18923 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18925 displayMsg : 'Displaying {0} - {1} of {2}',
18927 * @cfg {String} emptyMsg
18928 * The message to display when no records are found (defaults to "No data to display")
18930 emptyMsg : 'No data to display',
18932 * Customizable piece of the default paging text (defaults to "Page")
18935 beforePageText : "Page",
18937 * Customizable piece of the default paging text (defaults to "of %0")
18940 afterPageText : "of {0}",
18942 * Customizable piece of the default paging text (defaults to "First Page")
18945 firstText : "First Page",
18947 * Customizable piece of the default paging text (defaults to "Previous Page")
18950 prevText : "Previous Page",
18952 * Customizable piece of the default paging text (defaults to "Next Page")
18955 nextText : "Next Page",
18957 * Customizable piece of the default paging text (defaults to "Last Page")
18960 lastText : "Last Page",
18962 * Customizable piece of the default paging text (defaults to "Refresh")
18965 refreshText : "Refresh",
18969 onRender : function(ct, position)
18971 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18972 this.navgroup.parentId = this.id;
18973 this.navgroup.onRender(this.el, null);
18974 // add the buttons to the navgroup
18976 if(this.displayInfo){
18977 Roo.log(this.el.select('ul.navbar-nav',true).first());
18978 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18979 this.displayEl = this.el.select('.x-paging-info', true).first();
18980 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18981 // this.displayEl = navel.el.select('span',true).first();
18987 Roo.each(_this.buttons, function(e){
18988 Roo.factory(e).onRender(_this.el, null);
18992 Roo.each(_this.toolbarItems, function(e) {
18993 _this.navgroup.addItem(e);
18996 this.first = this.navgroup.addItem({
18997 tooltip: this.firstText,
18999 icon : 'fa fa-backward',
19001 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19004 this.prev = this.navgroup.addItem({
19005 tooltip: this.prevText,
19007 icon : 'fa fa-step-backward',
19009 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19011 //this.addSeparator();
19014 var field = this.navgroup.addItem( {
19016 cls : 'x-paging-position',
19018 html : this.beforePageText +
19019 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19020 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19023 this.field = field.el.select('input', true).first();
19024 this.field.on("keydown", this.onPagingKeydown, this);
19025 this.field.on("focus", function(){this.dom.select();});
19028 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19029 //this.field.setHeight(18);
19030 //this.addSeparator();
19031 this.next = this.navgroup.addItem({
19032 tooltip: this.nextText,
19034 html : ' <i class="fa fa-step-forward">',
19036 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19038 this.last = this.navgroup.addItem({
19039 tooltip: this.lastText,
19040 icon : 'fa fa-forward',
19043 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19045 //this.addSeparator();
19046 this.loading = this.navgroup.addItem({
19047 tooltip: this.refreshText,
19048 icon: 'fa fa-refresh',
19050 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19056 updateInfo : function(){
19057 if(this.displayEl){
19058 var count = this.ds.getCount();
19059 var msg = count == 0 ?
19063 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19065 this.displayEl.update(msg);
19070 onLoad : function(ds, r, o){
19071 this.cursor = o.params ? o.params.start : 0;
19072 var d = this.getPageData(),
19076 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19077 this.field.dom.value = ap;
19078 this.first.setDisabled(ap == 1);
19079 this.prev.setDisabled(ap == 1);
19080 this.next.setDisabled(ap == ps);
19081 this.last.setDisabled(ap == ps);
19082 this.loading.enable();
19087 getPageData : function(){
19088 var total = this.ds.getTotalCount();
19091 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19092 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19097 onLoadError : function(){
19098 this.loading.enable();
19102 onPagingKeydown : function(e){
19103 var k = e.getKey();
19104 var d = this.getPageData();
19106 var v = this.field.dom.value, pageNum;
19107 if(!v || isNaN(pageNum = parseInt(v, 10))){
19108 this.field.dom.value = d.activePage;
19111 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19112 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19115 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))
19117 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19118 this.field.dom.value = pageNum;
19119 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19122 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19124 var v = this.field.dom.value, pageNum;
19125 var increment = (e.shiftKey) ? 10 : 1;
19126 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19128 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19129 this.field.dom.value = d.activePage;
19132 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19134 this.field.dom.value = parseInt(v, 10) + increment;
19135 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19136 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19143 beforeLoad : function(){
19145 this.loading.disable();
19150 onClick : function(which){
19157 ds.load({params:{start: 0, limit: this.pageSize}});
19160 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19163 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19166 var total = ds.getTotalCount();
19167 var extra = total % this.pageSize;
19168 var lastStart = extra ? (total - extra) : total-this.pageSize;
19169 ds.load({params:{start: lastStart, limit: this.pageSize}});
19172 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19178 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19179 * @param {Roo.data.Store} store The data store to unbind
19181 unbind : function(ds){
19182 ds.un("beforeload", this.beforeLoad, this);
19183 ds.un("load", this.onLoad, this);
19184 ds.un("loadexception", this.onLoadError, this);
19185 ds.un("remove", this.updateInfo, this);
19186 ds.un("add", this.updateInfo, this);
19187 this.ds = undefined;
19191 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19192 * @param {Roo.data.Store} store The data store to bind
19194 bind : function(ds){
19195 ds.on("beforeload", this.beforeLoad, this);
19196 ds.on("load", this.onLoad, this);
19197 ds.on("loadexception", this.onLoadError, this);
19198 ds.on("remove", this.updateInfo, this);
19199 ds.on("add", this.updateInfo, this);
19210 * @class Roo.bootstrap.MessageBar
19211 * @extends Roo.bootstrap.Component
19212 * Bootstrap MessageBar class
19213 * @cfg {String} html contents of the MessageBar
19214 * @cfg {String} weight (info | success | warning | danger) default info
19215 * @cfg {String} beforeClass insert the bar before the given class
19216 * @cfg {Boolean} closable (true | false) default false
19217 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19220 * Create a new Element
19221 * @param {Object} config The config object
19224 Roo.bootstrap.MessageBar = function(config){
19225 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19228 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19234 beforeClass: 'bootstrap-sticky-wrap',
19236 getAutoCreate : function(){
19240 cls: 'alert alert-dismissable alert-' + this.weight,
19245 html: this.html || ''
19251 cfg.cls += ' alert-messages-fixed';
19265 onRender : function(ct, position)
19267 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19270 var cfg = Roo.apply({}, this.getAutoCreate());
19274 cfg.cls += ' ' + this.cls;
19277 cfg.style = this.style;
19279 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19281 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19284 this.el.select('>button.close').on('click', this.hide, this);
19290 if (!this.rendered) {
19296 this.fireEvent('show', this);
19302 if (!this.rendered) {
19308 this.fireEvent('hide', this);
19311 update : function()
19313 // var e = this.el.dom.firstChild;
19315 // if(this.closable){
19316 // e = e.nextSibling;
19319 // e.data = this.html || '';
19321 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19337 * @class Roo.bootstrap.Graph
19338 * @extends Roo.bootstrap.Component
19339 * Bootstrap Graph class
19343 @cfg {String} graphtype bar | vbar | pie
19344 @cfg {number} g_x coodinator | centre x (pie)
19345 @cfg {number} g_y coodinator | centre y (pie)
19346 @cfg {number} g_r radius (pie)
19347 @cfg {number} g_height height of the chart (respected by all elements in the set)
19348 @cfg {number} g_width width of the chart (respected by all elements in the set)
19349 @cfg {Object} title The title of the chart
19352 -opts (object) options for the chart
19354 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19355 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19357 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.
19358 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19360 o stretch (boolean)
19362 -opts (object) options for the pie
19365 o startAngle (number)
19366 o endAngle (number)
19370 * Create a new Input
19371 * @param {Object} config The config object
19374 Roo.bootstrap.Graph = function(config){
19375 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19381 * The img click event for the img.
19382 * @param {Roo.EventObject} e
19388 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19399 //g_colors: this.colors,
19406 getAutoCreate : function(){
19417 onRender : function(ct,position){
19418 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19419 this.raphael = Raphael(this.el.dom);
19421 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19422 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19423 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19424 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19426 r.text(160, 10, "Single Series Chart").attr(txtattr);
19427 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19428 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19429 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19431 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19432 r.barchart(330, 10, 300, 220, data1);
19433 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19434 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19437 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19438 // r.barchart(30, 30, 560, 250, xdata, {
19439 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19440 // axis : "0 0 1 1",
19441 // axisxlabels : xdata
19442 // //yvalues : cols,
19445 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19447 // this.load(null,xdata,{
19448 // axis : "0 0 1 1",
19449 // axisxlabels : xdata
19454 load : function(graphtype,xdata,opts){
19455 this.raphael.clear();
19457 graphtype = this.graphtype;
19462 var r = this.raphael,
19463 fin = function () {
19464 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19466 fout = function () {
19467 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19469 pfin = function() {
19470 this.sector.stop();
19471 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19474 this.label[0].stop();
19475 this.label[0].attr({ r: 7.5 });
19476 this.label[1].attr({ "font-weight": 800 });
19479 pfout = function() {
19480 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19483 this.label[0].animate({ r: 5 }, 500, "bounce");
19484 this.label[1].attr({ "font-weight": 400 });
19490 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19493 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19496 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19497 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19499 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19506 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19511 setTitle: function(o)
19516 initEvents: function() {
19519 this.el.on('click', this.onClick, this);
19523 onClick : function(e)
19525 Roo.log('img onclick');
19526 this.fireEvent('click', this, e);
19538 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19541 * @class Roo.bootstrap.dash.NumberBox
19542 * @extends Roo.bootstrap.Component
19543 * Bootstrap NumberBox class
19544 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19545 * @cfg {String} headline Box headline
19546 * @cfg {String} content Box content
19547 * @cfg {String} icon Box icon
19548 * @cfg {String} footer Footer text
19549 * @cfg {String} fhref Footer href
19552 * Create a new NumberBox
19553 * @param {Object} config The config object
19557 Roo.bootstrap.dash.NumberBox = function(config){
19558 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19562 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19572 getAutoCreate : function(){
19576 cls : 'small-box bg-' + this.bgcolor,
19584 cls : 'roo-headline',
19585 html : this.headline
19589 cls : 'roo-content',
19590 html : this.content
19604 cls : 'ion ' + this.icon
19613 cls : 'small-box-footer',
19614 href : this.fhref || '#',
19618 cfg.cn.push(footer);
19625 onRender : function(ct,position){
19626 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19633 setHeadline: function (value)
19635 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19638 setFooter: function (value, href)
19640 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19643 this.el.select('a.small-box-footer',true).first().attr('href', href);
19648 setContent: function (value)
19650 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19653 initEvents: function()
19667 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19670 * @class Roo.bootstrap.dash.TabBox
19671 * @extends Roo.bootstrap.Component
19672 * Bootstrap TabBox class
19673 * @cfg {String} title Title of the TabBox
19674 * @cfg {String} icon Icon of the TabBox
19675 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19678 * Create a new TabBox
19679 * @param {Object} config The config object
19683 Roo.bootstrap.dash.TabBox = function(config){
19684 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19689 * When a pane is added
19690 * @param {Roo.bootstrap.dash.TabPane} pane
19697 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19703 getChildContainer : function()
19705 return this.el.select('.tab-content', true).first();
19708 getAutoCreate : function(){
19712 cls: 'pull-left header',
19720 cls: 'fa ' + this.icon
19727 cls: 'nav-tabs-custom',
19731 cls: 'nav nav-tabs pull-right',
19738 cls: 'tab-content no-padding',
19746 initEvents : function()
19748 //Roo.log('add add pane handler');
19749 this.on('addpane', this.onAddPane, this);
19752 * Updates the box title
19753 * @param {String} html to set the title to.
19755 setTitle : function(value)
19757 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19759 onAddPane : function(pane)
19761 //Roo.log('addpane');
19763 // tabs are rendere left to right..
19764 if(!this.showtabs){
19768 var ctr = this.el.select('.nav-tabs', true).first();
19771 var existing = ctr.select('.nav-tab',true);
19772 var qty = existing.getCount();;
19775 var tab = ctr.createChild({
19777 cls : 'nav-tab' + (qty ? '' : ' active'),
19785 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19788 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19790 pane.el.addClass('active');
19795 onTabClick : function(ev,un,ob,pane)
19797 //Roo.log('tab - prev default');
19798 ev.preventDefault();
19801 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19802 pane.tab.addClass('active');
19803 //Roo.log(pane.title);
19804 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19805 // technically we should have a deactivate event.. but maybe add later.
19806 // and it should not de-activate the selected tab...
19808 pane.el.addClass('active');
19809 pane.fireEvent('activate');
19824 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19826 * @class Roo.bootstrap.TabPane
19827 * @extends Roo.bootstrap.Component
19828 * Bootstrap TabPane class
19829 * @cfg {Boolean} active (false | true) Default false
19830 * @cfg {String} title title of panel
19834 * Create a new TabPane
19835 * @param {Object} config The config object
19838 Roo.bootstrap.dash.TabPane = function(config){
19839 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19845 * When a pane is activated
19846 * @param {Roo.bootstrap.dash.TabPane} pane
19853 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19858 // the tabBox that this is attached to.
19861 getAutoCreate : function()
19869 cfg.cls += ' active';
19874 initEvents : function()
19876 //Roo.log('trigger add pane handler');
19877 this.parent().fireEvent('addpane', this)
19881 * Updates the tab title
19882 * @param {String} html to set the title to.
19884 setTitle: function(str)
19890 this.tab.select('a', true).first().dom.innerHTML = str;
19907 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19910 * @class Roo.bootstrap.menu.Menu
19911 * @extends Roo.bootstrap.Component
19912 * Bootstrap Menu class - container for Menu
19913 * @cfg {String} html Text of the menu
19914 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19915 * @cfg {String} icon Font awesome icon
19916 * @cfg {String} pos Menu align to (top | bottom) default bottom
19920 * Create a new Menu
19921 * @param {Object} config The config object
19925 Roo.bootstrap.menu.Menu = function(config){
19926 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19930 * @event beforeshow
19931 * Fires before this menu is displayed
19932 * @param {Roo.bootstrap.menu.Menu} this
19936 * @event beforehide
19937 * Fires before this menu is hidden
19938 * @param {Roo.bootstrap.menu.Menu} this
19943 * Fires after this menu is displayed
19944 * @param {Roo.bootstrap.menu.Menu} this
19949 * Fires after this menu is hidden
19950 * @param {Roo.bootstrap.menu.Menu} this
19955 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19956 * @param {Roo.bootstrap.menu.Menu} this
19957 * @param {Roo.EventObject} e
19964 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19968 weight : 'default',
19973 getChildContainer : function() {
19974 if(this.isSubMenu){
19978 return this.el.select('ul.dropdown-menu', true).first();
19981 getAutoCreate : function()
19986 cls : 'roo-menu-text',
19994 cls : 'fa ' + this.icon
20005 cls : 'dropdown-button btn btn-' + this.weight,
20010 cls : 'dropdown-toggle btn btn-' + this.weight,
20020 cls : 'dropdown-menu'
20026 if(this.pos == 'top'){
20027 cfg.cls += ' dropup';
20030 if(this.isSubMenu){
20033 cls : 'dropdown-menu'
20040 onRender : function(ct, position)
20042 this.isSubMenu = ct.hasClass('dropdown-submenu');
20044 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20047 initEvents : function()
20049 if(this.isSubMenu){
20053 this.hidden = true;
20055 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20056 this.triggerEl.on('click', this.onTriggerPress, this);
20058 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20059 this.buttonEl.on('click', this.onClick, this);
20065 if(this.isSubMenu){
20069 return this.el.select('ul.dropdown-menu', true).first();
20072 onClick : function(e)
20074 this.fireEvent("click", this, e);
20077 onTriggerPress : function(e)
20079 if (this.isVisible()) {
20086 isVisible : function(){
20087 return !this.hidden;
20092 this.fireEvent("beforeshow", this);
20094 this.hidden = false;
20095 this.el.addClass('open');
20097 Roo.get(document).on("mouseup", this.onMouseUp, this);
20099 this.fireEvent("show", this);
20106 this.fireEvent("beforehide", this);
20108 this.hidden = true;
20109 this.el.removeClass('open');
20111 Roo.get(document).un("mouseup", this.onMouseUp);
20113 this.fireEvent("hide", this);
20116 onMouseUp : function()
20130 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20133 * @class Roo.bootstrap.menu.Item
20134 * @extends Roo.bootstrap.Component
20135 * Bootstrap MenuItem class
20136 * @cfg {Boolean} submenu (true | false) default false
20137 * @cfg {String} html text of the item
20138 * @cfg {String} href the link
20139 * @cfg {Boolean} disable (true | false) default false
20140 * @cfg {Boolean} preventDefault (true | false) default true
20141 * @cfg {String} icon Font awesome icon
20142 * @cfg {String} pos Submenu align to (left | right) default right
20146 * Create a new Item
20147 * @param {Object} config The config object
20151 Roo.bootstrap.menu.Item = function(config){
20152 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20156 * Fires when the mouse is hovering over this menu
20157 * @param {Roo.bootstrap.menu.Item} this
20158 * @param {Roo.EventObject} e
20163 * Fires when the mouse exits this menu
20164 * @param {Roo.bootstrap.menu.Item} this
20165 * @param {Roo.EventObject} e
20171 * The raw click event for the entire grid.
20172 * @param {Roo.EventObject} e
20178 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20183 preventDefault: true,
20188 getAutoCreate : function()
20193 cls : 'roo-menu-item-text',
20201 cls : 'fa ' + this.icon
20210 href : this.href || '#',
20217 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20221 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20223 if(this.pos == 'left'){
20224 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20231 initEvents : function()
20233 this.el.on('mouseover', this.onMouseOver, this);
20234 this.el.on('mouseout', this.onMouseOut, this);
20236 this.el.select('a', true).first().on('click', this.onClick, this);
20240 onClick : function(e)
20242 if(this.preventDefault){
20243 e.preventDefault();
20246 this.fireEvent("click", this, e);
20249 onMouseOver : function(e)
20251 if(this.submenu && this.pos == 'left'){
20252 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20255 this.fireEvent("mouseover", this, e);
20258 onMouseOut : function(e)
20260 this.fireEvent("mouseout", this, e);
20272 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20275 * @class Roo.bootstrap.menu.Separator
20276 * @extends Roo.bootstrap.Component
20277 * Bootstrap Separator class
20280 * Create a new Separator
20281 * @param {Object} config The config object
20285 Roo.bootstrap.menu.Separator = function(config){
20286 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20289 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20291 getAutoCreate : function(){