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
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1160 if(!this.href || this.preventDefault){
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3180 Roo.bootstrap.NavGroup.register(this);
3184 * Fires when the active item changes
3185 * @param {Roo.bootstrap.NavGroup} this
3186 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3187 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3194 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3205 getAutoCreate : function()
3207 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3214 if (['tabs','pills'].indexOf(this.type)!==-1) {
3215 cfg.cls += ' nav-' + this.type
3217 if (this.type!=='nav') {
3218 Roo.log('nav type must be nav/tabs/pills')
3220 cfg.cls += ' navbar-nav'
3223 if (this.parent().sidebar) {
3226 cls: 'dashboard-menu sidebar-menu'
3232 if (this.form === true) {
3238 if (this.align === 'right') {
3239 cfg.cls += ' navbar-right';
3241 cfg.cls += ' navbar-left';
3245 if (this.align === 'right') {
3246 cfg.cls += ' navbar-right';
3250 cfg.cls += ' navbar-inverse';
3258 setActiveItem : function(item)
3261 Roo.each(this.navItems, function(v){
3266 v.setActive(false, true);
3273 item.setActive(true, true);
3274 this.fireEvent('changed', this, item, prev);
3279 addItem : function(cfg)
3281 var cn = new Roo.bootstrap.NavItem(cfg);
3283 cn.parentId = this.id;
3284 cn.onRender(this.el, null);
3288 register : function(item)
3290 this.navItems.push( item);
3291 item.navId = this.navId;
3294 getNavItem: function(tabId)
3297 Roo.each(this.navItems, function(e) {
3298 if (e.tabId == tabId) {
3314 Roo.apply(Roo.bootstrap.NavGroup, {
3318 register : function(navgrp)
3320 this.groups[navgrp.navId] = navgrp;
3323 get: function(navId) {
3324 return this.groups[navId];
3339 * @class Roo.bootstrap.NavItem
3340 * @extends Roo.bootstrap.Component
3341 * Bootstrap Navbar.NavItem class
3342 * @cfg {String} href link to
3343 * @cfg {String} html content of button
3344 * @cfg {String} badge text inside badge
3345 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3346 * @cfg {String} glyphicon name of glyphicon
3347 * @cfg {String} icon name of font awesome icon
3348 * @cfg {Boolean} active Is item active
3349 * @cfg {Boolean} disabled Is item disabled
3351 * @cfg {Boolean} preventDefault (true | false) default false
3352 * @cfg {String} tabId the tab that this item activates.
3353 * @cfg {String} tagtype (a|span) render as a href or span?
3356 * Create a new Navbar Item
3357 * @param {Object} config The config object
3359 Roo.bootstrap.NavItem = function(config){
3360 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3365 * The raw click event for the entire grid.
3366 * @param {Roo.EventObject} e
3371 * Fires when the active item active state changes
3372 * @param {Roo.bootstrap.NavItem} this
3373 * @param {boolean} state the new state
3381 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3389 preventDefault : false,
3394 getAutoCreate : function(){
3402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3404 if (this.disabled) {
3405 cfg.cls += ' disabled';
3408 if (this.href || this.html || this.glyphicon || this.icon) {
3412 href : this.href || "#",
3413 html: this.html || ''
3418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3421 if(this.glyphicon) {
3422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3427 cfg.cn[0].html += " <span class='caret'></span>";
3431 if (this.badge !== '') {
3433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3441 initEvents: function() {
3442 // Roo.log('init events?');
3443 // Roo.log(this.el.dom);
3444 if (typeof (this.menu) != 'undefined') {
3445 this.menu.parentType = this.xtype;
3446 this.menu.triggerEl = this.el;
3447 this.addxtype(Roo.apply({}, this.menu));
3451 this.el.select('a',true).on('click', this.onClick, this);
3452 // at this point parent should be available..
3453 this.parent().register(this);
3456 onClick : function(e)
3459 if(this.preventDefault){
3462 if (this.disabled) {
3465 Roo.log("fire event clicked");
3466 if(this.fireEvent('click', this, e) === false){
3470 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3471 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3472 this.parent().setActiveItem(this);
3480 isActive: function () {
3483 setActive : function(state, fire)
3485 this.active = state;
3487 this.el.removeClass('active');
3488 } else if (!this.el.hasClass('active')) {
3489 this.el.addClass('active');
3492 this.fireEvent('changed', this, state);
3497 // this should not be here...
3498 setDisabled : function(state)
3500 this.disabled = state;
3502 this.el.removeClass('disabled');
3503 } else if (!this.el.hasClass('disabled')) {
3504 this.el.addClass('disabled');
3517 * <span> icon </span>
3518 * <span> text </span>
3519 * <span>badge </span>
3523 * @class Roo.bootstrap.NavSidebarItem
3524 * @extends Roo.bootstrap.NavItem
3525 * Bootstrap Navbar.NavSidebarItem class
3527 * Create a new Navbar Button
3528 * @param {Object} config The config object
3530 Roo.bootstrap.NavSidebarItem = function(config){
3531 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3536 * The raw click event for the entire grid.
3537 * @param {Roo.EventObject} e
3542 * Fires when the active item active state changes
3543 * @param {Roo.bootstrap.NavSidebarItem} this
3544 * @param {boolean} state the new state
3552 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3555 getAutoCreate : function(){
3560 href : this.href || '#',
3572 html : this.html || ''
3577 cfg.cls += ' active';
3581 if (this.glyphicon || this.icon) {
3582 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3583 a.cn.push({ tag : 'i', cls : c }) ;
3588 if (this.badge !== '') {
3589 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3593 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3594 a.cls += 'dropdown-toggle treeview' ;
3618 * @class Roo.bootstrap.Row
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Row class (contains columns...)
3624 * @param {Object} config The config object
3627 Roo.bootstrap.Row = function(config){
3628 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3631 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3652 * @class Roo.bootstrap.Element
3653 * @extends Roo.bootstrap.Component
3654 * Bootstrap Element class
3655 * @cfg {String} html contents of the element
3656 * @cfg {String} tag tag of the element
3657 * @cfg {String} cls class of the element
3660 * Create a new Element
3661 * @param {Object} config The config object
3664 Roo.bootstrap.Element = function(config){
3665 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3675 getAutoCreate : function(){
3700 * @class Roo.bootstrap.Pagination
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap Pagination class
3703 * @cfg {String} size xs | sm | md | lg
3704 * @cfg {Boolean} inverse false | true
3707 * Create a new Pagination
3708 * @param {Object} config The config object
3711 Roo.bootstrap.Pagination = function(config){
3712 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3715 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3721 getAutoCreate : function(){
3727 cfg.cls += ' inverse';
3733 cfg.cls += " " + this.cls;
3751 * @class Roo.bootstrap.PaginationItem
3752 * @extends Roo.bootstrap.Component
3753 * Bootstrap PaginationItem class
3754 * @cfg {String} html text
3755 * @cfg {String} href the link
3756 * @cfg {Boolean} preventDefault (true | false) default true
3757 * @cfg {Boolean} active (true | false) default false
3761 * Create a new PaginationItem
3762 * @param {Object} config The config object
3766 Roo.bootstrap.PaginationItem = function(config){
3767 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3772 * The raw click event for the entire grid.
3773 * @param {Roo.EventObject} e
3779 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3783 preventDefault: true,
3787 getAutoCreate : function(){
3793 href : this.href ? this.href : '#',
3794 html : this.html ? this.html : ''
3804 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3810 initEvents: function() {
3812 this.el.on('click', this.onClick, this);
3815 onClick : function(e)
3817 Roo.log('PaginationItem on click ');
3818 if(this.preventDefault){
3822 this.fireEvent('click', this, e);
3838 * @class Roo.bootstrap.Slider
3839 * @extends Roo.bootstrap.Component
3840 * Bootstrap Slider class
3843 * Create a new Slider
3844 * @param {Object} config The config object
3847 Roo.bootstrap.Slider = function(config){
3848 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3851 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3853 getAutoCreate : function(){
3857 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3861 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.grid.ColumnModel
3885 * @extends Roo.util.Observable
3886 * This is the default implementation of a ColumnModel used by the Grid. It defines
3887 * the columns in the grid.
3890 var colModel = new Roo.grid.ColumnModel([
3891 {header: "Ticker", width: 60, sortable: true, locked: true},
3892 {header: "Company Name", width: 150, sortable: true},
3893 {header: "Market Cap.", width: 100, sortable: true},
3894 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3895 {header: "Employees", width: 100, sortable: true, resizable: false}
3900 * The config options listed for this class are options which may appear in each
3901 * individual column definition.
3902 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3904 * @param {Object} config An Array of column config objects. See this class's
3905 * config objects for details.
3907 Roo.grid.ColumnModel = function(config){
3909 * The config passed into the constructor
3911 this.config = config;
3914 // if no id, create one
3915 // if the column does not have a dataIndex mapping,
3916 // map it to the order it is in the config
3917 for(var i = 0, len = config.length; i < len; i++){
3919 if(typeof c.dataIndex == "undefined"){
3922 if(typeof c.renderer == "string"){
3923 c.renderer = Roo.util.Format[c.renderer];
3925 if(typeof c.id == "undefined"){
3928 if(c.editor && c.editor.xtype){
3929 c.editor = Roo.factory(c.editor, Roo.grid);
3931 if(c.editor && c.editor.isFormField){
3932 c.editor = new Roo.grid.GridEditor(c.editor);
3934 this.lookup[c.id] = c;
3938 * The width of columns which have no width specified (defaults to 100)
3941 this.defaultWidth = 100;
3944 * Default sortable of columns which have no sortable specified (defaults to false)
3947 this.defaultSortable = false;
3951 * @event widthchange
3952 * Fires when the width of a column changes.
3953 * @param {ColumnModel} this
3954 * @param {Number} columnIndex The column index
3955 * @param {Number} newWidth The new width
3957 "widthchange": true,
3959 * @event headerchange
3960 * Fires when the text of a header changes.
3961 * @param {ColumnModel} this
3962 * @param {Number} columnIndex The column index
3963 * @param {Number} newText The new header text
3965 "headerchange": true,
3967 * @event hiddenchange
3968 * Fires when a column is hidden or "unhidden".
3969 * @param {ColumnModel} this
3970 * @param {Number} columnIndex The column index
3971 * @param {Boolean} hidden true if hidden, false otherwise
3973 "hiddenchange": true,
3975 * @event columnmoved
3976 * Fires when a column is moved.
3977 * @param {ColumnModel} this
3978 * @param {Number} oldIndex
3979 * @param {Number} newIndex
3981 "columnmoved" : true,
3983 * @event columlockchange
3984 * Fires when a column's locked state is changed
3985 * @param {ColumnModel} this
3986 * @param {Number} colIndex
3987 * @param {Boolean} locked true if locked
3989 "columnlockchange" : true
3991 Roo.grid.ColumnModel.superclass.constructor.call(this);
3993 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3995 * @cfg {String} header The header text to display in the Grid view.
3998 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3999 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4000 * specified, the column's index is used as an index into the Record's data Array.
4003 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4004 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4007 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4008 * Defaults to the value of the {@link #defaultSortable} property.
4009 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4012 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4015 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4018 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4021 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4024 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4025 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4026 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4027 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4030 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4033 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4037 * Returns the id of the column at the specified index.
4038 * @param {Number} index The column index
4039 * @return {String} the id
4041 getColumnId : function(index){
4042 return this.config[index].id;
4046 * Returns the column for a specified id.
4047 * @param {String} id The column id
4048 * @return {Object} the column
4050 getColumnById : function(id){
4051 return this.lookup[id];
4056 * Returns the column for a specified dataIndex.
4057 * @param {String} dataIndex The column dataIndex
4058 * @return {Object|Boolean} the column or false if not found
4060 getColumnByDataIndex: function(dataIndex){
4061 var index = this.findColumnIndex(dataIndex);
4062 return index > -1 ? this.config[index] : false;
4066 * Returns the index for a specified column id.
4067 * @param {String} id The column id
4068 * @return {Number} the index, or -1 if not found
4070 getIndexById : function(id){
4071 for(var i = 0, len = this.config.length; i < len; i++){
4072 if(this.config[i].id == id){
4080 * Returns the index for a specified column dataIndex.
4081 * @param {String} dataIndex The column dataIndex
4082 * @return {Number} the index, or -1 if not found
4085 findColumnIndex : function(dataIndex){
4086 for(var i = 0, len = this.config.length; i < len; i++){
4087 if(this.config[i].dataIndex == dataIndex){
4095 moveColumn : function(oldIndex, newIndex){
4096 var c = this.config[oldIndex];
4097 this.config.splice(oldIndex, 1);
4098 this.config.splice(newIndex, 0, c);
4099 this.dataMap = null;
4100 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4103 isLocked : function(colIndex){
4104 return this.config[colIndex].locked === true;
4107 setLocked : function(colIndex, value, suppressEvent){
4108 if(this.isLocked(colIndex) == value){
4111 this.config[colIndex].locked = value;
4113 this.fireEvent("columnlockchange", this, colIndex, value);
4117 getTotalLockedWidth : function(){
4119 for(var i = 0; i < this.config.length; i++){
4120 if(this.isLocked(i) && !this.isHidden(i)){
4121 this.totalWidth += this.getColumnWidth(i);
4127 getLockedCount : function(){
4128 for(var i = 0, len = this.config.length; i < len; i++){
4129 if(!this.isLocked(i)){
4136 * Returns the number of columns.
4139 getColumnCount : function(visibleOnly){
4140 if(visibleOnly === true){
4142 for(var i = 0, len = this.config.length; i < len; i++){
4143 if(!this.isHidden(i)){
4149 return this.config.length;
4153 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4154 * @param {Function} fn
4155 * @param {Object} scope (optional)
4156 * @return {Array} result
4158 getColumnsBy : function(fn, scope){
4160 for(var i = 0, len = this.config.length; i < len; i++){
4161 var c = this.config[i];
4162 if(fn.call(scope||this, c, i) === true){
4170 * Returns true if the specified column is sortable.
4171 * @param {Number} col The column index
4174 isSortable : function(col){
4175 if(typeof this.config[col].sortable == "undefined"){
4176 return this.defaultSortable;
4178 return this.config[col].sortable;
4182 * Returns the rendering (formatting) function defined for the column.
4183 * @param {Number} col The column index.
4184 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4186 getRenderer : function(col){
4187 if(!this.config[col].renderer){
4188 return Roo.grid.ColumnModel.defaultRenderer;
4190 return this.config[col].renderer;
4194 * Sets the rendering (formatting) function for a column.
4195 * @param {Number} col The column index
4196 * @param {Function} fn The function to use to process the cell's raw data
4197 * to return HTML markup for the grid view. The render function is called with
4198 * the following parameters:<ul>
4199 * <li>Data value.</li>
4200 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4201 * <li>css A CSS style string to apply to the table cell.</li>
4202 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4203 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4204 * <li>Row index</li>
4205 * <li>Column index</li>
4206 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4208 setRenderer : function(col, fn){
4209 this.config[col].renderer = fn;
4213 * Returns the width for the specified column.
4214 * @param {Number} col The column index
4217 getColumnWidth : function(col){
4218 return this.config[col].width * 1 || this.defaultWidth;
4222 * Sets the width for a column.
4223 * @param {Number} col The column index
4224 * @param {Number} width The new width
4226 setColumnWidth : function(col, width, suppressEvent){
4227 this.config[col].width = width;
4228 this.totalWidth = null;
4230 this.fireEvent("widthchange", this, col, width);
4235 * Returns the total width of all columns.
4236 * @param {Boolean} includeHidden True to include hidden column widths
4239 getTotalWidth : function(includeHidden){
4240 if(!this.totalWidth){
4241 this.totalWidth = 0;
4242 for(var i = 0, len = this.config.length; i < len; i++){
4243 if(includeHidden || !this.isHidden(i)){
4244 this.totalWidth += this.getColumnWidth(i);
4248 return this.totalWidth;
4252 * Returns the header for the specified column.
4253 * @param {Number} col The column index
4256 getColumnHeader : function(col){
4257 return this.config[col].header;
4261 * Sets the header for a column.
4262 * @param {Number} col The column index
4263 * @param {String} header The new header
4265 setColumnHeader : function(col, header){
4266 this.config[col].header = header;
4267 this.fireEvent("headerchange", this, col, header);
4271 * Returns the tooltip for the specified column.
4272 * @param {Number} col The column index
4275 getColumnTooltip : function(col){
4276 return this.config[col].tooltip;
4279 * Sets the tooltip for a column.
4280 * @param {Number} col The column index
4281 * @param {String} tooltip The new tooltip
4283 setColumnTooltip : function(col, tooltip){
4284 this.config[col].tooltip = tooltip;
4288 * Returns the dataIndex for the specified column.
4289 * @param {Number} col The column index
4292 getDataIndex : function(col){
4293 return this.config[col].dataIndex;
4297 * Sets the dataIndex for a column.
4298 * @param {Number} col The column index
4299 * @param {Number} dataIndex The new dataIndex
4301 setDataIndex : function(col, dataIndex){
4302 this.config[col].dataIndex = dataIndex;
4308 * Returns true if the cell is editable.
4309 * @param {Number} colIndex The column index
4310 * @param {Number} rowIndex The row index
4313 isCellEditable : function(colIndex, rowIndex){
4314 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4318 * Returns the editor defined for the cell/column.
4319 * return false or null to disable editing.
4320 * @param {Number} colIndex The column index
4321 * @param {Number} rowIndex The row index
4324 getCellEditor : function(colIndex, rowIndex){
4325 return this.config[colIndex].editor;
4329 * Sets if a column is editable.
4330 * @param {Number} col The column index
4331 * @param {Boolean} editable True if the column is editable
4333 setEditable : function(col, editable){
4334 this.config[col].editable = editable;
4339 * Returns true if the column is hidden.
4340 * @param {Number} colIndex The column index
4343 isHidden : function(colIndex){
4344 return this.config[colIndex].hidden;
4349 * Returns true if the column width cannot be changed
4351 isFixed : function(colIndex){
4352 return this.config[colIndex].fixed;
4356 * Returns true if the column can be resized
4359 isResizable : function(colIndex){
4360 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4363 * Sets if a column is hidden.
4364 * @param {Number} colIndex The column index
4365 * @param {Boolean} hidden True if the column is hidden
4367 setHidden : function(colIndex, hidden){
4368 this.config[colIndex].hidden = hidden;
4369 this.totalWidth = null;
4370 this.fireEvent("hiddenchange", this, colIndex, hidden);
4374 * Sets the editor for a column.
4375 * @param {Number} col The column index
4376 * @param {Object} editor The editor object
4378 setEditor : function(col, editor){
4379 this.config[col].editor = editor;
4383 Roo.grid.ColumnModel.defaultRenderer = function(value){
4384 if(typeof value == "string" && value.length < 1){
4390 // Alias for backwards compatibility
4391 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4394 * Ext JS Library 1.1.1
4395 * Copyright(c) 2006-2007, Ext JS, LLC.
4397 * Originally Released Under LGPL - original licence link has changed is not relivant.
4400 * <script type="text/javascript">
4404 * @class Roo.LoadMask
4405 * A simple utility class for generically masking elements while loading data. If the element being masked has
4406 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4407 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4408 * element's UpdateManager load indicator and will be destroyed after the initial load.
4410 * Create a new LoadMask
4411 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4412 * @param {Object} config The config object
4414 Roo.LoadMask = function(el, config){
4415 this.el = Roo.get(el);
4416 Roo.apply(this, config);
4418 this.store.on('beforeload', this.onBeforeLoad, this);
4419 this.store.on('load', this.onLoad, this);
4420 this.store.on('loadexception', this.onLoadException, this);
4421 this.removeMask = false;
4423 var um = this.el.getUpdateManager();
4424 um.showLoadIndicator = false; // disable the default indicator
4425 um.on('beforeupdate', this.onBeforeLoad, this);
4426 um.on('update', this.onLoad, this);
4427 um.on('failure', this.onLoad, this);
4428 this.removeMask = true;
4432 Roo.LoadMask.prototype = {
4434 * @cfg {Boolean} removeMask
4435 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4436 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4440 * The text to display in a centered loading message box (defaults to 'Loading...')
4444 * @cfg {String} msgCls
4445 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4447 msgCls : 'x-mask-loading',
4450 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4456 * Disables the mask to prevent it from being displayed
4458 disable : function(){
4459 this.disabled = true;
4463 * Enables the mask so that it can be displayed
4465 enable : function(){
4466 this.disabled = false;
4469 onLoadException : function()
4473 if (typeof(arguments[3]) != 'undefined') {
4474 Roo.MessageBox.alert("Error loading",arguments[3]);
4478 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4479 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4488 this.el.unmask(this.removeMask);
4493 this.el.unmask(this.removeMask);
4497 onBeforeLoad : function(){
4499 this.el.mask(this.msg, this.msgCls);
4504 destroy : function(){
4506 this.store.un('beforeload', this.onBeforeLoad, this);
4507 this.store.un('load', this.onLoad, this);
4508 this.store.un('loadexception', this.onLoadException, this);
4510 var um = this.el.getUpdateManager();
4511 um.un('beforeupdate', this.onBeforeLoad, this);
4512 um.un('update', this.onLoad, this);
4513 um.un('failure', this.onLoad, this);
4524 * @class Roo.bootstrap.Table
4525 * @extends Roo.bootstrap.Component
4526 * Bootstrap Table class
4527 * @cfg {String} cls table class
4528 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4529 * @cfg {String} bgcolor Specifies the background color for a table
4530 * @cfg {Number} border Specifies whether the table cells should have borders or not
4531 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4532 * @cfg {Number} cellspacing Specifies the space between cells
4533 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4534 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4535 * @cfg {String} sortable Specifies that the table should be sortable
4536 * @cfg {String} summary Specifies a summary of the content of a table
4537 * @cfg {Number} width Specifies the width of a table
4538 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4540 * @cfg {boolean} striped Should the rows be alternative striped
4541 * @cfg {boolean} bordered Add borders to the table
4542 * @cfg {boolean} hover Add hover highlighting
4543 * @cfg {boolean} condensed Format condensed
4544 * @cfg {boolean} responsive Format condensed
4545 * @cfg {Boolean} loadMask (true|false) default false
4546 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4547 * @cfg {Boolean} thead (true|false) generate thead, default true
4548 * @cfg {Boolean} RowSelection (true|false) default false
4549 * @cfg {Boolean} CellSelection (true|false) default false
4551 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4555 * Create a new Table
4556 * @param {Object} config The config object
4559 Roo.bootstrap.Table = function(config){
4560 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4563 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4564 this.sm = this.selModel;
4565 this.sm.xmodule = this.xmodule || false;
4567 if (this.cm && typeof(this.cm.config) == 'undefined') {
4568 this.colModel = new Roo.grid.ColumnModel(this.cm);
4569 this.cm = this.colModel;
4570 this.cm.xmodule = this.xmodule || false;
4573 this.store= Roo.factory(this.store, Roo.data);
4574 this.ds = this.store;
4575 this.ds.xmodule = this.xmodule || false;
4578 if (this.footer && this.store) {
4579 this.footer.dataSource = this.ds;
4580 this.footer = Roo.factory(this.footer);
4587 * Fires when a cell is clicked
4588 * @param {Roo.bootstrap.Table} this
4589 * @param {Roo.Element} el
4590 * @param {Number} rowIndex
4591 * @param {Number} columnIndex
4592 * @param {Roo.EventObject} e
4596 * @event celldblclick
4597 * Fires when a cell is double clicked
4598 * @param {Roo.bootstrap.Table} this
4599 * @param {Roo.Element} el
4600 * @param {Number} rowIndex
4601 * @param {Number} columnIndex
4602 * @param {Roo.EventObject} e
4604 "celldblclick" : true,
4607 * Fires when a row is clicked
4608 * @param {Roo.bootstrap.Table} this
4609 * @param {Roo.Element} el
4610 * @param {Number} rowIndex
4611 * @param {Roo.EventObject} e
4615 * @event rowdblclick
4616 * Fires when a row is double clicked
4617 * @param {Roo.bootstrap.Table} this
4618 * @param {Roo.Element} el
4619 * @param {Number} rowIndex
4620 * @param {Roo.EventObject} e
4622 "rowdblclick" : true,
4625 * Fires when a mouseover occur
4626 * @param {Roo.bootstrap.Table} this
4627 * @param {Roo.Element} el
4628 * @param {Number} rowIndex
4629 * @param {Number} columnIndex
4630 * @param {Roo.EventObject} e
4635 * Fires when a mouseout occur
4636 * @param {Roo.bootstrap.Table} this
4637 * @param {Roo.Element} el
4638 * @param {Number} rowIndex
4639 * @param {Number} columnIndex
4640 * @param {Roo.EventObject} e
4645 * Fires when a row is rendered, so you can change add a style to it.
4646 * @param {Roo.bootstrap.Table} this
4647 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4654 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4678 RowSelection : false,
4679 CellSelection : false,
4682 // Roo.Element - the tbody
4685 getAutoCreate : function(){
4686 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4695 cfg.cls += ' table-striped';
4699 cfg.cls += ' table-hover';
4701 if (this.bordered) {
4702 cfg.cls += ' table-bordered';
4704 if (this.condensed) {
4705 cfg.cls += ' table-condensed';
4707 if (this.responsive) {
4708 cfg.cls += ' table-responsive';
4712 cfg.cls+= ' ' +this.cls;
4715 // this lot should be simplifed...
4718 cfg.align=this.align;
4721 cfg.bgcolor=this.bgcolor;
4724 cfg.border=this.border;
4726 if (this.cellpadding) {
4727 cfg.cellpadding=this.cellpadding;
4729 if (this.cellspacing) {
4730 cfg.cellspacing=this.cellspacing;
4733 cfg.frame=this.frame;
4736 cfg.rules=this.rules;
4738 if (this.sortable) {
4739 cfg.sortable=this.sortable;
4742 cfg.summary=this.summary;
4745 cfg.width=this.width;
4748 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4751 if(this.store || this.cm){
4753 cfg.cn.push(this.renderHeader());
4756 cfg.cn.push(this.renderBody());
4759 cfg.cn.push(this.renderFooter());
4762 cfg.cls+= ' TableGrid';
4765 return { cn : [ cfg ] };
4768 initEvents : function()
4770 if(!this.store || !this.cm){
4774 //Roo.log('initEvents with ds!!!!');
4776 this.mainBody = this.el.select('tbody', true).first();
4781 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4782 e.on('click', _this.sort, _this);
4785 this.el.on("click", this.onClick, this);
4786 this.el.on("dblclick", this.onDblClick, this);
4788 this.parent().el.setStyle('position', 'relative');
4790 this.footer.parentId = this.id;
4791 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4794 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4796 this.store.on('load', this.onLoad, this);
4797 this.store.on('beforeload', this.onBeforeLoad, this);
4798 this.store.on('update', this.onUpdate, this);
4802 onMouseover : function(e, el)
4804 var cell = Roo.get(el);
4810 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4811 cell = cell.findParent('td', false, true);
4814 var row = cell.findParent('tr', false, true);
4815 var cellIndex = cell.dom.cellIndex;
4816 var rowIndex = row.dom.rowIndex - 1; // start from 0
4818 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4822 onMouseout : function(e, el)
4824 var cell = Roo.get(el);
4830 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4831 cell = cell.findParent('td', false, true);
4834 var row = cell.findParent('tr', false, true);
4835 var cellIndex = cell.dom.cellIndex;
4836 var rowIndex = row.dom.rowIndex - 1; // start from 0
4838 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4842 onClick : function(e, el)
4844 var cell = Roo.get(el);
4846 if(!cell || (!this.CellSelection && !this.RowSelection)){
4851 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4852 cell = cell.findParent('td', false, true);
4855 var row = cell.findParent('tr', false, true);
4856 var cellIndex = cell.dom.cellIndex;
4857 var rowIndex = row.dom.rowIndex - 1;
4859 if(this.CellSelection){
4860 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4863 if(this.RowSelection){
4864 this.fireEvent('rowclick', this, row, rowIndex, e);
4870 onDblClick : function(e,el)
4872 var cell = Roo.get(el);
4874 if(!cell || (!this.CellSelection && !this.RowSelection)){
4878 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4879 cell = cell.findParent('td', false, true);
4882 var row = cell.findParent('tr', false, true);
4883 var cellIndex = cell.dom.cellIndex;
4884 var rowIndex = row.dom.rowIndex - 1;
4886 if(this.CellSelection){
4887 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4890 if(this.RowSelection){
4891 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4895 sort : function(e,el)
4897 var col = Roo.get(el)
4899 if(!col.hasClass('sortable')){
4903 var sort = col.attr('sort');
4906 if(col.hasClass('glyphicon-arrow-up')){
4910 this.store.sortInfo = {field : sort, direction : dir};
4913 Roo.log("calling footer first");
4914 this.footer.onClick('first');
4917 this.store.load({ params : { start : 0 } });
4921 renderHeader : function()
4930 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4932 var config = cm.config[i];
4937 html: cm.getColumnHeader(i)
4940 if(typeof(config.hidden) != 'undefined' && config.hidden){
4941 c.style += ' display:none;';
4944 if(typeof(config.dataIndex) != 'undefined'){
4945 c.sort = config.dataIndex;
4948 if(typeof(config.sortable) != 'undefined' && config.sortable){
4952 // if(typeof(config.align) != 'undefined' && config.align.length){
4953 // c.style += ' text-align:' + config.align + ';';
4956 if(typeof(config.width) != 'undefined'){
4957 c.style += ' width:' + config.width + 'px;';
4966 renderBody : function()
4976 colspan : this.cm.getColumnCount()
4986 renderFooter : function()
4996 colspan : this.cm.getColumnCount()
5010 Roo.log('ds onload');
5015 var ds = this.store;
5017 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5018 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5020 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5021 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5024 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5025 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5029 var tbody = this.mainBody;
5033 if(ds.getCount() > 0){
5034 ds.data.each(function(d,rowIndex){
5035 var row = this.renderRow(cm, ds, rowIndex);
5037 tbody.createChild(row);
5041 if(row.cellObjects.length){
5042 Roo.each(row.cellObjects, function(r){
5043 _this.renderCellObject(r);
5050 Roo.each(this.el.select('tbody td', true).elements, function(e){
5051 e.on('mouseover', _this.onMouseover, _this);
5054 Roo.each(this.el.select('tbody td', true).elements, function(e){
5055 e.on('mouseout', _this.onMouseout, _this);
5058 //if(this.loadMask){
5059 // this.maskEl.hide();
5064 onUpdate : function(ds,record)
5066 this.refreshRow(record);
5068 onRemove : function(ds, record, index, isUpdate){
5069 if(isUpdate !== true){
5070 this.fireEvent("beforerowremoved", this, index, record);
5072 var bt = this.mainBody.dom;
5074 bt.removeChild(bt.rows[index]);
5077 if(isUpdate !== true){
5078 //this.stripeRows(index);
5079 //this.syncRowHeights(index, index);
5081 this.fireEvent("rowremoved", this, index, record);
5086 refreshRow : function(record){
5087 var ds = this.store, index;
5088 if(typeof record == 'number'){
5090 record = ds.getAt(index);
5092 index = ds.indexOf(record);
5094 this.insertRow(ds, index, true);
5095 this.onRemove(ds, record, index+1, true);
5096 //this.syncRowHeights(index, index);
5098 this.fireEvent("rowupdated", this, index, record);
5101 insertRow : function(dm, rowIndex, isUpdate){
5104 this.fireEvent("beforerowsinserted", this, rowIndex);
5106 //var s = this.getScrollState();
5107 var row = this.renderRow(this.cm, this.store, rowIndex);
5108 // insert before rowIndex..
5109 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5114 if(row.cellObjects.length){
5115 Roo.each(row.cellObjects, function(r){
5116 _this.renderCellObject(r);
5121 this.fireEvent("rowsinserted", this, rowIndex);
5122 //this.syncRowHeights(firstRow, lastRow);
5123 //this.stripeRows(firstRow);
5130 getRowDom : function(rowIndex)
5132 // not sure if I need to check this.. but let's do it anyway..
5133 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5134 this.mainBody.dom.rows[rowIndex] : false
5136 // returns the object tree for a tr..
5139 renderRow : function(cm, ds, rowIndex) {
5141 var d = ds.getAt(rowIndex);
5148 var cellObjects = [];
5150 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5151 var config = cm.config[i];
5153 var renderer = cm.getRenderer(i);
5157 if(typeof(renderer) !== 'undefined'){
5158 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5160 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5161 // and are rendered into the cells after the row is rendered - using the id for the element.
5163 if(typeof(value) === 'object'){
5173 rowIndex : rowIndex,
5178 this.fireEvent('rowclass', this, rowcfg);
5182 cls : rowcfg.rowClass,
5184 html: (typeof(value) === 'object') ? '' : value
5191 if(typeof(config.hidden) != 'undefined' && config.hidden){
5192 td.style += ' display:none;';
5195 if(typeof(config.align) != 'undefined' && config.align.length){
5196 td.style += ' text-align:' + config.align + ';';
5199 if(typeof(config.width) != 'undefined'){
5200 td.style += ' width:' + config.width + 'px;';
5207 row.cellObjects = cellObjects;
5215 onBeforeLoad : function()
5217 //Roo.log('ds onBeforeLoad');
5221 //if(this.loadMask){
5222 // this.maskEl.show();
5228 this.el.select('tbody', true).first().dom.innerHTML = '';
5231 getSelectionModel : function(){
5233 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5235 return this.selModel;
5238 * Render the Roo.bootstrap object from renderder
5240 renderCellObject : function(r)
5244 var t = r.cfg.render(r.container);
5247 Roo.each(r.cfg.cn, function(c){
5249 container: t.getChildContainer(),
5252 _this.renderCellObject(child);
5269 * @class Roo.bootstrap.TableCell
5270 * @extends Roo.bootstrap.Component
5271 * Bootstrap TableCell class
5272 * @cfg {String} html cell contain text
5273 * @cfg {String} cls cell class
5274 * @cfg {String} tag cell tag (td|th) default td
5275 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5276 * @cfg {String} align Aligns the content in a cell
5277 * @cfg {String} axis Categorizes cells
5278 * @cfg {String} bgcolor Specifies the background color of a cell
5279 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5280 * @cfg {Number} colspan Specifies the number of columns a cell should span
5281 * @cfg {String} headers Specifies one or more header cells a cell is related to
5282 * @cfg {Number} height Sets the height of a cell
5283 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5284 * @cfg {Number} rowspan Sets the number of rows a cell should span
5285 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5286 * @cfg {String} valign Vertical aligns the content in a cell
5287 * @cfg {Number} width Specifies the width of a cell
5290 * Create a new TableCell
5291 * @param {Object} config The config object
5294 Roo.bootstrap.TableCell = function(config){
5295 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5298 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5318 getAutoCreate : function(){
5319 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5339 cfg.align=this.align
5345 cfg.bgcolor=this.bgcolor
5348 cfg.charoff=this.charoff
5351 cfg.colspan=this.colspan
5354 cfg.headers=this.headers
5357 cfg.height=this.height
5360 cfg.nowrap=this.nowrap
5363 cfg.rowspan=this.rowspan
5366 cfg.scope=this.scope
5369 cfg.valign=this.valign
5372 cfg.width=this.width
5391 * @class Roo.bootstrap.TableRow
5392 * @extends Roo.bootstrap.Component
5393 * Bootstrap TableRow class
5394 * @cfg {String} cls row class
5395 * @cfg {String} align Aligns the content in a table row
5396 * @cfg {String} bgcolor Specifies a background color for a table row
5397 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5398 * @cfg {String} valign Vertical aligns the content in a table row
5401 * Create a new TableRow
5402 * @param {Object} config The config object
5405 Roo.bootstrap.TableRow = function(config){
5406 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5409 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5417 getAutoCreate : function(){
5418 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5428 cfg.align = this.align;
5431 cfg.bgcolor = this.bgcolor;
5434 cfg.charoff = this.charoff;
5437 cfg.valign = this.valign;
5455 * @class Roo.bootstrap.TableBody
5456 * @extends Roo.bootstrap.Component
5457 * Bootstrap TableBody class
5458 * @cfg {String} cls element class
5459 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5460 * @cfg {String} align Aligns the content inside the element
5461 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5462 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5465 * Create a new TableBody
5466 * @param {Object} config The config object
5469 Roo.bootstrap.TableBody = function(config){
5470 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5473 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5481 getAutoCreate : function(){
5482 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5496 cfg.align = this.align;
5499 cfg.charoff = this.charoff;
5502 cfg.valign = this.valign;
5509 // initEvents : function()
5516 // this.store = Roo.factory(this.store, Roo.data);
5517 // this.store.on('load', this.onLoad, this);
5519 // this.store.load();
5523 // onLoad: function ()
5525 // this.fireEvent('load', this);
5535 * Ext JS Library 1.1.1
5536 * Copyright(c) 2006-2007, Ext JS, LLC.
5538 * Originally Released Under LGPL - original licence link has changed is not relivant.
5541 * <script type="text/javascript">
5544 // as we use this in bootstrap.
5545 Roo.namespace('Roo.form');
5547 * @class Roo.form.Action
5548 * Internal Class used to handle form actions
5550 * @param {Roo.form.BasicForm} el The form element or its id
5551 * @param {Object} config Configuration options
5556 // define the action interface
5557 Roo.form.Action = function(form, options){
5559 this.options = options || {};
5562 * Client Validation Failed
5565 Roo.form.Action.CLIENT_INVALID = 'client';
5567 * Server Validation Failed
5570 Roo.form.Action.SERVER_INVALID = 'server';
5572 * Connect to Server Failed
5575 Roo.form.Action.CONNECT_FAILURE = 'connect';
5577 * Reading Data from Server Failed
5580 Roo.form.Action.LOAD_FAILURE = 'load';
5582 Roo.form.Action.prototype = {
5584 failureType : undefined,
5585 response : undefined,
5589 run : function(options){
5594 success : function(response){
5599 handleResponse : function(response){
5603 // default connection failure
5604 failure : function(response){
5606 this.response = response;
5607 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5608 this.form.afterAction(this, false);
5611 processResponse : function(response){
5612 this.response = response;
5613 if(!response.responseText){
5616 this.result = this.handleResponse(response);
5620 // utility functions used internally
5621 getUrl : function(appendParams){
5622 var url = this.options.url || this.form.url || this.form.el.dom.action;
5624 var p = this.getParams();
5626 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5632 getMethod : function(){
5633 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5636 getParams : function(){
5637 var bp = this.form.baseParams;
5638 var p = this.options.params;
5640 if(typeof p == "object"){
5641 p = Roo.urlEncode(Roo.applyIf(p, bp));
5642 }else if(typeof p == 'string' && bp){
5643 p += '&' + Roo.urlEncode(bp);
5646 p = Roo.urlEncode(bp);
5651 createCallback : function(){
5653 success: this.success,
5654 failure: this.failure,
5656 timeout: (this.form.timeout*1000),
5657 upload: this.form.fileUpload ? this.success : undefined
5662 Roo.form.Action.Submit = function(form, options){
5663 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5666 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5669 haveProgress : false,
5670 uploadComplete : false,
5672 // uploadProgress indicator.
5673 uploadProgress : function()
5675 if (!this.form.progressUrl) {
5679 if (!this.haveProgress) {
5680 Roo.MessageBox.progress("Uploading", "Uploading");
5682 if (this.uploadComplete) {
5683 Roo.MessageBox.hide();
5687 this.haveProgress = true;
5689 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5691 var c = new Roo.data.Connection();
5693 url : this.form.progressUrl,
5698 success : function(req){
5699 //console.log(data);
5703 rdata = Roo.decode(req.responseText)
5705 Roo.log("Invalid data from server..");
5709 if (!rdata || !rdata.success) {
5711 Roo.MessageBox.alert(Roo.encode(rdata));
5714 var data = rdata.data;
5716 if (this.uploadComplete) {
5717 Roo.MessageBox.hide();
5722 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5723 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5726 this.uploadProgress.defer(2000,this);
5729 failure: function(data) {
5730 Roo.log('progress url failed ');
5741 // run get Values on the form, so it syncs any secondary forms.
5742 this.form.getValues();
5744 var o = this.options;
5745 var method = this.getMethod();
5746 var isPost = method == 'POST';
5747 if(o.clientValidation === false || this.form.isValid()){
5749 if (this.form.progressUrl) {
5750 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5751 (new Date() * 1) + '' + Math.random());
5756 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5757 form:this.form.el.dom,
5758 url:this.getUrl(!isPost),
5760 params:isPost ? this.getParams() : null,
5761 isUpload: this.form.fileUpload
5764 this.uploadProgress();
5766 }else if (o.clientValidation !== false){ // client validation failed
5767 this.failureType = Roo.form.Action.CLIENT_INVALID;
5768 this.form.afterAction(this, false);
5772 success : function(response)
5774 this.uploadComplete= true;
5775 if (this.haveProgress) {
5776 Roo.MessageBox.hide();
5780 var result = this.processResponse(response);
5781 if(result === true || result.success){
5782 this.form.afterAction(this, true);
5786 this.form.markInvalid(result.errors);
5787 this.failureType = Roo.form.Action.SERVER_INVALID;
5789 this.form.afterAction(this, false);
5791 failure : function(response)
5793 this.uploadComplete= true;
5794 if (this.haveProgress) {
5795 Roo.MessageBox.hide();
5798 this.response = response;
5799 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5800 this.form.afterAction(this, false);
5803 handleResponse : function(response){
5804 if(this.form.errorReader){
5805 var rs = this.form.errorReader.read(response);
5808 for(var i = 0, len = rs.records.length; i < len; i++) {
5809 var r = rs.records[i];
5813 if(errors.length < 1){
5817 success : rs.success,
5823 ret = Roo.decode(response.responseText);
5827 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5837 Roo.form.Action.Load = function(form, options){
5838 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5839 this.reader = this.form.reader;
5842 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5847 Roo.Ajax.request(Roo.apply(
5848 this.createCallback(), {
5849 method:this.getMethod(),
5850 url:this.getUrl(false),
5851 params:this.getParams()
5855 success : function(response){
5857 var result = this.processResponse(response);
5858 if(result === true || !result.success || !result.data){
5859 this.failureType = Roo.form.Action.LOAD_FAILURE;
5860 this.form.afterAction(this, false);
5863 this.form.clearInvalid();
5864 this.form.setValues(result.data);
5865 this.form.afterAction(this, true);
5868 handleResponse : function(response){
5869 if(this.form.reader){
5870 var rs = this.form.reader.read(response);
5871 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5873 success : rs.success,
5877 return Roo.decode(response.responseText);
5881 Roo.form.Action.ACTION_TYPES = {
5882 'load' : Roo.form.Action.Load,
5883 'submit' : Roo.form.Action.Submit
5892 * @class Roo.bootstrap.Form
5893 * @extends Roo.bootstrap.Component
5894 * Bootstrap Form class
5895 * @cfg {String} method GET | POST (default POST)
5896 * @cfg {String} labelAlign top | left (default top)
5897 * @cfg {String} align left | right - for navbars
5902 * @param {Object} config The config object
5906 Roo.bootstrap.Form = function(config){
5907 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5910 * @event clientvalidation
5911 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5912 * @param {Form} this
5913 * @param {Boolean} valid true if the form has passed client-side validation
5915 clientvalidation: true,
5917 * @event beforeaction
5918 * Fires before any action is performed. Return false to cancel the action.
5919 * @param {Form} this
5920 * @param {Action} action The action to be performed
5924 * @event actionfailed
5925 * Fires when an action fails.
5926 * @param {Form} this
5927 * @param {Action} action The action that failed
5929 actionfailed : true,
5931 * @event actioncomplete
5932 * Fires when an action is completed.
5933 * @param {Form} this
5934 * @param {Action} action The action that completed
5936 actioncomplete : true
5941 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5944 * @cfg {String} method
5945 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5950 * The URL to use for form actions if one isn't supplied in the action options.
5953 * @cfg {Boolean} fileUpload
5954 * Set to true if this form is a file upload.
5958 * @cfg {Object} baseParams
5959 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5963 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5967 * @cfg {Sting} align (left|right) for navbar forms
5972 activeAction : null,
5975 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5976 * element by passing it or its id or mask the form itself by passing in true.
5979 waitMsgTarget : false,
5984 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5985 * element by passing it or its id or mask the form itself by passing in true.
5989 getAutoCreate : function(){
5993 method : this.method || 'POST',
5994 id : this.id || Roo.id(),
5997 if (this.parent().xtype.match(/^Nav/)) {
5998 cfg.cls = 'navbar-form navbar-' + this.align;
6002 if (this.labelAlign == 'left' ) {
6003 cfg.cls += ' form-horizontal';
6009 initEvents : function()
6011 this.el.on('submit', this.onSubmit, this);
6012 // this was added as random key presses on the form where triggering form submit.
6013 this.el.on('keypress', function(e) {
6014 if (e.getCharCode() != 13) {
6017 // we might need to allow it for textareas.. and some other items.
6018 // check e.getTarget().
6020 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6024 Roo.log("keypress blocked");
6032 onSubmit : function(e){
6037 * Returns true if client-side validation on the form is successful.
6040 isValid : function(){
6041 var items = this.getItems();
6043 items.each(function(f){
6052 * Returns true if any fields in this form have changed since their original load.
6055 isDirty : function(){
6057 var items = this.getItems();
6058 items.each(function(f){
6068 * Performs a predefined action (submit or load) or custom actions you define on this form.
6069 * @param {String} actionName The name of the action type
6070 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6071 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6072 * accept other config options):
6074 Property Type Description
6075 ---------------- --------------- ----------------------------------------------------------------------------------
6076 url String The url for the action (defaults to the form's url)
6077 method String The form method to use (defaults to the form's method, or POST if not defined)
6078 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6079 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6080 validate the form on the client (defaults to false)
6082 * @return {BasicForm} this
6084 doAction : function(action, options){
6085 if(typeof action == 'string'){
6086 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6088 if(this.fireEvent('beforeaction', this, action) !== false){
6089 this.beforeAction(action);
6090 action.run.defer(100, action);
6096 beforeAction : function(action){
6097 var o = action.options;
6099 // not really supported yet.. ??
6101 //if(this.waitMsgTarget === true){
6102 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6103 //}else if(this.waitMsgTarget){
6104 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6105 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6107 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6113 afterAction : function(action, success){
6114 this.activeAction = null;
6115 var o = action.options;
6117 //if(this.waitMsgTarget === true){
6119 //}else if(this.waitMsgTarget){
6120 // this.waitMsgTarget.unmask();
6122 // Roo.MessageBox.updateProgress(1);
6123 // Roo.MessageBox.hide();
6130 Roo.callback(o.success, o.scope, [this, action]);
6131 this.fireEvent('actioncomplete', this, action);
6135 // failure condition..
6136 // we have a scenario where updates need confirming.
6137 // eg. if a locking scenario exists..
6138 // we look for { errors : { needs_confirm : true }} in the response.
6140 (typeof(action.result) != 'undefined') &&
6141 (typeof(action.result.errors) != 'undefined') &&
6142 (typeof(action.result.errors.needs_confirm) != 'undefined')
6145 Roo.log("not supported yet");
6148 Roo.MessageBox.confirm(
6149 "Change requires confirmation",
6150 action.result.errorMsg,
6155 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6165 Roo.callback(o.failure, o.scope, [this, action]);
6166 // show an error message if no failed handler is set..
6167 if (!this.hasListener('actionfailed')) {
6168 Roo.log("need to add dialog support");
6170 Roo.MessageBox.alert("Error",
6171 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6172 action.result.errorMsg :
6173 "Saving Failed, please check your entries or try again"
6178 this.fireEvent('actionfailed', this, action);
6183 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6184 * @param {String} id The value to search for
6187 findField : function(id){
6188 var items = this.getItems();
6189 var field = items.get(id);
6191 items.each(function(f){
6192 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6199 return field || null;
6202 * Mark fields in this form invalid in bulk.
6203 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6204 * @return {BasicForm} this
6206 markInvalid : function(errors){
6207 if(errors instanceof Array){
6208 for(var i = 0, len = errors.length; i < len; i++){
6209 var fieldError = errors[i];
6210 var f = this.findField(fieldError.id);
6212 f.markInvalid(fieldError.msg);
6218 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6219 field.markInvalid(errors[id]);
6223 //Roo.each(this.childForms || [], function (f) {
6224 // f.markInvalid(errors);
6231 * Set values for fields in this form in bulk.
6232 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6233 * @return {BasicForm} this
6235 setValues : function(values){
6236 if(values instanceof Array){ // array of objects
6237 for(var i = 0, len = values.length; i < len; i++){
6239 var f = this.findField(v.id);
6241 f.setValue(v.value);
6242 if(this.trackResetOnLoad){
6243 f.originalValue = f.getValue();
6247 }else{ // object hash
6250 if(typeof values[id] != 'function' && (field = this.findField(id))){
6252 if (field.setFromData &&
6254 field.displayField &&
6255 // combos' with local stores can
6256 // be queried via setValue()
6257 // to set their value..
6258 (field.store && !field.store.isLocal)
6262 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6263 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6264 field.setFromData(sd);
6267 field.setValue(values[id]);
6271 if(this.trackResetOnLoad){
6272 field.originalValue = field.getValue();
6278 //Roo.each(this.childForms || [], function (f) {
6279 // f.setValues(values);
6286 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6287 * they are returned as an array.
6288 * @param {Boolean} asString
6291 getValues : function(asString){
6292 //if (this.childForms) {
6293 // copy values from the child forms
6294 // Roo.each(this.childForms, function (f) {
6295 // this.setValues(f.getValues());
6301 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6302 if(asString === true){
6305 return Roo.urlDecode(fs);
6309 * Returns the fields in this form as an object with key/value pairs.
6310 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6313 getFieldValues : function(with_hidden)
6315 var items = this.getItems();
6317 items.each(function(f){
6321 var v = f.getValue();
6322 if (f.inputType =='radio') {
6323 if (typeof(ret[f.getName()]) == 'undefined') {
6324 ret[f.getName()] = ''; // empty..
6327 if (!f.el.dom.checked) {
6335 // not sure if this supported any more..
6336 if ((typeof(v) == 'object') && f.getRawValue) {
6337 v = f.getRawValue() ; // dates..
6339 // combo boxes where name != hiddenName...
6340 if (f.name != f.getName()) {
6341 ret[f.name] = f.getRawValue();
6343 ret[f.getName()] = v;
6350 * Clears all invalid messages in this form.
6351 * @return {BasicForm} this
6353 clearInvalid : function(){
6354 var items = this.getItems();
6356 items.each(function(f){
6367 * @return {BasicForm} this
6370 var items = this.getItems();
6371 items.each(function(f){
6375 Roo.each(this.childForms || [], function (f) {
6382 getItems : function()
6384 var r=new Roo.util.MixedCollection(false, function(o){
6385 return o.id || (o.id = Roo.id());
6387 var iter = function(el) {
6394 Roo.each(el.items,function(e) {
6413 * Ext JS Library 1.1.1
6414 * Copyright(c) 2006-2007, Ext JS, LLC.
6416 * Originally Released Under LGPL - original licence link has changed is not relivant.
6419 * <script type="text/javascript">
6422 * @class Roo.form.VTypes
6423 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6426 Roo.form.VTypes = function(){
6427 // closure these in so they are only created once.
6428 var alpha = /^[a-zA-Z_]+$/;
6429 var alphanum = /^[a-zA-Z0-9_]+$/;
6430 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6431 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6433 // All these messages and functions are configurable
6436 * The function used to validate email addresses
6437 * @param {String} value The email address
6439 'email' : function(v){
6440 return email.test(v);
6443 * The error text to display when the email validation function returns false
6446 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6448 * The keystroke filter mask to be applied on email input
6451 'emailMask' : /[a-z0-9_\.\-@]/i,
6454 * The function used to validate URLs
6455 * @param {String} value The URL
6457 'url' : function(v){
6461 * The error text to display when the url validation function returns false
6464 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6467 * The function used to validate alpha values
6468 * @param {String} value The value
6470 'alpha' : function(v){
6471 return alpha.test(v);
6474 * The error text to display when the alpha validation function returns false
6477 'alphaText' : 'This field should only contain letters and _',
6479 * The keystroke filter mask to be applied on alpha input
6482 'alphaMask' : /[a-z_]/i,
6485 * The function used to validate alphanumeric values
6486 * @param {String} value The value
6488 'alphanum' : function(v){
6489 return alphanum.test(v);
6492 * The error text to display when the alphanumeric validation function returns false
6495 'alphanumText' : 'This field should only contain letters, numbers and _',
6497 * The keystroke filter mask to be applied on alphanumeric input
6500 'alphanumMask' : /[a-z0-9_]/i
6510 * @class Roo.bootstrap.Input
6511 * @extends Roo.bootstrap.Component
6512 * Bootstrap Input class
6513 * @cfg {Boolean} disabled is it disabled
6514 * @cfg {String} fieldLabel - the label associated
6515 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6516 * @cfg {String} name name of the input
6517 * @cfg {string} fieldLabel - the label associated
6518 * @cfg {string} inputType - input / file submit ...
6519 * @cfg {string} placeholder - placeholder to put in text.
6520 * @cfg {string} before - input group add on before
6521 * @cfg {string} after - input group add on after
6522 * @cfg {string} size - (lg|sm) or leave empty..
6523 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6524 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6525 * @cfg {Number} md colspan out of 12 for computer-sized screens
6526 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6527 * @cfg {string} value default value of the input
6528 * @cfg {Number} labelWidth set the width of label (0-12)
6529 * @cfg {String} labelAlign (top|left)
6530 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6531 * @cfg {String} align (left|center|right) Default left
6535 * Create a new Input
6536 * @param {Object} config The config object
6539 Roo.bootstrap.Input = function(config){
6540 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6545 * Fires when this field receives input focus.
6546 * @param {Roo.form.Field} this
6551 * Fires when this field loses input focus.
6552 * @param {Roo.form.Field} this
6557 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6558 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6559 * @param {Roo.form.Field} this
6560 * @param {Roo.EventObject} e The event object
6565 * Fires just before the field blurs if the field value has changed.
6566 * @param {Roo.form.Field} this
6567 * @param {Mixed} newValue The new value
6568 * @param {Mixed} oldValue The original value
6573 * Fires after the field has been marked as invalid.
6574 * @param {Roo.form.Field} this
6575 * @param {String} msg The validation message
6580 * Fires after the field has been validated with no errors.
6581 * @param {Roo.form.Field} this
6586 * Fires after the key up
6587 * @param {Roo.form.Field} this
6588 * @param {Roo.EventObject} e The event Object
6594 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6596 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6597 automatic validation (defaults to "keyup").
6599 validationEvent : "keyup",
6601 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6603 validateOnBlur : true,
6605 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6607 validationDelay : 250,
6609 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6611 focusClass : "x-form-focus", // not needed???
6615 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6617 invalidClass : "has-error",
6620 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6622 selectOnFocus : false,
6625 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6629 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6634 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6636 disableKeyFilter : false,
6639 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6643 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6647 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6649 blankText : "This field is required",
6652 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6656 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6658 maxLength : Number.MAX_VALUE,
6660 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6662 minLengthText : "The minimum length for this field is {0}",
6664 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6666 maxLengthText : "The maximum length for this field is {0}",
6670 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6671 * If available, this function will be called only after the basic validators all return true, and will be passed the
6672 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6676 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6677 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6678 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6682 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6705 formatedValue : false,
6707 parentLabelAlign : function()
6710 while (parent.parent()) {
6711 parent = parent.parent();
6712 if (typeof(parent.labelAlign) !='undefined') {
6713 return parent.labelAlign;
6720 getAutoCreate : function(){
6722 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6728 if(this.inputType != 'hidden'){
6729 cfg.cls = 'form-group' //input-group
6735 type : this.inputType,
6737 cls : 'form-control',
6738 placeholder : this.placeholder || ''
6743 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6746 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6747 input.maxLength = this.maxLength;
6750 if (this.disabled) {
6751 input.disabled=true;
6754 if (this.readOnly) {
6755 input.readonly=true;
6759 input.name = this.name;
6762 input.cls += ' input-' + this.size;
6765 ['xs','sm','md','lg'].map(function(size){
6766 if (settings[size]) {
6767 cfg.cls += ' col-' + size + '-' + settings[size];
6771 var inputblock = input;
6773 if (this.before || this.after) {
6776 cls : 'input-group',
6779 if (this.before && typeof(this.before) == 'string') {
6781 inputblock.cn.push({
6783 cls : 'roo-input-before input-group-addon',
6787 if (this.before && typeof(this.before) == 'object') {
6788 this.before = Roo.factory(this.before);
6789 Roo.log(this.before);
6790 inputblock.cn.push({
6792 cls : 'roo-input-before input-group-' +
6793 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6797 inputblock.cn.push(input);
6799 if (this.after && typeof(this.after) == 'string') {
6800 inputblock.cn.push({
6802 cls : 'roo-input-after input-group-addon',
6806 if (this.after && typeof(this.after) == 'object') {
6807 this.after = Roo.factory(this.after);
6808 Roo.log(this.after);
6809 inputblock.cn.push({
6811 cls : 'roo-input-after input-group-' +
6812 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6817 if (align ==='left' && this.fieldLabel.length) {
6818 Roo.log("left and has label");
6824 cls : 'control-label col-sm-' + this.labelWidth,
6825 html : this.fieldLabel
6829 cls : "col-sm-" + (12 - this.labelWidth),
6836 } else if ( this.fieldLabel.length) {
6842 //cls : 'input-group-addon',
6843 html : this.fieldLabel
6853 Roo.log(" no label && no align");
6862 Roo.log('input-parentType: ' + this.parentType);
6864 if (this.parentType === 'Navbar' && this.parent().bar) {
6865 cfg.cls += ' navbar-form';
6873 * return the real input element.
6875 inputEl: function ()
6877 return this.el.select('input.form-control',true).first();
6879 setDisabled : function(v)
6881 var i = this.inputEl().dom;
6883 i.removeAttribute('disabled');
6887 i.setAttribute('disabled','true');
6889 initEvents : function()
6892 this.inputEl().on("keydown" , this.fireKey, this);
6893 this.inputEl().on("focus", this.onFocus, this);
6894 this.inputEl().on("blur", this.onBlur, this);
6896 this.inputEl().relayEvent('keyup', this);
6898 // reference to original value for reset
6899 this.originalValue = this.getValue();
6900 //Roo.form.TextField.superclass.initEvents.call(this);
6901 if(this.validationEvent == 'keyup'){
6902 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6903 this.inputEl().on('keyup', this.filterValidation, this);
6905 else if(this.validationEvent !== false){
6906 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6909 if(this.selectOnFocus){
6910 this.on("focus", this.preFocus, this);
6913 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6914 this.inputEl().on("keypress", this.filterKeys, this);
6917 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6918 this.el.on("click", this.autoSize, this);
6921 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6922 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6925 if (typeof(this.before) == 'object') {
6926 this.before.render(this.el.select('.roo-input-before',true).first());
6928 if (typeof(this.after) == 'object') {
6929 this.after.render(this.el.select('.roo-input-after',true).first());
6934 filterValidation : function(e){
6935 if(!e.isNavKeyPress()){
6936 this.validationTask.delay(this.validationDelay);
6940 * Validates the field value
6941 * @return {Boolean} True if the value is valid, else false
6943 validate : function(){
6944 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6945 if(this.disabled || this.validateValue(this.getRawValue())){
6946 this.clearInvalid();
6954 * Validates a value according to the field's validation rules and marks the field as invalid
6955 * if the validation fails
6956 * @param {Mixed} value The value to validate
6957 * @return {Boolean} True if the value is valid, else false
6959 validateValue : function(value){
6960 if(value.length < 1) { // if it's blank
6961 if(this.allowBlank){
6962 this.clearInvalid();
6965 this.markInvalid(this.blankText);
6969 if(value.length < this.minLength){
6970 this.markInvalid(String.format(this.minLengthText, this.minLength));
6973 if(value.length > this.maxLength){
6974 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6978 var vt = Roo.form.VTypes;
6979 if(!vt[this.vtype](value, this)){
6980 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6984 if(typeof this.validator == "function"){
6985 var msg = this.validator(value);
6987 this.markInvalid(msg);
6991 if(this.regex && !this.regex.test(value)){
6992 this.markInvalid(this.regexText);
7001 fireKey : function(e){
7002 //Roo.log('field ' + e.getKey());
7003 if(e.isNavKeyPress()){
7004 this.fireEvent("specialkey", this, e);
7007 focus : function (selectText){
7009 this.inputEl().focus();
7010 if(selectText === true){
7011 this.inputEl().dom.select();
7017 onFocus : function(){
7018 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7019 // this.el.addClass(this.focusClass);
7022 this.hasFocus = true;
7023 this.startValue = this.getValue();
7024 this.fireEvent("focus", this);
7028 beforeBlur : Roo.emptyFn,
7032 onBlur : function(){
7034 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7035 //this.el.removeClass(this.focusClass);
7037 this.hasFocus = false;
7038 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7041 var v = this.getValue();
7042 if(String(v) !== String(this.startValue)){
7043 this.fireEvent('change', this, v, this.startValue);
7045 this.fireEvent("blur", this);
7049 * Resets the current field value to the originally loaded value and clears any validation messages
7052 this.setValue(this.originalValue);
7053 this.clearInvalid();
7056 * Returns the name of the field
7057 * @return {Mixed} name The name field
7059 getName: function(){
7063 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7064 * @return {Mixed} value The field value
7066 getValue : function(){
7068 var v = this.inputEl().getValue();
7073 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7074 * @return {Mixed} value The field value
7076 getRawValue : function(){
7077 var v = this.inputEl().getValue();
7083 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7084 * @param {Mixed} value The value to set
7086 setRawValue : function(v){
7087 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7090 selectText : function(start, end){
7091 var v = this.getRawValue();
7093 start = start === undefined ? 0 : start;
7094 end = end === undefined ? v.length : end;
7095 var d = this.inputEl().dom;
7096 if(d.setSelectionRange){
7097 d.setSelectionRange(start, end);
7098 }else if(d.createTextRange){
7099 var range = d.createTextRange();
7100 range.moveStart("character", start);
7101 range.moveEnd("character", v.length-end);
7108 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7109 * @param {Mixed} value The value to set
7111 setValue : function(v){
7114 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7120 processValue : function(value){
7121 if(this.stripCharsRe){
7122 var newValue = value.replace(this.stripCharsRe, '');
7123 if(newValue !== value){
7124 this.setRawValue(newValue);
7131 preFocus : function(){
7133 if(this.selectOnFocus){
7134 this.inputEl().dom.select();
7137 filterKeys : function(e){
7139 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7142 var c = e.getCharCode(), cc = String.fromCharCode(c);
7143 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7146 if(!this.maskRe.test(cc)){
7151 * Clear any invalid styles/messages for this field
7153 clearInvalid : function(){
7155 if(!this.el || this.preventMark){ // not rendered
7158 this.el.removeClass(this.invalidClass);
7160 switch(this.msgTarget){
7162 this.el.dom.qtip = '';
7165 this.el.dom.title = '';
7169 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7174 this.errorIcon.dom.qtip = '';
7175 this.errorIcon.hide();
7176 this.un('resize', this.alignErrorIcon, this);
7180 var t = Roo.getDom(this.msgTarget);
7182 t.style.display = 'none';
7186 this.fireEvent('valid', this);
7189 * Mark this field as invalid
7190 * @param {String} msg The validation message
7192 markInvalid : function(msg){
7193 if(!this.el || this.preventMark){ // not rendered
7196 this.el.addClass(this.invalidClass);
7198 msg = msg || this.invalidText;
7199 switch(this.msgTarget){
7201 this.el.dom.qtip = msg;
7202 this.el.dom.qclass = 'x-form-invalid-tip';
7203 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7204 Roo.QuickTips.enable();
7208 this.el.dom.title = msg;
7212 var elp = this.el.findParent('.x-form-element', 5, true);
7213 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7214 this.errorEl.setWidth(elp.getWidth(true)-20);
7216 this.errorEl.update(msg);
7217 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7220 if(!this.errorIcon){
7221 var elp = this.el.findParent('.x-form-element', 5, true);
7222 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7224 this.alignErrorIcon();
7225 this.errorIcon.dom.qtip = msg;
7226 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7227 this.errorIcon.show();
7228 this.on('resize', this.alignErrorIcon, this);
7231 var t = Roo.getDom(this.msgTarget);
7233 t.style.display = this.msgDisplay;
7237 this.fireEvent('invalid', this, msg);
7240 SafariOnKeyDown : function(event)
7242 // this is a workaround for a password hang bug on chrome/ webkit.
7244 var isSelectAll = false;
7246 if(this.inputEl().dom.selectionEnd > 0){
7247 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7249 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7250 event.preventDefault();
7255 if(isSelectAll){ // backspace and delete key
7257 event.preventDefault();
7258 // this is very hacky as keydown always get's upper case.
7260 var cc = String.fromCharCode(event.getCharCode());
7261 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7265 adjustWidth : function(tag, w){
7266 tag = tag.toLowerCase();
7267 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7268 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7272 if(tag == 'textarea'){
7275 }else if(Roo.isOpera){
7279 if(tag == 'textarea'){
7298 * @class Roo.bootstrap.TextArea
7299 * @extends Roo.bootstrap.Input
7300 * Bootstrap TextArea class
7301 * @cfg {Number} cols Specifies the visible width of a text area
7302 * @cfg {Number} rows Specifies the visible number of lines in a text area
7303 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7304 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7305 * @cfg {string} html text
7308 * Create a new TextArea
7309 * @param {Object} config The config object
7312 Roo.bootstrap.TextArea = function(config){
7313 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7317 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7327 getAutoCreate : function(){
7329 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7340 value : this.value || '',
7341 html: this.html || '',
7342 cls : 'form-control',
7343 placeholder : this.placeholder || ''
7347 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7348 input.maxLength = this.maxLength;
7352 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7356 input.cols = this.cols;
7359 if (this.readOnly) {
7360 input.readonly = true;
7364 input.name = this.name;
7368 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7372 ['xs','sm','md','lg'].map(function(size){
7373 if (settings[size]) {
7374 cfg.cls += ' col-' + size + '-' + settings[size];
7378 var inputblock = input;
7380 if (this.before || this.after) {
7383 cls : 'input-group',
7387 inputblock.cn.push({
7389 cls : 'input-group-addon',
7393 inputblock.cn.push(input);
7395 inputblock.cn.push({
7397 cls : 'input-group-addon',
7404 if (align ==='left' && this.fieldLabel.length) {
7405 Roo.log("left and has label");
7411 cls : 'control-label col-sm-' + this.labelWidth,
7412 html : this.fieldLabel
7416 cls : "col-sm-" + (12 - this.labelWidth),
7423 } else if ( this.fieldLabel.length) {
7429 //cls : 'input-group-addon',
7430 html : this.fieldLabel
7440 Roo.log(" no label && no align");
7450 if (this.disabled) {
7451 input.disabled=true;
7458 * return the real textarea element.
7460 inputEl: function ()
7462 return this.el.select('textarea.form-control',true).first();
7470 * trigger field - base class for combo..
7475 * @class Roo.bootstrap.TriggerField
7476 * @extends Roo.bootstrap.Input
7477 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7478 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7479 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7480 * for which you can provide a custom implementation. For example:
7482 var trigger = new Roo.bootstrap.TriggerField();
7483 trigger.onTriggerClick = myTriggerFn;
7484 trigger.applyTo('my-field');
7487 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7488 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7489 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7490 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7492 * Create a new TriggerField.
7493 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7494 * to the base TextField)
7496 Roo.bootstrap.TriggerField = function(config){
7497 this.mimicing = false;
7498 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7501 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7503 * @cfg {String} triggerClass A CSS class to apply to the trigger
7506 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7510 /** @cfg {Boolean} grow @hide */
7511 /** @cfg {Number} growMin @hide */
7512 /** @cfg {Number} growMax @hide */
7518 autoSize: Roo.emptyFn,
7525 actionMode : 'wrap',
7529 getAutoCreate : function(){
7531 var parent = this.parent();
7533 var align = this.labelAlign || this.parentLabelAlign();
7538 cls: 'form-group' //input-group
7545 type : this.inputType,
7546 cls : 'form-control',
7547 autocomplete: 'off',
7548 placeholder : this.placeholder || ''
7552 input.name = this.name;
7555 input.cls += ' input-' + this.size;
7558 if (this.disabled) {
7559 input.disabled=true;
7562 var inputblock = input;
7564 if (this.before || this.after) {
7567 cls : 'input-group',
7571 inputblock.cn.push({
7573 cls : 'input-group-addon',
7577 inputblock.cn.push(input);
7579 inputblock.cn.push({
7581 cls : 'input-group-addon',
7594 cls: 'form-hidden-field'
7602 Roo.log('multiple');
7610 cls: 'form-hidden-field'
7614 cls: 'select2-choices',
7618 cls: 'select2-search-field',
7631 cls: 'select2-container input-group',
7636 cls: 'typeahead typeahead-long dropdown-menu',
7637 style: 'display:none'
7645 cls : 'input-group-addon btn dropdown-toggle',
7653 cls: 'combobox-clear',
7667 combobox.cls += ' select2-container-multi';
7670 if (align ==='left' && this.fieldLabel.length) {
7672 Roo.log("left and has label");
7678 cls : 'control-label col-sm-' + this.labelWidth,
7679 html : this.fieldLabel
7683 cls : "col-sm-" + (12 - this.labelWidth),
7690 } else if ( this.fieldLabel.length) {
7696 //cls : 'input-group-addon',
7697 html : this.fieldLabel
7707 Roo.log(" no label && no align");
7714 ['xs','sm','md','lg'].map(function(size){
7715 if (settings[size]) {
7716 cfg.cls += ' col-' + size + '-' + settings[size];
7727 onResize : function(w, h){
7728 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7729 // if(typeof w == 'number'){
7730 // var x = w - this.trigger.getWidth();
7731 // this.inputEl().setWidth(this.adjustWidth('input', x));
7732 // this.trigger.setStyle('left', x+'px');
7737 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7740 getResizeEl : function(){
7741 return this.inputEl();
7745 getPositionEl : function(){
7746 return this.inputEl();
7750 alignErrorIcon : function(){
7751 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7755 initEvents : function(){
7757 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7758 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7760 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7761 if(this.hideTrigger){
7762 this.trigger.setDisplayed(false);
7764 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7768 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7771 //this.trigger.addClassOnOver('x-form-trigger-over');
7772 //this.trigger.addClassOnClick('x-form-trigger-click');
7775 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7780 initTrigger : function(){
7785 onDestroy : function(){
7787 this.trigger.removeAllListeners();
7788 // this.trigger.remove();
7791 // this.wrap.remove();
7793 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7797 onFocus : function(){
7798 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7801 this.wrap.addClass('x-trigger-wrap-focus');
7802 this.mimicing = true;
7803 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7804 if(this.monitorTab){
7805 this.el.on("keydown", this.checkTab, this);
7812 checkTab : function(e){
7813 if(e.getKey() == e.TAB){
7819 onBlur : function(){
7824 mimicBlur : function(e, t){
7826 if(!this.wrap.contains(t) && this.validateBlur()){
7833 triggerBlur : function(){
7834 this.mimicing = false;
7835 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7836 if(this.monitorTab){
7837 this.el.un("keydown", this.checkTab, this);
7839 //this.wrap.removeClass('x-trigger-wrap-focus');
7840 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7844 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7845 validateBlur : function(e, t){
7850 onDisable : function(){
7851 this.inputEl().dom.disabled = true;
7852 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7854 // this.wrap.addClass('x-item-disabled');
7859 onEnable : function(){
7860 this.inputEl().dom.disabled = false;
7861 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7863 // this.el.removeClass('x-item-disabled');
7868 onShow : function(){
7869 var ae = this.getActionEl();
7872 ae.dom.style.display = '';
7873 ae.dom.style.visibility = 'visible';
7879 onHide : function(){
7880 var ae = this.getActionEl();
7881 ae.dom.style.display = 'none';
7885 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7886 * by an implementing function.
7888 * @param {EventObject} e
7890 onTriggerClick : Roo.emptyFn
7894 * Ext JS Library 1.1.1
7895 * Copyright(c) 2006-2007, Ext JS, LLC.
7897 * Originally Released Under LGPL - original licence link has changed is not relivant.
7900 * <script type="text/javascript">
7905 * @class Roo.data.SortTypes
7907 * Defines the default sorting (casting?) comparison functions used when sorting data.
7909 Roo.data.SortTypes = {
7911 * Default sort that does nothing
7912 * @param {Mixed} s The value being converted
7913 * @return {Mixed} The comparison value
7920 * The regular expression used to strip tags
7924 stripTagsRE : /<\/?[^>]+>/gi,
7927 * Strips all HTML tags to sort on text only
7928 * @param {Mixed} s The value being converted
7929 * @return {String} The comparison value
7931 asText : function(s){
7932 return String(s).replace(this.stripTagsRE, "");
7936 * Strips all HTML tags to sort on text only - Case insensitive
7937 * @param {Mixed} s The value being converted
7938 * @return {String} The comparison value
7940 asUCText : function(s){
7941 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7945 * Case insensitive string
7946 * @param {Mixed} s The value being converted
7947 * @return {String} The comparison value
7949 asUCString : function(s) {
7950 return String(s).toUpperCase();
7955 * @param {Mixed} s The value being converted
7956 * @return {Number} The comparison value
7958 asDate : function(s) {
7962 if(s instanceof Date){
7965 return Date.parse(String(s));
7970 * @param {Mixed} s The value being converted
7971 * @return {Float} The comparison value
7973 asFloat : function(s) {
7974 var val = parseFloat(String(s).replace(/,/g, ""));
7975 if(isNaN(val)) val = 0;
7981 * @param {Mixed} s The value being converted
7982 * @return {Number} The comparison value
7984 asInt : function(s) {
7985 var val = parseInt(String(s).replace(/,/g, ""));
7986 if(isNaN(val)) val = 0;
7991 * Ext JS Library 1.1.1
7992 * Copyright(c) 2006-2007, Ext JS, LLC.
7994 * Originally Released Under LGPL - original licence link has changed is not relivant.
7997 * <script type="text/javascript">
8001 * @class Roo.data.Record
8002 * Instances of this class encapsulate both record <em>definition</em> information, and record
8003 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8004 * to access Records cached in an {@link Roo.data.Store} object.<br>
8006 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8007 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8010 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8012 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8013 * {@link #create}. The parameters are the same.
8014 * @param {Array} data An associative Array of data values keyed by the field name.
8015 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8016 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8017 * not specified an integer id is generated.
8019 Roo.data.Record = function(data, id){
8020 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8025 * Generate a constructor for a specific record layout.
8026 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8027 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8028 * Each field definition object may contain the following properties: <ul>
8029 * <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,
8030 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8031 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8032 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8033 * is being used, then this is a string containing the javascript expression to reference the data relative to
8034 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8035 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8036 * this may be omitted.</p></li>
8037 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8038 * <ul><li>auto (Default, implies no conversion)</li>
8043 * <li>date</li></ul></p></li>
8044 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8045 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8046 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8047 * by the Reader into an object that will be stored in the Record. It is passed the
8048 * following parameters:<ul>
8049 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8051 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8053 * <br>usage:<br><pre><code>
8054 var TopicRecord = Roo.data.Record.create(
8055 {name: 'title', mapping: 'topic_title'},
8056 {name: 'author', mapping: 'username'},
8057 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8058 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8059 {name: 'lastPoster', mapping: 'user2'},
8060 {name: 'excerpt', mapping: 'post_text'}
8063 var myNewRecord = new TopicRecord({
8064 title: 'Do my job please',
8067 lastPost: new Date(),
8068 lastPoster: 'Animal',
8069 excerpt: 'No way dude!'
8071 myStore.add(myNewRecord);
8076 Roo.data.Record.create = function(o){
8078 f.superclass.constructor.apply(this, arguments);
8080 Roo.extend(f, Roo.data.Record);
8081 var p = f.prototype;
8082 p.fields = new Roo.util.MixedCollection(false, function(field){
8085 for(var i = 0, len = o.length; i < len; i++){
8086 p.fields.add(new Roo.data.Field(o[i]));
8088 f.getField = function(name){
8089 return p.fields.get(name);
8094 Roo.data.Record.AUTO_ID = 1000;
8095 Roo.data.Record.EDIT = 'edit';
8096 Roo.data.Record.REJECT = 'reject';
8097 Roo.data.Record.COMMIT = 'commit';
8099 Roo.data.Record.prototype = {
8101 * Readonly flag - true if this record has been modified.
8110 join : function(store){
8115 * Set the named field to the specified value.
8116 * @param {String} name The name of the field to set.
8117 * @param {Object} value The value to set the field to.
8119 set : function(name, value){
8120 if(this.data[name] == value){
8127 if(typeof this.modified[name] == 'undefined'){
8128 this.modified[name] = this.data[name];
8130 this.data[name] = value;
8131 if(!this.editing && this.store){
8132 this.store.afterEdit(this);
8137 * Get the value of the named field.
8138 * @param {String} name The name of the field to get the value of.
8139 * @return {Object} The value of the field.
8141 get : function(name){
8142 return this.data[name];
8146 beginEdit : function(){
8147 this.editing = true;
8152 cancelEdit : function(){
8153 this.editing = false;
8154 delete this.modified;
8158 endEdit : function(){
8159 this.editing = false;
8160 if(this.dirty && this.store){
8161 this.store.afterEdit(this);
8166 * Usually called by the {@link Roo.data.Store} which owns the Record.
8167 * Rejects all changes made to the Record since either creation, or the last commit operation.
8168 * Modified fields are reverted to their original values.
8170 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8171 * of reject operations.
8173 reject : function(){
8174 var m = this.modified;
8176 if(typeof m[n] != "function"){
8177 this.data[n] = m[n];
8181 delete this.modified;
8182 this.editing = false;
8184 this.store.afterReject(this);
8189 * Usually called by the {@link Roo.data.Store} which owns the Record.
8190 * Commits all changes made to the Record since either creation, or the last commit operation.
8192 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8193 * of commit operations.
8195 commit : function(){
8197 delete this.modified;
8198 this.editing = false;
8200 this.store.afterCommit(this);
8205 hasError : function(){
8206 return this.error != null;
8210 clearError : function(){
8215 * Creates a copy of this record.
8216 * @param {String} id (optional) A new record id if you don't want to use this record's id
8219 copy : function(newId) {
8220 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
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">
8236 * @class Roo.data.Store
8237 * @extends Roo.util.Observable
8238 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8239 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8241 * 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
8242 * has no knowledge of the format of the data returned by the Proxy.<br>
8244 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8245 * instances from the data object. These records are cached and made available through accessor functions.
8247 * Creates a new Store.
8248 * @param {Object} config A config object containing the objects needed for the Store to access data,
8249 * and read the data into Records.
8251 Roo.data.Store = function(config){
8252 this.data = new Roo.util.MixedCollection(false);
8253 this.data.getKey = function(o){
8256 this.baseParams = {};
8263 "multisort" : "_multisort"
8266 if(config && config.data){
8267 this.inlineData = config.data;
8271 Roo.apply(this, config);
8273 if(this.reader){ // reader passed
8274 this.reader = Roo.factory(this.reader, Roo.data);
8275 this.reader.xmodule = this.xmodule || false;
8276 if(!this.recordType){
8277 this.recordType = this.reader.recordType;
8279 if(this.reader.onMetaChange){
8280 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8284 if(this.recordType){
8285 this.fields = this.recordType.prototype.fields;
8291 * @event datachanged
8292 * Fires when the data cache has changed, and a widget which is using this Store
8293 * as a Record cache should refresh its view.
8294 * @param {Store} this
8299 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8300 * @param {Store} this
8301 * @param {Object} meta The JSON metadata
8306 * Fires when Records have been added to the Store
8307 * @param {Store} this
8308 * @param {Roo.data.Record[]} records The array of Records added
8309 * @param {Number} index The index at which the record(s) were added
8314 * Fires when a Record has been removed from the Store
8315 * @param {Store} this
8316 * @param {Roo.data.Record} record The Record that was removed
8317 * @param {Number} index The index at which the record was removed
8322 * Fires when a Record has been updated
8323 * @param {Store} this
8324 * @param {Roo.data.Record} record The Record that was updated
8325 * @param {String} operation The update operation being performed. Value may be one of:
8327 Roo.data.Record.EDIT
8328 Roo.data.Record.REJECT
8329 Roo.data.Record.COMMIT
8335 * Fires when the data cache has been cleared.
8336 * @param {Store} this
8341 * Fires before a request is made for a new data object. If the beforeload handler returns false
8342 * the load action will be canceled.
8343 * @param {Store} this
8344 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8348 * @event beforeloadadd
8349 * Fires after a new set of Records has been loaded.
8350 * @param {Store} this
8351 * @param {Roo.data.Record[]} records The Records that were loaded
8352 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8354 beforeloadadd : true,
8357 * Fires after a new set of Records has been loaded, before they are added to the store.
8358 * @param {Store} this
8359 * @param {Roo.data.Record[]} records The Records that were loaded
8360 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8361 * @params {Object} return from reader
8365 * @event loadexception
8366 * Fires if an exception occurs in the Proxy during loading.
8367 * Called with the signature of the Proxy's "loadexception" event.
8368 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8371 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8372 * @param {Object} load options
8373 * @param {Object} jsonData from your request (normally this contains the Exception)
8375 loadexception : true
8379 this.proxy = Roo.factory(this.proxy, Roo.data);
8380 this.proxy.xmodule = this.xmodule || false;
8381 this.relayEvents(this.proxy, ["loadexception"]);
8383 this.sortToggle = {};
8384 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8386 Roo.data.Store.superclass.constructor.call(this);
8388 if(this.inlineData){
8389 this.loadData(this.inlineData);
8390 delete this.inlineData;
8394 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8396 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8397 * without a remote query - used by combo/forms at present.
8401 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8404 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8407 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8408 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8411 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8412 * on any HTTP request
8415 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8418 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8422 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8423 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8428 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8429 * loaded or when a record is removed. (defaults to false).
8431 pruneModifiedRecords : false,
8437 * Add Records to the Store and fires the add event.
8438 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8440 add : function(records){
8441 records = [].concat(records);
8442 for(var i = 0, len = records.length; i < len; i++){
8443 records[i].join(this);
8445 var index = this.data.length;
8446 this.data.addAll(records);
8447 this.fireEvent("add", this, records, index);
8451 * Remove a Record from the Store and fires the remove event.
8452 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8454 remove : function(record){
8455 var index = this.data.indexOf(record);
8456 this.data.removeAt(index);
8457 if(this.pruneModifiedRecords){
8458 this.modified.remove(record);
8460 this.fireEvent("remove", this, record, index);
8464 * Remove all Records from the Store and fires the clear event.
8466 removeAll : function(){
8468 if(this.pruneModifiedRecords){
8471 this.fireEvent("clear", this);
8475 * Inserts Records to the Store at the given index and fires the add event.
8476 * @param {Number} index The start index at which to insert the passed Records.
8477 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8479 insert : function(index, records){
8480 records = [].concat(records);
8481 for(var i = 0, len = records.length; i < len; i++){
8482 this.data.insert(index, records[i]);
8483 records[i].join(this);
8485 this.fireEvent("add", this, records, index);
8489 * Get the index within the cache of the passed Record.
8490 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8491 * @return {Number} The index of the passed Record. Returns -1 if not found.
8493 indexOf : function(record){
8494 return this.data.indexOf(record);
8498 * Get the index within the cache of the Record with the passed id.
8499 * @param {String} id The id of the Record to find.
8500 * @return {Number} The index of the Record. Returns -1 if not found.
8502 indexOfId : function(id){
8503 return this.data.indexOfKey(id);
8507 * Get the Record with the specified id.
8508 * @param {String} id The id of the Record to find.
8509 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8511 getById : function(id){
8512 return this.data.key(id);
8516 * Get the Record at the specified index.
8517 * @param {Number} index The index of the Record to find.
8518 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8520 getAt : function(index){
8521 return this.data.itemAt(index);
8525 * Returns a range of Records between specified indices.
8526 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8527 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8528 * @return {Roo.data.Record[]} An array of Records
8530 getRange : function(start, end){
8531 return this.data.getRange(start, end);
8535 storeOptions : function(o){
8536 o = Roo.apply({}, o);
8539 this.lastOptions = o;
8543 * Loads the Record cache from the configured Proxy using the configured Reader.
8545 * If using remote paging, then the first load call must specify the <em>start</em>
8546 * and <em>limit</em> properties in the options.params property to establish the initial
8547 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8549 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8550 * and this call will return before the new data has been loaded. Perform any post-processing
8551 * in a callback function, or in a "load" event handler.</strong>
8553 * @param {Object} options An object containing properties which control loading options:<ul>
8554 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8555 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8556 * passed the following arguments:<ul>
8557 * <li>r : Roo.data.Record[]</li>
8558 * <li>options: Options object from the load call</li>
8559 * <li>success: Boolean success indicator</li></ul></li>
8560 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8561 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8564 load : function(options){
8565 options = options || {};
8566 if(this.fireEvent("beforeload", this, options) !== false){
8567 this.storeOptions(options);
8568 var p = Roo.apply(options.params || {}, this.baseParams);
8569 // if meta was not loaded from remote source.. try requesting it.
8570 if (!this.reader.metaFromRemote) {
8573 if(this.sortInfo && this.remoteSort){
8574 var pn = this.paramNames;
8575 p[pn["sort"]] = this.sortInfo.field;
8576 p[pn["dir"]] = this.sortInfo.direction;
8578 if (this.multiSort) {
8579 var pn = this.paramNames;
8580 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8583 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8588 * Reloads the Record cache from the configured Proxy using the configured Reader and
8589 * the options from the last load operation performed.
8590 * @param {Object} options (optional) An object containing properties which may override the options
8591 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8592 * the most recently used options are reused).
8594 reload : function(options){
8595 this.load(Roo.applyIf(options||{}, this.lastOptions));
8599 // Called as a callback by the Reader during a load operation.
8600 loadRecords : function(o, options, success){
8601 if(!o || success === false){
8602 if(success !== false){
8603 this.fireEvent("load", this, [], options, o);
8605 if(options.callback){
8606 options.callback.call(options.scope || this, [], options, false);
8610 // if data returned failure - throw an exception.
8611 if (o.success === false) {
8612 // show a message if no listener is registered.
8613 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8614 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8616 // loadmask wil be hooked into this..
8617 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8620 var r = o.records, t = o.totalRecords || r.length;
8622 this.fireEvent("beforeloadadd", this, r, options, o);
8624 if(!options || options.add !== true){
8625 if(this.pruneModifiedRecords){
8628 for(var i = 0, len = r.length; i < len; i++){
8632 this.data = this.snapshot;
8633 delete this.snapshot;
8636 this.data.addAll(r);
8637 this.totalLength = t;
8639 this.fireEvent("datachanged", this);
8641 this.totalLength = Math.max(t, this.data.length+r.length);
8644 this.fireEvent("load", this, r, options, o);
8645 if(options.callback){
8646 options.callback.call(options.scope || this, r, options, true);
8652 * Loads data from a passed data block. A Reader which understands the format of the data
8653 * must have been configured in the constructor.
8654 * @param {Object} data The data block from which to read the Records. The format of the data expected
8655 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8656 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8658 loadData : function(o, append){
8659 var r = this.reader.readRecords(o);
8660 this.loadRecords(r, {add: append}, true);
8664 * Gets the number of cached records.
8666 * <em>If using paging, this may not be the total size of the dataset. If the data object
8667 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8668 * the data set size</em>
8670 getCount : function(){
8671 return this.data.length || 0;
8675 * Gets the total number of records in the dataset as returned by the server.
8677 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8678 * the dataset size</em>
8680 getTotalCount : function(){
8681 return this.totalLength || 0;
8685 * Returns the sort state of the Store as an object with two properties:
8687 field {String} The name of the field by which the Records are sorted
8688 direction {String} The sort order, "ASC" or "DESC"
8691 getSortState : function(){
8692 return this.sortInfo;
8696 applySort : function(){
8697 if(this.sortInfo && !this.remoteSort){
8698 var s = this.sortInfo, f = s.field;
8699 var st = this.fields.get(f).sortType;
8700 var fn = function(r1, r2){
8701 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8702 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8704 this.data.sort(s.direction, fn);
8705 if(this.snapshot && this.snapshot != this.data){
8706 this.snapshot.sort(s.direction, fn);
8712 * Sets the default sort column and order to be used by the next load operation.
8713 * @param {String} fieldName The name of the field to sort by.
8714 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8716 setDefaultSort : function(field, dir){
8717 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8722 * If remote sorting is used, the sort is performed on the server, and the cache is
8723 * reloaded. If local sorting is used, the cache is sorted internally.
8724 * @param {String} fieldName The name of the field to sort by.
8725 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8727 sort : function(fieldName, dir){
8728 var f = this.fields.get(fieldName);
8730 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8732 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8733 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8738 this.sortToggle[f.name] = dir;
8739 this.sortInfo = {field: f.name, direction: dir};
8740 if(!this.remoteSort){
8742 this.fireEvent("datachanged", this);
8744 this.load(this.lastOptions);
8749 * Calls the specified function for each of the Records in the cache.
8750 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8751 * Returning <em>false</em> aborts and exits the iteration.
8752 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8754 each : function(fn, scope){
8755 this.data.each(fn, scope);
8759 * Gets all records modified since the last commit. Modified records are persisted across load operations
8760 * (e.g., during paging).
8761 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8763 getModifiedRecords : function(){
8764 return this.modified;
8768 createFilterFn : function(property, value, anyMatch){
8769 if(!value.exec){ // not a regex
8770 value = String(value);
8771 if(value.length == 0){
8774 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8777 return value.test(r.data[property]);
8782 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8783 * @param {String} property A field on your records
8784 * @param {Number} start The record index to start at (defaults to 0)
8785 * @param {Number} end The last record index to include (defaults to length - 1)
8786 * @return {Number} The sum
8788 sum : function(property, start, end){
8789 var rs = this.data.items, v = 0;
8791 end = (end || end === 0) ? end : rs.length-1;
8793 for(var i = start; i <= end; i++){
8794 v += (rs[i].data[property] || 0);
8800 * Filter the records by a specified property.
8801 * @param {String} field A field on your records
8802 * @param {String/RegExp} value Either a string that the field
8803 * should start with or a RegExp to test against the field
8804 * @param {Boolean} anyMatch True to match any part not just the beginning
8806 filter : function(property, value, anyMatch){
8807 var fn = this.createFilterFn(property, value, anyMatch);
8808 return fn ? this.filterBy(fn) : this.clearFilter();
8812 * Filter by a function. The specified function will be called with each
8813 * record in this data source. If the function returns true the record is included,
8814 * otherwise it is filtered.
8815 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8816 * @param {Object} scope (optional) The scope of the function (defaults to this)
8818 filterBy : function(fn, scope){
8819 this.snapshot = this.snapshot || this.data;
8820 this.data = this.queryBy(fn, scope||this);
8821 this.fireEvent("datachanged", this);
8825 * Query the records by a specified property.
8826 * @param {String} field A field on your records
8827 * @param {String/RegExp} value Either a string that the field
8828 * should start with or a RegExp to test against the field
8829 * @param {Boolean} anyMatch True to match any part not just the beginning
8830 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8832 query : function(property, value, anyMatch){
8833 var fn = this.createFilterFn(property, value, anyMatch);
8834 return fn ? this.queryBy(fn) : this.data.clone();
8838 * Query by a function. The specified function will be called with each
8839 * record in this data source. If the function returns true the record is included
8841 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8842 * @param {Object} scope (optional) The scope of the function (defaults to this)
8843 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8845 queryBy : function(fn, scope){
8846 var data = this.snapshot || this.data;
8847 return data.filterBy(fn, scope||this);
8851 * Collects unique values for a particular dataIndex from this store.
8852 * @param {String} dataIndex The property to collect
8853 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8854 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8855 * @return {Array} An array of the unique values
8857 collect : function(dataIndex, allowNull, bypassFilter){
8858 var d = (bypassFilter === true && this.snapshot) ?
8859 this.snapshot.items : this.data.items;
8860 var v, sv, r = [], l = {};
8861 for(var i = 0, len = d.length; i < len; i++){
8862 v = d[i].data[dataIndex];
8864 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8873 * Revert to a view of the Record cache with no filtering applied.
8874 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8876 clearFilter : function(suppressEvent){
8877 if(this.snapshot && this.snapshot != this.data){
8878 this.data = this.snapshot;
8879 delete this.snapshot;
8880 if(suppressEvent !== true){
8881 this.fireEvent("datachanged", this);
8887 afterEdit : function(record){
8888 if(this.modified.indexOf(record) == -1){
8889 this.modified.push(record);
8891 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8895 afterReject : function(record){
8896 this.modified.remove(record);
8897 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8901 afterCommit : function(record){
8902 this.modified.remove(record);
8903 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8907 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8908 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8910 commitChanges : function(){
8911 var m = this.modified.slice(0);
8913 for(var i = 0, len = m.length; i < len; i++){
8919 * Cancel outstanding changes on all changed records.
8921 rejectChanges : function(){
8922 var m = this.modified.slice(0);
8924 for(var i = 0, len = m.length; i < len; i++){
8929 onMetaChange : function(meta, rtype, o){
8930 this.recordType = rtype;
8931 this.fields = rtype.prototype.fields;
8932 delete this.snapshot;
8933 this.sortInfo = meta.sortInfo || this.sortInfo;
8935 this.fireEvent('metachange', this, this.reader.meta);
8938 moveIndex : function(data, type)
8940 var index = this.indexOf(data);
8942 var newIndex = index + type;
8946 this.insert(newIndex, data);
8951 * Ext JS Library 1.1.1
8952 * Copyright(c) 2006-2007, Ext JS, LLC.
8954 * Originally Released Under LGPL - original licence link has changed is not relivant.
8957 * <script type="text/javascript">
8961 * @class Roo.data.SimpleStore
8962 * @extends Roo.data.Store
8963 * Small helper class to make creating Stores from Array data easier.
8964 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8965 * @cfg {Array} fields An array of field definition objects, or field name strings.
8966 * @cfg {Array} data The multi-dimensional array of data
8968 * @param {Object} config
8970 Roo.data.SimpleStore = function(config){
8971 Roo.data.SimpleStore.superclass.constructor.call(this, {
8973 reader: new Roo.data.ArrayReader({
8976 Roo.data.Record.create(config.fields)
8978 proxy : new Roo.data.MemoryProxy(config.data)
8982 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8984 * Ext JS Library 1.1.1
8985 * Copyright(c) 2006-2007, Ext JS, LLC.
8987 * Originally Released Under LGPL - original licence link has changed is not relivant.
8990 * <script type="text/javascript">
8995 * @extends Roo.data.Store
8996 * @class Roo.data.JsonStore
8997 * Small helper class to make creating Stores for JSON data easier. <br/>
8999 var store = new Roo.data.JsonStore({
9000 url: 'get-images.php',
9002 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9005 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9006 * JsonReader and HttpProxy (unless inline data is provided).</b>
9007 * @cfg {Array} fields An array of field definition objects, or field name strings.
9009 * @param {Object} config
9011 Roo.data.JsonStore = function(c){
9012 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9013 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9014 reader: new Roo.data.JsonReader(c, c.fields)
9017 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9019 * Ext JS Library 1.1.1
9020 * Copyright(c) 2006-2007, Ext JS, LLC.
9022 * Originally Released Under LGPL - original licence link has changed is not relivant.
9025 * <script type="text/javascript">
9029 Roo.data.Field = function(config){
9030 if(typeof config == "string"){
9031 config = {name: config};
9033 Roo.apply(this, config);
9039 var st = Roo.data.SortTypes;
9040 // named sortTypes are supported, here we look them up
9041 if(typeof this.sortType == "string"){
9042 this.sortType = st[this.sortType];
9045 // set default sortType for strings and dates
9049 this.sortType = st.asUCString;
9052 this.sortType = st.asDate;
9055 this.sortType = st.none;
9060 var stripRe = /[\$,%]/g;
9062 // prebuilt conversion function for this field, instead of
9063 // switching every time we're reading a value
9065 var cv, dateFormat = this.dateFormat;
9070 cv = function(v){ return v; };
9073 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9077 return v !== undefined && v !== null && v !== '' ?
9078 parseInt(String(v).replace(stripRe, ""), 10) : '';
9083 return v !== undefined && v !== null && v !== '' ?
9084 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9089 cv = function(v){ return v === true || v === "true" || v == 1; };
9096 if(v instanceof Date){
9100 if(dateFormat == "timestamp"){
9101 return new Date(v*1000);
9103 return Date.parseDate(v, dateFormat);
9105 var parsed = Date.parse(v);
9106 return parsed ? new Date(parsed) : null;
9115 Roo.data.Field.prototype = {
9123 * Ext JS Library 1.1.1
9124 * Copyright(c) 2006-2007, Ext JS, LLC.
9126 * Originally Released Under LGPL - original licence link has changed is not relivant.
9129 * <script type="text/javascript">
9132 // Base class for reading structured data from a data source. This class is intended to be
9133 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9136 * @class Roo.data.DataReader
9137 * Base class for reading structured data from a data source. This class is intended to be
9138 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9141 Roo.data.DataReader = function(meta, recordType){
9145 this.recordType = recordType instanceof Array ?
9146 Roo.data.Record.create(recordType) : recordType;
9149 Roo.data.DataReader.prototype = {
9151 * Create an empty record
9152 * @param {Object} data (optional) - overlay some values
9153 * @return {Roo.data.Record} record created.
9155 newRow : function(d) {
9157 this.recordType.prototype.fields.each(function(c) {
9159 case 'int' : da[c.name] = 0; break;
9160 case 'date' : da[c.name] = new Date(); break;
9161 case 'float' : da[c.name] = 0.0; break;
9162 case 'boolean' : da[c.name] = false; break;
9163 default : da[c.name] = ""; break;
9167 return new this.recordType(Roo.apply(da, d));
9172 * Ext JS Library 1.1.1
9173 * Copyright(c) 2006-2007, Ext JS, LLC.
9175 * Originally Released Under LGPL - original licence link has changed is not relivant.
9178 * <script type="text/javascript">
9182 * @class Roo.data.DataProxy
9183 * @extends Roo.data.Observable
9184 * This class is an abstract base class for implementations which provide retrieval of
9185 * unformatted data objects.<br>
9187 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9188 * (of the appropriate type which knows how to parse the data object) to provide a block of
9189 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9191 * Custom implementations must implement the load method as described in
9192 * {@link Roo.data.HttpProxy#load}.
9194 Roo.data.DataProxy = function(){
9198 * Fires before a network request is made to retrieve a data object.
9199 * @param {Object} This DataProxy object.
9200 * @param {Object} params The params parameter to the load function.
9205 * Fires before the load method's callback is called.
9206 * @param {Object} This DataProxy object.
9207 * @param {Object} o The data object.
9208 * @param {Object} arg The callback argument object passed to the load function.
9212 * @event loadexception
9213 * Fires if an Exception occurs during data retrieval.
9214 * @param {Object} This DataProxy object.
9215 * @param {Object} o The data object.
9216 * @param {Object} arg The callback argument object passed to the load function.
9217 * @param {Object} e The Exception.
9219 loadexception : true
9221 Roo.data.DataProxy.superclass.constructor.call(this);
9224 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9227 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9231 * Ext JS Library 1.1.1
9232 * Copyright(c) 2006-2007, Ext JS, LLC.
9234 * Originally Released Under LGPL - original licence link has changed is not relivant.
9237 * <script type="text/javascript">
9240 * @class Roo.data.MemoryProxy
9241 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9242 * to the Reader when its load method is called.
9244 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9246 Roo.data.MemoryProxy = function(data){
9250 Roo.data.MemoryProxy.superclass.constructor.call(this);
9254 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9256 * Load data from the requested source (in this case an in-memory
9257 * data object passed to the constructor), read the data object into
9258 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9259 * process that block using the passed callback.
9260 * @param {Object} params This parameter is not used by the MemoryProxy class.
9261 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9262 * object into a block of Roo.data.Records.
9263 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9264 * The function must be passed <ul>
9265 * <li>The Record block object</li>
9266 * <li>The "arg" argument from the load function</li>
9267 * <li>A boolean success indicator</li>
9269 * @param {Object} scope The scope in which to call the callback
9270 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9272 load : function(params, reader, callback, scope, arg){
9273 params = params || {};
9276 result = reader.readRecords(this.data);
9278 this.fireEvent("loadexception", this, arg, null, e);
9279 callback.call(scope, null, arg, false);
9282 callback.call(scope, result, arg, true);
9286 update : function(params, records){
9291 * Ext JS Library 1.1.1
9292 * Copyright(c) 2006-2007, Ext JS, LLC.
9294 * Originally Released Under LGPL - original licence link has changed is not relivant.
9297 * <script type="text/javascript">
9300 * @class Roo.data.HttpProxy
9301 * @extends Roo.data.DataProxy
9302 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9303 * configured to reference a certain URL.<br><br>
9305 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9306 * from which the running page was served.<br><br>
9308 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9310 * Be aware that to enable the browser to parse an XML document, the server must set
9311 * the Content-Type header in the HTTP response to "text/xml".
9313 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9314 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9315 * will be used to make the request.
9317 Roo.data.HttpProxy = function(conn){
9318 Roo.data.HttpProxy.superclass.constructor.call(this);
9319 // is conn a conn config or a real conn?
9321 this.useAjax = !conn || !conn.events;
9325 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9326 // thse are take from connection...
9329 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9332 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9333 * extra parameters to each request made by this object. (defaults to undefined)
9336 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9337 * to each request made by this object. (defaults to undefined)
9340 * @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)
9343 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9346 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9352 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9356 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9357 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9358 * a finer-grained basis than the DataProxy events.
9360 getConnection : function(){
9361 return this.useAjax ? Roo.Ajax : this.conn;
9365 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9366 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9367 * process that block using the passed callback.
9368 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9369 * for the request to the remote server.
9370 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9371 * object into a block of Roo.data.Records.
9372 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9373 * The function must be passed <ul>
9374 * <li>The Record block object</li>
9375 * <li>The "arg" argument from the load function</li>
9376 * <li>A boolean success indicator</li>
9378 * @param {Object} scope The scope in which to call the callback
9379 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9381 load : function(params, reader, callback, scope, arg){
9382 if(this.fireEvent("beforeload", this, params) !== false){
9384 params : params || {},
9386 callback : callback,
9391 callback : this.loadResponse,
9395 Roo.applyIf(o, this.conn);
9396 if(this.activeRequest){
9397 Roo.Ajax.abort(this.activeRequest);
9399 this.activeRequest = Roo.Ajax.request(o);
9401 this.conn.request(o);
9404 callback.call(scope||this, null, arg, false);
9409 loadResponse : function(o, success, response){
9410 delete this.activeRequest;
9412 this.fireEvent("loadexception", this, o, response);
9413 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9418 result = o.reader.read(response);
9420 this.fireEvent("loadexception", this, o, response, e);
9421 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9425 this.fireEvent("load", this, o, o.request.arg);
9426 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9430 update : function(dataSet){
9435 updateResponse : function(dataSet){
9440 * Ext JS Library 1.1.1
9441 * Copyright(c) 2006-2007, Ext JS, LLC.
9443 * Originally Released Under LGPL - original licence link has changed is not relivant.
9446 * <script type="text/javascript">
9450 * @class Roo.data.ScriptTagProxy
9451 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9452 * other than the originating domain of the running page.<br><br>
9454 * <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
9455 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9457 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9458 * source code that is used as the source inside a <script> tag.<br><br>
9460 * In order for the browser to process the returned data, the server must wrap the data object
9461 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9462 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9463 * depending on whether the callback name was passed:
9466 boolean scriptTag = false;
9467 String cb = request.getParameter("callback");
9470 response.setContentType("text/javascript");
9472 response.setContentType("application/x-json");
9474 Writer out = response.getWriter();
9476 out.write(cb + "(");
9478 out.print(dataBlock.toJsonString());
9485 * @param {Object} config A configuration object.
9487 Roo.data.ScriptTagProxy = function(config){
9488 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9489 Roo.apply(this, config);
9490 this.head = document.getElementsByTagName("head")[0];
9493 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9495 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9497 * @cfg {String} url The URL from which to request the data object.
9500 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9504 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9505 * the server the name of the callback function set up by the load call to process the returned data object.
9506 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9507 * javascript output which calls this named function passing the data object as its only parameter.
9509 callbackParam : "callback",
9511 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9512 * name to the request.
9517 * Load data from the configured URL, read the data object into
9518 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9519 * process that block using the passed callback.
9520 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9521 * for the request to the remote server.
9522 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9523 * object into a block of Roo.data.Records.
9524 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9525 * The function must be passed <ul>
9526 * <li>The Record block object</li>
9527 * <li>The "arg" argument from the load function</li>
9528 * <li>A boolean success indicator</li>
9530 * @param {Object} scope The scope in which to call the callback
9531 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9533 load : function(params, reader, callback, scope, arg){
9534 if(this.fireEvent("beforeload", this, params) !== false){
9536 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9539 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9541 url += "&_dc=" + (new Date().getTime());
9543 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9546 cb : "stcCallback"+transId,
9547 scriptId : "stcScript"+transId,
9551 callback : callback,
9557 window[trans.cb] = function(o){
9558 conn.handleResponse(o, trans);
9561 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9563 if(this.autoAbort !== false){
9567 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9569 var script = document.createElement("script");
9570 script.setAttribute("src", url);
9571 script.setAttribute("type", "text/javascript");
9572 script.setAttribute("id", trans.scriptId);
9573 this.head.appendChild(script);
9577 callback.call(scope||this, null, arg, false);
9582 isLoading : function(){
9583 return this.trans ? true : false;
9587 * Abort the current server request.
9590 if(this.isLoading()){
9591 this.destroyTrans(this.trans);
9596 destroyTrans : function(trans, isLoaded){
9597 this.head.removeChild(document.getElementById(trans.scriptId));
9598 clearTimeout(trans.timeoutId);
9600 window[trans.cb] = undefined;
9602 delete window[trans.cb];
9605 // if hasn't been loaded, wait for load to remove it to prevent script error
9606 window[trans.cb] = function(){
9607 window[trans.cb] = undefined;
9609 delete window[trans.cb];
9616 handleResponse : function(o, trans){
9618 this.destroyTrans(trans, true);
9621 result = trans.reader.readRecords(o);
9623 this.fireEvent("loadexception", this, o, trans.arg, e);
9624 trans.callback.call(trans.scope||window, null, trans.arg, false);
9627 this.fireEvent("load", this, o, trans.arg);
9628 trans.callback.call(trans.scope||window, result, trans.arg, true);
9632 handleFailure : function(trans){
9634 this.destroyTrans(trans, false);
9635 this.fireEvent("loadexception", this, null, trans.arg);
9636 trans.callback.call(trans.scope||window, null, trans.arg, false);
9640 * Ext JS Library 1.1.1
9641 * Copyright(c) 2006-2007, Ext JS, LLC.
9643 * Originally Released Under LGPL - original licence link has changed is not relivant.
9646 * <script type="text/javascript">
9650 * @class Roo.data.JsonReader
9651 * @extends Roo.data.DataReader
9652 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9653 * based on mappings in a provided Roo.data.Record constructor.
9655 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9656 * in the reply previously.
9661 var RecordDef = Roo.data.Record.create([
9662 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9663 {name: 'occupation'} // This field will use "occupation" as the mapping.
9665 var myReader = new Roo.data.JsonReader({
9666 totalProperty: "results", // The property which contains the total dataset size (optional)
9667 root: "rows", // The property which contains an Array of row objects
9668 id: "id" // The property within each row object that provides an ID for the record (optional)
9672 * This would consume a JSON file like this:
9674 { 'results': 2, 'rows': [
9675 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9676 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9679 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9680 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9681 * paged from the remote server.
9682 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9683 * @cfg {String} root name of the property which contains the Array of row objects.
9684 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9686 * Create a new JsonReader
9687 * @param {Object} meta Metadata configuration options
9688 * @param {Object} recordType Either an Array of field definition objects,
9689 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9691 Roo.data.JsonReader = function(meta, recordType){
9694 // set some defaults:
9696 totalProperty: 'total',
9697 successProperty : 'success',
9702 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9704 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9707 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9708 * Used by Store query builder to append _requestMeta to params.
9711 metaFromRemote : false,
9713 * This method is only used by a DataProxy which has retrieved data from a remote server.
9714 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9715 * @return {Object} data A data block which is used by an Roo.data.Store object as
9716 * a cache of Roo.data.Records.
9718 read : function(response){
9719 var json = response.responseText;
9721 var o = /* eval:var:o */ eval("("+json+")");
9723 throw {message: "JsonReader.read: Json object not found"};
9729 this.metaFromRemote = true;
9730 this.meta = o.metaData;
9731 this.recordType = Roo.data.Record.create(o.metaData.fields);
9732 this.onMetaChange(this.meta, this.recordType, o);
9734 return this.readRecords(o);
9737 // private function a store will implement
9738 onMetaChange : function(meta, recordType, o){
9745 simpleAccess: function(obj, subsc) {
9752 getJsonAccessor: function(){
9754 return function(expr) {
9756 return(re.test(expr))
9757 ? new Function("obj", "return obj." + expr)
9767 * Create a data block containing Roo.data.Records from an XML document.
9768 * @param {Object} o An object which contains an Array of row objects in the property specified
9769 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9770 * which contains the total size of the dataset.
9771 * @return {Object} data A data block which is used by an Roo.data.Store object as
9772 * a cache of Roo.data.Records.
9774 readRecords : function(o){
9776 * After any data loads, the raw JSON data is available for further custom processing.
9780 var s = this.meta, Record = this.recordType,
9781 f = Record.prototype.fields, fi = f.items, fl = f.length;
9783 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9785 if(s.totalProperty) {
9786 this.getTotal = this.getJsonAccessor(s.totalProperty);
9788 if(s.successProperty) {
9789 this.getSuccess = this.getJsonAccessor(s.successProperty);
9791 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9793 var g = this.getJsonAccessor(s.id);
9794 this.getId = function(rec) {
9796 return (r === undefined || r === "") ? null : r;
9799 this.getId = function(){return null;};
9802 for(var jj = 0; jj < fl; jj++){
9804 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9805 this.ef[jj] = this.getJsonAccessor(map);
9809 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9810 if(s.totalProperty){
9811 var vt = parseInt(this.getTotal(o), 10);
9816 if(s.successProperty){
9817 var vs = this.getSuccess(o);
9818 if(vs === false || vs === 'false'){
9823 for(var i = 0; i < c; i++){
9826 var id = this.getId(n);
9827 for(var j = 0; j < fl; j++){
9829 var v = this.ef[j](n);
9831 Roo.log('missing convert for ' + f.name);
9835 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9837 var record = new Record(values, id);
9839 records[i] = record;
9845 totalRecords : totalRecords
9850 * Ext JS Library 1.1.1
9851 * Copyright(c) 2006-2007, Ext JS, LLC.
9853 * Originally Released Under LGPL - original licence link has changed is not relivant.
9856 * <script type="text/javascript">
9860 * @class Roo.data.ArrayReader
9861 * @extends Roo.data.DataReader
9862 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9863 * Each element of that Array represents a row of data fields. The
9864 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9865 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9869 var RecordDef = Roo.data.Record.create([
9870 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9871 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9873 var myReader = new Roo.data.ArrayReader({
9874 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9878 * This would consume an Array like this:
9880 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9882 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9884 * Create a new JsonReader
9885 * @param {Object} meta Metadata configuration options.
9886 * @param {Object} recordType Either an Array of field definition objects
9887 * as specified to {@link Roo.data.Record#create},
9888 * or an {@link Roo.data.Record} object
9889 * created using {@link Roo.data.Record#create}.
9891 Roo.data.ArrayReader = function(meta, recordType){
9892 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9895 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9897 * Create a data block containing Roo.data.Records from an XML document.
9898 * @param {Object} o An Array of row objects which represents the dataset.
9899 * @return {Object} data A data block which is used by an Roo.data.Store object as
9900 * a cache of Roo.data.Records.
9902 readRecords : function(o){
9903 var sid = this.meta ? this.meta.id : null;
9904 var recordType = this.recordType, fields = recordType.prototype.fields;
9907 for(var i = 0; i < root.length; i++){
9910 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9911 for(var j = 0, jlen = fields.length; j < jlen; j++){
9912 var f = fields.items[j];
9913 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9914 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9918 var record = new recordType(values, id);
9920 records[records.length] = record;
9924 totalRecords : records.length
9933 * @class Roo.bootstrap.ComboBox
9934 * @extends Roo.bootstrap.TriggerField
9935 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9936 * @cfg {Boolean} append (true|false) default false
9937 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9938 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9939 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9941 * Create a new ComboBox.
9942 * @param {Object} config Configuration options
9944 Roo.bootstrap.ComboBox = function(config){
9945 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9949 * Fires when the dropdown list is expanded
9950 * @param {Roo.bootstrap.ComboBox} combo This combo box
9955 * Fires when the dropdown list is collapsed
9956 * @param {Roo.bootstrap.ComboBox} combo This combo box
9960 * @event beforeselect
9961 * Fires before a list item is selected. Return false to cancel the selection.
9962 * @param {Roo.bootstrap.ComboBox} combo This combo box
9963 * @param {Roo.data.Record} record The data record returned from the underlying store
9964 * @param {Number} index The index of the selected item in the dropdown list
9966 'beforeselect' : true,
9969 * Fires when a list item is selected
9970 * @param {Roo.bootstrap.ComboBox} combo This combo box
9971 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9972 * @param {Number} index The index of the selected item in the dropdown list
9976 * @event beforequery
9977 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9978 * The event object passed has these properties:
9979 * @param {Roo.bootstrap.ComboBox} combo This combo box
9980 * @param {String} query The query
9981 * @param {Boolean} forceAll true to force "all" query
9982 * @param {Boolean} cancel true to cancel the query
9983 * @param {Object} e The query event object
9985 'beforequery': true,
9988 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9989 * @param {Roo.bootstrap.ComboBox} combo This combo box
9994 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9995 * @param {Roo.bootstrap.ComboBox} combo This combo box
9996 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10001 * Fires when the remove value from the combobox array
10002 * @param {Roo.bootstrap.ComboBox} combo This combo box
10009 this.tickItems = [];
10011 this.selectedIndex = -1;
10012 if(this.mode == 'local'){
10013 if(config.queryDelay === undefined){
10014 this.queryDelay = 10;
10016 if(config.minChars === undefined){
10022 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10025 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10026 * rendering into an Roo.Editor, defaults to false)
10029 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10030 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10033 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10036 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10037 * the dropdown list (defaults to undefined, with no header element)
10041 * @cfg {String/Roo.Template} tpl The template to use to render the output
10045 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10047 listWidth: undefined,
10049 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10050 * mode = 'remote' or 'text' if mode = 'local')
10052 displayField: undefined,
10054 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10055 * mode = 'remote' or 'value' if mode = 'local').
10056 * Note: use of a valueField requires the user make a selection
10057 * in order for a value to be mapped.
10059 valueField: undefined,
10063 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10064 * field's data value (defaults to the underlying DOM element's name)
10066 hiddenName: undefined,
10068 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10072 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10074 selectedClass: 'active',
10077 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10081 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10082 * anchor positions (defaults to 'tl-bl')
10084 listAlign: 'tl-bl?',
10086 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10090 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10091 * query specified by the allQuery config option (defaults to 'query')
10093 triggerAction: 'query',
10095 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10096 * (defaults to 4, does not apply if editable = false)
10100 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10101 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10105 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10106 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10110 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10111 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10115 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10116 * when editable = true (defaults to false)
10118 selectOnFocus:false,
10120 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10122 queryParam: 'query',
10124 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10125 * when mode = 'remote' (defaults to 'Loading...')
10127 loadingText: 'Loading...',
10129 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10133 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10137 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10138 * traditional select (defaults to true)
10142 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10146 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10150 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10151 * listWidth has a higher value)
10155 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10156 * allow the user to set arbitrary text into the field (defaults to false)
10158 forceSelection:false,
10160 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10161 * if typeAhead = true (defaults to 250)
10163 typeAheadDelay : 250,
10165 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10166 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10168 valueNotFoundText : undefined,
10170 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10172 blockFocus : false,
10175 * @cfg {Boolean} disableClear Disable showing of clear button.
10177 disableClear : false,
10179 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10181 alwaysQuery : false,
10184 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10198 btnPosition : 'right',
10200 // element that contains real text value.. (when hidden is used..)
10202 getAutoCreate : function()
10209 if(!this.tickable){
10210 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10215 * ComboBox with tickable selections
10218 var align = this.labelAlign || this.parentLabelAlign();
10221 cls : 'form-group roo-combobox-tickable' //input-group
10227 cls : 'tickable-buttons',
10232 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10239 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10246 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10253 Roo.each(buttons.cn, function(c){
10255 c.cls += ' btn-' + _this.size;
10258 if (_this.disabled) {
10269 cls: 'form-hidden-field'
10273 cls: 'select2-choices',
10277 cls: 'select2-search-field',
10289 cls: 'select2-container input-group select2-container-multi',
10294 cls: 'typeahead typeahead-long dropdown-menu',
10295 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10300 if (align ==='left' && this.fieldLabel.length) {
10302 Roo.log("left and has label");
10308 cls : 'control-label col-sm-' + this.labelWidth,
10309 html : this.fieldLabel
10313 cls : "col-sm-" + (12 - this.labelWidth),
10320 } else if ( this.fieldLabel.length) {
10326 //cls : 'input-group-addon',
10327 html : this.fieldLabel
10337 Roo.log(" no label && no align");
10344 ['xs','sm','md','lg'].map(function(size){
10345 if (settings[size]) {
10346 cfg.cls += ' col-' + size + '-' + settings[size];
10355 initEvents: function()
10359 throw "can not find store for combo";
10361 this.store = Roo.factory(this.store, Roo.data);
10364 this.initTickableEvnets();
10368 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10371 if(this.hiddenName){
10373 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10375 this.hiddenField.dom.value =
10376 this.hiddenValue !== undefined ? this.hiddenValue :
10377 this.value !== undefined ? this.value : '';
10379 // prevent input submission
10380 this.el.dom.removeAttribute('name');
10381 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10386 // this.el.dom.setAttribute('autocomplete', 'off');
10389 var cls = 'x-combo-list';
10390 this.list = this.el.select('ul.dropdown-menu',true).first();
10392 //this.list = new Roo.Layer({
10393 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10399 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10400 _this.list.setWidth(lw);
10403 this.list.on('mouseover', this.onViewOver, this);
10404 this.list.on('mousemove', this.onViewMove, this);
10406 this.list.on('scroll', this.onViewScroll, this);
10409 this.list.swallowEvent('mousewheel');
10410 this.assetHeight = 0;
10413 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10414 this.assetHeight += this.header.getHeight();
10417 this.innerList = this.list.createChild({cls:cls+'-inner'});
10418 this.innerList.on('mouseover', this.onViewOver, this);
10419 this.innerList.on('mousemove', this.onViewMove, this);
10420 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10422 if(this.allowBlank && !this.pageSize && !this.disableClear){
10423 this.footer = this.list.createChild({cls:cls+'-ft'});
10424 this.pageTb = new Roo.Toolbar(this.footer);
10428 this.footer = this.list.createChild({cls:cls+'-ft'});
10429 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10430 {pageSize: this.pageSize});
10434 if (this.pageTb && this.allowBlank && !this.disableClear) {
10436 this.pageTb.add(new Roo.Toolbar.Fill(), {
10437 cls: 'x-btn-icon x-btn-clear',
10439 handler: function()
10442 _this.clearValue();
10443 _this.onSelect(false, -1);
10448 this.assetHeight += this.footer.getHeight();
10453 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10456 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10457 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10459 //this.view.wrapEl.setDisplayed(false);
10460 this.view.on('click', this.onViewClick, this);
10464 this.store.on('beforeload', this.onBeforeLoad, this);
10465 this.store.on('load', this.onLoad, this);
10466 this.store.on('loadexception', this.onLoadException, this);
10468 if(this.resizable){
10469 this.resizer = new Roo.Resizable(this.list, {
10470 pinned:true, handles:'se'
10472 this.resizer.on('resize', function(r, w, h){
10473 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10474 this.listWidth = w;
10475 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10476 this.restrictHeight();
10478 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10481 if(!this.editable){
10482 this.editable = true;
10483 this.setEditable(false);
10488 if (typeof(this.events.add.listeners) != 'undefined') {
10490 this.addicon = this.wrap.createChild(
10491 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10493 this.addicon.on('click', function(e) {
10494 this.fireEvent('add', this);
10497 if (typeof(this.events.edit.listeners) != 'undefined') {
10499 this.editicon = this.wrap.createChild(
10500 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10501 if (this.addicon) {
10502 this.editicon.setStyle('margin-left', '40px');
10504 this.editicon.on('click', function(e) {
10506 // we fire even if inothing is selected..
10507 this.fireEvent('edit', this, this.lastData );
10513 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10514 "up" : function(e){
10515 this.inKeyMode = true;
10519 "down" : function(e){
10520 if(!this.isExpanded()){
10521 this.onTriggerClick();
10523 this.inKeyMode = true;
10528 "enter" : function(e){
10529 // this.onViewClick();
10533 if(this.fireEvent("specialkey", this, e)){
10534 this.onViewClick(false);
10540 "esc" : function(e){
10544 "tab" : function(e){
10547 if(this.fireEvent("specialkey", this, e)){
10548 this.onViewClick(false);
10556 doRelay : function(foo, bar, hname){
10557 if(hname == 'down' || this.scope.isExpanded()){
10558 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10567 this.queryDelay = Math.max(this.queryDelay || 10,
10568 this.mode == 'local' ? 10 : 250);
10571 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10573 if(this.typeAhead){
10574 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10576 if(this.editable !== false){
10577 this.inputEl().on("keyup", this.onKeyUp, this);
10579 if(this.forceSelection){
10580 this.inputEl().on('blur', this.doForce, this);
10584 this.choices = this.el.select('ul.select2-choices', true).first();
10585 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10589 initTickableEvnets: function()
10591 if(this.hiddenName){
10593 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10595 this.hiddenField.dom.value =
10596 this.hiddenValue !== undefined ? this.hiddenValue :
10597 this.value !== undefined ? this.value : '';
10599 // prevent input submission
10600 this.el.dom.removeAttribute('name');
10601 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10606 this.list = this.el.select('ul.dropdown-menu',true).first();
10608 this.choices = this.el.select('ul.select2-choices', true).first();
10609 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10610 this.searchField.on("click", this.onTriggerClick, this, {preventDefault:true});
10612 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10613 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10615 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10616 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10618 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10619 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10621 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10622 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10623 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10626 this.cancelBtn.hide();
10631 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10632 _this.list.setWidth(lw);
10635 this.list.on('mouseover', this.onViewOver, this);
10636 this.list.on('mousemove', this.onViewMove, this);
10638 this.list.on('scroll', this.onViewScroll, this);
10641 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>';
10644 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10645 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10648 //this.view.wrapEl.setDisplayed(false);
10649 this.view.on('click', this.onViewClick, this);
10653 this.store.on('beforeload', this.onBeforeLoad, this);
10654 this.store.on('load', this.onLoad, this);
10655 this.store.on('loadexception', this.onLoadException, this);
10657 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10658 // "up" : function(e){
10659 // this.inKeyMode = true;
10660 // this.selectPrev();
10663 // "down" : function(e){
10664 // if(!this.isExpanded()){
10665 // this.onTriggerClick();
10667 // this.inKeyMode = true;
10668 // this.selectNext();
10672 // "enter" : function(e){
10673 //// this.onViewClick();
10675 // this.collapse();
10677 // if(this.fireEvent("specialkey", this, e)){
10678 // this.onViewClick(false);
10684 // "esc" : function(e){
10685 // this.collapse();
10688 // "tab" : function(e){
10689 // this.collapse();
10691 // if(this.fireEvent("specialkey", this, e)){
10692 // this.onViewClick(false);
10700 // doRelay : function(foo, bar, hname){
10701 // if(hname == 'down' || this.scope.isExpanded()){
10702 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10707 // forceKeyDown: true
10711 this.queryDelay = Math.max(this.queryDelay || 10,
10712 this.mode == 'local' ? 10 : 250);
10715 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10717 if(this.typeAhead){
10718 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10722 onDestroy : function(){
10724 this.view.setStore(null);
10725 this.view.el.removeAllListeners();
10726 this.view.el.remove();
10727 this.view.purgeListeners();
10730 this.list.dom.innerHTML = '';
10734 this.store.un('beforeload', this.onBeforeLoad, this);
10735 this.store.un('load', this.onLoad, this);
10736 this.store.un('loadexception', this.onLoadException, this);
10738 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10742 fireKey : function(e){
10743 if(e.isNavKeyPress() && !this.list.isVisible()){
10744 this.fireEvent("specialkey", this, e);
10749 onResize: function(w, h){
10750 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10752 // if(typeof w != 'number'){
10753 // // we do not handle it!?!?
10756 // var tw = this.trigger.getWidth();
10757 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10758 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10760 // this.inputEl().setWidth( this.adjustWidth('input', x));
10762 // //this.trigger.setStyle('left', x+'px');
10764 // if(this.list && this.listWidth === undefined){
10765 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10766 // this.list.setWidth(lw);
10767 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10775 * Allow or prevent the user from directly editing the field text. If false is passed,
10776 * the user will only be able to select from the items defined in the dropdown list. This method
10777 * is the runtime equivalent of setting the 'editable' config option at config time.
10778 * @param {Boolean} value True to allow the user to directly edit the field text
10780 setEditable : function(value){
10781 if(value == this.editable){
10784 this.editable = value;
10786 this.inputEl().dom.setAttribute('readOnly', true);
10787 this.inputEl().on('mousedown', this.onTriggerClick, this);
10788 this.inputEl().addClass('x-combo-noedit');
10790 this.inputEl().dom.setAttribute('readOnly', false);
10791 this.inputEl().un('mousedown', this.onTriggerClick, this);
10792 this.inputEl().removeClass('x-combo-noedit');
10798 onBeforeLoad : function(combo,opts){
10799 if(!this.hasFocus){
10803 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10805 this.restrictHeight();
10806 this.selectedIndex = -1;
10810 onLoad : function(){
10812 this.hasQuery = false;
10814 if(!this.hasFocus){
10818 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10819 this.loading.hide();
10822 if(this.store.getCount() > 0){
10824 this.restrictHeight();
10825 if(this.lastQuery == this.allQuery){
10826 if(this.editable && !this.tickable){
10827 this.inputEl().dom.select();
10829 if(!this.selectByValue(this.value, true) && this.autoFocus){
10830 this.select(0, true);
10833 if(this.autoFocus){
10836 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10837 this.taTask.delay(this.typeAheadDelay);
10841 this.onEmptyResults();
10847 onLoadException : function()
10849 this.hasQuery = false;
10851 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10852 this.loading.hide();
10856 Roo.log(this.store.reader.jsonData);
10857 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10859 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10865 onTypeAhead : function(){
10866 if(this.store.getCount() > 0){
10867 var r = this.store.getAt(0);
10868 var newValue = r.data[this.displayField];
10869 var len = newValue.length;
10870 var selStart = this.getRawValue().length;
10872 if(selStart != len){
10873 this.setRawValue(newValue);
10874 this.selectText(selStart, newValue.length);
10880 onSelect : function(record, index){
10882 if(this.fireEvent('beforeselect', this, record, index) !== false){
10884 this.setFromData(index > -1 ? record.data : false);
10887 this.fireEvent('select', this, record, index);
10892 * Returns the currently selected field value or empty string if no value is set.
10893 * @return {String} value The selected value
10895 getValue : function(){
10898 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10901 if(this.valueField){
10902 return typeof this.value != 'undefined' ? this.value : '';
10904 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10909 * Clears any text/value currently set in the field
10911 clearValue : function(){
10912 if(this.hiddenField){
10913 this.hiddenField.dom.value = '';
10916 this.setRawValue('');
10917 this.lastSelectionText = '';
10922 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10923 * will be displayed in the field. If the value does not match the data value of an existing item,
10924 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10925 * Otherwise the field will be blank (although the value will still be set).
10926 * @param {String} value The value to match
10928 setValue : function(v){
10935 if(this.valueField){
10936 var r = this.findRecord(this.valueField, v);
10938 text = r.data[this.displayField];
10939 }else if(this.valueNotFoundText !== undefined){
10940 text = this.valueNotFoundText;
10943 this.lastSelectionText = text;
10944 if(this.hiddenField){
10945 this.hiddenField.dom.value = v;
10947 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10951 * @property {Object} the last set data for the element
10956 * Sets the value of the field based on a object which is related to the record format for the store.
10957 * @param {Object} value the value to set as. or false on reset?
10959 setFromData : function(o){
10966 var dv = ''; // display value
10967 var vv = ''; // value value..
10969 if (this.displayField) {
10970 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10972 // this is an error condition!!!
10973 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10976 if(this.valueField){
10977 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10980 if(this.hiddenField){
10981 this.hiddenField.dom.value = vv;
10983 this.lastSelectionText = dv;
10984 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10988 // no hidden field.. - we store the value in 'value', but still display
10989 // display field!!!!
10990 this.lastSelectionText = dv;
10991 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10997 reset : function(){
10998 // overridden so that last data is reset..
10999 this.setValue(this.originalValue);
11000 this.clearInvalid();
11001 this.lastData = false;
11003 this.view.clearSelections();
11007 findRecord : function(prop, value){
11009 if(this.store.getCount() > 0){
11010 this.store.each(function(r){
11011 if(r.data[prop] == value){
11021 getName: function()
11023 // returns hidden if it's set..
11024 if (!this.rendered) {return ''};
11025 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11029 onViewMove : function(e, t){
11030 this.inKeyMode = false;
11034 onViewOver : function(e, t){
11035 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11038 var item = this.view.findItemFromChild(t);
11041 var index = this.view.indexOf(item);
11042 this.select(index, false);
11047 onViewClick : function(view, doFocus, el, e)
11049 var index = this.view.getSelectedIndexes()[0];
11051 var r = this.store.getAt(index);
11055 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11062 Roo.each(this.tickItems, function(v,k){
11064 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11065 _this.tickItems.splice(k, 1);
11075 this.tickItems.push(r.data);
11080 this.onSelect(r, index);
11082 if(doFocus !== false && !this.blockFocus){
11083 this.inputEl().focus();
11088 restrictHeight : function(){
11089 //this.innerList.dom.style.height = '';
11090 //var inner = this.innerList.dom;
11091 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11092 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11093 //this.list.beginUpdate();
11094 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11095 this.list.alignTo(this.inputEl(), this.listAlign);
11096 //this.list.endUpdate();
11100 onEmptyResults : function(){
11105 * Returns true if the dropdown list is expanded, else false.
11107 isExpanded : function(){
11108 return this.list.isVisible();
11112 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11113 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11114 * @param {String} value The data value of the item to select
11115 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11116 * selected item if it is not currently in view (defaults to true)
11117 * @return {Boolean} True if the value matched an item in the list, else false
11119 selectByValue : function(v, scrollIntoView){
11120 if(v !== undefined && v !== null){
11121 var r = this.findRecord(this.valueField || this.displayField, v);
11123 this.select(this.store.indexOf(r), scrollIntoView);
11131 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11132 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11133 * @param {Number} index The zero-based index of the list item to select
11134 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11135 * selected item if it is not currently in view (defaults to true)
11137 select : function(index, scrollIntoView){
11138 this.selectedIndex = index;
11139 this.view.select(index);
11140 if(scrollIntoView !== false){
11141 var el = this.view.getNode(index);
11143 //this.innerList.scrollChildIntoView(el, false);
11150 selectNext : function(){
11151 var ct = this.store.getCount();
11153 if(this.selectedIndex == -1){
11155 }else if(this.selectedIndex < ct-1){
11156 this.select(this.selectedIndex+1);
11162 selectPrev : function(){
11163 var ct = this.store.getCount();
11165 if(this.selectedIndex == -1){
11167 }else if(this.selectedIndex != 0){
11168 this.select(this.selectedIndex-1);
11174 onKeyUp : function(e){
11175 if(this.editable !== false && !e.isSpecialKey()){
11176 this.lastKey = e.getKey();
11177 this.dqTask.delay(this.queryDelay);
11182 validateBlur : function(){
11183 return !this.list || !this.list.isVisible();
11187 initQuery : function(){
11188 this.doQuery(this.getRawValue());
11192 doForce : function(){
11193 if(this.inputEl().dom.value.length > 0){
11194 this.inputEl().dom.value =
11195 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11201 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11202 * query allowing the query action to be canceled if needed.
11203 * @param {String} query The SQL query to execute
11204 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11205 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11206 * saved in the current store (defaults to false)
11208 doQuery : function(q, forceAll){
11210 if(q === undefined || q === null){
11215 forceAll: forceAll,
11219 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11224 forceAll = qe.forceAll;
11225 if(forceAll === true || (q.length >= this.minChars)){
11227 this.hasQuery = true;
11229 if(this.lastQuery != q || this.alwaysQuery){
11230 this.lastQuery = q;
11231 if(this.mode == 'local'){
11232 this.selectedIndex = -1;
11234 this.store.clearFilter();
11236 this.store.filter(this.displayField, q);
11240 this.store.baseParams[this.queryParam] = q;
11242 var options = {params : this.getParams(q)};
11245 options.add = true;
11246 options.params.start = this.page * this.pageSize;
11249 this.store.load(options);
11251 * this code will make the page width larger, at the beginning, the list not align correctly,
11252 * we should expand the list on onLoad
11253 * so command out it
11258 this.selectedIndex = -1;
11263 this.loadNext = false;
11267 getParams : function(q){
11269 //p[this.queryParam] = q;
11273 p.limit = this.pageSize;
11279 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11281 collapse : function(){
11282 if(!this.isExpanded()){
11290 this.cancelBtn.hide();
11291 this.trigger.show();
11294 Roo.get(document).un('mousedown', this.collapseIf, this);
11295 Roo.get(document).un('mousewheel', this.collapseIf, this);
11296 if (!this.editable) {
11297 Roo.get(document).un('keydown', this.listKeyPress, this);
11299 this.fireEvent('collapse', this);
11303 collapseIf : function(e){
11304 var in_combo = e.within(this.el);
11305 var in_list = e.within(this.list);
11307 if (in_combo || in_list) {
11308 //e.stopPropagation();
11313 this.onTickableFooterButtonClick(e, false, false);
11321 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11323 expand : function(){
11325 if(this.isExpanded() || !this.hasFocus){
11329 this.list.alignTo(this.inputEl(), this.listAlign);
11334 this.tickItems = Roo.apply([], this.item);
11337 this.cancelBtn.show();
11338 this.trigger.hide();
11342 Roo.get(document).on('mousedown', this.collapseIf, this);
11343 Roo.get(document).on('mousewheel', this.collapseIf, this);
11344 if (!this.editable) {
11345 Roo.get(document).on('keydown', this.listKeyPress, this);
11348 this.fireEvent('expand', this);
11352 // Implements the default empty TriggerField.onTriggerClick function
11353 onTriggerClick : function()
11355 Roo.log('trigger click');
11362 this.onTickableTriggerClick();
11367 this.loadNext = false;
11369 if(this.isExpanded()){
11371 if (!this.blockFocus) {
11372 this.inputEl().focus();
11376 this.hasFocus = true;
11377 if(this.triggerAction == 'all') {
11378 this.doQuery(this.allQuery, true);
11380 this.doQuery(this.getRawValue());
11382 if (!this.blockFocus) {
11383 this.inputEl().focus();
11388 onTickableTriggerClick : function()
11391 this.loadNext = false;
11392 this.hasFocus = true;
11394 if(this.triggerAction == 'all') {
11395 this.doQuery(this.allQuery, true);
11397 this.doQuery(this.getRawValue());
11401 listKeyPress : function(e)
11403 //Roo.log('listkeypress');
11404 // scroll to first matching element based on key pres..
11405 if (e.isSpecialKey()) {
11408 var k = String.fromCharCode(e.getKey()).toUpperCase();
11411 var csel = this.view.getSelectedNodes();
11412 var cselitem = false;
11414 var ix = this.view.indexOf(csel[0]);
11415 cselitem = this.store.getAt(ix);
11416 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11422 this.store.each(function(v) {
11424 // start at existing selection.
11425 if (cselitem.id == v.id) {
11431 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11432 match = this.store.indexOf(v);
11438 if (match === false) {
11439 return true; // no more action?
11442 this.view.select(match);
11443 var sn = Roo.get(this.view.getSelectedNodes()[0])
11444 //sn.scrollIntoView(sn.dom.parentNode, false);
11447 onViewScroll : function(e, t){
11449 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11453 this.hasQuery = true;
11455 this.loading = this.list.select('.loading', true).first();
11457 if(this.loading === null){
11458 this.list.createChild({
11460 cls: 'loading select2-more-results select2-active',
11461 html: 'Loading more results...'
11464 this.loading = this.list.select('.loading', true).first();
11466 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11468 this.loading.hide();
11471 this.loading.show();
11476 this.loadNext = true;
11478 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11483 addItem : function(o)
11485 var dv = ''; // display value
11487 if (this.displayField) {
11488 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11490 // this is an error condition!!!
11491 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11498 var choice = this.choices.createChild({
11500 cls: 'select2-search-choice',
11509 cls: 'select2-search-choice-close',
11514 }, this.searchField);
11516 var close = choice.select('a.select2-search-choice-close', true).first()
11518 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11526 this.inputEl().dom.value = '';
11530 onRemoveItem : function(e, _self, o)
11532 e.preventDefault();
11533 var index = this.item.indexOf(o.data) * 1;
11536 Roo.log('not this item?!');
11540 this.item.splice(index, 1);
11545 this.fireEvent('remove', this, e);
11549 syncValue : function()
11551 if(!this.item.length){
11558 Roo.each(this.item, function(i){
11559 if(_this.valueField){
11560 value.push(i[_this.valueField]);
11567 this.value = value.join(',');
11569 if(this.hiddenField){
11570 this.hiddenField.dom.value = this.value;
11574 clearItem : function()
11576 if(!this.multiple){
11582 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11589 inputEl: function ()
11592 return this.searchField;
11594 return this.el.select('input.form-control',true).first();
11598 onTickableFooterButtonClick : function(e, btn, el)
11600 e.preventDefault();
11602 if(btn && btn.name == 'cancel'){
11603 this.tickItems = Roo.apply([], this.item);
11612 Roo.each(this.tickItems, function(o){
11623 * @cfg {Boolean} grow
11627 * @cfg {Number} growMin
11631 * @cfg {Number} growMax
11641 * Ext JS Library 1.1.1
11642 * Copyright(c) 2006-2007, Ext JS, LLC.
11644 * Originally Released Under LGPL - original licence link has changed is not relivant.
11647 * <script type="text/javascript">
11652 * @extends Roo.util.Observable
11653 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11654 * This class also supports single and multi selection modes. <br>
11655 * Create a data model bound view:
11657 var store = new Roo.data.Store(...);
11659 var view = new Roo.View({
11661 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11663 singleSelect: true,
11664 selectedClass: "ydataview-selected",
11668 // listen for node click?
11669 view.on("click", function(vw, index, node, e){
11670 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11674 dataModel.load("foobar.xml");
11676 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11678 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11679 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11681 * Note: old style constructor is still suported (container, template, config)
11684 * Create a new View
11685 * @param {Object} config The config object
11688 Roo.View = function(config, depreciated_tpl, depreciated_config){
11690 this.parent = false;
11692 if (typeof(depreciated_tpl) == 'undefined') {
11693 // new way.. - universal constructor.
11694 Roo.apply(this, config);
11695 this.el = Roo.get(this.el);
11698 this.el = Roo.get(config);
11699 this.tpl = depreciated_tpl;
11700 Roo.apply(this, depreciated_config);
11702 this.wrapEl = this.el.wrap().wrap();
11703 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11706 if(typeof(this.tpl) == "string"){
11707 this.tpl = new Roo.Template(this.tpl);
11709 // support xtype ctors..
11710 this.tpl = new Roo.factory(this.tpl, Roo);
11714 this.tpl.compile();
11719 * @event beforeclick
11720 * Fires before a click is processed. Returns false to cancel the default action.
11721 * @param {Roo.View} this
11722 * @param {Number} index The index of the target node
11723 * @param {HTMLElement} node The target node
11724 * @param {Roo.EventObject} e The raw event object
11726 "beforeclick" : true,
11729 * Fires when a template node is clicked.
11730 * @param {Roo.View} this
11731 * @param {Number} index The index of the target node
11732 * @param {HTMLElement} node The target node
11733 * @param {Roo.EventObject} e The raw event object
11738 * Fires when a template node is double clicked.
11739 * @param {Roo.View} this
11740 * @param {Number} index The index of the target node
11741 * @param {HTMLElement} node The target node
11742 * @param {Roo.EventObject} e The raw event object
11746 * @event contextmenu
11747 * Fires when a template node is right clicked.
11748 * @param {Roo.View} this
11749 * @param {Number} index The index of the target node
11750 * @param {HTMLElement} node The target node
11751 * @param {Roo.EventObject} e The raw event object
11753 "contextmenu" : true,
11755 * @event selectionchange
11756 * Fires when the selected nodes change.
11757 * @param {Roo.View} this
11758 * @param {Array} selections Array of the selected nodes
11760 "selectionchange" : true,
11763 * @event beforeselect
11764 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11765 * @param {Roo.View} this
11766 * @param {HTMLElement} node The node to be selected
11767 * @param {Array} selections Array of currently selected nodes
11769 "beforeselect" : true,
11771 * @event preparedata
11772 * Fires on every row to render, to allow you to change the data.
11773 * @param {Roo.View} this
11774 * @param {Object} data to be rendered (change this)
11776 "preparedata" : true
11784 "click": this.onClick,
11785 "dblclick": this.onDblClick,
11786 "contextmenu": this.onContextMenu,
11790 this.selections = [];
11792 this.cmp = new Roo.CompositeElementLite([]);
11794 this.store = Roo.factory(this.store, Roo.data);
11795 this.setStore(this.store, true);
11798 if ( this.footer && this.footer.xtype) {
11800 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11802 this.footer.dataSource = this.store
11803 this.footer.container = fctr;
11804 this.footer = Roo.factory(this.footer, Roo);
11805 fctr.insertFirst(this.el);
11807 // this is a bit insane - as the paging toolbar seems to detach the el..
11808 // dom.parentNode.parentNode.parentNode
11809 // they get detached?
11813 Roo.View.superclass.constructor.call(this);
11818 Roo.extend(Roo.View, Roo.util.Observable, {
11821 * @cfg {Roo.data.Store} store Data store to load data from.
11826 * @cfg {String|Roo.Element} el The container element.
11831 * @cfg {String|Roo.Template} tpl The template used by this View
11835 * @cfg {String} dataName the named area of the template to use as the data area
11836 * Works with domtemplates roo-name="name"
11840 * @cfg {String} selectedClass The css class to add to selected nodes
11842 selectedClass : "x-view-selected",
11844 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11849 * @cfg {String} text to display on mask (default Loading)
11853 * @cfg {Boolean} multiSelect Allow multiple selection
11855 multiSelect : false,
11857 * @cfg {Boolean} singleSelect Allow single selection
11859 singleSelect: false,
11862 * @cfg {Boolean} toggleSelect - selecting
11864 toggleSelect : false,
11867 * @cfg {Boolean} tickable - selecting
11872 * Returns the element this view is bound to.
11873 * @return {Roo.Element}
11875 getEl : function(){
11876 return this.wrapEl;
11882 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11884 refresh : function(){
11885 Roo.log('refresh');
11888 // if we are using something like 'domtemplate', then
11889 // the what gets used is:
11890 // t.applySubtemplate(NAME, data, wrapping data..)
11891 // the outer template then get' applied with
11892 // the store 'extra data'
11893 // and the body get's added to the
11894 // roo-name="data" node?
11895 // <span class='roo-tpl-{name}'></span> ?????
11899 this.clearSelections();
11900 this.el.update("");
11902 var records = this.store.getRange();
11903 if(records.length < 1) {
11905 // is this valid?? = should it render a template??
11907 this.el.update(this.emptyText);
11911 if (this.dataName) {
11912 this.el.update(t.apply(this.store.meta)); //????
11913 el = this.el.child('.roo-tpl-' + this.dataName);
11916 for(var i = 0, len = records.length; i < len; i++){
11917 var data = this.prepareData(records[i].data, i, records[i]);
11918 this.fireEvent("preparedata", this, data, i, records[i]);
11920 var d = Roo.apply({}, data);
11923 Roo.apply(d, {'roo-id' : Roo.id()});
11927 Roo.each(this.parent.item, function(item){
11928 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11931 Roo.apply(d, {'roo-data-checked' : 'checked'});
11935 html[html.length] = Roo.util.Format.trim(
11937 t.applySubtemplate(this.dataName, d, this.store.meta) :
11944 el.update(html.join(""));
11945 this.nodes = el.dom.childNodes;
11946 this.updateIndexes(0);
11951 * Function to override to reformat the data that is sent to
11952 * the template for each node.
11953 * DEPRICATED - use the preparedata event handler.
11954 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11955 * a JSON object for an UpdateManager bound view).
11957 prepareData : function(data, index, record)
11959 this.fireEvent("preparedata", this, data, index, record);
11963 onUpdate : function(ds, record){
11964 Roo.log('on update');
11965 this.clearSelections();
11966 var index = this.store.indexOf(record);
11967 var n = this.nodes[index];
11968 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11969 n.parentNode.removeChild(n);
11970 this.updateIndexes(index, index);
11976 onAdd : function(ds, records, index)
11978 Roo.log(['on Add', ds, records, index] );
11979 this.clearSelections();
11980 if(this.nodes.length == 0){
11984 var n = this.nodes[index];
11985 for(var i = 0, len = records.length; i < len; i++){
11986 var d = this.prepareData(records[i].data, i, records[i]);
11988 this.tpl.insertBefore(n, d);
11991 this.tpl.append(this.el, d);
11994 this.updateIndexes(index);
11997 onRemove : function(ds, record, index){
11998 Roo.log('onRemove');
11999 this.clearSelections();
12000 var el = this.dataName ?
12001 this.el.child('.roo-tpl-' + this.dataName) :
12004 el.dom.removeChild(this.nodes[index]);
12005 this.updateIndexes(index);
12009 * Refresh an individual node.
12010 * @param {Number} index
12012 refreshNode : function(index){
12013 this.onUpdate(this.store, this.store.getAt(index));
12016 updateIndexes : function(startIndex, endIndex){
12017 var ns = this.nodes;
12018 startIndex = startIndex || 0;
12019 endIndex = endIndex || ns.length - 1;
12020 for(var i = startIndex; i <= endIndex; i++){
12021 ns[i].nodeIndex = i;
12026 * Changes the data store this view uses and refresh the view.
12027 * @param {Store} store
12029 setStore : function(store, initial){
12030 if(!initial && this.store){
12031 this.store.un("datachanged", this.refresh);
12032 this.store.un("add", this.onAdd);
12033 this.store.un("remove", this.onRemove);
12034 this.store.un("update", this.onUpdate);
12035 this.store.un("clear", this.refresh);
12036 this.store.un("beforeload", this.onBeforeLoad);
12037 this.store.un("load", this.onLoad);
12038 this.store.un("loadexception", this.onLoad);
12042 store.on("datachanged", this.refresh, this);
12043 store.on("add", this.onAdd, this);
12044 store.on("remove", this.onRemove, this);
12045 store.on("update", this.onUpdate, this);
12046 store.on("clear", this.refresh, this);
12047 store.on("beforeload", this.onBeforeLoad, this);
12048 store.on("load", this.onLoad, this);
12049 store.on("loadexception", this.onLoad, this);
12057 * onbeforeLoad - masks the loading area.
12060 onBeforeLoad : function(store,opts)
12062 Roo.log('onBeforeLoad');
12064 this.el.update("");
12066 this.el.mask(this.mask ? this.mask : "Loading" );
12068 onLoad : function ()
12075 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12076 * @param {HTMLElement} node
12077 * @return {HTMLElement} The template node
12079 findItemFromChild : function(node){
12080 var el = this.dataName ?
12081 this.el.child('.roo-tpl-' + this.dataName,true) :
12084 if(!node || node.parentNode == el){
12087 var p = node.parentNode;
12088 while(p && p != el){
12089 if(p.parentNode == el){
12098 onClick : function(e){
12099 var item = this.findItemFromChild(e.getTarget());
12101 var index = this.indexOf(item);
12102 if(this.onItemClick(item, index, e) !== false){
12103 this.fireEvent("click", this, index, item, e);
12106 this.clearSelections();
12111 onContextMenu : function(e){
12112 var item = this.findItemFromChild(e.getTarget());
12114 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12119 onDblClick : function(e){
12120 var item = this.findItemFromChild(e.getTarget());
12122 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12126 onItemClick : function(item, index, e)
12128 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12131 if (this.toggleSelect) {
12132 var m = this.isSelected(item) ? 'unselect' : 'select';
12135 _t[m](item, true, false);
12138 if(this.multiSelect || this.singleSelect){
12139 if(this.multiSelect && e.shiftKey && this.lastSelection){
12140 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12142 this.select(item, this.multiSelect && e.ctrlKey);
12143 this.lastSelection = item;
12146 if(!this.tickable){
12147 e.preventDefault();
12155 * Get the number of selected nodes.
12158 getSelectionCount : function(){
12159 return this.selections.length;
12163 * Get the currently selected nodes.
12164 * @return {Array} An array of HTMLElements
12166 getSelectedNodes : function(){
12167 return this.selections;
12171 * Get the indexes of the selected nodes.
12174 getSelectedIndexes : function(){
12175 var indexes = [], s = this.selections;
12176 for(var i = 0, len = s.length; i < len; i++){
12177 indexes.push(s[i].nodeIndex);
12183 * Clear all selections
12184 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12186 clearSelections : function(suppressEvent){
12187 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12188 this.cmp.elements = this.selections;
12189 this.cmp.removeClass(this.selectedClass);
12190 this.selections = [];
12191 if(!suppressEvent){
12192 this.fireEvent("selectionchange", this, this.selections);
12198 * Returns true if the passed node is selected
12199 * @param {HTMLElement/Number} node The node or node index
12200 * @return {Boolean}
12202 isSelected : function(node){
12203 var s = this.selections;
12207 node = this.getNode(node);
12208 return s.indexOf(node) !== -1;
12213 * @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
12214 * @param {Boolean} keepExisting (optional) true to keep existing selections
12215 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12217 select : function(nodeInfo, keepExisting, suppressEvent){
12218 if(nodeInfo instanceof Array){
12220 this.clearSelections(true);
12222 for(var i = 0, len = nodeInfo.length; i < len; i++){
12223 this.select(nodeInfo[i], true, true);
12227 var node = this.getNode(nodeInfo);
12228 if(!node || this.isSelected(node)){
12229 return; // already selected.
12232 this.clearSelections(true);
12234 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12235 Roo.fly(node).addClass(this.selectedClass);
12236 this.selections.push(node);
12237 if(!suppressEvent){
12238 this.fireEvent("selectionchange", this, this.selections);
12246 * @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
12247 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12248 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12250 unselect : function(nodeInfo, keepExisting, suppressEvent)
12252 if(nodeInfo instanceof Array){
12253 Roo.each(this.selections, function(s) {
12254 this.unselect(s, nodeInfo);
12258 var node = this.getNode(nodeInfo);
12259 if(!node || !this.isSelected(node)){
12260 Roo.log("not selected");
12261 return; // not selected.
12265 Roo.each(this.selections, function(s) {
12267 Roo.fly(node).removeClass(this.selectedClass);
12274 this.selections= ns;
12275 this.fireEvent("selectionchange", this, this.selections);
12279 * Gets a template node.
12280 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12281 * @return {HTMLElement} The node or null if it wasn't found
12283 getNode : function(nodeInfo){
12284 if(typeof nodeInfo == "string"){
12285 return document.getElementById(nodeInfo);
12286 }else if(typeof nodeInfo == "number"){
12287 return this.nodes[nodeInfo];
12293 * Gets a range template nodes.
12294 * @param {Number} startIndex
12295 * @param {Number} endIndex
12296 * @return {Array} An array of nodes
12298 getNodes : function(start, end){
12299 var ns = this.nodes;
12300 start = start || 0;
12301 end = typeof end == "undefined" ? ns.length - 1 : end;
12304 for(var i = start; i <= end; i++){
12308 for(var i = start; i >= end; i--){
12316 * Finds the index of the passed node
12317 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12318 * @return {Number} The index of the node or -1
12320 indexOf : function(node){
12321 node = this.getNode(node);
12322 if(typeof node.nodeIndex == "number"){
12323 return node.nodeIndex;
12325 var ns = this.nodes;
12326 for(var i = 0, len = ns.length; i < len; i++){
12337 * based on jquery fullcalendar
12341 Roo.bootstrap = Roo.bootstrap || {};
12343 * @class Roo.bootstrap.Calendar
12344 * @extends Roo.bootstrap.Component
12345 * Bootstrap Calendar class
12346 * @cfg {Boolean} loadMask (true|false) default false
12347 * @cfg {Object} header generate the user specific header of the calendar, default false
12350 * Create a new Container
12351 * @param {Object} config The config object
12356 Roo.bootstrap.Calendar = function(config){
12357 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12361 * Fires when a date is selected
12362 * @param {DatePicker} this
12363 * @param {Date} date The selected date
12367 * @event monthchange
12368 * Fires when the displayed month changes
12369 * @param {DatePicker} this
12370 * @param {Date} date The selected month
12372 'monthchange': true,
12374 * @event evententer
12375 * Fires when mouse over an event
12376 * @param {Calendar} this
12377 * @param {event} Event
12379 'evententer': true,
12381 * @event eventleave
12382 * Fires when the mouse leaves an
12383 * @param {Calendar} this
12386 'eventleave': true,
12388 * @event eventclick
12389 * Fires when the mouse click an
12390 * @param {Calendar} this
12399 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12402 * @cfg {Number} startDay
12403 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12411 getAutoCreate : function(){
12414 var fc_button = function(name, corner, style, content ) {
12415 return Roo.apply({},{
12417 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12419 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12422 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12433 style : 'width:100%',
12440 cls : 'fc-header-left',
12442 fc_button('prev', 'left', 'arrow', '‹' ),
12443 fc_button('next', 'right', 'arrow', '›' ),
12444 { tag: 'span', cls: 'fc-header-space' },
12445 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12453 cls : 'fc-header-center',
12457 cls: 'fc-header-title',
12460 html : 'month / year'
12468 cls : 'fc-header-right',
12470 /* fc_button('month', 'left', '', 'month' ),
12471 fc_button('week', '', '', 'week' ),
12472 fc_button('day', 'right', '', 'day' )
12484 header = this.header;
12487 var cal_heads = function() {
12489 // fixme - handle this.
12491 for (var i =0; i < Date.dayNames.length; i++) {
12492 var d = Date.dayNames[i];
12495 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12496 html : d.substring(0,3)
12500 ret[0].cls += ' fc-first';
12501 ret[6].cls += ' fc-last';
12504 var cal_cell = function(n) {
12507 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12512 cls: 'fc-day-number',
12516 cls: 'fc-day-content',
12520 style: 'position: relative;' // height: 17px;
12532 var cal_rows = function() {
12535 for (var r = 0; r < 6; r++) {
12542 for (var i =0; i < Date.dayNames.length; i++) {
12543 var d = Date.dayNames[i];
12544 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12547 row.cn[0].cls+=' fc-first';
12548 row.cn[0].cn[0].style = 'min-height:90px';
12549 row.cn[6].cls+=' fc-last';
12553 ret[0].cls += ' fc-first';
12554 ret[4].cls += ' fc-prev-last';
12555 ret[5].cls += ' fc-last';
12562 cls: 'fc-border-separate',
12563 style : 'width:100%',
12571 cls : 'fc-first fc-last',
12589 cls : 'fc-content',
12590 style : "position: relative;",
12593 cls : 'fc-view fc-view-month fc-grid',
12594 style : 'position: relative',
12595 unselectable : 'on',
12598 cls : 'fc-event-container',
12599 style : 'position:absolute;z-index:8;top:0;left:0;'
12617 initEvents : function()
12620 throw "can not find store for calendar";
12626 style: "text-align:center",
12630 style: "background-color:white;width:50%;margin:250 auto",
12634 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12645 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12647 var size = this.el.select('.fc-content', true).first().getSize();
12648 this.maskEl.setSize(size.width, size.height);
12649 this.maskEl.enableDisplayMode("block");
12650 if(!this.loadMask){
12651 this.maskEl.hide();
12654 this.store = Roo.factory(this.store, Roo.data);
12655 this.store.on('load', this.onLoad, this);
12656 this.store.on('beforeload', this.onBeforeLoad, this);
12660 this.cells = this.el.select('.fc-day',true);
12661 //Roo.log(this.cells);
12662 this.textNodes = this.el.query('.fc-day-number');
12663 this.cells.addClassOnOver('fc-state-hover');
12665 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12666 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12667 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12668 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12670 this.on('monthchange', this.onMonthChange, this);
12672 this.update(new Date().clearTime());
12675 resize : function() {
12676 var sz = this.el.getSize();
12678 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12679 this.el.select('.fc-day-content div',true).setHeight(34);
12684 showPrevMonth : function(e){
12685 this.update(this.activeDate.add("mo", -1));
12687 showToday : function(e){
12688 this.update(new Date().clearTime());
12691 showNextMonth : function(e){
12692 this.update(this.activeDate.add("mo", 1));
12696 showPrevYear : function(){
12697 this.update(this.activeDate.add("y", -1));
12701 showNextYear : function(){
12702 this.update(this.activeDate.add("y", 1));
12707 update : function(date)
12709 var vd = this.activeDate;
12710 this.activeDate = date;
12711 // if(vd && this.el){
12712 // var t = date.getTime();
12713 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12714 // Roo.log('using add remove');
12716 // this.fireEvent('monthchange', this, date);
12718 // this.cells.removeClass("fc-state-highlight");
12719 // this.cells.each(function(c){
12720 // if(c.dateValue == t){
12721 // c.addClass("fc-state-highlight");
12722 // setTimeout(function(){
12723 // try{c.dom.firstChild.focus();}catch(e){}
12733 var days = date.getDaysInMonth();
12735 var firstOfMonth = date.getFirstDateOfMonth();
12736 var startingPos = firstOfMonth.getDay()-this.startDay;
12738 if(startingPos < this.startDay){
12742 var pm = date.add(Date.MONTH, -1);
12743 var prevStart = pm.getDaysInMonth()-startingPos;
12745 this.cells = this.el.select('.fc-day',true);
12746 this.textNodes = this.el.query('.fc-day-number');
12747 this.cells.addClassOnOver('fc-state-hover');
12749 var cells = this.cells.elements;
12750 var textEls = this.textNodes;
12752 Roo.each(cells, function(cell){
12753 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12756 days += startingPos;
12758 // convert everything to numbers so it's fast
12759 var day = 86400000;
12760 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12763 //Roo.log(prevStart);
12765 var today = new Date().clearTime().getTime();
12766 var sel = date.clearTime().getTime();
12767 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12768 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12769 var ddMatch = this.disabledDatesRE;
12770 var ddText = this.disabledDatesText;
12771 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12772 var ddaysText = this.disabledDaysText;
12773 var format = this.format;
12775 var setCellClass = function(cal, cell){
12779 //Roo.log('set Cell Class');
12781 var t = d.getTime();
12785 cell.dateValue = t;
12787 cell.className += " fc-today";
12788 cell.className += " fc-state-highlight";
12789 cell.title = cal.todayText;
12792 // disable highlight in other month..
12793 //cell.className += " fc-state-highlight";
12798 cell.className = " fc-state-disabled";
12799 cell.title = cal.minText;
12803 cell.className = " fc-state-disabled";
12804 cell.title = cal.maxText;
12808 if(ddays.indexOf(d.getDay()) != -1){
12809 cell.title = ddaysText;
12810 cell.className = " fc-state-disabled";
12813 if(ddMatch && format){
12814 var fvalue = d.dateFormat(format);
12815 if(ddMatch.test(fvalue)){
12816 cell.title = ddText.replace("%0", fvalue);
12817 cell.className = " fc-state-disabled";
12821 if (!cell.initialClassName) {
12822 cell.initialClassName = cell.dom.className;
12825 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12830 for(; i < startingPos; i++) {
12831 textEls[i].innerHTML = (++prevStart);
12832 d.setDate(d.getDate()+1);
12834 cells[i].className = "fc-past fc-other-month";
12835 setCellClass(this, cells[i]);
12840 for(; i < days; i++){
12841 intDay = i - startingPos + 1;
12842 textEls[i].innerHTML = (intDay);
12843 d.setDate(d.getDate()+1);
12845 cells[i].className = ''; // "x-date-active";
12846 setCellClass(this, cells[i]);
12850 for(; i < 42; i++) {
12851 textEls[i].innerHTML = (++extraDays);
12852 d.setDate(d.getDate()+1);
12854 cells[i].className = "fc-future fc-other-month";
12855 setCellClass(this, cells[i]);
12858 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12860 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12862 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12863 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12865 if(totalRows != 6){
12866 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12867 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12870 this.fireEvent('monthchange', this, date);
12874 if(!this.internalRender){
12875 var main = this.el.dom.firstChild;
12876 var w = main.offsetWidth;
12877 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12878 Roo.fly(main).setWidth(w);
12879 this.internalRender = true;
12880 // opera does not respect the auto grow header center column
12881 // then, after it gets a width opera refuses to recalculate
12882 // without a second pass
12883 if(Roo.isOpera && !this.secondPass){
12884 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12885 this.secondPass = true;
12886 this.update.defer(10, this, [date]);
12893 findCell : function(dt) {
12894 dt = dt.clearTime().getTime();
12896 this.cells.each(function(c){
12897 //Roo.log("check " +c.dateValue + '?=' + dt);
12898 if(c.dateValue == dt){
12908 findCells : function(ev) {
12909 var s = ev.start.clone().clearTime().getTime();
12911 var e= ev.end.clone().clearTime().getTime();
12914 this.cells.each(function(c){
12915 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12917 if(c.dateValue > e){
12920 if(c.dateValue < s){
12929 // findBestRow: function(cells)
12933 // for (var i =0 ; i < cells.length;i++) {
12934 // ret = Math.max(cells[i].rows || 0,ret);
12941 addItem : function(ev)
12943 // look for vertical location slot in
12944 var cells = this.findCells(ev);
12946 // ev.row = this.findBestRow(cells);
12948 // work out the location.
12952 for(var i =0; i < cells.length; i++) {
12954 cells[i].row = cells[0].row;
12957 cells[i].row = cells[i].row + 1;
12967 if (crow.start.getY() == cells[i].getY()) {
12969 crow.end = cells[i];
12986 cells[0].events.push(ev);
12988 this.calevents.push(ev);
12991 clearEvents: function() {
12993 if(!this.calevents){
12997 Roo.each(this.cells.elements, function(c){
13003 Roo.each(this.calevents, function(e) {
13004 Roo.each(e.els, function(el) {
13005 el.un('mouseenter' ,this.onEventEnter, this);
13006 el.un('mouseleave' ,this.onEventLeave, this);
13011 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13017 renderEvents: function()
13021 this.cells.each(function(c) {
13030 if(c.row != c.events.length){
13031 r = 4 - (4 - (c.row - c.events.length));
13034 c.events = ev.slice(0, r);
13035 c.more = ev.slice(r);
13037 if(c.more.length && c.more.length == 1){
13038 c.events.push(c.more.pop());
13041 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13045 this.cells.each(function(c) {
13047 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13050 for (var e = 0; e < c.events.length; e++){
13051 var ev = c.events[e];
13052 var rows = ev.rows;
13054 for(var i = 0; i < rows.length; i++) {
13056 // how many rows should it span..
13059 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13060 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13062 unselectable : "on",
13065 cls: 'fc-event-inner',
13069 // cls: 'fc-event-time',
13070 // html : cells.length > 1 ? '' : ev.time
13074 cls: 'fc-event-title',
13075 html : String.format('{0}', ev.title)
13082 cls: 'ui-resizable-handle ui-resizable-e',
13083 html : '  '
13090 cfg.cls += ' fc-event-start';
13092 if ((i+1) == rows.length) {
13093 cfg.cls += ' fc-event-end';
13096 var ctr = _this.el.select('.fc-event-container',true).first();
13097 var cg = ctr.createChild(cfg);
13099 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13100 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13102 var r = (c.more.length) ? 1 : 0;
13103 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13104 cg.setWidth(ebox.right - sbox.x -2);
13106 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13107 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13108 cg.on('click', _this.onEventClick, _this, ev);
13119 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13120 style : 'position: absolute',
13121 unselectable : "on",
13124 cls: 'fc-event-inner',
13128 cls: 'fc-event-title',
13136 cls: 'ui-resizable-handle ui-resizable-e',
13137 html : '  '
13143 var ctr = _this.el.select('.fc-event-container',true).first();
13144 var cg = ctr.createChild(cfg);
13146 var sbox = c.select('.fc-day-content',true).first().getBox();
13147 var ebox = c.select('.fc-day-content',true).first().getBox();
13149 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13150 cg.setWidth(ebox.right - sbox.x -2);
13152 cg.on('click', _this.onMoreEventClick, _this, c.more);
13162 onEventEnter: function (e, el,event,d) {
13163 this.fireEvent('evententer', this, el, event);
13166 onEventLeave: function (e, el,event,d) {
13167 this.fireEvent('eventleave', this, el, event);
13170 onEventClick: function (e, el,event,d) {
13171 this.fireEvent('eventclick', this, el, event);
13174 onMonthChange: function () {
13178 onMoreEventClick: function(e, el, more)
13182 this.calpopover.placement = 'right';
13183 this.calpopover.setTitle('More');
13185 this.calpopover.setContent('');
13187 var ctr = this.calpopover.el.select('.popover-content', true).first();
13189 Roo.each(more, function(m){
13191 cls : 'fc-event-hori fc-event-draggable',
13194 var cg = ctr.createChild(cfg);
13196 cg.on('click', _this.onEventClick, _this, m);
13199 this.calpopover.show(el);
13204 onLoad: function ()
13206 this.calevents = [];
13209 if(this.store.getCount() > 0){
13210 this.store.data.each(function(d){
13213 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13214 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13215 time : d.data.start_time,
13216 title : d.data.title,
13217 description : d.data.description,
13218 venue : d.data.venue
13223 this.renderEvents();
13225 if(this.calevents.length && this.loadMask){
13226 this.maskEl.hide();
13230 onBeforeLoad: function()
13232 this.clearEvents();
13234 this.maskEl.show();
13248 * @class Roo.bootstrap.Popover
13249 * @extends Roo.bootstrap.Component
13250 * Bootstrap Popover class
13251 * @cfg {String} html contents of the popover (or false to use children..)
13252 * @cfg {String} title of popover (or false to hide)
13253 * @cfg {String} placement how it is placed
13254 * @cfg {String} trigger click || hover (or false to trigger manually)
13255 * @cfg {String} over what (parent or false to trigger manually.)
13258 * Create a new Popover
13259 * @param {Object} config The config object
13262 Roo.bootstrap.Popover = function(config){
13263 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13266 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13268 title: 'Fill in a title',
13271 placement : 'right',
13272 trigger : 'hover', // hover
13276 can_build_overlaid : false,
13278 getChildContainer : function()
13280 return this.el.select('.popover-content',true).first();
13283 getAutoCreate : function(){
13284 Roo.log('make popover?');
13286 cls : 'popover roo-dynamic',
13287 style: 'display:block',
13293 cls : 'popover-inner',
13297 cls: 'popover-title',
13301 cls : 'popover-content',
13312 setTitle: function(str)
13314 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13316 setContent: function(str)
13318 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13320 // as it get's added to the bottom of the page.
13321 onRender : function(ct, position)
13323 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13325 var cfg = Roo.apply({}, this.getAutoCreate());
13329 cfg.cls += ' ' + this.cls;
13332 cfg.style = this.style;
13334 Roo.log("adding to ")
13335 this.el = Roo.get(document.body).createChild(cfg, position);
13341 initEvents : function()
13343 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13344 this.el.enableDisplayMode('block');
13346 if (this.over === false) {
13349 if (this.triggers === false) {
13352 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13353 var triggers = this.trigger ? this.trigger.split(' ') : [];
13354 Roo.each(triggers, function(trigger) {
13356 if (trigger == 'click') {
13357 on_el.on('click', this.toggle, this);
13358 } else if (trigger != 'manual') {
13359 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13360 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13362 on_el.on(eventIn ,this.enter, this);
13363 on_el.on(eventOut, this.leave, this);
13374 toggle : function () {
13375 this.hoverState == 'in' ? this.leave() : this.enter();
13378 enter : function () {
13381 clearTimeout(this.timeout);
13383 this.hoverState = 'in'
13385 if (!this.delay || !this.delay.show) {
13390 this.timeout = setTimeout(function () {
13391 if (_t.hoverState == 'in') {
13394 }, this.delay.show)
13396 leave : function() {
13397 clearTimeout(this.timeout);
13399 this.hoverState = 'out'
13401 if (!this.delay || !this.delay.hide) {
13406 this.timeout = setTimeout(function () {
13407 if (_t.hoverState == 'out') {
13410 }, this.delay.hide)
13413 show : function (on_el)
13416 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13419 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13420 if (this.html !== false) {
13421 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13423 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13424 if (!this.title.length) {
13425 this.el.select('.popover-title',true).hide();
13428 var placement = typeof this.placement == 'function' ?
13429 this.placement.call(this, this.el, on_el) :
13432 var autoToken = /\s?auto?\s?/i;
13433 var autoPlace = autoToken.test(placement);
13435 placement = placement.replace(autoToken, '') || 'top';
13439 //this.el.setXY([0,0]);
13441 this.el.dom.style.display='block';
13442 this.el.addClass(placement);
13444 //this.el.appendTo(on_el);
13446 var p = this.getPosition();
13447 var box = this.el.getBox();
13452 var align = Roo.bootstrap.Popover.alignment[placement]
13453 this.el.alignTo(on_el, align[0],align[1]);
13454 //var arrow = this.el.select('.arrow',true).first();
13455 //arrow.set(align[2],
13457 this.el.addClass('in');
13458 this.hoverState = null;
13460 if (this.el.hasClass('fade')) {
13467 this.el.setXY([0,0]);
13468 this.el.removeClass('in');
13475 Roo.bootstrap.Popover.alignment = {
13476 'left' : ['r-l', [-10,0], 'right'],
13477 'right' : ['l-r', [10,0], 'left'],
13478 'bottom' : ['t-b', [0,10], 'top'],
13479 'top' : [ 'b-t', [0,-10], 'bottom']
13490 * @class Roo.bootstrap.Progress
13491 * @extends Roo.bootstrap.Component
13492 * Bootstrap Progress class
13493 * @cfg {Boolean} striped striped of the progress bar
13494 * @cfg {Boolean} active animated of the progress bar
13498 * Create a new Progress
13499 * @param {Object} config The config object
13502 Roo.bootstrap.Progress = function(config){
13503 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13506 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13511 getAutoCreate : function(){
13519 cfg.cls += ' progress-striped';
13523 cfg.cls += ' active';
13542 * @class Roo.bootstrap.ProgressBar
13543 * @extends Roo.bootstrap.Component
13544 * Bootstrap ProgressBar class
13545 * @cfg {Number} aria_valuenow aria-value now
13546 * @cfg {Number} aria_valuemin aria-value min
13547 * @cfg {Number} aria_valuemax aria-value max
13548 * @cfg {String} label label for the progress bar
13549 * @cfg {String} panel (success | info | warning | danger )
13550 * @cfg {String} role role of the progress bar
13551 * @cfg {String} sr_only text
13555 * Create a new ProgressBar
13556 * @param {Object} config The config object
13559 Roo.bootstrap.ProgressBar = function(config){
13560 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13563 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13567 aria_valuemax : 100,
13573 getAutoCreate : function()
13578 cls: 'progress-bar',
13579 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13591 cfg.role = this.role;
13594 if(this.aria_valuenow){
13595 cfg['aria-valuenow'] = this.aria_valuenow;
13598 if(this.aria_valuemin){
13599 cfg['aria-valuemin'] = this.aria_valuemin;
13602 if(this.aria_valuemax){
13603 cfg['aria-valuemax'] = this.aria_valuemax;
13606 if(this.label && !this.sr_only){
13607 cfg.html = this.label;
13611 cfg.cls += ' progress-bar-' + this.panel;
13617 update : function(aria_valuenow)
13619 this.aria_valuenow = aria_valuenow;
13621 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13636 * @class Roo.bootstrap.TabPanel
13637 * @extends Roo.bootstrap.Component
13638 * Bootstrap TabPanel class
13639 * @cfg {Boolean} active panel active
13640 * @cfg {String} html panel content
13641 * @cfg {String} tabId tab relate id
13642 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13646 * Create a new TabPanel
13647 * @param {Object} config The config object
13650 Roo.bootstrap.TabPanel = function(config){
13651 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13655 * Fires when the active status changes
13656 * @param {Roo.bootstrap.TabPanel} this
13657 * @param {Boolean} state the new state
13664 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13671 getAutoCreate : function(){
13675 html: this.html || ''
13679 cfg.cls += ' active';
13683 cfg.tabId = this.tabId;
13688 onRender : function(ct, position)
13690 // Roo.log("Call onRender: " + this.xtype);
13692 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13694 if (this.navId && this.tabId) {
13695 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13697 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13699 item.on('changed', function(item, state) {
13700 this.setActive(state);
13706 setActive: function(state)
13708 Roo.log("panel - set active " + this.tabId + "=" + state);
13710 this.active = state;
13712 this.el.removeClass('active');
13714 } else if (!this.el.hasClass('active')) {
13715 this.el.addClass('active');
13717 this.fireEvent('changed', this, state);
13734 * @class Roo.bootstrap.DateField
13735 * @extends Roo.bootstrap.Input
13736 * Bootstrap DateField class
13737 * @cfg {Number} weekStart default 0
13738 * @cfg {Number} weekStart default 0
13739 * @cfg {Number} viewMode default empty, (months|years)
13740 * @cfg {Number} minViewMode default empty, (months|years)
13741 * @cfg {Number} startDate default -Infinity
13742 * @cfg {Number} endDate default Infinity
13743 * @cfg {Boolean} todayHighlight default false
13744 * @cfg {Boolean} todayBtn default false
13745 * @cfg {Boolean} calendarWeeks default false
13746 * @cfg {Object} daysOfWeekDisabled default empty
13748 * @cfg {Boolean} keyboardNavigation default true
13749 * @cfg {String} language default en
13752 * Create a new DateField
13753 * @param {Object} config The config object
13756 Roo.bootstrap.DateField = function(config){
13757 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13761 * Fires when this field show.
13762 * @param {Roo.bootstrap.DateField} this
13763 * @param {Mixed} date The date value
13768 * Fires when this field hide.
13769 * @param {Roo.bootstrap.DateField} this
13770 * @param {Mixed} date The date value
13775 * Fires when select a date.
13776 * @param {Roo.bootstrap.DateField} this
13777 * @param {Mixed} date The date value
13783 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13786 * @cfg {String} format
13787 * The default date format string which can be overriden for localization support. The format must be
13788 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13792 * @cfg {String} altFormats
13793 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13794 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13796 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13804 todayHighlight : false,
13810 keyboardNavigation: true,
13812 calendarWeeks: false,
13814 startDate: -Infinity,
13818 daysOfWeekDisabled: [],
13822 UTCDate: function()
13824 return new Date(Date.UTC.apply(Date, arguments));
13827 UTCToday: function()
13829 var today = new Date();
13830 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13833 getDate: function() {
13834 var d = this.getUTCDate();
13835 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13838 getUTCDate: function() {
13842 setDate: function(d) {
13843 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13846 setUTCDate: function(d) {
13848 this.setValue(this.formatDate(this.date));
13851 onRender: function(ct, position)
13854 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13856 this.language = this.language || 'en';
13857 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13858 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13860 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13861 this.format = this.format || 'm/d/y';
13862 this.isInline = false;
13863 this.isInput = true;
13864 this.component = this.el.select('.add-on', true).first() || false;
13865 this.component = (this.component && this.component.length === 0) ? false : this.component;
13866 this.hasInput = this.component && this.inputEL().length;
13868 if (typeof(this.minViewMode === 'string')) {
13869 switch (this.minViewMode) {
13871 this.minViewMode = 1;
13874 this.minViewMode = 2;
13877 this.minViewMode = 0;
13882 if (typeof(this.viewMode === 'string')) {
13883 switch (this.viewMode) {
13896 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13898 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13900 this.picker().on('mousedown', this.onMousedown, this);
13901 this.picker().on('click', this.onClick, this);
13903 this.picker().addClass('datepicker-dropdown');
13905 this.startViewMode = this.viewMode;
13908 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13909 if(!this.calendarWeeks){
13914 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13915 v.attr('colspan', function(i, val){
13916 return parseInt(val) + 1;
13921 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13923 this.setStartDate(this.startDate);
13924 this.setEndDate(this.endDate);
13926 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13933 if(this.isInline) {
13938 picker : function()
13940 return this.el.select('.datepicker', true).first();
13943 fillDow: function()
13945 var dowCnt = this.weekStart;
13954 if(this.calendarWeeks){
13962 while (dowCnt < this.weekStart + 7) {
13966 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13970 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13973 fillMonths: function()
13976 var months = this.picker().select('>.datepicker-months td', true).first();
13978 months.dom.innerHTML = '';
13984 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13987 months.createChild(month);
13995 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13997 if (this.date < this.startDate) {
13998 this.viewDate = new Date(this.startDate);
13999 } else if (this.date > this.endDate) {
14000 this.viewDate = new Date(this.endDate);
14002 this.viewDate = new Date(this.date);
14010 var d = new Date(this.viewDate),
14011 year = d.getUTCFullYear(),
14012 month = d.getUTCMonth(),
14013 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14014 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14015 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14016 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14017 currentDate = this.date && this.date.valueOf(),
14018 today = this.UTCToday();
14020 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14022 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14024 // this.picker.select('>tfoot th.today').
14025 // .text(dates[this.language].today)
14026 // .toggle(this.todayBtn !== false);
14028 this.updateNavArrows();
14031 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14033 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14035 prevMonth.setUTCDate(day);
14037 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14039 var nextMonth = new Date(prevMonth);
14041 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14043 nextMonth = nextMonth.valueOf();
14045 var fillMonths = false;
14047 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14049 while(prevMonth.valueOf() < nextMonth) {
14052 if (prevMonth.getUTCDay() === this.weekStart) {
14054 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14062 if(this.calendarWeeks){
14063 // ISO 8601: First week contains first thursday.
14064 // ISO also states week starts on Monday, but we can be more abstract here.
14066 // Start of current week: based on weekstart/current date
14067 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14068 // Thursday of this week
14069 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14070 // First Thursday of year, year from thursday
14071 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14072 // Calendar week: ms between thursdays, div ms per day, div 7 days
14073 calWeek = (th - yth) / 864e5 / 7 + 1;
14075 fillMonths.cn.push({
14083 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14085 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14088 if (this.todayHighlight &&
14089 prevMonth.getUTCFullYear() == today.getFullYear() &&
14090 prevMonth.getUTCMonth() == today.getMonth() &&
14091 prevMonth.getUTCDate() == today.getDate()) {
14092 clsName += ' today';
14095 if (currentDate && prevMonth.valueOf() === currentDate) {
14096 clsName += ' active';
14099 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14100 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14101 clsName += ' disabled';
14104 fillMonths.cn.push({
14106 cls: 'day ' + clsName,
14107 html: prevMonth.getDate()
14110 prevMonth.setDate(prevMonth.getDate()+1);
14113 var currentYear = this.date && this.date.getUTCFullYear();
14114 var currentMonth = this.date && this.date.getUTCMonth();
14116 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14118 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14119 v.removeClass('active');
14121 if(currentYear === year && k === currentMonth){
14122 v.addClass('active');
14125 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14126 v.addClass('disabled');
14132 year = parseInt(year/10, 10) * 10;
14134 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14136 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14139 for (var i = -1; i < 11; i++) {
14140 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14142 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14150 showMode: function(dir)
14153 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14155 Roo.each(this.picker().select('>div',true).elements, function(v){
14156 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14159 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14164 if(this.isInline) return;
14166 this.picker().removeClass(['bottom', 'top']);
14168 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14170 * place to the top of element!
14174 this.picker().addClass('top');
14175 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14180 this.picker().addClass('bottom');
14182 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14185 parseDate : function(value)
14187 if(!value || value instanceof Date){
14190 var v = Date.parseDate(value, this.format);
14191 if (!v && this.useIso) {
14192 v = Date.parseDate(value, 'Y-m-d');
14194 if(!v && this.altFormats){
14195 if(!this.altFormatsArray){
14196 this.altFormatsArray = this.altFormats.split("|");
14198 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14199 v = Date.parseDate(value, this.altFormatsArray[i]);
14205 formatDate : function(date, fmt)
14207 return (!date || !(date instanceof Date)) ?
14208 date : date.dateFormat(fmt || this.format);
14211 onFocus : function()
14213 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14217 onBlur : function()
14219 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14221 var d = this.inputEl().getValue();
14232 this.picker().show();
14236 this.fireEvent('show', this, this.date);
14241 if(this.isInline) return;
14242 this.picker().hide();
14243 this.viewMode = this.startViewMode;
14246 this.fireEvent('hide', this, this.date);
14250 onMousedown: function(e)
14252 e.stopPropagation();
14253 e.preventDefault();
14258 Roo.bootstrap.DateField.superclass.keyup.call(this);
14262 setValue: function(v)
14264 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14266 var d = new Date(v);
14268 if(isNaN(d.getTime())){
14272 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14276 this.fireEvent('select', this, this.date);
14280 getValue: function()
14282 return this.formatDate(this.date);
14285 fireKey: function(e)
14287 if (!this.picker().isVisible()){
14288 if (e.keyCode == 27) // allow escape to hide and re-show picker
14292 var dateChanged = false,
14294 newDate, newViewDate;
14299 e.preventDefault();
14303 if (!this.keyboardNavigation) break;
14304 dir = e.keyCode == 37 ? -1 : 1;
14307 newDate = this.moveYear(this.date, dir);
14308 newViewDate = this.moveYear(this.viewDate, dir);
14309 } else if (e.shiftKey){
14310 newDate = this.moveMonth(this.date, dir);
14311 newViewDate = this.moveMonth(this.viewDate, dir);
14313 newDate = new Date(this.date);
14314 newDate.setUTCDate(this.date.getUTCDate() + dir);
14315 newViewDate = new Date(this.viewDate);
14316 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14318 if (this.dateWithinRange(newDate)){
14319 this.date = newDate;
14320 this.viewDate = newViewDate;
14321 this.setValue(this.formatDate(this.date));
14323 e.preventDefault();
14324 dateChanged = true;
14329 if (!this.keyboardNavigation) break;
14330 dir = e.keyCode == 38 ? -1 : 1;
14332 newDate = this.moveYear(this.date, dir);
14333 newViewDate = this.moveYear(this.viewDate, dir);
14334 } else if (e.shiftKey){
14335 newDate = this.moveMonth(this.date, dir);
14336 newViewDate = this.moveMonth(this.viewDate, dir);
14338 newDate = new Date(this.date);
14339 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14340 newViewDate = new Date(this.viewDate);
14341 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14343 if (this.dateWithinRange(newDate)){
14344 this.date = newDate;
14345 this.viewDate = newViewDate;
14346 this.setValue(this.formatDate(this.date));
14348 e.preventDefault();
14349 dateChanged = true;
14353 this.setValue(this.formatDate(this.date));
14355 e.preventDefault();
14358 this.setValue(this.formatDate(this.date));
14366 onClick: function(e)
14368 e.stopPropagation();
14369 e.preventDefault();
14371 var target = e.getTarget();
14373 if(target.nodeName.toLowerCase() === 'i'){
14374 target = Roo.get(target).dom.parentNode;
14377 var nodeName = target.nodeName;
14378 var className = target.className;
14379 var html = target.innerHTML;
14381 switch(nodeName.toLowerCase()) {
14383 switch(className) {
14389 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14390 switch(this.viewMode){
14392 this.viewDate = this.moveMonth(this.viewDate, dir);
14396 this.viewDate = this.moveYear(this.viewDate, dir);
14402 var date = new Date();
14403 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14405 this.setValue(this.formatDate(this.date));
14412 if (className.indexOf('disabled') === -1) {
14413 this.viewDate.setUTCDate(1);
14414 if (className.indexOf('month') !== -1) {
14415 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14417 var year = parseInt(html, 10) || 0;
14418 this.viewDate.setUTCFullYear(year);
14427 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14428 var day = parseInt(html, 10) || 1;
14429 var year = this.viewDate.getUTCFullYear(),
14430 month = this.viewDate.getUTCMonth();
14432 if (className.indexOf('old') !== -1) {
14439 } else if (className.indexOf('new') !== -1) {
14447 this.date = this.UTCDate(year, month, day,0,0,0,0);
14448 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14450 this.setValue(this.formatDate(this.date));
14457 setStartDate: function(startDate)
14459 this.startDate = startDate || -Infinity;
14460 if (this.startDate !== -Infinity) {
14461 this.startDate = this.parseDate(this.startDate);
14464 this.updateNavArrows();
14467 setEndDate: function(endDate)
14469 this.endDate = endDate || Infinity;
14470 if (this.endDate !== Infinity) {
14471 this.endDate = this.parseDate(this.endDate);
14474 this.updateNavArrows();
14477 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14479 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14480 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14481 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14483 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14484 return parseInt(d, 10);
14487 this.updateNavArrows();
14490 updateNavArrows: function()
14492 var d = new Date(this.viewDate),
14493 year = d.getUTCFullYear(),
14494 month = d.getUTCMonth();
14496 Roo.each(this.picker().select('.prev', true).elements, function(v){
14498 switch (this.viewMode) {
14501 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14507 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14514 Roo.each(this.picker().select('.next', true).elements, function(v){
14516 switch (this.viewMode) {
14519 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14525 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14533 moveMonth: function(date, dir)
14535 if (!dir) return date;
14536 var new_date = new Date(date.valueOf()),
14537 day = new_date.getUTCDate(),
14538 month = new_date.getUTCMonth(),
14539 mag = Math.abs(dir),
14541 dir = dir > 0 ? 1 : -1;
14544 // If going back one month, make sure month is not current month
14545 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14547 return new_date.getUTCMonth() == month;
14549 // If going forward one month, make sure month is as expected
14550 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14552 return new_date.getUTCMonth() != new_month;
14554 new_month = month + dir;
14555 new_date.setUTCMonth(new_month);
14556 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14557 if (new_month < 0 || new_month > 11)
14558 new_month = (new_month + 12) % 12;
14560 // For magnitudes >1, move one month at a time...
14561 for (var i=0; i<mag; i++)
14562 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14563 new_date = this.moveMonth(new_date, dir);
14564 // ...then reset the day, keeping it in the new month
14565 new_month = new_date.getUTCMonth();
14566 new_date.setUTCDate(day);
14568 return new_month != new_date.getUTCMonth();
14571 // Common date-resetting loop -- if date is beyond end of month, make it
14574 new_date.setUTCDate(--day);
14575 new_date.setUTCMonth(new_month);
14580 moveYear: function(date, dir)
14582 return this.moveMonth(date, dir*12);
14585 dateWithinRange: function(date)
14587 return date >= this.startDate && date <= this.endDate;
14593 this.picker().remove();
14598 Roo.apply(Roo.bootstrap.DateField, {
14609 html: '<i class="fa fa-arrow-left"/>'
14619 html: '<i class="fa fa-arrow-right"/>'
14661 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14662 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14663 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14664 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14665 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14678 navFnc: 'FullYear',
14683 navFnc: 'FullYear',
14688 Roo.apply(Roo.bootstrap.DateField, {
14692 cls: 'datepicker dropdown-menu',
14696 cls: 'datepicker-days',
14700 cls: 'table-condensed',
14702 Roo.bootstrap.DateField.head,
14706 Roo.bootstrap.DateField.footer
14713 cls: 'datepicker-months',
14717 cls: 'table-condensed',
14719 Roo.bootstrap.DateField.head,
14720 Roo.bootstrap.DateField.content,
14721 Roo.bootstrap.DateField.footer
14728 cls: 'datepicker-years',
14732 cls: 'table-condensed',
14734 Roo.bootstrap.DateField.head,
14735 Roo.bootstrap.DateField.content,
14736 Roo.bootstrap.DateField.footer
14755 * @class Roo.bootstrap.TimeField
14756 * @extends Roo.bootstrap.Input
14757 * Bootstrap DateField class
14761 * Create a new TimeField
14762 * @param {Object} config The config object
14765 Roo.bootstrap.TimeField = function(config){
14766 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14770 * Fires when this field show.
14771 * @param {Roo.bootstrap.DateField} this
14772 * @param {Mixed} date The date value
14777 * Fires when this field hide.
14778 * @param {Roo.bootstrap.DateField} this
14779 * @param {Mixed} date The date value
14784 * Fires when select a date.
14785 * @param {Roo.bootstrap.DateField} this
14786 * @param {Mixed} date The date value
14792 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14795 * @cfg {String} format
14796 * The default time format string which can be overriden for localization support. The format must be
14797 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14801 onRender: function(ct, position)
14804 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14806 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14808 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14810 this.pop = this.picker().select('>.datepicker-time',true).first();
14811 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14813 this.picker().on('mousedown', this.onMousedown, this);
14814 this.picker().on('click', this.onClick, this);
14816 this.picker().addClass('datepicker-dropdown');
14821 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14822 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14823 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14824 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14825 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14826 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14830 fireKey: function(e){
14831 if (!this.picker().isVisible()){
14832 if (e.keyCode == 27) // allow escape to hide and re-show picker
14837 e.preventDefault();
14845 this.onTogglePeriod();
14848 this.onIncrementMinutes();
14851 this.onDecrementMinutes();
14860 onClick: function(e) {
14861 e.stopPropagation();
14862 e.preventDefault();
14865 picker : function()
14867 return this.el.select('.datepicker', true).first();
14870 fillTime: function()
14872 var time = this.pop.select('tbody', true).first();
14874 time.dom.innerHTML = '';
14889 cls: 'hours-up glyphicon glyphicon-chevron-up'
14909 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14930 cls: 'timepicker-hour',
14945 cls: 'timepicker-minute',
14960 cls: 'btn btn-primary period',
14982 cls: 'hours-down glyphicon glyphicon-chevron-down'
15002 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15020 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15027 var hours = this.time.getHours();
15028 var minutes = this.time.getMinutes();
15041 hours = hours - 12;
15045 hours = '0' + hours;
15049 minutes = '0' + minutes;
15052 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15053 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15054 this.pop.select('button', true).first().dom.innerHTML = period;
15060 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15062 var cls = ['bottom'];
15064 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15071 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15076 this.picker().addClass(cls.join('-'));
15080 Roo.each(cls, function(c){
15082 _this.picker().setTop(_this.inputEl().getHeight());
15086 _this.picker().setTop(0 - _this.picker().getHeight());
15091 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15095 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15102 onFocus : function()
15104 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15108 onBlur : function()
15110 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15116 this.picker().show();
15121 this.fireEvent('show', this, this.date);
15126 this.picker().hide();
15129 this.fireEvent('hide', this, this.date);
15132 setTime : function()
15135 this.setValue(this.time.format(this.format));
15137 this.fireEvent('select', this, this.date);
15142 onMousedown: function(e){
15143 e.stopPropagation();
15144 e.preventDefault();
15147 onIncrementHours: function()
15149 Roo.log('onIncrementHours');
15150 this.time = this.time.add(Date.HOUR, 1);
15155 onDecrementHours: function()
15157 Roo.log('onDecrementHours');
15158 this.time = this.time.add(Date.HOUR, -1);
15162 onIncrementMinutes: function()
15164 Roo.log('onIncrementMinutes');
15165 this.time = this.time.add(Date.MINUTE, 1);
15169 onDecrementMinutes: function()
15171 Roo.log('onDecrementMinutes');
15172 this.time = this.time.add(Date.MINUTE, -1);
15176 onTogglePeriod: function()
15178 Roo.log('onTogglePeriod');
15179 this.time = this.time.add(Date.HOUR, 12);
15186 Roo.apply(Roo.bootstrap.TimeField, {
15216 cls: 'btn btn-info ok',
15228 Roo.apply(Roo.bootstrap.TimeField, {
15232 cls: 'datepicker dropdown-menu',
15236 cls: 'datepicker-time',
15240 cls: 'table-condensed',
15242 Roo.bootstrap.TimeField.content,
15243 Roo.bootstrap.TimeField.footer
15262 * @class Roo.bootstrap.CheckBox
15263 * @extends Roo.bootstrap.Input
15264 * Bootstrap CheckBox class
15266 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15267 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15268 * @cfg {String} boxLabel The text that appears beside the checkbox
15269 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15270 * @cfg {Boolean} checked initnal the element
15274 * Create a new CheckBox
15275 * @param {Object} config The config object
15278 Roo.bootstrap.CheckBox = function(config){
15279 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15284 * Fires when the element is checked or unchecked.
15285 * @param {Roo.bootstrap.CheckBox} this This input
15286 * @param {Boolean} checked The new checked value
15292 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15294 inputType: 'checkbox',
15301 getAutoCreate : function()
15303 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15309 cfg.cls = 'form-group checkbox' //input-group
15317 type : this.inputType,
15318 value : (!this.checked) ? this.valueOff : this.inputValue,
15319 cls : 'roo-checkbox', //'form-box',
15320 placeholder : this.placeholder || ''
15324 if (this.weight) { // Validity check?
15325 cfg.cls += " checkbox-" + this.weight;
15328 if (this.disabled) {
15329 input.disabled=true;
15333 input.checked = this.checked;
15337 input.name = this.name;
15341 input.cls += ' input-' + this.size;
15345 ['xs','sm','md','lg'].map(function(size){
15346 if (settings[size]) {
15347 cfg.cls += ' col-' + size + '-' + settings[size];
15353 var inputblock = input;
15358 if (this.before || this.after) {
15361 cls : 'input-group',
15365 inputblock.cn.push({
15367 cls : 'input-group-addon',
15371 inputblock.cn.push(input);
15373 inputblock.cn.push({
15375 cls : 'input-group-addon',
15382 if (align ==='left' && this.fieldLabel.length) {
15383 Roo.log("left and has label");
15389 cls : 'control-label col-md-' + this.labelWidth,
15390 html : this.fieldLabel
15394 cls : "col-md-" + (12 - this.labelWidth),
15401 } else if ( this.fieldLabel.length) {
15406 tag: this.boxLabel ? 'span' : 'label',
15408 cls: 'control-label box-input-label',
15409 //cls : 'input-group-addon',
15410 html : this.fieldLabel
15420 Roo.log(" no label && no align");
15421 cfg.cn = [ inputblock ] ;
15430 html: this.boxLabel
15442 * return the real input element.
15444 inputEl: function ()
15446 return this.el.select('input.roo-checkbox',true).first();
15451 return this.el.select('label.control-label',true).first();
15454 initEvents : function()
15456 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15458 this.inputEl().on('click', this.onClick, this);
15462 onClick : function()
15464 this.setChecked(!this.checked);
15467 setChecked : function(state,suppressEvent)
15469 this.checked = state;
15471 this.inputEl().dom.checked = state;
15473 if(suppressEvent !== true){
15474 this.fireEvent('check', this, state);
15477 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15481 setValue : function(v,suppressEvent)
15483 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15497 * @class Roo.bootstrap.Radio
15498 * @extends Roo.bootstrap.CheckBox
15499 * Bootstrap Radio class
15502 * Create a new Radio
15503 * @param {Object} config The config object
15506 Roo.bootstrap.Radio = function(config){
15507 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15511 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15513 inputType: 'radio',
15517 getAutoCreate : function()
15519 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15525 cfg.cls = 'form-group radio' //input-group
15530 type : this.inputType,
15531 value : (!this.checked) ? this.valueOff : this.inputValue,
15533 placeholder : this.placeholder || ''
15536 if (this.weight) { // Validity check?
15537 cfg.cls += " radio-" + this.weight;
15539 if (this.disabled) {
15540 input.disabled=true;
15544 input.checked = this.checked;
15548 input.name = this.name;
15552 input.cls += ' input-' + this.size;
15556 ['xs','sm','md','lg'].map(function(size){
15557 if (settings[size]) {
15558 cfg.cls += ' col-' + size + '-' + settings[size];
15562 var inputblock = input;
15564 if (this.before || this.after) {
15567 cls : 'input-group',
15571 inputblock.cn.push({
15573 cls : 'input-group-addon',
15577 inputblock.cn.push(input);
15579 inputblock.cn.push({
15581 cls : 'input-group-addon',
15588 if (align ==='left' && this.fieldLabel.length) {
15589 Roo.log("left and has label");
15595 cls : 'control-label col-md-' + this.labelWidth,
15596 html : this.fieldLabel
15600 cls : "col-md-" + (12 - this.labelWidth),
15607 } else if ( this.fieldLabel.length) {
15614 cls: 'control-label box-input-label',
15615 //cls : 'input-group-addon',
15616 html : this.fieldLabel
15626 Roo.log(" no label && no align");
15641 html: this.boxLabel
15648 inputEl: function ()
15650 return this.el.select('input.roo-radio',true).first();
15652 onClick : function()
15654 this.setChecked(true);
15657 setChecked : function(state,suppressEvent)
15660 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15661 v.dom.checked = false;
15665 this.checked = state;
15666 this.inputEl().dom.checked = state;
15668 if(suppressEvent !== true){
15669 this.fireEvent('check', this, state);
15672 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15676 getGroupValue : function()
15679 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15680 if(v.dom.checked == true){
15681 value = v.dom.value;
15689 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15690 * @return {Mixed} value The field value
15692 getValue : function(){
15693 return this.getGroupValue();
15699 //<script type="text/javascript">
15702 * Based Ext JS Library 1.1.1
15703 * Copyright(c) 2006-2007, Ext JS, LLC.
15709 * @class Roo.HtmlEditorCore
15710 * @extends Roo.Component
15711 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15713 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15716 Roo.HtmlEditorCore = function(config){
15719 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15722 * @event initialize
15723 * Fires when the editor is fully initialized (including the iframe)
15724 * @param {Roo.HtmlEditorCore} this
15729 * Fires when the editor is first receives the focus. Any insertion must wait
15730 * until after this event.
15731 * @param {Roo.HtmlEditorCore} this
15735 * @event beforesync
15736 * Fires before the textarea is updated with content from the editor iframe. Return false
15737 * to cancel the sync.
15738 * @param {Roo.HtmlEditorCore} this
15739 * @param {String} html
15743 * @event beforepush
15744 * Fires before the iframe editor is updated with content from the textarea. Return false
15745 * to cancel the push.
15746 * @param {Roo.HtmlEditorCore} this
15747 * @param {String} html
15752 * Fires when the textarea is updated with content from the editor iframe.
15753 * @param {Roo.HtmlEditorCore} this
15754 * @param {String} html
15759 * Fires when the iframe editor is updated with content from the textarea.
15760 * @param {Roo.HtmlEditorCore} this
15761 * @param {String} html
15766 * @event editorevent
15767 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15768 * @param {Roo.HtmlEditorCore} this
15776 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15780 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15786 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15791 * @cfg {Number} height (in pixels)
15795 * @cfg {Number} width (in pixels)
15800 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15803 stylesheets: false,
15808 // private properties
15809 validationEvent : false,
15811 initialized : false,
15813 sourceEditMode : false,
15814 onFocus : Roo.emptyFn,
15816 hideMode:'offsets',
15824 * Protected method that will not generally be called directly. It
15825 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15826 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15828 getDocMarkup : function(){
15831 Roo.log(this.stylesheets);
15833 // inherit styels from page...??
15834 if (this.stylesheets === false) {
15836 Roo.get(document.head).select('style').each(function(node) {
15837 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15840 Roo.get(document.head).select('link').each(function(node) {
15841 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15844 } else if (!this.stylesheets.length) {
15846 st = '<style type="text/css">' +
15847 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15850 Roo.each(this.stylesheets, function(s) {
15851 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15856 st += '<style type="text/css">' +
15857 'IMG { cursor: pointer } ' +
15861 return '<html><head>' + st +
15862 //<style type="text/css">' +
15863 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15865 ' </head><body class="roo-htmleditor-body"></body></html>';
15869 onRender : function(ct, position)
15872 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15873 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15876 this.el.dom.style.border = '0 none';
15877 this.el.dom.setAttribute('tabIndex', -1);
15878 this.el.addClass('x-hidden hide');
15882 if(Roo.isIE){ // fix IE 1px bogus margin
15883 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15887 this.frameId = Roo.id();
15891 var iframe = this.owner.wrap.createChild({
15893 cls: 'form-control', // bootstrap..
15895 name: this.frameId,
15896 frameBorder : 'no',
15897 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15902 this.iframe = iframe.dom;
15904 this.assignDocWin();
15906 this.doc.designMode = 'on';
15909 this.doc.write(this.getDocMarkup());
15913 var task = { // must defer to wait for browser to be ready
15915 //console.log("run task?" + this.doc.readyState);
15916 this.assignDocWin();
15917 if(this.doc.body || this.doc.readyState == 'complete'){
15919 this.doc.designMode="on";
15923 Roo.TaskMgr.stop(task);
15924 this.initEditor.defer(10, this);
15931 Roo.TaskMgr.start(task);
15938 onResize : function(w, h)
15940 Roo.log('resize: ' +w + ',' + h );
15941 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15945 if(typeof w == 'number'){
15947 this.iframe.style.width = w + 'px';
15949 if(typeof h == 'number'){
15951 this.iframe.style.height = h + 'px';
15953 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15960 * Toggles the editor between standard and source edit mode.
15961 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15963 toggleSourceEdit : function(sourceEditMode){
15965 this.sourceEditMode = sourceEditMode === true;
15967 if(this.sourceEditMode){
15969 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15972 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15973 //this.iframe.className = '';
15976 //this.setSize(this.owner.wrap.getSize());
15977 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15984 * Protected method that will not generally be called directly. If you need/want
15985 * custom HTML cleanup, this is the method you should override.
15986 * @param {String} html The HTML to be cleaned
15987 * return {String} The cleaned HTML
15989 cleanHtml : function(html){
15990 html = String(html);
15991 if(html.length > 5){
15992 if(Roo.isSafari){ // strip safari nonsense
15993 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15996 if(html == ' '){
16003 * HTML Editor -> Textarea
16004 * Protected method that will not generally be called directly. Syncs the contents
16005 * of the editor iframe with the textarea.
16007 syncValue : function(){
16008 if(this.initialized){
16009 var bd = (this.doc.body || this.doc.documentElement);
16010 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16011 var html = bd.innerHTML;
16013 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16014 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16016 html = '<div style="'+m[0]+'">' + html + '</div>';
16019 html = this.cleanHtml(html);
16020 // fix up the special chars.. normaly like back quotes in word...
16021 // however we do not want to do this with chinese..
16022 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16023 var cc = b.charCodeAt();
16025 (cc >= 0x4E00 && cc < 0xA000 ) ||
16026 (cc >= 0x3400 && cc < 0x4E00 ) ||
16027 (cc >= 0xf900 && cc < 0xfb00 )
16033 if(this.owner.fireEvent('beforesync', this, html) !== false){
16034 this.el.dom.value = html;
16035 this.owner.fireEvent('sync', this, html);
16041 * Protected method that will not generally be called directly. Pushes the value of the textarea
16042 * into the iframe editor.
16044 pushValue : function(){
16045 if(this.initialized){
16046 var v = this.el.dom.value.trim();
16048 // if(v.length < 1){
16052 if(this.owner.fireEvent('beforepush', this, v) !== false){
16053 var d = (this.doc.body || this.doc.documentElement);
16055 this.cleanUpPaste();
16056 this.el.dom.value = d.innerHTML;
16057 this.owner.fireEvent('push', this, v);
16063 deferFocus : function(){
16064 this.focus.defer(10, this);
16068 focus : function(){
16069 if(this.win && !this.sourceEditMode){
16076 assignDocWin: function()
16078 var iframe = this.iframe;
16081 this.doc = iframe.contentWindow.document;
16082 this.win = iframe.contentWindow;
16084 if (!Roo.get(this.frameId)) {
16087 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16088 this.win = Roo.get(this.frameId).dom.contentWindow;
16093 initEditor : function(){
16094 //console.log("INIT EDITOR");
16095 this.assignDocWin();
16099 this.doc.designMode="on";
16101 this.doc.write(this.getDocMarkup());
16104 var dbody = (this.doc.body || this.doc.documentElement);
16105 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16106 // this copies styles from the containing element into thsi one..
16107 // not sure why we need all of this..
16108 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16110 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16111 //ss['background-attachment'] = 'fixed'; // w3c
16112 dbody.bgProperties = 'fixed'; // ie
16113 //Roo.DomHelper.applyStyles(dbody, ss);
16114 Roo.EventManager.on(this.doc, {
16115 //'mousedown': this.onEditorEvent,
16116 'mouseup': this.onEditorEvent,
16117 'dblclick': this.onEditorEvent,
16118 'click': this.onEditorEvent,
16119 'keyup': this.onEditorEvent,
16124 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16126 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16127 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16129 this.initialized = true;
16131 this.owner.fireEvent('initialize', this);
16136 onDestroy : function(){
16142 //for (var i =0; i < this.toolbars.length;i++) {
16143 // // fixme - ask toolbars for heights?
16144 // this.toolbars[i].onDestroy();
16147 //this.wrap.dom.innerHTML = '';
16148 //this.wrap.remove();
16153 onFirstFocus : function(){
16155 this.assignDocWin();
16158 this.activated = true;
16161 if(Roo.isGecko){ // prevent silly gecko errors
16163 var s = this.win.getSelection();
16164 if(!s.focusNode || s.focusNode.nodeType != 3){
16165 var r = s.getRangeAt(0);
16166 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16171 this.execCmd('useCSS', true);
16172 this.execCmd('styleWithCSS', false);
16175 this.owner.fireEvent('activate', this);
16179 adjustFont: function(btn){
16180 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16181 //if(Roo.isSafari){ // safari
16184 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16185 if(Roo.isSafari){ // safari
16186 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16187 v = (v < 10) ? 10 : v;
16188 v = (v > 48) ? 48 : v;
16189 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16194 v = Math.max(1, v+adjust);
16196 this.execCmd('FontSize', v );
16199 onEditorEvent : function(e){
16200 this.owner.fireEvent('editorevent', this, e);
16201 // this.updateToolbar();
16202 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16205 insertTag : function(tg)
16207 // could be a bit smarter... -> wrap the current selected tRoo..
16208 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16210 range = this.createRange(this.getSelection());
16211 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16212 wrappingNode.appendChild(range.extractContents());
16213 range.insertNode(wrappingNode);
16220 this.execCmd("formatblock", tg);
16224 insertText : function(txt)
16228 var range = this.createRange();
16229 range.deleteContents();
16230 //alert(Sender.getAttribute('label'));
16232 range.insertNode(this.doc.createTextNode(txt));
16238 * Executes a Midas editor command on the editor document and performs necessary focus and
16239 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16240 * @param {String} cmd The Midas command
16241 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16243 relayCmd : function(cmd, value){
16245 this.execCmd(cmd, value);
16246 this.owner.fireEvent('editorevent', this);
16247 //this.updateToolbar();
16248 this.owner.deferFocus();
16252 * Executes a Midas editor command directly on the editor document.
16253 * For visual commands, you should use {@link #relayCmd} instead.
16254 * <b>This should only be called after the editor is initialized.</b>
16255 * @param {String} cmd The Midas command
16256 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16258 execCmd : function(cmd, value){
16259 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16266 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16268 * @param {String} text | dom node..
16270 insertAtCursor : function(text)
16275 if(!this.activated){
16281 var r = this.doc.selection.createRange();
16292 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16296 // from jquery ui (MIT licenced)
16298 var win = this.win;
16300 if (win.getSelection && win.getSelection().getRangeAt) {
16301 range = win.getSelection().getRangeAt(0);
16302 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16303 range.insertNode(node);
16304 } else if (win.document.selection && win.document.selection.createRange) {
16305 // no firefox support
16306 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16307 win.document.selection.createRange().pasteHTML(txt);
16309 // no firefox support
16310 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16311 this.execCmd('InsertHTML', txt);
16320 mozKeyPress : function(e){
16322 var c = e.getCharCode(), cmd;
16325 c = String.fromCharCode(c).toLowerCase();
16339 this.cleanUpPaste.defer(100, this);
16347 e.preventDefault();
16355 fixKeys : function(){ // load time branching for fastest keydown performance
16357 return function(e){
16358 var k = e.getKey(), r;
16361 r = this.doc.selection.createRange();
16364 r.pasteHTML('    ');
16371 r = this.doc.selection.createRange();
16373 var target = r.parentElement();
16374 if(!target || target.tagName.toLowerCase() != 'li'){
16376 r.pasteHTML('<br />');
16382 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16383 this.cleanUpPaste.defer(100, this);
16389 }else if(Roo.isOpera){
16390 return function(e){
16391 var k = e.getKey();
16395 this.execCmd('InsertHTML','    ');
16398 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16399 this.cleanUpPaste.defer(100, this);
16404 }else if(Roo.isSafari){
16405 return function(e){
16406 var k = e.getKey();
16410 this.execCmd('InsertText','\t');
16414 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16415 this.cleanUpPaste.defer(100, this);
16423 getAllAncestors: function()
16425 var p = this.getSelectedNode();
16428 a.push(p); // push blank onto stack..
16429 p = this.getParentElement();
16433 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16437 a.push(this.doc.body);
16441 lastSelNode : false,
16444 getSelection : function()
16446 this.assignDocWin();
16447 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16450 getSelectedNode: function()
16452 // this may only work on Gecko!!!
16454 // should we cache this!!!!
16459 var range = this.createRange(this.getSelection()).cloneRange();
16462 var parent = range.parentElement();
16464 var testRange = range.duplicate();
16465 testRange.moveToElementText(parent);
16466 if (testRange.inRange(range)) {
16469 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16472 parent = parent.parentElement;
16477 // is ancestor a text element.
16478 var ac = range.commonAncestorContainer;
16479 if (ac.nodeType == 3) {
16480 ac = ac.parentNode;
16483 var ar = ac.childNodes;
16486 var other_nodes = [];
16487 var has_other_nodes = false;
16488 for (var i=0;i<ar.length;i++) {
16489 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16492 // fullly contained node.
16494 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16499 // probably selected..
16500 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16501 other_nodes.push(ar[i]);
16505 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16510 has_other_nodes = true;
16512 if (!nodes.length && other_nodes.length) {
16513 nodes= other_nodes;
16515 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16521 createRange: function(sel)
16523 // this has strange effects when using with
16524 // top toolbar - not sure if it's a great idea.
16525 //this.editor.contentWindow.focus();
16526 if (typeof sel != "undefined") {
16528 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16530 return this.doc.createRange();
16533 return this.doc.createRange();
16536 getParentElement: function()
16539 this.assignDocWin();
16540 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16542 var range = this.createRange(sel);
16545 var p = range.commonAncestorContainer;
16546 while (p.nodeType == 3) { // text node
16557 * Range intersection.. the hard stuff...
16561 * [ -- selected range --- ]
16565 * if end is before start or hits it. fail.
16566 * if start is after end or hits it fail.
16568 * if either hits (but other is outside. - then it's not
16574 // @see http://www.thismuchiknow.co.uk/?p=64.
16575 rangeIntersectsNode : function(range, node)
16577 var nodeRange = node.ownerDocument.createRange();
16579 nodeRange.selectNode(node);
16581 nodeRange.selectNodeContents(node);
16584 var rangeStartRange = range.cloneRange();
16585 rangeStartRange.collapse(true);
16587 var rangeEndRange = range.cloneRange();
16588 rangeEndRange.collapse(false);
16590 var nodeStartRange = nodeRange.cloneRange();
16591 nodeStartRange.collapse(true);
16593 var nodeEndRange = nodeRange.cloneRange();
16594 nodeEndRange.collapse(false);
16596 return rangeStartRange.compareBoundaryPoints(
16597 Range.START_TO_START, nodeEndRange) == -1 &&
16598 rangeEndRange.compareBoundaryPoints(
16599 Range.START_TO_START, nodeStartRange) == 1;
16603 rangeCompareNode : function(range, node)
16605 var nodeRange = node.ownerDocument.createRange();
16607 nodeRange.selectNode(node);
16609 nodeRange.selectNodeContents(node);
16613 range.collapse(true);
16615 nodeRange.collapse(true);
16617 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16618 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16620 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16622 var nodeIsBefore = ss == 1;
16623 var nodeIsAfter = ee == -1;
16625 if (nodeIsBefore && nodeIsAfter)
16627 if (!nodeIsBefore && nodeIsAfter)
16628 return 1; //right trailed.
16630 if (nodeIsBefore && !nodeIsAfter)
16631 return 2; // left trailed.
16636 // private? - in a new class?
16637 cleanUpPaste : function()
16639 // cleans up the whole document..
16640 Roo.log('cleanuppaste');
16642 this.cleanUpChildren(this.doc.body);
16643 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16644 if (clean != this.doc.body.innerHTML) {
16645 this.doc.body.innerHTML = clean;
16650 cleanWordChars : function(input) {// change the chars to hex code
16651 var he = Roo.HtmlEditorCore;
16653 var output = input;
16654 Roo.each(he.swapCodes, function(sw) {
16655 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16657 output = output.replace(swapper, sw[1]);
16664 cleanUpChildren : function (n)
16666 if (!n.childNodes.length) {
16669 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16670 this.cleanUpChild(n.childNodes[i]);
16677 cleanUpChild : function (node)
16680 //console.log(node);
16681 if (node.nodeName == "#text") {
16682 // clean up silly Windows -- stuff?
16685 if (node.nodeName == "#comment") {
16686 node.parentNode.removeChild(node);
16687 // clean up silly Windows -- stuff?
16691 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16693 node.parentNode.removeChild(node);
16698 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16700 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16701 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16703 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16704 // remove_keep_children = true;
16707 if (remove_keep_children) {
16708 this.cleanUpChildren(node);
16709 // inserts everything just before this node...
16710 while (node.childNodes.length) {
16711 var cn = node.childNodes[0];
16712 node.removeChild(cn);
16713 node.parentNode.insertBefore(cn, node);
16715 node.parentNode.removeChild(node);
16719 if (!node.attributes || !node.attributes.length) {
16720 this.cleanUpChildren(node);
16724 function cleanAttr(n,v)
16727 if (v.match(/^\./) || v.match(/^\//)) {
16730 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16733 if (v.match(/^#/)) {
16736 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16737 node.removeAttribute(n);
16741 function cleanStyle(n,v)
16743 if (v.match(/expression/)) { //XSS?? should we even bother..
16744 node.removeAttribute(n);
16747 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16748 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16751 var parts = v.split(/;/);
16754 Roo.each(parts, function(p) {
16755 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16759 var l = p.split(':').shift().replace(/\s+/g,'');
16760 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16762 if ( cblack.indexOf(l) > -1) {
16763 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16764 //node.removeAttribute(n);
16768 // only allow 'c whitelisted system attributes'
16769 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16770 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16771 //node.removeAttribute(n);
16781 if (clean.length) {
16782 node.setAttribute(n, clean.join(';'));
16784 node.removeAttribute(n);
16790 for (var i = node.attributes.length-1; i > -1 ; i--) {
16791 var a = node.attributes[i];
16794 if (a.name.toLowerCase().substr(0,2)=='on') {
16795 node.removeAttribute(a.name);
16798 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16799 node.removeAttribute(a.name);
16802 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16803 cleanAttr(a.name,a.value); // fixme..
16806 if (a.name == 'style') {
16807 cleanStyle(a.name,a.value);
16810 /// clean up MS crap..
16811 // tecnically this should be a list of valid class'es..
16814 if (a.name == 'class') {
16815 if (a.value.match(/^Mso/)) {
16816 node.className = '';
16819 if (a.value.match(/body/)) {
16820 node.className = '';
16831 this.cleanUpChildren(node);
16836 * Clean up MS wordisms...
16838 cleanWord : function(node)
16841 var cleanWordChildren = function()
16843 if (!node.childNodes.length) {
16846 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16847 _t.cleanWord(node.childNodes[i]);
16853 this.cleanWord(this.doc.body);
16856 if (node.nodeName == "#text") {
16857 // clean up silly Windows -- stuff?
16860 if (node.nodeName == "#comment") {
16861 node.parentNode.removeChild(node);
16862 // clean up silly Windows -- stuff?
16866 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16867 node.parentNode.removeChild(node);
16871 // remove - but keep children..
16872 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16873 while (node.childNodes.length) {
16874 var cn = node.childNodes[0];
16875 node.removeChild(cn);
16876 node.parentNode.insertBefore(cn, node);
16878 node.parentNode.removeChild(node);
16879 cleanWordChildren();
16883 if (node.className.length) {
16885 var cn = node.className.split(/\W+/);
16887 Roo.each(cn, function(cls) {
16888 if (cls.match(/Mso[a-zA-Z]+/)) {
16893 node.className = cna.length ? cna.join(' ') : '';
16895 node.removeAttribute("class");
16899 if (node.hasAttribute("lang")) {
16900 node.removeAttribute("lang");
16903 if (node.hasAttribute("style")) {
16905 var styles = node.getAttribute("style").split(";");
16907 Roo.each(styles, function(s) {
16908 if (!s.match(/:/)) {
16911 var kv = s.split(":");
16912 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16915 // what ever is left... we allow.
16918 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16919 if (!nstyle.length) {
16920 node.removeAttribute('style');
16924 cleanWordChildren();
16928 domToHTML : function(currentElement, depth, nopadtext) {
16930 depth = depth || 0;
16931 nopadtext = nopadtext || false;
16933 if (!currentElement) {
16934 return this.domToHTML(this.doc.body);
16937 //Roo.log(currentElement);
16939 var allText = false;
16940 var nodeName = currentElement.nodeName;
16941 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16943 if (nodeName == '#text') {
16944 return currentElement.nodeValue;
16949 if (nodeName != 'BODY') {
16952 // Prints the node tagName, such as <A>, <IMG>, etc
16955 for(i = 0; i < currentElement.attributes.length;i++) {
16957 var aname = currentElement.attributes.item(i).name;
16958 if (!currentElement.attributes.item(i).value.length) {
16961 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16964 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16973 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16976 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16981 // Traverse the tree
16983 var currentElementChild = currentElement.childNodes.item(i);
16984 var allText = true;
16985 var innerHTML = '';
16987 while (currentElementChild) {
16988 // Formatting code (indent the tree so it looks nice on the screen)
16989 var nopad = nopadtext;
16990 if (lastnode == 'SPAN') {
16994 if (currentElementChild.nodeName == '#text') {
16995 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16996 if (!nopad && toadd.length > 80) {
16997 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16999 innerHTML += toadd;
17002 currentElementChild = currentElement.childNodes.item(i);
17008 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17010 // Recursively traverse the tree structure of the child node
17011 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17012 lastnode = currentElementChild.nodeName;
17014 currentElementChild=currentElement.childNodes.item(i);
17020 // The remaining code is mostly for formatting the tree
17021 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17026 ret+= "</"+tagName+">";
17032 // hide stuff that is not compatible
17046 * @event specialkey
17050 * @cfg {String} fieldClass @hide
17053 * @cfg {String} focusClass @hide
17056 * @cfg {String} autoCreate @hide
17059 * @cfg {String} inputType @hide
17062 * @cfg {String} invalidClass @hide
17065 * @cfg {String} invalidText @hide
17068 * @cfg {String} msgFx @hide
17071 * @cfg {String} validateOnBlur @hide
17075 Roo.HtmlEditorCore.white = [
17076 'area', 'br', 'img', 'input', 'hr', 'wbr',
17078 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17079 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17080 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17081 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17082 'table', 'ul', 'xmp',
17084 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17087 'dir', 'menu', 'ol', 'ul', 'dl',
17093 Roo.HtmlEditorCore.black = [
17094 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17096 'base', 'basefont', 'bgsound', 'blink', 'body',
17097 'frame', 'frameset', 'head', 'html', 'ilayer',
17098 'iframe', 'layer', 'link', 'meta', 'object',
17099 'script', 'style' ,'title', 'xml' // clean later..
17101 Roo.HtmlEditorCore.clean = [
17102 'script', 'style', 'title', 'xml'
17104 Roo.HtmlEditorCore.remove = [
17109 Roo.HtmlEditorCore.ablack = [
17113 Roo.HtmlEditorCore.aclean = [
17114 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17118 Roo.HtmlEditorCore.pwhite= [
17119 'http', 'https', 'mailto'
17122 // white listed style attributes.
17123 Roo.HtmlEditorCore.cwhite= [
17124 // 'text-align', /// default is to allow most things..
17130 // black listed style attributes.
17131 Roo.HtmlEditorCore.cblack= [
17132 // 'font-size' -- this can be set by the project
17136 Roo.HtmlEditorCore.swapCodes =[
17155 * @class Roo.bootstrap.HtmlEditor
17156 * @extends Roo.bootstrap.TextArea
17157 * Bootstrap HtmlEditor class
17160 * Create a new HtmlEditor
17161 * @param {Object} config The config object
17164 Roo.bootstrap.HtmlEditor = function(config){
17165 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17166 if (!this.toolbars) {
17167 this.toolbars = [];
17169 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17172 * @event initialize
17173 * Fires when the editor is fully initialized (including the iframe)
17174 * @param {HtmlEditor} this
17179 * Fires when the editor is first receives the focus. Any insertion must wait
17180 * until after this event.
17181 * @param {HtmlEditor} this
17185 * @event beforesync
17186 * Fires before the textarea is updated with content from the editor iframe. Return false
17187 * to cancel the sync.
17188 * @param {HtmlEditor} this
17189 * @param {String} html
17193 * @event beforepush
17194 * Fires before the iframe editor is updated with content from the textarea. Return false
17195 * to cancel the push.
17196 * @param {HtmlEditor} this
17197 * @param {String} html
17202 * Fires when the textarea is updated with content from the editor iframe.
17203 * @param {HtmlEditor} this
17204 * @param {String} html
17209 * Fires when the iframe editor is updated with content from the textarea.
17210 * @param {HtmlEditor} this
17211 * @param {String} html
17215 * @event editmodechange
17216 * Fires when the editor switches edit modes
17217 * @param {HtmlEditor} this
17218 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17220 editmodechange: true,
17222 * @event editorevent
17223 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17224 * @param {HtmlEditor} this
17228 * @event firstfocus
17229 * Fires when on first focus - needed by toolbars..
17230 * @param {HtmlEditor} this
17235 * Auto save the htmlEditor value as a file into Events
17236 * @param {HtmlEditor} this
17240 * @event savedpreview
17241 * preview the saved version of htmlEditor
17242 * @param {HtmlEditor} this
17249 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17253 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17258 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17263 * @cfg {Number} height (in pixels)
17267 * @cfg {Number} width (in pixels)
17272 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17275 stylesheets: false,
17280 // private properties
17281 validationEvent : false,
17283 initialized : false,
17286 onFocus : Roo.emptyFn,
17288 hideMode:'offsets',
17291 tbContainer : false,
17293 toolbarContainer :function() {
17294 return this.wrap.select('.x-html-editor-tb',true).first();
17298 * Protected method that will not generally be called directly. It
17299 * is called when the editor creates its toolbar. Override this method if you need to
17300 * add custom toolbar buttons.
17301 * @param {HtmlEditor} editor
17303 createToolbar : function(){
17305 Roo.log("create toolbars");
17307 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17308 this.toolbars[0].render(this.toolbarContainer());
17312 // if (!editor.toolbars || !editor.toolbars.length) {
17313 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17316 // for (var i =0 ; i < editor.toolbars.length;i++) {
17317 // editor.toolbars[i] = Roo.factory(
17318 // typeof(editor.toolbars[i]) == 'string' ?
17319 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17320 // Roo.bootstrap.HtmlEditor);
17321 // editor.toolbars[i].init(editor);
17327 onRender : function(ct, position)
17329 // Roo.log("Call onRender: " + this.xtype);
17331 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17333 this.wrap = this.inputEl().wrap({
17334 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17337 this.editorcore.onRender(ct, position);
17339 if (this.resizable) {
17340 this.resizeEl = new Roo.Resizable(this.wrap, {
17344 minHeight : this.height,
17345 height: this.height,
17346 handles : this.resizable,
17349 resize : function(r, w, h) {
17350 _t.onResize(w,h); // -something
17356 this.createToolbar(this);
17359 if(!this.width && this.resizable){
17360 this.setSize(this.wrap.getSize());
17362 if (this.resizeEl) {
17363 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17364 // should trigger onReize..
17370 onResize : function(w, h)
17372 Roo.log('resize: ' +w + ',' + h );
17373 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17377 if(this.inputEl() ){
17378 if(typeof w == 'number'){
17379 var aw = w - this.wrap.getFrameWidth('lr');
17380 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17383 if(typeof h == 'number'){
17384 var tbh = -11; // fixme it needs to tool bar size!
17385 for (var i =0; i < this.toolbars.length;i++) {
17386 // fixme - ask toolbars for heights?
17387 tbh += this.toolbars[i].el.getHeight();
17388 //if (this.toolbars[i].footer) {
17389 // tbh += this.toolbars[i].footer.el.getHeight();
17397 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17398 ah -= 5; // knock a few pixes off for look..
17399 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17403 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17404 this.editorcore.onResize(ew,eh);
17409 * Toggles the editor between standard and source edit mode.
17410 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17412 toggleSourceEdit : function(sourceEditMode)
17414 this.editorcore.toggleSourceEdit(sourceEditMode);
17416 if(this.editorcore.sourceEditMode){
17417 Roo.log('editor - showing textarea');
17420 // Roo.log(this.syncValue());
17422 this.inputEl().removeClass(['hide', 'x-hidden']);
17423 this.inputEl().dom.removeAttribute('tabIndex');
17424 this.inputEl().focus();
17426 Roo.log('editor - hiding textarea');
17428 // Roo.log(this.pushValue());
17431 this.inputEl().addClass(['hide', 'x-hidden']);
17432 this.inputEl().dom.setAttribute('tabIndex', -1);
17433 //this.deferFocus();
17436 if(this.resizable){
17437 this.setSize(this.wrap.getSize());
17440 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17443 // private (for BoxComponent)
17444 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17446 // private (for BoxComponent)
17447 getResizeEl : function(){
17451 // private (for BoxComponent)
17452 getPositionEl : function(){
17457 initEvents : function(){
17458 this.originalValue = this.getValue();
17462 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17465 // markInvalid : Roo.emptyFn,
17467 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17470 // clearInvalid : Roo.emptyFn,
17472 setValue : function(v){
17473 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17474 this.editorcore.pushValue();
17479 deferFocus : function(){
17480 this.focus.defer(10, this);
17484 focus : function(){
17485 this.editorcore.focus();
17491 onDestroy : function(){
17497 for (var i =0; i < this.toolbars.length;i++) {
17498 // fixme - ask toolbars for heights?
17499 this.toolbars[i].onDestroy();
17502 this.wrap.dom.innerHTML = '';
17503 this.wrap.remove();
17508 onFirstFocus : function(){
17509 //Roo.log("onFirstFocus");
17510 this.editorcore.onFirstFocus();
17511 for (var i =0; i < this.toolbars.length;i++) {
17512 this.toolbars[i].onFirstFocus();
17518 syncValue : function()
17520 this.editorcore.syncValue();
17523 pushValue : function()
17525 this.editorcore.pushValue();
17529 // hide stuff that is not compatible
17543 * @event specialkey
17547 * @cfg {String} fieldClass @hide
17550 * @cfg {String} focusClass @hide
17553 * @cfg {String} autoCreate @hide
17556 * @cfg {String} inputType @hide
17559 * @cfg {String} invalidClass @hide
17562 * @cfg {String} invalidText @hide
17565 * @cfg {String} msgFx @hide
17568 * @cfg {String} validateOnBlur @hide
17577 Roo.namespace('Roo.bootstrap.htmleditor');
17579 * @class Roo.bootstrap.HtmlEditorToolbar1
17584 new Roo.bootstrap.HtmlEditor({
17587 new Roo.bootstrap.HtmlEditorToolbar1({
17588 disable : { fonts: 1 , format: 1, ..., ... , ...],
17594 * @cfg {Object} disable List of elements to disable..
17595 * @cfg {Array} btns List of additional buttons.
17599 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17602 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17605 Roo.apply(this, config);
17607 // default disabled, based on 'good practice'..
17608 this.disable = this.disable || {};
17609 Roo.applyIf(this.disable, {
17612 specialElements : true
17614 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17616 this.editor = config.editor;
17617 this.editorcore = config.editor.editorcore;
17619 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17621 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17622 // dont call parent... till later.
17624 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17629 editorcore : false,
17634 "h1","h2","h3","h4","h5","h6",
17636 "abbr", "acronym", "address", "cite", "samp", "var",
17640 onRender : function(ct, position)
17642 // Roo.log("Call onRender: " + this.xtype);
17644 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17646 this.el.dom.style.marginBottom = '0';
17648 var editorcore = this.editorcore;
17649 var editor= this.editor;
17652 var btn = function(id,cmd , toggle, handler){
17654 var event = toggle ? 'toggle' : 'click';
17659 xns: Roo.bootstrap,
17662 enableToggle:toggle !== false,
17664 pressed : toggle ? false : null,
17667 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17668 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17677 xns: Roo.bootstrap,
17678 glyphicon : 'font',
17682 xns: Roo.bootstrap,
17686 Roo.each(this.formats, function(f) {
17687 style.menu.items.push({
17689 xns: Roo.bootstrap,
17690 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17695 editorcore.insertTag(this.tagname);
17702 children.push(style);
17705 btn('bold',false,true);
17706 btn('italic',false,true);
17707 btn('align-left', 'justifyleft',true);
17708 btn('align-center', 'justifycenter',true);
17709 btn('align-right' , 'justifyright',true);
17710 btn('link', false, false, function(btn) {
17711 //Roo.log("create link?");
17712 var url = prompt(this.createLinkText, this.defaultLinkValue);
17713 if(url && url != 'http:/'+'/'){
17714 this.editorcore.relayCmd('createlink', url);
17717 btn('list','insertunorderedlist',true);
17718 btn('pencil', false,true, function(btn){
17721 this.toggleSourceEdit(btn.pressed);
17727 xns: Roo.bootstrap,
17732 xns: Roo.bootstrap,
17737 cog.menu.items.push({
17739 xns: Roo.bootstrap,
17740 html : Clean styles,
17745 editorcore.insertTag(this.tagname);
17754 this.xtype = 'NavSimplebar';
17756 for(var i=0;i< children.length;i++) {
17758 this.buttons.add(this.addxtypeChild(children[i]));
17762 editor.on('editorevent', this.updateToolbar, this);
17764 onBtnClick : function(id)
17766 this.editorcore.relayCmd(id);
17767 this.editorcore.focus();
17771 * Protected method that will not generally be called directly. It triggers
17772 * a toolbar update by reading the markup state of the current selection in the editor.
17774 updateToolbar: function(){
17776 if(!this.editorcore.activated){
17777 this.editor.onFirstFocus(); // is this neeed?
17781 var btns = this.buttons;
17782 var doc = this.editorcore.doc;
17783 btns.get('bold').setActive(doc.queryCommandState('bold'));
17784 btns.get('italic').setActive(doc.queryCommandState('italic'));
17785 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17787 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17788 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17789 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17791 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17792 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17795 var ans = this.editorcore.getAllAncestors();
17796 if (this.formatCombo) {
17799 var store = this.formatCombo.store;
17800 this.formatCombo.setValue("");
17801 for (var i =0; i < ans.length;i++) {
17802 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17804 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17812 // hides menus... - so this cant be on a menu...
17813 Roo.bootstrap.MenuMgr.hideAll();
17815 Roo.bootstrap.MenuMgr.hideAll();
17816 //this.editorsyncValue();
17818 onFirstFocus: function() {
17819 this.buttons.each(function(item){
17823 toggleSourceEdit : function(sourceEditMode){
17826 if(sourceEditMode){
17827 Roo.log("disabling buttons");
17828 this.buttons.each( function(item){
17829 if(item.cmd != 'pencil'){
17835 Roo.log("enabling buttons");
17836 if(this.editorcore.initialized){
17837 this.buttons.each( function(item){
17843 Roo.log("calling toggole on editor");
17844 // tell the editor that it's been pressed..
17845 this.editor.toggleSourceEdit(sourceEditMode);
17855 * @class Roo.bootstrap.Table.AbstractSelectionModel
17856 * @extends Roo.util.Observable
17857 * Abstract base class for grid SelectionModels. It provides the interface that should be
17858 * implemented by descendant classes. This class should not be directly instantiated.
17861 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17862 this.locked = false;
17863 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17867 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17868 /** @ignore Called by the grid automatically. Do not call directly. */
17869 init : function(grid){
17875 * Locks the selections.
17878 this.locked = true;
17882 * Unlocks the selections.
17884 unlock : function(){
17885 this.locked = false;
17889 * Returns true if the selections are locked.
17890 * @return {Boolean}
17892 isLocked : function(){
17893 return this.locked;
17897 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17898 * @class Roo.bootstrap.Table.RowSelectionModel
17899 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17900 * It supports multiple selections and keyboard selection/navigation.
17902 * @param {Object} config
17905 Roo.bootstrap.Table.RowSelectionModel = function(config){
17906 Roo.apply(this, config);
17907 this.selections = new Roo.util.MixedCollection(false, function(o){
17912 this.lastActive = false;
17916 * @event selectionchange
17917 * Fires when the selection changes
17918 * @param {SelectionModel} this
17920 "selectionchange" : true,
17922 * @event afterselectionchange
17923 * Fires after the selection changes (eg. by key press or clicking)
17924 * @param {SelectionModel} this
17926 "afterselectionchange" : true,
17928 * @event beforerowselect
17929 * Fires when a row is selected being selected, return false to cancel.
17930 * @param {SelectionModel} this
17931 * @param {Number} rowIndex The selected index
17932 * @param {Boolean} keepExisting False if other selections will be cleared
17934 "beforerowselect" : true,
17937 * Fires when a row is selected.
17938 * @param {SelectionModel} this
17939 * @param {Number} rowIndex The selected index
17940 * @param {Roo.data.Record} r The record
17942 "rowselect" : true,
17944 * @event rowdeselect
17945 * Fires when a row is deselected.
17946 * @param {SelectionModel} this
17947 * @param {Number} rowIndex The selected index
17949 "rowdeselect" : true
17951 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17952 this.locked = false;
17955 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17957 * @cfg {Boolean} singleSelect
17958 * True to allow selection of only one row at a time (defaults to false)
17960 singleSelect : false,
17963 initEvents : function(){
17965 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17966 this.grid.on("mousedown", this.handleMouseDown, this);
17967 }else{ // allow click to work like normal
17968 this.grid.on("rowclick", this.handleDragableRowClick, this);
17971 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17972 "up" : function(e){
17974 this.selectPrevious(e.shiftKey);
17975 }else if(this.last !== false && this.lastActive !== false){
17976 var last = this.last;
17977 this.selectRange(this.last, this.lastActive-1);
17978 this.grid.getView().focusRow(this.lastActive);
17979 if(last !== false){
17983 this.selectFirstRow();
17985 this.fireEvent("afterselectionchange", this);
17987 "down" : function(e){
17989 this.selectNext(e.shiftKey);
17990 }else if(this.last !== false && this.lastActive !== false){
17991 var last = this.last;
17992 this.selectRange(this.last, this.lastActive+1);
17993 this.grid.getView().focusRow(this.lastActive);
17994 if(last !== false){
17998 this.selectFirstRow();
18000 this.fireEvent("afterselectionchange", this);
18005 var view = this.grid.view;
18006 view.on("refresh", this.onRefresh, this);
18007 view.on("rowupdated", this.onRowUpdated, this);
18008 view.on("rowremoved", this.onRemove, this);
18012 onRefresh : function(){
18013 var ds = this.grid.dataSource, i, v = this.grid.view;
18014 var s = this.selections;
18015 s.each(function(r){
18016 if((i = ds.indexOfId(r.id)) != -1){
18025 onRemove : function(v, index, r){
18026 this.selections.remove(r);
18030 onRowUpdated : function(v, index, r){
18031 if(this.isSelected(r)){
18032 v.onRowSelect(index);
18038 * @param {Array} records The records to select
18039 * @param {Boolean} keepExisting (optional) True to keep existing selections
18041 selectRecords : function(records, keepExisting){
18043 this.clearSelections();
18045 var ds = this.grid.dataSource;
18046 for(var i = 0, len = records.length; i < len; i++){
18047 this.selectRow(ds.indexOf(records[i]), true);
18052 * Gets the number of selected rows.
18055 getCount : function(){
18056 return this.selections.length;
18060 * Selects the first row in the grid.
18062 selectFirstRow : function(){
18067 * Select the last row.
18068 * @param {Boolean} keepExisting (optional) True to keep existing selections
18070 selectLastRow : function(keepExisting){
18071 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18075 * Selects the row immediately following the last selected row.
18076 * @param {Boolean} keepExisting (optional) True to keep existing selections
18078 selectNext : function(keepExisting){
18079 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18080 this.selectRow(this.last+1, keepExisting);
18081 this.grid.getView().focusRow(this.last);
18086 * Selects the row that precedes the last selected row.
18087 * @param {Boolean} keepExisting (optional) True to keep existing selections
18089 selectPrevious : function(keepExisting){
18091 this.selectRow(this.last-1, keepExisting);
18092 this.grid.getView().focusRow(this.last);
18097 * Returns the selected records
18098 * @return {Array} Array of selected records
18100 getSelections : function(){
18101 return [].concat(this.selections.items);
18105 * Returns the first selected record.
18108 getSelected : function(){
18109 return this.selections.itemAt(0);
18114 * Clears all selections.
18116 clearSelections : function(fast){
18117 if(this.locked) return;
18119 var ds = this.grid.dataSource;
18120 var s = this.selections;
18121 s.each(function(r){
18122 this.deselectRow(ds.indexOfId(r.id));
18126 this.selections.clear();
18133 * Selects all rows.
18135 selectAll : function(){
18136 if(this.locked) return;
18137 this.selections.clear();
18138 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18139 this.selectRow(i, true);
18144 * Returns True if there is a selection.
18145 * @return {Boolean}
18147 hasSelection : function(){
18148 return this.selections.length > 0;
18152 * Returns True if the specified row is selected.
18153 * @param {Number/Record} record The record or index of the record to check
18154 * @return {Boolean}
18156 isSelected : function(index){
18157 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18158 return (r && this.selections.key(r.id) ? true : false);
18162 * Returns True if the specified record id is selected.
18163 * @param {String} id The id of record to check
18164 * @return {Boolean}
18166 isIdSelected : function(id){
18167 return (this.selections.key(id) ? true : false);
18171 handleMouseDown : function(e, t){
18172 var view = this.grid.getView(), rowIndex;
18173 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18176 if(e.shiftKey && this.last !== false){
18177 var last = this.last;
18178 this.selectRange(last, rowIndex, e.ctrlKey);
18179 this.last = last; // reset the last
18180 view.focusRow(rowIndex);
18182 var isSelected = this.isSelected(rowIndex);
18183 if(e.button !== 0 && isSelected){
18184 view.focusRow(rowIndex);
18185 }else if(e.ctrlKey && isSelected){
18186 this.deselectRow(rowIndex);
18187 }else if(!isSelected){
18188 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18189 view.focusRow(rowIndex);
18192 this.fireEvent("afterselectionchange", this);
18195 handleDragableRowClick : function(grid, rowIndex, e)
18197 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18198 this.selectRow(rowIndex, false);
18199 grid.view.focusRow(rowIndex);
18200 this.fireEvent("afterselectionchange", this);
18205 * Selects multiple rows.
18206 * @param {Array} rows Array of the indexes of the row to select
18207 * @param {Boolean} keepExisting (optional) True to keep existing selections
18209 selectRows : function(rows, keepExisting){
18211 this.clearSelections();
18213 for(var i = 0, len = rows.length; i < len; i++){
18214 this.selectRow(rows[i], true);
18219 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18220 * @param {Number} startRow The index of the first row in the range
18221 * @param {Number} endRow The index of the last row in the range
18222 * @param {Boolean} keepExisting (optional) True to retain existing selections
18224 selectRange : function(startRow, endRow, keepExisting){
18225 if(this.locked) return;
18227 this.clearSelections();
18229 if(startRow <= endRow){
18230 for(var i = startRow; i <= endRow; i++){
18231 this.selectRow(i, true);
18234 for(var i = startRow; i >= endRow; i--){
18235 this.selectRow(i, true);
18241 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18242 * @param {Number} startRow The index of the first row in the range
18243 * @param {Number} endRow The index of the last row in the range
18245 deselectRange : function(startRow, endRow, preventViewNotify){
18246 if(this.locked) return;
18247 for(var i = startRow; i <= endRow; i++){
18248 this.deselectRow(i, preventViewNotify);
18254 * @param {Number} row The index of the row to select
18255 * @param {Boolean} keepExisting (optional) True to keep existing selections
18257 selectRow : function(index, keepExisting, preventViewNotify){
18258 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18259 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18260 if(!keepExisting || this.singleSelect){
18261 this.clearSelections();
18263 var r = this.grid.dataSource.getAt(index);
18264 this.selections.add(r);
18265 this.last = this.lastActive = index;
18266 if(!preventViewNotify){
18267 this.grid.getView().onRowSelect(index);
18269 this.fireEvent("rowselect", this, index, r);
18270 this.fireEvent("selectionchange", this);
18276 * @param {Number} row The index of the row to deselect
18278 deselectRow : function(index, preventViewNotify){
18279 if(this.locked) return;
18280 if(this.last == index){
18283 if(this.lastActive == index){
18284 this.lastActive = false;
18286 var r = this.grid.dataSource.getAt(index);
18287 this.selections.remove(r);
18288 if(!preventViewNotify){
18289 this.grid.getView().onRowDeselect(index);
18291 this.fireEvent("rowdeselect", this, index);
18292 this.fireEvent("selectionchange", this);
18296 restoreLast : function(){
18298 this.last = this._last;
18303 acceptsNav : function(row, col, cm){
18304 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18308 onEditorKey : function(field, e){
18309 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18314 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18316 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18318 }else if(k == e.ENTER && !e.ctrlKey){
18322 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18324 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18326 }else if(k == e.ESC){
18330 g.startEditing(newCell[0], newCell[1]);
18335 * Ext JS Library 1.1.1
18336 * Copyright(c) 2006-2007, Ext JS, LLC.
18338 * Originally Released Under LGPL - original licence link has changed is not relivant.
18341 * <script type="text/javascript">
18345 * @class Roo.bootstrap.PagingToolbar
18347 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18349 * Create a new PagingToolbar
18350 * @param {Object} config The config object
18352 Roo.bootstrap.PagingToolbar = function(config)
18354 // old args format still supported... - xtype is prefered..
18355 // created from xtype...
18356 var ds = config.dataSource;
18357 this.toolbarItems = [];
18358 if (config.items) {
18359 this.toolbarItems = config.items;
18360 // config.items = [];
18363 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18370 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18374 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18376 * @cfg {Roo.data.Store} dataSource
18377 * The underlying data store providing the paged data
18380 * @cfg {String/HTMLElement/Element} container
18381 * container The id or element that will contain the toolbar
18384 * @cfg {Boolean} displayInfo
18385 * True to display the displayMsg (defaults to false)
18388 * @cfg {Number} pageSize
18389 * The number of records to display per page (defaults to 20)
18393 * @cfg {String} displayMsg
18394 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18396 displayMsg : 'Displaying {0} - {1} of {2}',
18398 * @cfg {String} emptyMsg
18399 * The message to display when no records are found (defaults to "No data to display")
18401 emptyMsg : 'No data to display',
18403 * Customizable piece of the default paging text (defaults to "Page")
18406 beforePageText : "Page",
18408 * Customizable piece of the default paging text (defaults to "of %0")
18411 afterPageText : "of {0}",
18413 * Customizable piece of the default paging text (defaults to "First Page")
18416 firstText : "First Page",
18418 * Customizable piece of the default paging text (defaults to "Previous Page")
18421 prevText : "Previous Page",
18423 * Customizable piece of the default paging text (defaults to "Next Page")
18426 nextText : "Next Page",
18428 * Customizable piece of the default paging text (defaults to "Last Page")
18431 lastText : "Last Page",
18433 * Customizable piece of the default paging text (defaults to "Refresh")
18436 refreshText : "Refresh",
18440 onRender : function(ct, position)
18442 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18443 this.navgroup.parentId = this.id;
18444 this.navgroup.onRender(this.el, null);
18445 // add the buttons to the navgroup
18447 if(this.displayInfo){
18448 Roo.log(this.el.select('ul.navbar-nav',true).first());
18449 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18450 this.displayEl = this.el.select('.x-paging-info', true).first();
18451 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18452 // this.displayEl = navel.el.select('span',true).first();
18458 Roo.each(_this.buttons, function(e){
18459 Roo.factory(e).onRender(_this.el, null);
18463 Roo.each(_this.toolbarItems, function(e) {
18464 _this.navgroup.addItem(e);
18467 this.first = this.navgroup.addItem({
18468 tooltip: this.firstText,
18470 icon : 'fa fa-backward',
18472 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18475 this.prev = this.navgroup.addItem({
18476 tooltip: this.prevText,
18478 icon : 'fa fa-step-backward',
18480 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18482 //this.addSeparator();
18485 var field = this.navgroup.addItem( {
18487 cls : 'x-paging-position',
18489 html : this.beforePageText +
18490 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18491 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18494 this.field = field.el.select('input', true).first();
18495 this.field.on("keydown", this.onPagingKeydown, this);
18496 this.field.on("focus", function(){this.dom.select();});
18499 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18500 //this.field.setHeight(18);
18501 //this.addSeparator();
18502 this.next = this.navgroup.addItem({
18503 tooltip: this.nextText,
18505 html : ' <i class="fa fa-step-forward">',
18507 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18509 this.last = this.navgroup.addItem({
18510 tooltip: this.lastText,
18511 icon : 'fa fa-forward',
18514 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18516 //this.addSeparator();
18517 this.loading = this.navgroup.addItem({
18518 tooltip: this.refreshText,
18519 icon: 'fa fa-refresh',
18521 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18527 updateInfo : function(){
18528 if(this.displayEl){
18529 var count = this.ds.getCount();
18530 var msg = count == 0 ?
18534 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18536 this.displayEl.update(msg);
18541 onLoad : function(ds, r, o){
18542 this.cursor = o.params ? o.params.start : 0;
18543 var d = this.getPageData(),
18547 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18548 this.field.dom.value = ap;
18549 this.first.setDisabled(ap == 1);
18550 this.prev.setDisabled(ap == 1);
18551 this.next.setDisabled(ap == ps);
18552 this.last.setDisabled(ap == ps);
18553 this.loading.enable();
18558 getPageData : function(){
18559 var total = this.ds.getTotalCount();
18562 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18563 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18568 onLoadError : function(){
18569 this.loading.enable();
18573 onPagingKeydown : function(e){
18574 var k = e.getKey();
18575 var d = this.getPageData();
18577 var v = this.field.dom.value, pageNum;
18578 if(!v || isNaN(pageNum = parseInt(v, 10))){
18579 this.field.dom.value = d.activePage;
18582 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18583 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18586 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))
18588 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18589 this.field.dom.value = pageNum;
18590 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18593 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18595 var v = this.field.dom.value, pageNum;
18596 var increment = (e.shiftKey) ? 10 : 1;
18597 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18599 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18600 this.field.dom.value = d.activePage;
18603 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18605 this.field.dom.value = parseInt(v, 10) + increment;
18606 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18607 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18614 beforeLoad : function(){
18616 this.loading.disable();
18621 onClick : function(which){
18628 ds.load({params:{start: 0, limit: this.pageSize}});
18631 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18634 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18637 var total = ds.getTotalCount();
18638 var extra = total % this.pageSize;
18639 var lastStart = extra ? (total - extra) : total-this.pageSize;
18640 ds.load({params:{start: lastStart, limit: this.pageSize}});
18643 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18649 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18650 * @param {Roo.data.Store} store The data store to unbind
18652 unbind : function(ds){
18653 ds.un("beforeload", this.beforeLoad, this);
18654 ds.un("load", this.onLoad, this);
18655 ds.un("loadexception", this.onLoadError, this);
18656 ds.un("remove", this.updateInfo, this);
18657 ds.un("add", this.updateInfo, this);
18658 this.ds = undefined;
18662 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18663 * @param {Roo.data.Store} store The data store to bind
18665 bind : function(ds){
18666 ds.on("beforeload", this.beforeLoad, this);
18667 ds.on("load", this.onLoad, this);
18668 ds.on("loadexception", this.onLoadError, this);
18669 ds.on("remove", this.updateInfo, this);
18670 ds.on("add", this.updateInfo, this);
18681 * @class Roo.bootstrap.MessageBar
18682 * @extends Roo.bootstrap.Component
18683 * Bootstrap MessageBar class
18684 * @cfg {String} html contents of the MessageBar
18685 * @cfg {String} weight (info | success | warning | danger) default info
18686 * @cfg {String} beforeClass insert the bar before the given class
18687 * @cfg {Boolean} closable (true | false) default false
18688 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18691 * Create a new Element
18692 * @param {Object} config The config object
18695 Roo.bootstrap.MessageBar = function(config){
18696 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18699 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18705 beforeClass: 'bootstrap-sticky-wrap',
18707 getAutoCreate : function(){
18711 cls: 'alert alert-dismissable alert-' + this.weight,
18716 html: this.html || ''
18722 cfg.cls += ' alert-messages-fixed';
18736 onRender : function(ct, position)
18738 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18741 var cfg = Roo.apply({}, this.getAutoCreate());
18745 cfg.cls += ' ' + this.cls;
18748 cfg.style = this.style;
18750 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18752 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18755 this.el.select('>button.close').on('click', this.hide, this);
18761 if (!this.rendered) {
18767 this.fireEvent('show', this);
18773 if (!this.rendered) {
18779 this.fireEvent('hide', this);
18782 update : function()
18784 // var e = this.el.dom.firstChild;
18786 // if(this.closable){
18787 // e = e.nextSibling;
18790 // e.data = this.html || '';
18792 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18808 * @class Roo.bootstrap.Graph
18809 * @extends Roo.bootstrap.Component
18810 * Bootstrap Graph class
18814 @cfg {String} graphtype bar | vbar | pie
18815 @cfg {number} g_x coodinator | centre x (pie)
18816 @cfg {number} g_y coodinator | centre y (pie)
18817 @cfg {number} g_r radius (pie)
18818 @cfg {number} g_height height of the chart (respected by all elements in the set)
18819 @cfg {number} g_width width of the chart (respected by all elements in the set)
18820 @cfg {Object} title The title of the chart
18823 -opts (object) options for the chart
18825 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18826 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18828 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.
18829 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18831 o stretch (boolean)
18833 -opts (object) options for the pie
18836 o startAngle (number)
18837 o endAngle (number)
18841 * Create a new Input
18842 * @param {Object} config The config object
18845 Roo.bootstrap.Graph = function(config){
18846 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18852 * The img click event for the img.
18853 * @param {Roo.EventObject} e
18859 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18870 //g_colors: this.colors,
18877 getAutoCreate : function(){
18888 onRender : function(ct,position){
18889 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18890 this.raphael = Raphael(this.el.dom);
18892 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18893 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18894 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18895 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18897 r.text(160, 10, "Single Series Chart").attr(txtattr);
18898 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18899 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18900 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18902 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18903 r.barchart(330, 10, 300, 220, data1);
18904 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18905 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18908 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18909 // r.barchart(30, 30, 560, 250, xdata, {
18910 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18911 // axis : "0 0 1 1",
18912 // axisxlabels : xdata
18913 // //yvalues : cols,
18916 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18918 // this.load(null,xdata,{
18919 // axis : "0 0 1 1",
18920 // axisxlabels : xdata
18925 load : function(graphtype,xdata,opts){
18926 this.raphael.clear();
18928 graphtype = this.graphtype;
18933 var r = this.raphael,
18934 fin = function () {
18935 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18937 fout = function () {
18938 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18940 pfin = function() {
18941 this.sector.stop();
18942 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18945 this.label[0].stop();
18946 this.label[0].attr({ r: 7.5 });
18947 this.label[1].attr({ "font-weight": 800 });
18950 pfout = function() {
18951 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18954 this.label[0].animate({ r: 5 }, 500, "bounce");
18955 this.label[1].attr({ "font-weight": 400 });
18961 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18964 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18967 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18968 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18970 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18977 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18982 setTitle: function(o)
18987 initEvents: function() {
18990 this.el.on('click', this.onClick, this);
18994 onClick : function(e)
18996 Roo.log('img onclick');
18997 this.fireEvent('click', this, e);
19009 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19012 * @class Roo.bootstrap.dash.NumberBox
19013 * @extends Roo.bootstrap.Component
19014 * Bootstrap NumberBox class
19015 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19016 * @cfg {String} headline Box headline
19017 * @cfg {String} content Box content
19018 * @cfg {String} icon Box icon
19019 * @cfg {String} footer Footer text
19020 * @cfg {String} fhref Footer href
19023 * Create a new NumberBox
19024 * @param {Object} config The config object
19028 Roo.bootstrap.dash.NumberBox = function(config){
19029 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19033 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19043 getAutoCreate : function(){
19047 cls : 'small-box bg-' + this.bgcolor,
19055 cls : 'roo-headline',
19056 html : this.headline
19060 cls : 'roo-content',
19061 html : this.content
19075 cls : 'ion ' + this.icon
19084 cls : 'small-box-footer',
19085 href : this.fhref || '#',
19089 cfg.cn.push(footer);
19096 onRender : function(ct,position){
19097 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19104 setHeadline: function (value)
19106 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19109 setFooter: function (value, href)
19111 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19114 this.el.select('a.small-box-footer',true).first().attr('href', href);
19119 setContent: function (value)
19121 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19124 initEvents: function()
19138 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19141 * @class Roo.bootstrap.dash.TabBox
19142 * @extends Roo.bootstrap.Component
19143 * Bootstrap TabBox class
19144 * @cfg {String} title Title of the TabBox
19145 * @cfg {String} icon Icon of the TabBox
19148 * Create a new TabBox
19149 * @param {Object} config The config object
19153 Roo.bootstrap.dash.TabBox = function(config){
19154 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19159 * When a pane is added
19160 * @param {Roo.bootstrap.dash.TabPane} pane
19167 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19172 getChildContainer : function()
19174 return this.el.select('.tab-content', true).first();
19177 getAutoCreate : function(){
19181 cls: 'pull-left header',
19189 cls: 'fa ' + this.icon
19196 cls: 'nav-tabs-custom',
19200 cls: 'nav nav-tabs pull-right',
19207 cls: 'tab-content no-padding',
19215 initEvents : function()
19217 //Roo.log('add add pane handler');
19218 this.on('addpane', this.onAddPane, this);
19221 * Updates the box title
19222 * @param {String} html to set the title to.
19224 setTitle : function(value)
19226 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19228 onAddPane : function(pane)
19230 //Roo.log('addpane');
19232 // tabs are rendere left to right..
19233 var ctr = this.el.select('.nav-tabs', true).first();
19236 var existing = ctr.select('.nav-tab',true);
19237 var qty = existing.getCount();;
19240 var tab = ctr.createChild({
19242 cls : 'nav-tab' + (qty ? '' : ' active'),
19250 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19253 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19255 pane.el.addClass('active');
19260 onTabClick : function(ev,un,ob,pane)
19262 //Roo.log('tab - prev default');
19263 ev.preventDefault();
19266 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19267 pane.tab.addClass('active');
19268 //Roo.log(pane.title);
19269 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19270 // technically we should have a deactivate event.. but maybe add later.
19271 // and it should not de-activate the selected tab...
19273 pane.el.addClass('active');
19274 pane.fireEvent('activate');
19289 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19291 * @class Roo.bootstrap.TabPane
19292 * @extends Roo.bootstrap.Component
19293 * Bootstrap TabPane class
19294 * @cfg {Boolean} active (false | true) Default false
19295 * @cfg {String} title title of panel
19299 * Create a new TabPane
19300 * @param {Object} config The config object
19303 Roo.bootstrap.dash.TabPane = function(config){
19304 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19308 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19313 // the tabBox that this is attached to.
19316 getAutoCreate : function()
19324 cfg.cls += ' active';
19329 initEvents : function()
19331 //Roo.log('trigger add pane handler');
19332 this.parent().fireEvent('addpane', this)
19336 * Updates the tab title
19337 * @param {String} html to set the title to.
19339 setTitle: function(str)
19345 this.tab.select('a'.true).first().dom.innerHTML = str;
19362 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19365 * @class Roo.bootstrap.menu.Menu
19366 * @extends Roo.bootstrap.Component
19367 * Bootstrap Menu class - container for Menu
19368 * @cfg {String} html Text of the menu
19369 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19370 * @cfg {String} icon Font awesome icon
19371 * @cfg {String} pos Menu align to (top | bottom) default bottom
19375 * Create a new Menu
19376 * @param {Object} config The config object
19380 Roo.bootstrap.menu.Menu = function(config){
19381 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19385 * @event beforeshow
19386 * Fires before this menu is displayed
19387 * @param {Roo.bootstrap.menu.Menu} this
19391 * @event beforehide
19392 * Fires before this menu is hidden
19393 * @param {Roo.bootstrap.menu.Menu} this
19398 * Fires after this menu is displayed
19399 * @param {Roo.bootstrap.menu.Menu} this
19404 * Fires after this menu is hidden
19405 * @param {Roo.bootstrap.menu.Menu} this
19410 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19411 * @param {Roo.bootstrap.menu.Menu} this
19412 * @param {Roo.EventObject} e
19419 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19423 weight : 'default',
19428 getChildContainer : function() {
19429 if(this.isSubMenu){
19433 return this.el.select('ul.dropdown-menu', true).first();
19436 getAutoCreate : function()
19441 cls : 'roo-menu-text',
19449 cls : 'fa ' + this.icon
19460 cls : 'dropdown-button btn btn-' + this.weight,
19465 cls : 'dropdown-toggle btn btn-' + this.weight,
19475 cls : 'dropdown-menu'
19481 if(this.pos == 'top'){
19482 cfg.cls += ' dropup';
19485 if(this.isSubMenu){
19488 cls : 'dropdown-menu'
19495 onRender : function(ct, position)
19497 this.isSubMenu = ct.hasClass('dropdown-submenu');
19499 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19502 initEvents : function()
19504 if(this.isSubMenu){
19508 this.hidden = true;
19510 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19511 this.triggerEl.on('click', this.onTriggerPress, this);
19513 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19514 this.buttonEl.on('click', this.onClick, this);
19520 if(this.isSubMenu){
19524 return this.el.select('ul.dropdown-menu', true).first();
19527 onClick : function(e)
19529 this.fireEvent("click", this, e);
19532 onTriggerPress : function(e)
19534 if (this.isVisible()) {
19541 isVisible : function(){
19542 return !this.hidden;
19547 this.fireEvent("beforeshow", this);
19549 this.hidden = false;
19550 this.el.addClass('open');
19552 Roo.get(document).on("mouseup", this.onMouseUp, this);
19554 this.fireEvent("show", this);
19561 this.fireEvent("beforehide", this);
19563 this.hidden = true;
19564 this.el.removeClass('open');
19566 Roo.get(document).un("mouseup", this.onMouseUp);
19568 this.fireEvent("hide", this);
19571 onMouseUp : function()
19585 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19588 * @class Roo.bootstrap.menu.Item
19589 * @extends Roo.bootstrap.Component
19590 * Bootstrap MenuItem class
19591 * @cfg {Boolean} submenu (true | false) default false
19592 * @cfg {String} html text of the item
19593 * @cfg {String} href the link
19594 * @cfg {Boolean} disable (true | false) default false
19595 * @cfg {Boolean} preventDefault (true | false) default true
19596 * @cfg {String} icon Font awesome icon
19597 * @cfg {String} pos Submenu align to (left | right) default right
19601 * Create a new Item
19602 * @param {Object} config The config object
19606 Roo.bootstrap.menu.Item = function(config){
19607 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19611 * Fires when the mouse is hovering over this menu
19612 * @param {Roo.bootstrap.menu.Item} this
19613 * @param {Roo.EventObject} e
19618 * Fires when the mouse exits this menu
19619 * @param {Roo.bootstrap.menu.Item} this
19620 * @param {Roo.EventObject} e
19626 * The raw click event for the entire grid.
19627 * @param {Roo.EventObject} e
19633 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19638 preventDefault: true,
19643 getAutoCreate : function()
19648 cls : 'roo-menu-item-text',
19656 cls : 'fa ' + this.icon
19665 href : this.href || '#',
19672 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19676 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19678 if(this.pos == 'left'){
19679 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19686 initEvents : function()
19688 this.el.on('mouseover', this.onMouseOver, this);
19689 this.el.on('mouseout', this.onMouseOut, this);
19691 this.el.select('a', true).first().on('click', this.onClick, this);
19695 onClick : function(e)
19697 if(this.preventDefault){
19698 e.preventDefault();
19701 this.fireEvent("click", this, e);
19704 onMouseOver : function(e)
19706 if(this.submenu && this.pos == 'left'){
19707 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19710 this.fireEvent("mouseover", this, e);
19713 onMouseOut : function(e)
19715 this.fireEvent("mouseout", this, e);
19727 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19730 * @class Roo.bootstrap.menu.Separator
19731 * @extends Roo.bootstrap.Component
19732 * Bootstrap Separator class
19735 * Create a new Separator
19736 * @param {Object} config The config object
19740 Roo.bootstrap.menu.Separator = function(config){
19741 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19744 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19746 getAutoCreate : function(){