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.
4029 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4032 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4036 * Returns the id of the column at the specified index.
4037 * @param {Number} index The column index
4038 * @return {String} the id
4040 getColumnId : function(index){
4041 return this.config[index].id;
4045 * Returns the column for a specified id.
4046 * @param {String} id The column id
4047 * @return {Object} the column
4049 getColumnById : function(id){
4050 return this.lookup[id];
4055 * Returns the column for a specified dataIndex.
4056 * @param {String} dataIndex The column dataIndex
4057 * @return {Object|Boolean} the column or false if not found
4059 getColumnByDataIndex: function(dataIndex){
4060 var index = this.findColumnIndex(dataIndex);
4061 return index > -1 ? this.config[index] : false;
4065 * Returns the index for a specified column id.
4066 * @param {String} id The column id
4067 * @return {Number} the index, or -1 if not found
4069 getIndexById : function(id){
4070 for(var i = 0, len = this.config.length; i < len; i++){
4071 if(this.config[i].id == id){
4079 * Returns the index for a specified column dataIndex.
4080 * @param {String} dataIndex The column dataIndex
4081 * @return {Number} the index, or -1 if not found
4084 findColumnIndex : function(dataIndex){
4085 for(var i = 0, len = this.config.length; i < len; i++){
4086 if(this.config[i].dataIndex == dataIndex){
4094 moveColumn : function(oldIndex, newIndex){
4095 var c = this.config[oldIndex];
4096 this.config.splice(oldIndex, 1);
4097 this.config.splice(newIndex, 0, c);
4098 this.dataMap = null;
4099 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4102 isLocked : function(colIndex){
4103 return this.config[colIndex].locked === true;
4106 setLocked : function(colIndex, value, suppressEvent){
4107 if(this.isLocked(colIndex) == value){
4110 this.config[colIndex].locked = value;
4112 this.fireEvent("columnlockchange", this, colIndex, value);
4116 getTotalLockedWidth : function(){
4118 for(var i = 0; i < this.config.length; i++){
4119 if(this.isLocked(i) && !this.isHidden(i)){
4120 this.totalWidth += this.getColumnWidth(i);
4126 getLockedCount : function(){
4127 for(var i = 0, len = this.config.length; i < len; i++){
4128 if(!this.isLocked(i)){
4135 * Returns the number of columns.
4138 getColumnCount : function(visibleOnly){
4139 if(visibleOnly === true){
4141 for(var i = 0, len = this.config.length; i < len; i++){
4142 if(!this.isHidden(i)){
4148 return this.config.length;
4152 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4153 * @param {Function} fn
4154 * @param {Object} scope (optional)
4155 * @return {Array} result
4157 getColumnsBy : function(fn, scope){
4159 for(var i = 0, len = this.config.length; i < len; i++){
4160 var c = this.config[i];
4161 if(fn.call(scope||this, c, i) === true){
4169 * Returns true if the specified column is sortable.
4170 * @param {Number} col The column index
4173 isSortable : function(col){
4174 if(typeof this.config[col].sortable == "undefined"){
4175 return this.defaultSortable;
4177 return this.config[col].sortable;
4181 * Returns the rendering (formatting) function defined for the column.
4182 * @param {Number} col The column index.
4183 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4185 getRenderer : function(col){
4186 if(!this.config[col].renderer){
4187 return Roo.grid.ColumnModel.defaultRenderer;
4189 return this.config[col].renderer;
4193 * Sets the rendering (formatting) function for a column.
4194 * @param {Number} col The column index
4195 * @param {Function} fn The function to use to process the cell's raw data
4196 * to return HTML markup for the grid view. The render function is called with
4197 * the following parameters:<ul>
4198 * <li>Data value.</li>
4199 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4200 * <li>css A CSS style string to apply to the table cell.</li>
4201 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4202 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4203 * <li>Row index</li>
4204 * <li>Column index</li>
4205 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4207 setRenderer : function(col, fn){
4208 this.config[col].renderer = fn;
4212 * Returns the width for the specified column.
4213 * @param {Number} col The column index
4216 getColumnWidth : function(col){
4217 return this.config[col].width * 1 || this.defaultWidth;
4221 * Sets the width for a column.
4222 * @param {Number} col The column index
4223 * @param {Number} width The new width
4225 setColumnWidth : function(col, width, suppressEvent){
4226 this.config[col].width = width;
4227 this.totalWidth = null;
4229 this.fireEvent("widthchange", this, col, width);
4234 * Returns the total width of all columns.
4235 * @param {Boolean} includeHidden True to include hidden column widths
4238 getTotalWidth : function(includeHidden){
4239 if(!this.totalWidth){
4240 this.totalWidth = 0;
4241 for(var i = 0, len = this.config.length; i < len; i++){
4242 if(includeHidden || !this.isHidden(i)){
4243 this.totalWidth += this.getColumnWidth(i);
4247 return this.totalWidth;
4251 * Returns the header for the specified column.
4252 * @param {Number} col The column index
4255 getColumnHeader : function(col){
4256 return this.config[col].header;
4260 * Sets the header for a column.
4261 * @param {Number} col The column index
4262 * @param {String} header The new header
4264 setColumnHeader : function(col, header){
4265 this.config[col].header = header;
4266 this.fireEvent("headerchange", this, col, header);
4270 * Returns the tooltip for the specified column.
4271 * @param {Number} col The column index
4274 getColumnTooltip : function(col){
4275 return this.config[col].tooltip;
4278 * Sets the tooltip for a column.
4279 * @param {Number} col The column index
4280 * @param {String} tooltip The new tooltip
4282 setColumnTooltip : function(col, tooltip){
4283 this.config[col].tooltip = tooltip;
4287 * Returns the dataIndex for the specified column.
4288 * @param {Number} col The column index
4291 getDataIndex : function(col){
4292 return this.config[col].dataIndex;
4296 * Sets the dataIndex for a column.
4297 * @param {Number} col The column index
4298 * @param {Number} dataIndex The new dataIndex
4300 setDataIndex : function(col, dataIndex){
4301 this.config[col].dataIndex = dataIndex;
4307 * Returns true if the cell is editable.
4308 * @param {Number} colIndex The column index
4309 * @param {Number} rowIndex The row index
4312 isCellEditable : function(colIndex, rowIndex){
4313 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4317 * Returns the editor defined for the cell/column.
4318 * return false or null to disable editing.
4319 * @param {Number} colIndex The column index
4320 * @param {Number} rowIndex The row index
4323 getCellEditor : function(colIndex, rowIndex){
4324 return this.config[colIndex].editor;
4328 * Sets if a column is editable.
4329 * @param {Number} col The column index
4330 * @param {Boolean} editable True if the column is editable
4332 setEditable : function(col, editable){
4333 this.config[col].editable = editable;
4338 * Returns true if the column is hidden.
4339 * @param {Number} colIndex The column index
4342 isHidden : function(colIndex){
4343 return this.config[colIndex].hidden;
4348 * Returns true if the column width cannot be changed
4350 isFixed : function(colIndex){
4351 return this.config[colIndex].fixed;
4355 * Returns true if the column can be resized
4358 isResizable : function(colIndex){
4359 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4362 * Sets if a column is hidden.
4363 * @param {Number} colIndex The column index
4364 * @param {Boolean} hidden True if the column is hidden
4366 setHidden : function(colIndex, hidden){
4367 this.config[colIndex].hidden = hidden;
4368 this.totalWidth = null;
4369 this.fireEvent("hiddenchange", this, colIndex, hidden);
4373 * Sets the editor for a column.
4374 * @param {Number} col The column index
4375 * @param {Object} editor The editor object
4377 setEditor : function(col, editor){
4378 this.config[col].editor = editor;
4382 Roo.grid.ColumnModel.defaultRenderer = function(value){
4383 if(typeof value == "string" && value.length < 1){
4389 // Alias for backwards compatibility
4390 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4393 * Ext JS Library 1.1.1
4394 * Copyright(c) 2006-2007, Ext JS, LLC.
4396 * Originally Released Under LGPL - original licence link has changed is not relivant.
4399 * <script type="text/javascript">
4403 * @class Roo.LoadMask
4404 * A simple utility class for generically masking elements while loading data. If the element being masked has
4405 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4406 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4407 * element's UpdateManager load indicator and will be destroyed after the initial load.
4409 * Create a new LoadMask
4410 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4411 * @param {Object} config The config object
4413 Roo.LoadMask = function(el, config){
4414 this.el = Roo.get(el);
4415 Roo.apply(this, config);
4417 this.store.on('beforeload', this.onBeforeLoad, this);
4418 this.store.on('load', this.onLoad, this);
4419 this.store.on('loadexception', this.onLoadException, this);
4420 this.removeMask = false;
4422 var um = this.el.getUpdateManager();
4423 um.showLoadIndicator = false; // disable the default indicator
4424 um.on('beforeupdate', this.onBeforeLoad, this);
4425 um.on('update', this.onLoad, this);
4426 um.on('failure', this.onLoad, this);
4427 this.removeMask = true;
4431 Roo.LoadMask.prototype = {
4433 * @cfg {Boolean} removeMask
4434 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4435 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4439 * The text to display in a centered loading message box (defaults to 'Loading...')
4443 * @cfg {String} msgCls
4444 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4446 msgCls : 'x-mask-loading',
4449 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4455 * Disables the mask to prevent it from being displayed
4457 disable : function(){
4458 this.disabled = true;
4462 * Enables the mask so that it can be displayed
4464 enable : function(){
4465 this.disabled = false;
4468 onLoadException : function()
4472 if (typeof(arguments[3]) != 'undefined') {
4473 Roo.MessageBox.alert("Error loading",arguments[3]);
4477 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4478 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4487 this.el.unmask(this.removeMask);
4492 this.el.unmask(this.removeMask);
4496 onBeforeLoad : function(){
4498 this.el.mask(this.msg, this.msgCls);
4503 destroy : function(){
4505 this.store.un('beforeload', this.onBeforeLoad, this);
4506 this.store.un('load', this.onLoad, this);
4507 this.store.un('loadexception', this.onLoadException, this);
4509 var um = this.el.getUpdateManager();
4510 um.un('beforeupdate', this.onBeforeLoad, this);
4511 um.un('update', this.onLoad, this);
4512 um.un('failure', this.onLoad, this);
4523 * @class Roo.bootstrap.Table
4524 * @extends Roo.bootstrap.Component
4525 * Bootstrap Table class
4526 * @cfg {String} cls table class
4527 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4528 * @cfg {String} bgcolor Specifies the background color for a table
4529 * @cfg {Number} border Specifies whether the table cells should have borders or not
4530 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4531 * @cfg {Number} cellspacing Specifies the space between cells
4532 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4533 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4534 * @cfg {String} sortable Specifies that the table should be sortable
4535 * @cfg {String} summary Specifies a summary of the content of a table
4536 * @cfg {Number} width Specifies the width of a table
4537 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4539 * @cfg {boolean} striped Should the rows be alternative striped
4540 * @cfg {boolean} bordered Add borders to the table
4541 * @cfg {boolean} hover Add hover highlighting
4542 * @cfg {boolean} condensed Format condensed
4543 * @cfg {boolean} responsive Format condensed
4544 * @cfg {Boolean} loadMask (true|false) default false
4545 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4546 * @cfg {Boolean} thead (true|false) generate thead, default true
4547 * @cfg {Boolean} RowSelection (true|false) default false
4548 * @cfg {Boolean} CellSelection (true|false) default false
4550 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4554 * Create a new Table
4555 * @param {Object} config The config object
4558 Roo.bootstrap.Table = function(config){
4559 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4562 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4563 this.sm = this.selModel;
4564 this.sm.xmodule = this.xmodule || false;
4566 if (this.cm && typeof(this.cm.config) == 'undefined') {
4567 this.colModel = new Roo.grid.ColumnModel(this.cm);
4568 this.cm = this.colModel;
4569 this.cm.xmodule = this.xmodule || false;
4572 this.store= Roo.factory(this.store, Roo.data);
4573 this.ds = this.store;
4574 this.ds.xmodule = this.xmodule || false;
4577 if (this.footer && this.store) {
4578 this.footer.dataSource = this.ds;
4579 this.footer = Roo.factory(this.footer);
4586 * Fires when a cell is clicked
4587 * @param {Roo.bootstrap.Table} this
4588 * @param {Roo.Element} el
4589 * @param {Number} rowIndex
4590 * @param {Number} columnIndex
4591 * @param {Roo.EventObject} e
4595 * @event celldblclick
4596 * Fires when a cell is double clicked
4597 * @param {Roo.bootstrap.Table} this
4598 * @param {Roo.Element} el
4599 * @param {Number} rowIndex
4600 * @param {Number} columnIndex
4601 * @param {Roo.EventObject} e
4603 "celldblclick" : true,
4606 * Fires when a row is clicked
4607 * @param {Roo.bootstrap.Table} this
4608 * @param {Roo.Element} el
4609 * @param {Number} rowIndex
4610 * @param {Roo.EventObject} e
4614 * @event rowdblclick
4615 * Fires when a row is double clicked
4616 * @param {Roo.bootstrap.Table} this
4617 * @param {Roo.Element} el
4618 * @param {Number} rowIndex
4619 * @param {Roo.EventObject} e
4621 "rowdblclick" : true,
4624 * Fires when a mouseover occur
4625 * @param {Roo.bootstrap.Table} this
4626 * @param {Roo.Element} el
4627 * @param {Number} rowIndex
4628 * @param {Number} columnIndex
4629 * @param {Roo.EventObject} e
4634 * Fires when a mouseout occur
4635 * @param {Roo.bootstrap.Table} this
4636 * @param {Roo.Element} el
4637 * @param {Number} rowIndex
4638 * @param {Number} columnIndex
4639 * @param {Roo.EventObject} e
4644 * Fires when a row is rendered, so you can change add a style to it.
4645 * @param {Roo.bootstrap.Table} this
4646 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4653 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4677 RowSelection : false,
4678 CellSelection : false,
4681 // Roo.Element - the tbody
4684 getAutoCreate : function(){
4685 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4694 cfg.cls += ' table-striped';
4698 cfg.cls += ' table-hover';
4700 if (this.bordered) {
4701 cfg.cls += ' table-bordered';
4703 if (this.condensed) {
4704 cfg.cls += ' table-condensed';
4706 if (this.responsive) {
4707 cfg.cls += ' table-responsive';
4711 cfg.cls+= ' ' +this.cls;
4714 // this lot should be simplifed...
4717 cfg.align=this.align;
4720 cfg.bgcolor=this.bgcolor;
4723 cfg.border=this.border;
4725 if (this.cellpadding) {
4726 cfg.cellpadding=this.cellpadding;
4728 if (this.cellspacing) {
4729 cfg.cellspacing=this.cellspacing;
4732 cfg.frame=this.frame;
4735 cfg.rules=this.rules;
4737 if (this.sortable) {
4738 cfg.sortable=this.sortable;
4741 cfg.summary=this.summary;
4744 cfg.width=this.width;
4747 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4750 if(this.store || this.cm){
4752 cfg.cn.push(this.renderHeader());
4755 cfg.cn.push(this.renderBody());
4758 cfg.cn.push(this.renderFooter());
4761 cfg.cls+= ' TableGrid';
4764 return { cn : [ cfg ] };
4767 initEvents : function()
4769 if(!this.store || !this.cm){
4773 //Roo.log('initEvents with ds!!!!');
4775 this.mainBody = this.el.select('tbody', true).first();
4780 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4781 e.on('click', _this.sort, _this);
4784 this.el.on("click", this.onClick, this);
4785 this.el.on("dblclick", this.onDblClick, this);
4787 this.parent().el.setStyle('position', 'relative');
4789 this.footer.parentId = this.id;
4790 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4793 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4795 this.store.on('load', this.onLoad, this);
4796 this.store.on('beforeload', this.onBeforeLoad, this);
4797 this.store.on('update', this.onUpdate, this);
4801 onMouseover : function(e, el)
4803 var cell = Roo.get(el);
4809 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4810 cell = cell.findParent('td', false, true);
4813 var row = cell.findParent('tr', false, true);
4814 var cellIndex = cell.dom.cellIndex;
4815 var rowIndex = row.dom.rowIndex - 1; // start from 0
4817 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4821 onMouseout : function(e, el)
4823 var cell = Roo.get(el);
4829 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4830 cell = cell.findParent('td', false, true);
4833 var row = cell.findParent('tr', false, true);
4834 var cellIndex = cell.dom.cellIndex;
4835 var rowIndex = row.dom.rowIndex - 1; // start from 0
4837 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4841 onClick : function(e, el)
4843 var cell = Roo.get(el);
4845 if(!cell || (!this.CellSelection && !this.RowSelection)){
4850 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4851 cell = cell.findParent('td', false, true);
4854 var row = cell.findParent('tr', false, true);
4855 var cellIndex = cell.dom.cellIndex;
4856 var rowIndex = row.dom.rowIndex - 1;
4858 if(this.CellSelection){
4859 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4862 if(this.RowSelection){
4863 this.fireEvent('rowclick', this, row, rowIndex, e);
4869 onDblClick : function(e,el)
4871 var cell = Roo.get(el);
4873 if(!cell || (!this.CellSelection && !this.RowSelection)){
4877 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4878 cell = cell.findParent('td', false, true);
4881 var row = cell.findParent('tr', false, true);
4882 var cellIndex = cell.dom.cellIndex;
4883 var rowIndex = row.dom.rowIndex - 1;
4885 if(this.CellSelection){
4886 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4889 if(this.RowSelection){
4890 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4894 sort : function(e,el)
4896 var col = Roo.get(el)
4898 if(!col.hasClass('sortable')){
4902 var sort = col.attr('sort');
4905 if(col.hasClass('glyphicon-arrow-up')){
4909 this.store.sortInfo = {field : sort, direction : dir};
4912 Roo.log("calling footer first");
4913 this.footer.onClick('first');
4916 this.store.load({ params : { start : 0 } });
4920 renderHeader : function()
4929 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4931 var config = cm.config[i];
4936 html: cm.getColumnHeader(i)
4939 if(typeof(config.hidden) != 'undefined' && config.hidden){
4940 c.style += ' display:none;';
4943 if(typeof(config.dataIndex) != 'undefined'){
4944 c.sort = config.dataIndex;
4947 if(typeof(config.sortable) != 'undefined' && config.sortable){
4951 // if(typeof(config.align) != 'undefined' && config.align.length){
4952 // c.style += ' text-align:' + config.align + ';';
4955 if(typeof(config.width) != 'undefined'){
4956 c.style += ' width:' + config.width + 'px;';
4965 renderBody : function()
4975 colspan : this.cm.getColumnCount()
4985 renderFooter : function()
4995 colspan : this.cm.getColumnCount()
5009 Roo.log('ds onload');
5014 var ds = this.store;
5016 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5017 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5019 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5020 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5023 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5024 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5028 var tbody = this.mainBody;
5032 if(ds.getCount() > 0){
5033 ds.data.each(function(d,rowIndex){
5034 var row = this.renderRow(cm, ds, rowIndex);
5036 tbody.createChild(row);
5044 Roo.each(renders, function(r){
5045 _this.renderColumn(r);
5049 Roo.each(this.el.select('tbody td', true).elements, function(e){
5050 e.on('mouseover', _this.onMouseover, _this);
5053 Roo.each(this.el.select('tbody td', true).elements, function(e){
5054 e.on('mouseout', _this.onMouseout, _this);
5057 //if(this.loadMask){
5058 // this.maskEl.hide();
5063 onUpdate : function(ds,record)
5065 this.refreshRow(record);
5067 onRemove : function(ds, record, index, isUpdate){
5068 if(isUpdate !== true){
5069 this.fireEvent("beforerowremoved", this, index, record);
5071 var bt = this.mainBody.dom;
5073 bt.removeChild(bt.rows[index]);
5076 if(isUpdate !== true){
5077 //this.stripeRows(index);
5078 //this.syncRowHeights(index, index);
5080 this.fireEvent("rowremoved", this, index, record);
5085 refreshRow : function(record){
5086 var ds = this.store, index;
5087 if(typeof record == 'number'){
5089 record = ds.getAt(index);
5091 index = ds.indexOf(record);
5093 this.insertRow(ds, index, true);
5094 this.onRemove(ds, record, index+1, true);
5095 //this.syncRowHeights(index, index);
5097 this.fireEvent("rowupdated", this, index, record);
5100 insertRow : function(dm, rowIndex, isUpdate){
5103 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
5105 //var s = this.getScrollState();
5106 var row = this.renderRow(this.cm, this.store, rowIndex);
5107 // insert before rowIndex..
5108 this.mainBody.createChild(row,this.getRowDom(rowIndex));
5111 this.fireEvent("rowsinserted", this, firstRow, lastRow);
5112 //this.syncRowHeights(firstRow, lastRow);
5113 //this.stripeRows(firstRow);
5120 getRowDom : function(rowIndex)
5122 // not sure if I need to check this.. but let's do it anyway..
5123 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5124 this.mainBody.dom.rows[rowIndex] : false
5126 // returns the object tree for a tr..
5129 renderRow : function(cm, ds, rowIndex) {
5131 var d = ds.getAt(rowIndex);
5140 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5141 var config = cm.config[i];
5143 var renderer = cm.getRenderer(i);
5147 if(typeof(renderer) !== 'undefined'){
5148 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5151 if(typeof(value) === 'object'){
5160 rowIndex : rowIndex,
5165 this.fireEvent('rowclass', this, rowcfg);
5170 cls : rowcfg.rowClass,
5172 html: (typeof(value) === 'object') ? '' : value
5175 if(typeof(config.hidden) != 'undefined' && config.hidden){
5176 td.style += ' display:none;';
5179 if(typeof(config.align) != 'undefined' && config.align.length){
5180 td.style += ' text-align:' + config.align + ';';
5183 if(typeof(config.width) != 'undefined'){
5184 td.style += ' width:' + config.width + 'px;';
5196 onBeforeLoad : function()
5198 //Roo.log('ds onBeforeLoad');
5202 //if(this.loadMask){
5203 // this.maskEl.show();
5209 this.el.select('tbody', true).first().dom.innerHTML = '';
5212 getSelectionModel : function(){
5214 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5216 return this.selModel;
5219 renderColumn : function(r)
5223 var t = r.cfg.render(r.container);
5226 Roo.each(r.cfg.cn, function(c){
5228 container: t.getChildContainer(),
5231 _this.renderColumn(child);
5248 * @class Roo.bootstrap.TableCell
5249 * @extends Roo.bootstrap.Component
5250 * Bootstrap TableCell class
5251 * @cfg {String} html cell contain text
5252 * @cfg {String} cls cell class
5253 * @cfg {String} tag cell tag (td|th) default td
5254 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5255 * @cfg {String} align Aligns the content in a cell
5256 * @cfg {String} axis Categorizes cells
5257 * @cfg {String} bgcolor Specifies the background color of a cell
5258 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5259 * @cfg {Number} colspan Specifies the number of columns a cell should span
5260 * @cfg {String} headers Specifies one or more header cells a cell is related to
5261 * @cfg {Number} height Sets the height of a cell
5262 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5263 * @cfg {Number} rowspan Sets the number of rows a cell should span
5264 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5265 * @cfg {String} valign Vertical aligns the content in a cell
5266 * @cfg {Number} width Specifies the width of a cell
5269 * Create a new TableCell
5270 * @param {Object} config The config object
5273 Roo.bootstrap.TableCell = function(config){
5274 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5277 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5297 getAutoCreate : function(){
5298 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5318 cfg.align=this.align
5324 cfg.bgcolor=this.bgcolor
5327 cfg.charoff=this.charoff
5330 cfg.colspan=this.colspan
5333 cfg.headers=this.headers
5336 cfg.height=this.height
5339 cfg.nowrap=this.nowrap
5342 cfg.rowspan=this.rowspan
5345 cfg.scope=this.scope
5348 cfg.valign=this.valign
5351 cfg.width=this.width
5370 * @class Roo.bootstrap.TableRow
5371 * @extends Roo.bootstrap.Component
5372 * Bootstrap TableRow class
5373 * @cfg {String} cls row class
5374 * @cfg {String} align Aligns the content in a table row
5375 * @cfg {String} bgcolor Specifies a background color for a table row
5376 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5377 * @cfg {String} valign Vertical aligns the content in a table row
5380 * Create a new TableRow
5381 * @param {Object} config The config object
5384 Roo.bootstrap.TableRow = function(config){
5385 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5388 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5396 getAutoCreate : function(){
5397 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5407 cfg.align = this.align;
5410 cfg.bgcolor = this.bgcolor;
5413 cfg.charoff = this.charoff;
5416 cfg.valign = this.valign;
5434 * @class Roo.bootstrap.TableBody
5435 * @extends Roo.bootstrap.Component
5436 * Bootstrap TableBody class
5437 * @cfg {String} cls element class
5438 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5439 * @cfg {String} align Aligns the content inside the element
5440 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5441 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5444 * Create a new TableBody
5445 * @param {Object} config The config object
5448 Roo.bootstrap.TableBody = function(config){
5449 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5452 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5460 getAutoCreate : function(){
5461 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5475 cfg.align = this.align;
5478 cfg.charoff = this.charoff;
5481 cfg.valign = this.valign;
5488 // initEvents : function()
5495 // this.store = Roo.factory(this.store, Roo.data);
5496 // this.store.on('load', this.onLoad, this);
5498 // this.store.load();
5502 // onLoad: function ()
5504 // this.fireEvent('load', this);
5514 * Ext JS Library 1.1.1
5515 * Copyright(c) 2006-2007, Ext JS, LLC.
5517 * Originally Released Under LGPL - original licence link has changed is not relivant.
5520 * <script type="text/javascript">
5523 // as we use this in bootstrap.
5524 Roo.namespace('Roo.form');
5526 * @class Roo.form.Action
5527 * Internal Class used to handle form actions
5529 * @param {Roo.form.BasicForm} el The form element or its id
5530 * @param {Object} config Configuration options
5535 // define the action interface
5536 Roo.form.Action = function(form, options){
5538 this.options = options || {};
5541 * Client Validation Failed
5544 Roo.form.Action.CLIENT_INVALID = 'client';
5546 * Server Validation Failed
5549 Roo.form.Action.SERVER_INVALID = 'server';
5551 * Connect to Server Failed
5554 Roo.form.Action.CONNECT_FAILURE = 'connect';
5556 * Reading Data from Server Failed
5559 Roo.form.Action.LOAD_FAILURE = 'load';
5561 Roo.form.Action.prototype = {
5563 failureType : undefined,
5564 response : undefined,
5568 run : function(options){
5573 success : function(response){
5578 handleResponse : function(response){
5582 // default connection failure
5583 failure : function(response){
5585 this.response = response;
5586 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5587 this.form.afterAction(this, false);
5590 processResponse : function(response){
5591 this.response = response;
5592 if(!response.responseText){
5595 this.result = this.handleResponse(response);
5599 // utility functions used internally
5600 getUrl : function(appendParams){
5601 var url = this.options.url || this.form.url || this.form.el.dom.action;
5603 var p = this.getParams();
5605 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5611 getMethod : function(){
5612 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5615 getParams : function(){
5616 var bp = this.form.baseParams;
5617 var p = this.options.params;
5619 if(typeof p == "object"){
5620 p = Roo.urlEncode(Roo.applyIf(p, bp));
5621 }else if(typeof p == 'string' && bp){
5622 p += '&' + Roo.urlEncode(bp);
5625 p = Roo.urlEncode(bp);
5630 createCallback : function(){
5632 success: this.success,
5633 failure: this.failure,
5635 timeout: (this.form.timeout*1000),
5636 upload: this.form.fileUpload ? this.success : undefined
5641 Roo.form.Action.Submit = function(form, options){
5642 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5645 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5648 haveProgress : false,
5649 uploadComplete : false,
5651 // uploadProgress indicator.
5652 uploadProgress : function()
5654 if (!this.form.progressUrl) {
5658 if (!this.haveProgress) {
5659 Roo.MessageBox.progress("Uploading", "Uploading");
5661 if (this.uploadComplete) {
5662 Roo.MessageBox.hide();
5666 this.haveProgress = true;
5668 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5670 var c = new Roo.data.Connection();
5672 url : this.form.progressUrl,
5677 success : function(req){
5678 //console.log(data);
5682 rdata = Roo.decode(req.responseText)
5684 Roo.log("Invalid data from server..");
5688 if (!rdata || !rdata.success) {
5690 Roo.MessageBox.alert(Roo.encode(rdata));
5693 var data = rdata.data;
5695 if (this.uploadComplete) {
5696 Roo.MessageBox.hide();
5701 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5702 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5705 this.uploadProgress.defer(2000,this);
5708 failure: function(data) {
5709 Roo.log('progress url failed ');
5720 // run get Values on the form, so it syncs any secondary forms.
5721 this.form.getValues();
5723 var o = this.options;
5724 var method = this.getMethod();
5725 var isPost = method == 'POST';
5726 if(o.clientValidation === false || this.form.isValid()){
5728 if (this.form.progressUrl) {
5729 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5730 (new Date() * 1) + '' + Math.random());
5735 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5736 form:this.form.el.dom,
5737 url:this.getUrl(!isPost),
5739 params:isPost ? this.getParams() : null,
5740 isUpload: this.form.fileUpload
5743 this.uploadProgress();
5745 }else if (o.clientValidation !== false){ // client validation failed
5746 this.failureType = Roo.form.Action.CLIENT_INVALID;
5747 this.form.afterAction(this, false);
5751 success : function(response)
5753 this.uploadComplete= true;
5754 if (this.haveProgress) {
5755 Roo.MessageBox.hide();
5759 var result = this.processResponse(response);
5760 if(result === true || result.success){
5761 this.form.afterAction(this, true);
5765 this.form.markInvalid(result.errors);
5766 this.failureType = Roo.form.Action.SERVER_INVALID;
5768 this.form.afterAction(this, false);
5770 failure : function(response)
5772 this.uploadComplete= true;
5773 if (this.haveProgress) {
5774 Roo.MessageBox.hide();
5777 this.response = response;
5778 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5779 this.form.afterAction(this, false);
5782 handleResponse : function(response){
5783 if(this.form.errorReader){
5784 var rs = this.form.errorReader.read(response);
5787 for(var i = 0, len = rs.records.length; i < len; i++) {
5788 var r = rs.records[i];
5792 if(errors.length < 1){
5796 success : rs.success,
5802 ret = Roo.decode(response.responseText);
5806 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5816 Roo.form.Action.Load = function(form, options){
5817 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5818 this.reader = this.form.reader;
5821 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5826 Roo.Ajax.request(Roo.apply(
5827 this.createCallback(), {
5828 method:this.getMethod(),
5829 url:this.getUrl(false),
5830 params:this.getParams()
5834 success : function(response){
5836 var result = this.processResponse(response);
5837 if(result === true || !result.success || !result.data){
5838 this.failureType = Roo.form.Action.LOAD_FAILURE;
5839 this.form.afterAction(this, false);
5842 this.form.clearInvalid();
5843 this.form.setValues(result.data);
5844 this.form.afterAction(this, true);
5847 handleResponse : function(response){
5848 if(this.form.reader){
5849 var rs = this.form.reader.read(response);
5850 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5852 success : rs.success,
5856 return Roo.decode(response.responseText);
5860 Roo.form.Action.ACTION_TYPES = {
5861 'load' : Roo.form.Action.Load,
5862 'submit' : Roo.form.Action.Submit
5871 * @class Roo.bootstrap.Form
5872 * @extends Roo.bootstrap.Component
5873 * Bootstrap Form class
5874 * @cfg {String} method GET | POST (default POST)
5875 * @cfg {String} labelAlign top | left (default top)
5876 * @cfg {String} align left | right - for navbars
5881 * @param {Object} config The config object
5885 Roo.bootstrap.Form = function(config){
5886 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5889 * @event clientvalidation
5890 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5891 * @param {Form} this
5892 * @param {Boolean} valid true if the form has passed client-side validation
5894 clientvalidation: true,
5896 * @event beforeaction
5897 * Fires before any action is performed. Return false to cancel the action.
5898 * @param {Form} this
5899 * @param {Action} action The action to be performed
5903 * @event actionfailed
5904 * Fires when an action fails.
5905 * @param {Form} this
5906 * @param {Action} action The action that failed
5908 actionfailed : true,
5910 * @event actioncomplete
5911 * Fires when an action is completed.
5912 * @param {Form} this
5913 * @param {Action} action The action that completed
5915 actioncomplete : true
5920 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5923 * @cfg {String} method
5924 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5929 * The URL to use for form actions if one isn't supplied in the action options.
5932 * @cfg {Boolean} fileUpload
5933 * Set to true if this form is a file upload.
5937 * @cfg {Object} baseParams
5938 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5942 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5946 * @cfg {Sting} align (left|right) for navbar forms
5951 activeAction : null,
5954 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5955 * element by passing it or its id or mask the form itself by passing in true.
5958 waitMsgTarget : false,
5963 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5964 * element by passing it or its id or mask the form itself by passing in true.
5968 getAutoCreate : function(){
5972 method : this.method || 'POST',
5973 id : this.id || Roo.id(),
5976 if (this.parent().xtype.match(/^Nav/)) {
5977 cfg.cls = 'navbar-form navbar-' + this.align;
5981 if (this.labelAlign == 'left' ) {
5982 cfg.cls += ' form-horizontal';
5988 initEvents : function()
5990 this.el.on('submit', this.onSubmit, this);
5991 // this was added as random key presses on the form where triggering form submit.
5992 this.el.on('keypress', function(e) {
5993 if (e.getCharCode() != 13) {
5996 // we might need to allow it for textareas.. and some other items.
5997 // check e.getTarget().
5999 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6003 Roo.log("keypress blocked");
6011 onSubmit : function(e){
6016 * Returns true if client-side validation on the form is successful.
6019 isValid : function(){
6020 var items = this.getItems();
6022 items.each(function(f){
6031 * Returns true if any fields in this form have changed since their original load.
6034 isDirty : function(){
6036 var items = this.getItems();
6037 items.each(function(f){
6047 * Performs a predefined action (submit or load) or custom actions you define on this form.
6048 * @param {String} actionName The name of the action type
6049 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6050 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6051 * accept other config options):
6053 Property Type Description
6054 ---------------- --------------- ----------------------------------------------------------------------------------
6055 url String The url for the action (defaults to the form's url)
6056 method String The form method to use (defaults to the form's method, or POST if not defined)
6057 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6058 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6059 validate the form on the client (defaults to false)
6061 * @return {BasicForm} this
6063 doAction : function(action, options){
6064 if(typeof action == 'string'){
6065 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6067 if(this.fireEvent('beforeaction', this, action) !== false){
6068 this.beforeAction(action);
6069 action.run.defer(100, action);
6075 beforeAction : function(action){
6076 var o = action.options;
6078 // not really supported yet.. ??
6080 //if(this.waitMsgTarget === true){
6081 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6082 //}else if(this.waitMsgTarget){
6083 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6084 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6086 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6092 afterAction : function(action, success){
6093 this.activeAction = null;
6094 var o = action.options;
6096 //if(this.waitMsgTarget === true){
6098 //}else if(this.waitMsgTarget){
6099 // this.waitMsgTarget.unmask();
6101 // Roo.MessageBox.updateProgress(1);
6102 // Roo.MessageBox.hide();
6109 Roo.callback(o.success, o.scope, [this, action]);
6110 this.fireEvent('actioncomplete', this, action);
6114 // failure condition..
6115 // we have a scenario where updates need confirming.
6116 // eg. if a locking scenario exists..
6117 // we look for { errors : { needs_confirm : true }} in the response.
6119 (typeof(action.result) != 'undefined') &&
6120 (typeof(action.result.errors) != 'undefined') &&
6121 (typeof(action.result.errors.needs_confirm) != 'undefined')
6124 Roo.log("not supported yet");
6127 Roo.MessageBox.confirm(
6128 "Change requires confirmation",
6129 action.result.errorMsg,
6134 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6144 Roo.callback(o.failure, o.scope, [this, action]);
6145 // show an error message if no failed handler is set..
6146 if (!this.hasListener('actionfailed')) {
6147 Roo.log("need to add dialog support");
6149 Roo.MessageBox.alert("Error",
6150 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6151 action.result.errorMsg :
6152 "Saving Failed, please check your entries or try again"
6157 this.fireEvent('actionfailed', this, action);
6162 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6163 * @param {String} id The value to search for
6166 findField : function(id){
6167 var items = this.getItems();
6168 var field = items.get(id);
6170 items.each(function(f){
6171 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6178 return field || null;
6181 * Mark fields in this form invalid in bulk.
6182 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6183 * @return {BasicForm} this
6185 markInvalid : function(errors){
6186 if(errors instanceof Array){
6187 for(var i = 0, len = errors.length; i < len; i++){
6188 var fieldError = errors[i];
6189 var f = this.findField(fieldError.id);
6191 f.markInvalid(fieldError.msg);
6197 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6198 field.markInvalid(errors[id]);
6202 //Roo.each(this.childForms || [], function (f) {
6203 // f.markInvalid(errors);
6210 * Set values for fields in this form in bulk.
6211 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6212 * @return {BasicForm} this
6214 setValues : function(values){
6215 if(values instanceof Array){ // array of objects
6216 for(var i = 0, len = values.length; i < len; i++){
6218 var f = this.findField(v.id);
6220 f.setValue(v.value);
6221 if(this.trackResetOnLoad){
6222 f.originalValue = f.getValue();
6226 }else{ // object hash
6229 if(typeof values[id] != 'function' && (field = this.findField(id))){
6231 if (field.setFromData &&
6233 field.displayField &&
6234 // combos' with local stores can
6235 // be queried via setValue()
6236 // to set their value..
6237 (field.store && !field.store.isLocal)
6241 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6242 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6243 field.setFromData(sd);
6246 field.setValue(values[id]);
6250 if(this.trackResetOnLoad){
6251 field.originalValue = field.getValue();
6257 //Roo.each(this.childForms || [], function (f) {
6258 // f.setValues(values);
6265 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6266 * they are returned as an array.
6267 * @param {Boolean} asString
6270 getValues : function(asString){
6271 //if (this.childForms) {
6272 // copy values from the child forms
6273 // Roo.each(this.childForms, function (f) {
6274 // this.setValues(f.getValues());
6280 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6281 if(asString === true){
6284 return Roo.urlDecode(fs);
6288 * Returns the fields in this form as an object with key/value pairs.
6289 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6292 getFieldValues : function(with_hidden)
6294 var items = this.getItems();
6296 items.each(function(f){
6300 var v = f.getValue();
6301 if (f.inputType =='radio') {
6302 if (typeof(ret[f.getName()]) == 'undefined') {
6303 ret[f.getName()] = ''; // empty..
6306 if (!f.el.dom.checked) {
6314 // not sure if this supported any more..
6315 if ((typeof(v) == 'object') && f.getRawValue) {
6316 v = f.getRawValue() ; // dates..
6318 // combo boxes where name != hiddenName...
6319 if (f.name != f.getName()) {
6320 ret[f.name] = f.getRawValue();
6322 ret[f.getName()] = v;
6329 * Clears all invalid messages in this form.
6330 * @return {BasicForm} this
6332 clearInvalid : function(){
6333 var items = this.getItems();
6335 items.each(function(f){
6346 * @return {BasicForm} this
6349 var items = this.getItems();
6350 items.each(function(f){
6354 Roo.each(this.childForms || [], function (f) {
6361 getItems : function()
6363 var r=new Roo.util.MixedCollection(false, function(o){
6364 return o.id || (o.id = Roo.id());
6366 var iter = function(el) {
6373 Roo.each(el.items,function(e) {
6392 * Ext JS Library 1.1.1
6393 * Copyright(c) 2006-2007, Ext JS, LLC.
6395 * Originally Released Under LGPL - original licence link has changed is not relivant.
6398 * <script type="text/javascript">
6401 * @class Roo.form.VTypes
6402 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6405 Roo.form.VTypes = function(){
6406 // closure these in so they are only created once.
6407 var alpha = /^[a-zA-Z_]+$/;
6408 var alphanum = /^[a-zA-Z0-9_]+$/;
6409 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6410 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6412 // All these messages and functions are configurable
6415 * The function used to validate email addresses
6416 * @param {String} value The email address
6418 'email' : function(v){
6419 return email.test(v);
6422 * The error text to display when the email validation function returns false
6425 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6427 * The keystroke filter mask to be applied on email input
6430 'emailMask' : /[a-z0-9_\.\-@]/i,
6433 * The function used to validate URLs
6434 * @param {String} value The URL
6436 'url' : function(v){
6440 * The error text to display when the url validation function returns false
6443 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6446 * The function used to validate alpha values
6447 * @param {String} value The value
6449 'alpha' : function(v){
6450 return alpha.test(v);
6453 * The error text to display when the alpha validation function returns false
6456 'alphaText' : 'This field should only contain letters and _',
6458 * The keystroke filter mask to be applied on alpha input
6461 'alphaMask' : /[a-z_]/i,
6464 * The function used to validate alphanumeric values
6465 * @param {String} value The value
6467 'alphanum' : function(v){
6468 return alphanum.test(v);
6471 * The error text to display when the alphanumeric validation function returns false
6474 'alphanumText' : 'This field should only contain letters, numbers and _',
6476 * The keystroke filter mask to be applied on alphanumeric input
6479 'alphanumMask' : /[a-z0-9_]/i
6489 * @class Roo.bootstrap.Input
6490 * @extends Roo.bootstrap.Component
6491 * Bootstrap Input class
6492 * @cfg {Boolean} disabled is it disabled
6493 * @cfg {String} fieldLabel - the label associated
6494 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6495 * @cfg {String} name name of the input
6496 * @cfg {string} fieldLabel - the label associated
6497 * @cfg {string} inputType - input / file submit ...
6498 * @cfg {string} placeholder - placeholder to put in text.
6499 * @cfg {string} before - input group add on before
6500 * @cfg {string} after - input group add on after
6501 * @cfg {string} size - (lg|sm) or leave empty..
6502 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6503 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6504 * @cfg {Number} md colspan out of 12 for computer-sized screens
6505 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6506 * @cfg {string} value default value of the input
6507 * @cfg {Number} labelWidth set the width of label (0-12)
6508 * @cfg {String} labelAlign (top|left)
6509 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6510 * @cfg {String} align (left|center|right) Default left
6511 * @cfg {Boolean} formatedValue (true | false) Default false
6515 * Create a new Input
6516 * @param {Object} config The config object
6519 Roo.bootstrap.Input = function(config){
6520 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6525 * Fires when this field receives input focus.
6526 * @param {Roo.form.Field} this
6531 * Fires when this field loses input focus.
6532 * @param {Roo.form.Field} this
6537 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6538 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6539 * @param {Roo.form.Field} this
6540 * @param {Roo.EventObject} e The event object
6545 * Fires just before the field blurs if the field value has changed.
6546 * @param {Roo.form.Field} this
6547 * @param {Mixed} newValue The new value
6548 * @param {Mixed} oldValue The original value
6553 * Fires after the field has been marked as invalid.
6554 * @param {Roo.form.Field} this
6555 * @param {String} msg The validation message
6560 * Fires after the field has been validated with no errors.
6561 * @param {Roo.form.Field} this
6566 * Fires after the key up
6567 * @param {Roo.form.Field} this
6568 * @param {Roo.EventObject} e The event Object
6572 * @event formatedValue
6573 * Fires when get the value of the formated input
6574 * @param {Roo.bootstrap.Input} this
6575 * @param {String} value
6577 formatedValue : true
6581 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6583 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6584 automatic validation (defaults to "keyup").
6586 validationEvent : "keyup",
6588 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6590 validateOnBlur : true,
6592 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6594 validationDelay : 250,
6596 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6598 focusClass : "x-form-focus", // not needed???
6602 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6604 invalidClass : "has-error",
6607 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6609 selectOnFocus : false,
6612 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6616 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6621 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6623 disableKeyFilter : false,
6626 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6630 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6634 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6636 blankText : "This field is required",
6639 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6643 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6645 maxLength : Number.MAX_VALUE,
6647 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6649 minLengthText : "The minimum length for this field is {0}",
6651 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6653 maxLengthText : "The maximum length for this field is {0}",
6657 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6658 * If available, this function will be called only after the basic validators all return true, and will be passed the
6659 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6663 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6664 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6665 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6669 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6692 formatedValue : false,
6694 parentLabelAlign : function()
6697 while (parent.parent()) {
6698 parent = parent.parent();
6699 if (typeof(parent.labelAlign) !='undefined') {
6700 return parent.labelAlign;
6707 getAutoCreate : function(){
6709 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6715 if(this.inputType != 'hidden'){
6716 cfg.cls = 'form-group' //input-group
6722 type : this.inputType,
6724 cls : 'form-control',
6725 placeholder : this.placeholder || ''
6730 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6733 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6734 input.maxLength = this.maxLength;
6737 if (this.disabled) {
6738 input.disabled=true;
6741 if (this.readOnly) {
6742 input.readonly=true;
6746 input.name = this.name;
6749 input.cls += ' input-' + this.size;
6752 ['xs','sm','md','lg'].map(function(size){
6753 if (settings[size]) {
6754 cfg.cls += ' col-' + size + '-' + settings[size];
6758 var inputblock = input;
6760 if (this.before || this.after) {
6763 cls : 'input-group',
6766 if (this.before && typeof(this.before) == 'string') {
6768 inputblock.cn.push({
6770 cls : 'roo-input-before input-group-addon',
6774 if (this.before && typeof(this.before) == 'object') {
6775 this.before = Roo.factory(this.before);
6776 Roo.log(this.before);
6777 inputblock.cn.push({
6779 cls : 'roo-input-before input-group-' +
6780 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6784 inputblock.cn.push(input);
6786 if (this.after && typeof(this.after) == 'string') {
6787 inputblock.cn.push({
6789 cls : 'roo-input-after input-group-addon',
6793 if (this.after && typeof(this.after) == 'object') {
6794 this.after = Roo.factory(this.after);
6795 Roo.log(this.after);
6796 inputblock.cn.push({
6798 cls : 'roo-input-after input-group-' +
6799 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6804 if (align ==='left' && this.fieldLabel.length) {
6805 Roo.log("left and has label");
6811 cls : 'control-label col-sm-' + this.labelWidth,
6812 html : this.fieldLabel
6816 cls : "col-sm-" + (12 - this.labelWidth),
6823 } else if ( this.fieldLabel.length) {
6829 //cls : 'input-group-addon',
6830 html : this.fieldLabel
6840 Roo.log(" no label && no align");
6849 Roo.log('input-parentType: ' + this.parentType);
6851 if (this.parentType === 'Navbar' && this.parent().bar) {
6852 cfg.cls += ' navbar-form';
6860 * return the real input element.
6862 inputEl: function ()
6864 return this.el.select('input.form-control',true).first();
6866 setDisabled : function(v)
6868 var i = this.inputEl().dom;
6870 i.removeAttribute('disabled');
6874 i.setAttribute('disabled','true');
6876 initEvents : function()
6879 this.inputEl().on("keydown" , this.fireKey, this);
6880 this.inputEl().on("focus", this.onFocus, this);
6881 this.inputEl().on("blur", this.onBlur, this);
6883 this.inputEl().relayEvent('keyup', this);
6885 // reference to original value for reset
6886 this.originalValue = this.getValue();
6887 //Roo.form.TextField.superclass.initEvents.call(this);
6888 if(this.validationEvent == 'keyup'){
6889 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6890 this.inputEl().on('keyup', this.filterValidation, this);
6892 else if(this.validationEvent !== false){
6893 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6896 if(this.selectOnFocus){
6897 this.on("focus", this.preFocus, this);
6900 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6901 this.inputEl().on("keypress", this.filterKeys, this);
6904 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6905 this.el.on("click", this.autoSize, this);
6908 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6909 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6912 if (typeof(this.before) == 'object') {
6913 this.before.render(this.el.select('.roo-input-before',true).first());
6915 if (typeof(this.after) == 'object') {
6916 this.after.render(this.el.select('.roo-input-after',true).first());
6921 filterValidation : function(e){
6922 if(!e.isNavKeyPress()){
6923 this.validationTask.delay(this.validationDelay);
6927 * Validates the field value
6928 * @return {Boolean} True if the value is valid, else false
6930 validate : function(){
6931 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6932 if(this.disabled || this.validateValue(this.getRawValue())){
6933 this.clearInvalid();
6941 * Validates a value according to the field's validation rules and marks the field as invalid
6942 * if the validation fails
6943 * @param {Mixed} value The value to validate
6944 * @return {Boolean} True if the value is valid, else false
6946 validateValue : function(value){
6947 if(value.length < 1) { // if it's blank
6948 if(this.allowBlank){
6949 this.clearInvalid();
6952 this.markInvalid(this.blankText);
6956 if(value.length < this.minLength){
6957 this.markInvalid(String.format(this.minLengthText, this.minLength));
6960 if(value.length > this.maxLength){
6961 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6965 var vt = Roo.form.VTypes;
6966 if(!vt[this.vtype](value, this)){
6967 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6971 if(typeof this.validator == "function"){
6972 var msg = this.validator(value);
6974 this.markInvalid(msg);
6978 if(this.regex && !this.regex.test(value)){
6979 this.markInvalid(this.regexText);
6988 fireKey : function(e){
6989 //Roo.log('field ' + e.getKey());
6990 if(e.isNavKeyPress()){
6991 this.fireEvent("specialkey", this, e);
6994 focus : function (selectText){
6996 this.inputEl().focus();
6997 if(selectText === true){
6998 this.inputEl().dom.select();
7004 onFocus : function(){
7005 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7006 // this.el.addClass(this.focusClass);
7009 this.hasFocus = true;
7010 this.startValue = this.getValue();
7011 this.fireEvent("focus", this);
7015 beforeBlur : Roo.emptyFn,
7019 onBlur : function(){
7021 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7022 //this.el.removeClass(this.focusClass);
7024 this.hasFocus = false;
7025 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7028 var v = this.getValue();
7029 if(String(v) !== String(this.startValue)){
7030 this.fireEvent('change', this, v, this.startValue);
7032 this.fireEvent("blur", this);
7036 * Resets the current field value to the originally loaded value and clears any validation messages
7039 this.setValue(this.originalValue);
7040 this.clearInvalid();
7043 * Returns the name of the field
7044 * @return {Mixed} name The name field
7046 getName: function(){
7050 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7051 * @return {Mixed} value The field value
7053 getValue : function(){
7055 var v = this.inputEl().getValue();
7057 if(this.formatedValue){
7059 this.fireEvent("formatedValue", this, v);
7067 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7068 * @return {Mixed} value The field value
7070 getRawValue : function(){
7071 var v = this.inputEl().getValue();
7077 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7078 * @param {Mixed} value The value to set
7080 setRawValue : function(v){
7081 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7084 selectText : function(start, end){
7085 var v = this.getRawValue();
7087 start = start === undefined ? 0 : start;
7088 end = end === undefined ? v.length : end;
7089 var d = this.inputEl().dom;
7090 if(d.setSelectionRange){
7091 d.setSelectionRange(start, end);
7092 }else if(d.createTextRange){
7093 var range = d.createTextRange();
7094 range.moveStart("character", start);
7095 range.moveEnd("character", v.length-end);
7102 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7103 * @param {Mixed} value The value to set
7105 setValue : function(v){
7108 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7114 processValue : function(value){
7115 if(this.stripCharsRe){
7116 var newValue = value.replace(this.stripCharsRe, '');
7117 if(newValue !== value){
7118 this.setRawValue(newValue);
7125 preFocus : function(){
7127 if(this.selectOnFocus){
7128 this.inputEl().dom.select();
7131 filterKeys : function(e){
7133 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7136 var c = e.getCharCode(), cc = String.fromCharCode(c);
7137 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7140 if(!this.maskRe.test(cc)){
7145 * Clear any invalid styles/messages for this field
7147 clearInvalid : function(){
7149 if(!this.el || this.preventMark){ // not rendered
7152 this.el.removeClass(this.invalidClass);
7154 switch(this.msgTarget){
7156 this.el.dom.qtip = '';
7159 this.el.dom.title = '';
7163 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7168 this.errorIcon.dom.qtip = '';
7169 this.errorIcon.hide();
7170 this.un('resize', this.alignErrorIcon, this);
7174 var t = Roo.getDom(this.msgTarget);
7176 t.style.display = 'none';
7180 this.fireEvent('valid', this);
7183 * Mark this field as invalid
7184 * @param {String} msg The validation message
7186 markInvalid : function(msg){
7187 if(!this.el || this.preventMark){ // not rendered
7190 this.el.addClass(this.invalidClass);
7192 msg = msg || this.invalidText;
7193 switch(this.msgTarget){
7195 this.el.dom.qtip = msg;
7196 this.el.dom.qclass = 'x-form-invalid-tip';
7197 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7198 Roo.QuickTips.enable();
7202 this.el.dom.title = msg;
7206 var elp = this.el.findParent('.x-form-element', 5, true);
7207 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7208 this.errorEl.setWidth(elp.getWidth(true)-20);
7210 this.errorEl.update(msg);
7211 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7214 if(!this.errorIcon){
7215 var elp = this.el.findParent('.x-form-element', 5, true);
7216 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7218 this.alignErrorIcon();
7219 this.errorIcon.dom.qtip = msg;
7220 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7221 this.errorIcon.show();
7222 this.on('resize', this.alignErrorIcon, this);
7225 var t = Roo.getDom(this.msgTarget);
7227 t.style.display = this.msgDisplay;
7231 this.fireEvent('invalid', this, msg);
7234 SafariOnKeyDown : function(event)
7236 // this is a workaround for a password hang bug on chrome/ webkit.
7238 var isSelectAll = false;
7240 if(this.inputEl().dom.selectionEnd > 0){
7241 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7243 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7244 event.preventDefault();
7249 if(isSelectAll){ // backspace and delete key
7251 event.preventDefault();
7252 // this is very hacky as keydown always get's upper case.
7254 var cc = String.fromCharCode(event.getCharCode());
7255 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7259 adjustWidth : function(tag, w){
7260 tag = tag.toLowerCase();
7261 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7262 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7266 if(tag == 'textarea'){
7269 }else if(Roo.isOpera){
7273 if(tag == 'textarea'){
7292 * @class Roo.bootstrap.TextArea
7293 * @extends Roo.bootstrap.Input
7294 * Bootstrap TextArea class
7295 * @cfg {Number} cols Specifies the visible width of a text area
7296 * @cfg {Number} rows Specifies the visible number of lines in a text area
7297 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7298 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7299 * @cfg {string} html text
7302 * Create a new TextArea
7303 * @param {Object} config The config object
7306 Roo.bootstrap.TextArea = function(config){
7307 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7311 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7321 getAutoCreate : function(){
7323 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7334 value : this.value || '',
7335 html: this.html || '',
7336 cls : 'form-control',
7337 placeholder : this.placeholder || ''
7341 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7342 input.maxLength = this.maxLength;
7346 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7350 input.cols = this.cols;
7353 if (this.readOnly) {
7354 input.readonly = true;
7358 input.name = this.name;
7362 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7366 ['xs','sm','md','lg'].map(function(size){
7367 if (settings[size]) {
7368 cfg.cls += ' col-' + size + '-' + settings[size];
7372 var inputblock = input;
7374 if (this.before || this.after) {
7377 cls : 'input-group',
7381 inputblock.cn.push({
7383 cls : 'input-group-addon',
7387 inputblock.cn.push(input);
7389 inputblock.cn.push({
7391 cls : 'input-group-addon',
7398 if (align ==='left' && this.fieldLabel.length) {
7399 Roo.log("left and has label");
7405 cls : 'control-label col-sm-' + this.labelWidth,
7406 html : this.fieldLabel
7410 cls : "col-sm-" + (12 - this.labelWidth),
7417 } else if ( this.fieldLabel.length) {
7423 //cls : 'input-group-addon',
7424 html : this.fieldLabel
7434 Roo.log(" no label && no align");
7444 if (this.disabled) {
7445 input.disabled=true;
7452 * return the real textarea element.
7454 inputEl: function ()
7456 return this.el.select('textarea.form-control',true).first();
7464 * trigger field - base class for combo..
7469 * @class Roo.bootstrap.TriggerField
7470 * @extends Roo.bootstrap.Input
7471 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7472 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7473 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7474 * for which you can provide a custom implementation. For example:
7476 var trigger = new Roo.bootstrap.TriggerField();
7477 trigger.onTriggerClick = myTriggerFn;
7478 trigger.applyTo('my-field');
7481 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7482 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7483 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7484 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7486 * Create a new TriggerField.
7487 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7488 * to the base TextField)
7490 Roo.bootstrap.TriggerField = function(config){
7491 this.mimicing = false;
7492 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7495 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7497 * @cfg {String} triggerClass A CSS class to apply to the trigger
7500 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7504 /** @cfg {Boolean} grow @hide */
7505 /** @cfg {Number} growMin @hide */
7506 /** @cfg {Number} growMax @hide */
7512 autoSize: Roo.emptyFn,
7519 actionMode : 'wrap',
7523 getAutoCreate : function(){
7525 var parent = this.parent();
7527 var align = this.labelAlign || this.parentLabelAlign();
7532 cls: 'form-group' //input-group
7539 type : this.inputType,
7540 cls : 'form-control',
7541 autocomplete: 'off',
7542 placeholder : this.placeholder || ''
7546 input.name = this.name;
7549 input.cls += ' input-' + this.size;
7552 if (this.disabled) {
7553 input.disabled=true;
7556 var inputblock = input;
7558 if (this.before || this.after) {
7561 cls : 'input-group',
7565 inputblock.cn.push({
7567 cls : 'input-group-addon',
7571 inputblock.cn.push(input);
7573 inputblock.cn.push({
7575 cls : 'input-group-addon',
7588 cls: 'form-hidden-field'
7596 Roo.log('multiple');
7604 cls: 'form-hidden-field'
7608 cls: 'select2-choices',
7612 cls: 'select2-search-field',
7625 cls: 'select2-container input-group',
7630 cls: 'typeahead typeahead-long dropdown-menu',
7631 style: 'display:none'
7639 cls : 'input-group-addon btn dropdown-toggle',
7647 cls: 'combobox-clear',
7661 combobox.cls += ' select2-container-multi';
7664 if (align ==='left' && this.fieldLabel.length) {
7666 Roo.log("left and has label");
7672 cls : 'control-label col-sm-' + this.labelWidth,
7673 html : this.fieldLabel
7677 cls : "col-sm-" + (12 - this.labelWidth),
7684 } else if ( this.fieldLabel.length) {
7690 //cls : 'input-group-addon',
7691 html : this.fieldLabel
7701 Roo.log(" no label && no align");
7708 ['xs','sm','md','lg'].map(function(size){
7709 if (settings[size]) {
7710 cfg.cls += ' col-' + size + '-' + settings[size];
7721 onResize : function(w, h){
7722 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7723 // if(typeof w == 'number'){
7724 // var x = w - this.trigger.getWidth();
7725 // this.inputEl().setWidth(this.adjustWidth('input', x));
7726 // this.trigger.setStyle('left', x+'px');
7731 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7734 getResizeEl : function(){
7735 return this.inputEl();
7739 getPositionEl : function(){
7740 return this.inputEl();
7744 alignErrorIcon : function(){
7745 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7749 initEvents : function(){
7751 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7752 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7754 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7755 if(this.hideTrigger){
7756 this.trigger.setDisplayed(false);
7758 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7762 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7765 //this.trigger.addClassOnOver('x-form-trigger-over');
7766 //this.trigger.addClassOnClick('x-form-trigger-click');
7769 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7774 initTrigger : function(){
7779 onDestroy : function(){
7781 this.trigger.removeAllListeners();
7782 // this.trigger.remove();
7785 // this.wrap.remove();
7787 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7791 onFocus : function(){
7792 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7795 this.wrap.addClass('x-trigger-wrap-focus');
7796 this.mimicing = true;
7797 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7798 if(this.monitorTab){
7799 this.el.on("keydown", this.checkTab, this);
7806 checkTab : function(e){
7807 if(e.getKey() == e.TAB){
7813 onBlur : function(){
7818 mimicBlur : function(e, t){
7820 if(!this.wrap.contains(t) && this.validateBlur()){
7827 triggerBlur : function(){
7828 this.mimicing = false;
7829 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7830 if(this.monitorTab){
7831 this.el.un("keydown", this.checkTab, this);
7833 //this.wrap.removeClass('x-trigger-wrap-focus');
7834 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7838 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7839 validateBlur : function(e, t){
7844 onDisable : function(){
7845 this.inputEl().dom.disabled = true;
7846 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7848 // this.wrap.addClass('x-item-disabled');
7853 onEnable : function(){
7854 this.inputEl().dom.disabled = false;
7855 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7857 // this.el.removeClass('x-item-disabled');
7862 onShow : function(){
7863 var ae = this.getActionEl();
7866 ae.dom.style.display = '';
7867 ae.dom.style.visibility = 'visible';
7873 onHide : function(){
7874 var ae = this.getActionEl();
7875 ae.dom.style.display = 'none';
7879 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7880 * by an implementing function.
7882 * @param {EventObject} e
7884 onTriggerClick : Roo.emptyFn
7888 * Ext JS Library 1.1.1
7889 * Copyright(c) 2006-2007, Ext JS, LLC.
7891 * Originally Released Under LGPL - original licence link has changed is not relivant.
7894 * <script type="text/javascript">
7899 * @class Roo.data.SortTypes
7901 * Defines the default sorting (casting?) comparison functions used when sorting data.
7903 Roo.data.SortTypes = {
7905 * Default sort that does nothing
7906 * @param {Mixed} s The value being converted
7907 * @return {Mixed} The comparison value
7914 * The regular expression used to strip tags
7918 stripTagsRE : /<\/?[^>]+>/gi,
7921 * Strips all HTML tags to sort on text only
7922 * @param {Mixed} s The value being converted
7923 * @return {String} The comparison value
7925 asText : function(s){
7926 return String(s).replace(this.stripTagsRE, "");
7930 * Strips all HTML tags to sort on text only - Case insensitive
7931 * @param {Mixed} s The value being converted
7932 * @return {String} The comparison value
7934 asUCText : function(s){
7935 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7939 * Case insensitive string
7940 * @param {Mixed} s The value being converted
7941 * @return {String} The comparison value
7943 asUCString : function(s) {
7944 return String(s).toUpperCase();
7949 * @param {Mixed} s The value being converted
7950 * @return {Number} The comparison value
7952 asDate : function(s) {
7956 if(s instanceof Date){
7959 return Date.parse(String(s));
7964 * @param {Mixed} s The value being converted
7965 * @return {Float} The comparison value
7967 asFloat : function(s) {
7968 var val = parseFloat(String(s).replace(/,/g, ""));
7969 if(isNaN(val)) val = 0;
7975 * @param {Mixed} s The value being converted
7976 * @return {Number} The comparison value
7978 asInt : function(s) {
7979 var val = parseInt(String(s).replace(/,/g, ""));
7980 if(isNaN(val)) val = 0;
7985 * Ext JS Library 1.1.1
7986 * Copyright(c) 2006-2007, Ext JS, LLC.
7988 * Originally Released Under LGPL - original licence link has changed is not relivant.
7991 * <script type="text/javascript">
7995 * @class Roo.data.Record
7996 * Instances of this class encapsulate both record <em>definition</em> information, and record
7997 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7998 * to access Records cached in an {@link Roo.data.Store} object.<br>
8000 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8001 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8004 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8006 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8007 * {@link #create}. The parameters are the same.
8008 * @param {Array} data An associative Array of data values keyed by the field name.
8009 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8010 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8011 * not specified an integer id is generated.
8013 Roo.data.Record = function(data, id){
8014 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8019 * Generate a constructor for a specific record layout.
8020 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8021 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8022 * Each field definition object may contain the following properties: <ul>
8023 * <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,
8024 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8025 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8026 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8027 * is being used, then this is a string containing the javascript expression to reference the data relative to
8028 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8029 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8030 * this may be omitted.</p></li>
8031 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8032 * <ul><li>auto (Default, implies no conversion)</li>
8037 * <li>date</li></ul></p></li>
8038 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8039 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8040 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8041 * by the Reader into an object that will be stored in the Record. It is passed the
8042 * following parameters:<ul>
8043 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8045 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8047 * <br>usage:<br><pre><code>
8048 var TopicRecord = Roo.data.Record.create(
8049 {name: 'title', mapping: 'topic_title'},
8050 {name: 'author', mapping: 'username'},
8051 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8052 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8053 {name: 'lastPoster', mapping: 'user2'},
8054 {name: 'excerpt', mapping: 'post_text'}
8057 var myNewRecord = new TopicRecord({
8058 title: 'Do my job please',
8061 lastPost: new Date(),
8062 lastPoster: 'Animal',
8063 excerpt: 'No way dude!'
8065 myStore.add(myNewRecord);
8070 Roo.data.Record.create = function(o){
8072 f.superclass.constructor.apply(this, arguments);
8074 Roo.extend(f, Roo.data.Record);
8075 var p = f.prototype;
8076 p.fields = new Roo.util.MixedCollection(false, function(field){
8079 for(var i = 0, len = o.length; i < len; i++){
8080 p.fields.add(new Roo.data.Field(o[i]));
8082 f.getField = function(name){
8083 return p.fields.get(name);
8088 Roo.data.Record.AUTO_ID = 1000;
8089 Roo.data.Record.EDIT = 'edit';
8090 Roo.data.Record.REJECT = 'reject';
8091 Roo.data.Record.COMMIT = 'commit';
8093 Roo.data.Record.prototype = {
8095 * Readonly flag - true if this record has been modified.
8104 join : function(store){
8109 * Set the named field to the specified value.
8110 * @param {String} name The name of the field to set.
8111 * @param {Object} value The value to set the field to.
8113 set : function(name, value){
8114 if(this.data[name] == value){
8121 if(typeof this.modified[name] == 'undefined'){
8122 this.modified[name] = this.data[name];
8124 this.data[name] = value;
8125 if(!this.editing && this.store){
8126 this.store.afterEdit(this);
8131 * Get the value of the named field.
8132 * @param {String} name The name of the field to get the value of.
8133 * @return {Object} The value of the field.
8135 get : function(name){
8136 return this.data[name];
8140 beginEdit : function(){
8141 this.editing = true;
8146 cancelEdit : function(){
8147 this.editing = false;
8148 delete this.modified;
8152 endEdit : function(){
8153 this.editing = false;
8154 if(this.dirty && this.store){
8155 this.store.afterEdit(this);
8160 * Usually called by the {@link Roo.data.Store} which owns the Record.
8161 * Rejects all changes made to the Record since either creation, or the last commit operation.
8162 * Modified fields are reverted to their original values.
8164 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8165 * of reject operations.
8167 reject : function(){
8168 var m = this.modified;
8170 if(typeof m[n] != "function"){
8171 this.data[n] = m[n];
8175 delete this.modified;
8176 this.editing = false;
8178 this.store.afterReject(this);
8183 * Usually called by the {@link Roo.data.Store} which owns the Record.
8184 * Commits all changes made to the Record since either creation, or the last commit operation.
8186 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8187 * of commit operations.
8189 commit : function(){
8191 delete this.modified;
8192 this.editing = false;
8194 this.store.afterCommit(this);
8199 hasError : function(){
8200 return this.error != null;
8204 clearError : function(){
8209 * Creates a copy of this record.
8210 * @param {String} id (optional) A new record id if you don't want to use this record's id
8213 copy : function(newId) {
8214 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8218 * Ext JS Library 1.1.1
8219 * Copyright(c) 2006-2007, Ext JS, LLC.
8221 * Originally Released Under LGPL - original licence link has changed is not relivant.
8224 * <script type="text/javascript">
8230 * @class Roo.data.Store
8231 * @extends Roo.util.Observable
8232 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8233 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8235 * 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
8236 * has no knowledge of the format of the data returned by the Proxy.<br>
8238 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8239 * instances from the data object. These records are cached and made available through accessor functions.
8241 * Creates a new Store.
8242 * @param {Object} config A config object containing the objects needed for the Store to access data,
8243 * and read the data into Records.
8245 Roo.data.Store = function(config){
8246 this.data = new Roo.util.MixedCollection(false);
8247 this.data.getKey = function(o){
8250 this.baseParams = {};
8257 "multisort" : "_multisort"
8260 if(config && config.data){
8261 this.inlineData = config.data;
8265 Roo.apply(this, config);
8267 if(this.reader){ // reader passed
8268 this.reader = Roo.factory(this.reader, Roo.data);
8269 this.reader.xmodule = this.xmodule || false;
8270 if(!this.recordType){
8271 this.recordType = this.reader.recordType;
8273 if(this.reader.onMetaChange){
8274 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8278 if(this.recordType){
8279 this.fields = this.recordType.prototype.fields;
8285 * @event datachanged
8286 * Fires when the data cache has changed, and a widget which is using this Store
8287 * as a Record cache should refresh its view.
8288 * @param {Store} this
8293 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8294 * @param {Store} this
8295 * @param {Object} meta The JSON metadata
8300 * Fires when Records have been added to the Store
8301 * @param {Store} this
8302 * @param {Roo.data.Record[]} records The array of Records added
8303 * @param {Number} index The index at which the record(s) were added
8308 * Fires when a Record has been removed from the Store
8309 * @param {Store} this
8310 * @param {Roo.data.Record} record The Record that was removed
8311 * @param {Number} index The index at which the record was removed
8316 * Fires when a Record has been updated
8317 * @param {Store} this
8318 * @param {Roo.data.Record} record The Record that was updated
8319 * @param {String} operation The update operation being performed. Value may be one of:
8321 Roo.data.Record.EDIT
8322 Roo.data.Record.REJECT
8323 Roo.data.Record.COMMIT
8329 * Fires when the data cache has been cleared.
8330 * @param {Store} this
8335 * Fires before a request is made for a new data object. If the beforeload handler returns false
8336 * the load action will be canceled.
8337 * @param {Store} this
8338 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8342 * @event beforeloadadd
8343 * Fires after a new set of Records has been loaded.
8344 * @param {Store} this
8345 * @param {Roo.data.Record[]} records The Records that were loaded
8346 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8348 beforeloadadd : true,
8351 * Fires after a new set of Records has been loaded, before they are added to the store.
8352 * @param {Store} this
8353 * @param {Roo.data.Record[]} records The Records that were loaded
8354 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8355 * @params {Object} return from reader
8359 * @event loadexception
8360 * Fires if an exception occurs in the Proxy during loading.
8361 * Called with the signature of the Proxy's "loadexception" event.
8362 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8365 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8366 * @param {Object} load options
8367 * @param {Object} jsonData from your request (normally this contains the Exception)
8369 loadexception : true
8373 this.proxy = Roo.factory(this.proxy, Roo.data);
8374 this.proxy.xmodule = this.xmodule || false;
8375 this.relayEvents(this.proxy, ["loadexception"]);
8377 this.sortToggle = {};
8378 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8380 Roo.data.Store.superclass.constructor.call(this);
8382 if(this.inlineData){
8383 this.loadData(this.inlineData);
8384 delete this.inlineData;
8388 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8390 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8391 * without a remote query - used by combo/forms at present.
8395 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8398 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8401 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8402 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8405 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8406 * on any HTTP request
8409 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8412 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8416 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8417 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8422 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8423 * loaded or when a record is removed. (defaults to false).
8425 pruneModifiedRecords : false,
8431 * Add Records to the Store and fires the add event.
8432 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8434 add : function(records){
8435 records = [].concat(records);
8436 for(var i = 0, len = records.length; i < len; i++){
8437 records[i].join(this);
8439 var index = this.data.length;
8440 this.data.addAll(records);
8441 this.fireEvent("add", this, records, index);
8445 * Remove a Record from the Store and fires the remove event.
8446 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8448 remove : function(record){
8449 var index = this.data.indexOf(record);
8450 this.data.removeAt(index);
8451 if(this.pruneModifiedRecords){
8452 this.modified.remove(record);
8454 this.fireEvent("remove", this, record, index);
8458 * Remove all Records from the Store and fires the clear event.
8460 removeAll : function(){
8462 if(this.pruneModifiedRecords){
8465 this.fireEvent("clear", this);
8469 * Inserts Records to the Store at the given index and fires the add event.
8470 * @param {Number} index The start index at which to insert the passed Records.
8471 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8473 insert : function(index, records){
8474 records = [].concat(records);
8475 for(var i = 0, len = records.length; i < len; i++){
8476 this.data.insert(index, records[i]);
8477 records[i].join(this);
8479 this.fireEvent("add", this, records, index);
8483 * Get the index within the cache of the passed Record.
8484 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8485 * @return {Number} The index of the passed Record. Returns -1 if not found.
8487 indexOf : function(record){
8488 return this.data.indexOf(record);
8492 * Get the index within the cache of the Record with the passed id.
8493 * @param {String} id The id of the Record to find.
8494 * @return {Number} The index of the Record. Returns -1 if not found.
8496 indexOfId : function(id){
8497 return this.data.indexOfKey(id);
8501 * Get the Record with the specified id.
8502 * @param {String} id The id of the Record to find.
8503 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8505 getById : function(id){
8506 return this.data.key(id);
8510 * Get the Record at the specified index.
8511 * @param {Number} index The index of the Record to find.
8512 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8514 getAt : function(index){
8515 return this.data.itemAt(index);
8519 * Returns a range of Records between specified indices.
8520 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8521 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8522 * @return {Roo.data.Record[]} An array of Records
8524 getRange : function(start, end){
8525 return this.data.getRange(start, end);
8529 storeOptions : function(o){
8530 o = Roo.apply({}, o);
8533 this.lastOptions = o;
8537 * Loads the Record cache from the configured Proxy using the configured Reader.
8539 * If using remote paging, then the first load call must specify the <em>start</em>
8540 * and <em>limit</em> properties in the options.params property to establish the initial
8541 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8543 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8544 * and this call will return before the new data has been loaded. Perform any post-processing
8545 * in a callback function, or in a "load" event handler.</strong>
8547 * @param {Object} options An object containing properties which control loading options:<ul>
8548 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8549 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8550 * passed the following arguments:<ul>
8551 * <li>r : Roo.data.Record[]</li>
8552 * <li>options: Options object from the load call</li>
8553 * <li>success: Boolean success indicator</li></ul></li>
8554 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8555 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8558 load : function(options){
8559 options = options || {};
8560 if(this.fireEvent("beforeload", this, options) !== false){
8561 this.storeOptions(options);
8562 var p = Roo.apply(options.params || {}, this.baseParams);
8563 // if meta was not loaded from remote source.. try requesting it.
8564 if (!this.reader.metaFromRemote) {
8567 if(this.sortInfo && this.remoteSort){
8568 var pn = this.paramNames;
8569 p[pn["sort"]] = this.sortInfo.field;
8570 p[pn["dir"]] = this.sortInfo.direction;
8572 if (this.multiSort) {
8573 var pn = this.paramNames;
8574 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8577 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8582 * Reloads the Record cache from the configured Proxy using the configured Reader and
8583 * the options from the last load operation performed.
8584 * @param {Object} options (optional) An object containing properties which may override the options
8585 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8586 * the most recently used options are reused).
8588 reload : function(options){
8589 this.load(Roo.applyIf(options||{}, this.lastOptions));
8593 // Called as a callback by the Reader during a load operation.
8594 loadRecords : function(o, options, success){
8595 if(!o || success === false){
8596 if(success !== false){
8597 this.fireEvent("load", this, [], options, o);
8599 if(options.callback){
8600 options.callback.call(options.scope || this, [], options, false);
8604 // if data returned failure - throw an exception.
8605 if (o.success === false) {
8606 // show a message if no listener is registered.
8607 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8608 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8610 // loadmask wil be hooked into this..
8611 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8614 var r = o.records, t = o.totalRecords || r.length;
8616 this.fireEvent("beforeloadadd", this, r, options, o);
8618 if(!options || options.add !== true){
8619 if(this.pruneModifiedRecords){
8622 for(var i = 0, len = r.length; i < len; i++){
8626 this.data = this.snapshot;
8627 delete this.snapshot;
8630 this.data.addAll(r);
8631 this.totalLength = t;
8633 this.fireEvent("datachanged", this);
8635 this.totalLength = Math.max(t, this.data.length+r.length);
8638 this.fireEvent("load", this, r, options, o);
8639 if(options.callback){
8640 options.callback.call(options.scope || this, r, options, true);
8646 * Loads data from a passed data block. A Reader which understands the format of the data
8647 * must have been configured in the constructor.
8648 * @param {Object} data The data block from which to read the Records. The format of the data expected
8649 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8650 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8652 loadData : function(o, append){
8653 var r = this.reader.readRecords(o);
8654 this.loadRecords(r, {add: append}, true);
8658 * Gets the number of cached records.
8660 * <em>If using paging, this may not be the total size of the dataset. If the data object
8661 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8662 * the data set size</em>
8664 getCount : function(){
8665 return this.data.length || 0;
8669 * Gets the total number of records in the dataset as returned by the server.
8671 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8672 * the dataset size</em>
8674 getTotalCount : function(){
8675 return this.totalLength || 0;
8679 * Returns the sort state of the Store as an object with two properties:
8681 field {String} The name of the field by which the Records are sorted
8682 direction {String} The sort order, "ASC" or "DESC"
8685 getSortState : function(){
8686 return this.sortInfo;
8690 applySort : function(){
8691 if(this.sortInfo && !this.remoteSort){
8692 var s = this.sortInfo, f = s.field;
8693 var st = this.fields.get(f).sortType;
8694 var fn = function(r1, r2){
8695 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8696 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8698 this.data.sort(s.direction, fn);
8699 if(this.snapshot && this.snapshot != this.data){
8700 this.snapshot.sort(s.direction, fn);
8706 * Sets the default sort column and order to be used by the next load operation.
8707 * @param {String} fieldName The name of the field to sort by.
8708 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8710 setDefaultSort : function(field, dir){
8711 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8716 * If remote sorting is used, the sort is performed on the server, and the cache is
8717 * reloaded. If local sorting is used, the cache is sorted internally.
8718 * @param {String} fieldName The name of the field to sort by.
8719 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8721 sort : function(fieldName, dir){
8722 var f = this.fields.get(fieldName);
8724 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8726 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8727 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8732 this.sortToggle[f.name] = dir;
8733 this.sortInfo = {field: f.name, direction: dir};
8734 if(!this.remoteSort){
8736 this.fireEvent("datachanged", this);
8738 this.load(this.lastOptions);
8743 * Calls the specified function for each of the Records in the cache.
8744 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8745 * Returning <em>false</em> aborts and exits the iteration.
8746 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8748 each : function(fn, scope){
8749 this.data.each(fn, scope);
8753 * Gets all records modified since the last commit. Modified records are persisted across load operations
8754 * (e.g., during paging).
8755 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8757 getModifiedRecords : function(){
8758 return this.modified;
8762 createFilterFn : function(property, value, anyMatch){
8763 if(!value.exec){ // not a regex
8764 value = String(value);
8765 if(value.length == 0){
8768 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8771 return value.test(r.data[property]);
8776 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8777 * @param {String} property A field on your records
8778 * @param {Number} start The record index to start at (defaults to 0)
8779 * @param {Number} end The last record index to include (defaults to length - 1)
8780 * @return {Number} The sum
8782 sum : function(property, start, end){
8783 var rs = this.data.items, v = 0;
8785 end = (end || end === 0) ? end : rs.length-1;
8787 for(var i = start; i <= end; i++){
8788 v += (rs[i].data[property] || 0);
8794 * Filter the records by a specified property.
8795 * @param {String} field A field on your records
8796 * @param {String/RegExp} value Either a string that the field
8797 * should start with or a RegExp to test against the field
8798 * @param {Boolean} anyMatch True to match any part not just the beginning
8800 filter : function(property, value, anyMatch){
8801 var fn = this.createFilterFn(property, value, anyMatch);
8802 return fn ? this.filterBy(fn) : this.clearFilter();
8806 * Filter by a function. The specified function will be called with each
8807 * record in this data source. If the function returns true the record is included,
8808 * otherwise it is filtered.
8809 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8810 * @param {Object} scope (optional) The scope of the function (defaults to this)
8812 filterBy : function(fn, scope){
8813 this.snapshot = this.snapshot || this.data;
8814 this.data = this.queryBy(fn, scope||this);
8815 this.fireEvent("datachanged", this);
8819 * Query the records by a specified property.
8820 * @param {String} field A field on your records
8821 * @param {String/RegExp} value Either a string that the field
8822 * should start with or a RegExp to test against the field
8823 * @param {Boolean} anyMatch True to match any part not just the beginning
8824 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8826 query : function(property, value, anyMatch){
8827 var fn = this.createFilterFn(property, value, anyMatch);
8828 return fn ? this.queryBy(fn) : this.data.clone();
8832 * Query by a function. The specified function will be called with each
8833 * record in this data source. If the function returns true the record is included
8835 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8836 * @param {Object} scope (optional) The scope of the function (defaults to this)
8837 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8839 queryBy : function(fn, scope){
8840 var data = this.snapshot || this.data;
8841 return data.filterBy(fn, scope||this);
8845 * Collects unique values for a particular dataIndex from this store.
8846 * @param {String} dataIndex The property to collect
8847 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8848 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8849 * @return {Array} An array of the unique values
8851 collect : function(dataIndex, allowNull, bypassFilter){
8852 var d = (bypassFilter === true && this.snapshot) ?
8853 this.snapshot.items : this.data.items;
8854 var v, sv, r = [], l = {};
8855 for(var i = 0, len = d.length; i < len; i++){
8856 v = d[i].data[dataIndex];
8858 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8867 * Revert to a view of the Record cache with no filtering applied.
8868 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8870 clearFilter : function(suppressEvent){
8871 if(this.snapshot && this.snapshot != this.data){
8872 this.data = this.snapshot;
8873 delete this.snapshot;
8874 if(suppressEvent !== true){
8875 this.fireEvent("datachanged", this);
8881 afterEdit : function(record){
8882 if(this.modified.indexOf(record) == -1){
8883 this.modified.push(record);
8885 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8889 afterReject : function(record){
8890 this.modified.remove(record);
8891 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8895 afterCommit : function(record){
8896 this.modified.remove(record);
8897 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8901 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8902 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8904 commitChanges : function(){
8905 var m = this.modified.slice(0);
8907 for(var i = 0, len = m.length; i < len; i++){
8913 * Cancel outstanding changes on all changed records.
8915 rejectChanges : function(){
8916 var m = this.modified.slice(0);
8918 for(var i = 0, len = m.length; i < len; i++){
8923 onMetaChange : function(meta, rtype, o){
8924 this.recordType = rtype;
8925 this.fields = rtype.prototype.fields;
8926 delete this.snapshot;
8927 this.sortInfo = meta.sortInfo || this.sortInfo;
8929 this.fireEvent('metachange', this, this.reader.meta);
8932 moveIndex : function(data, type)
8934 var index = this.indexOf(data);
8936 var newIndex = index + type;
8940 this.insert(newIndex, data);
8945 * Ext JS Library 1.1.1
8946 * Copyright(c) 2006-2007, Ext JS, LLC.
8948 * Originally Released Under LGPL - original licence link has changed is not relivant.
8951 * <script type="text/javascript">
8955 * @class Roo.data.SimpleStore
8956 * @extends Roo.data.Store
8957 * Small helper class to make creating Stores from Array data easier.
8958 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8959 * @cfg {Array} fields An array of field definition objects, or field name strings.
8960 * @cfg {Array} data The multi-dimensional array of data
8962 * @param {Object} config
8964 Roo.data.SimpleStore = function(config){
8965 Roo.data.SimpleStore.superclass.constructor.call(this, {
8967 reader: new Roo.data.ArrayReader({
8970 Roo.data.Record.create(config.fields)
8972 proxy : new Roo.data.MemoryProxy(config.data)
8976 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8978 * Ext JS Library 1.1.1
8979 * Copyright(c) 2006-2007, Ext JS, LLC.
8981 * Originally Released Under LGPL - original licence link has changed is not relivant.
8984 * <script type="text/javascript">
8989 * @extends Roo.data.Store
8990 * @class Roo.data.JsonStore
8991 * Small helper class to make creating Stores for JSON data easier. <br/>
8993 var store = new Roo.data.JsonStore({
8994 url: 'get-images.php',
8996 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8999 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9000 * JsonReader and HttpProxy (unless inline data is provided).</b>
9001 * @cfg {Array} fields An array of field definition objects, or field name strings.
9003 * @param {Object} config
9005 Roo.data.JsonStore = function(c){
9006 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9007 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9008 reader: new Roo.data.JsonReader(c, c.fields)
9011 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9013 * Ext JS Library 1.1.1
9014 * Copyright(c) 2006-2007, Ext JS, LLC.
9016 * Originally Released Under LGPL - original licence link has changed is not relivant.
9019 * <script type="text/javascript">
9023 Roo.data.Field = function(config){
9024 if(typeof config == "string"){
9025 config = {name: config};
9027 Roo.apply(this, config);
9033 var st = Roo.data.SortTypes;
9034 // named sortTypes are supported, here we look them up
9035 if(typeof this.sortType == "string"){
9036 this.sortType = st[this.sortType];
9039 // set default sortType for strings and dates
9043 this.sortType = st.asUCString;
9046 this.sortType = st.asDate;
9049 this.sortType = st.none;
9054 var stripRe = /[\$,%]/g;
9056 // prebuilt conversion function for this field, instead of
9057 // switching every time we're reading a value
9059 var cv, dateFormat = this.dateFormat;
9064 cv = function(v){ return v; };
9067 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9071 return v !== undefined && v !== null && v !== '' ?
9072 parseInt(String(v).replace(stripRe, ""), 10) : '';
9077 return v !== undefined && v !== null && v !== '' ?
9078 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9083 cv = function(v){ return v === true || v === "true" || v == 1; };
9090 if(v instanceof Date){
9094 if(dateFormat == "timestamp"){
9095 return new Date(v*1000);
9097 return Date.parseDate(v, dateFormat);
9099 var parsed = Date.parse(v);
9100 return parsed ? new Date(parsed) : null;
9109 Roo.data.Field.prototype = {
9117 * Ext JS Library 1.1.1
9118 * Copyright(c) 2006-2007, Ext JS, LLC.
9120 * Originally Released Under LGPL - original licence link has changed is not relivant.
9123 * <script type="text/javascript">
9126 // Base class for reading structured data from a data source. This class is intended to be
9127 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9130 * @class Roo.data.DataReader
9131 * Base class for reading structured data from a data source. This class is intended to be
9132 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9135 Roo.data.DataReader = function(meta, recordType){
9139 this.recordType = recordType instanceof Array ?
9140 Roo.data.Record.create(recordType) : recordType;
9143 Roo.data.DataReader.prototype = {
9145 * Create an empty record
9146 * @param {Object} data (optional) - overlay some values
9147 * @return {Roo.data.Record} record created.
9149 newRow : function(d) {
9151 this.recordType.prototype.fields.each(function(c) {
9153 case 'int' : da[c.name] = 0; break;
9154 case 'date' : da[c.name] = new Date(); break;
9155 case 'float' : da[c.name] = 0.0; break;
9156 case 'boolean' : da[c.name] = false; break;
9157 default : da[c.name] = ""; break;
9161 return new this.recordType(Roo.apply(da, d));
9166 * Ext JS Library 1.1.1
9167 * Copyright(c) 2006-2007, Ext JS, LLC.
9169 * Originally Released Under LGPL - original licence link has changed is not relivant.
9172 * <script type="text/javascript">
9176 * @class Roo.data.DataProxy
9177 * @extends Roo.data.Observable
9178 * This class is an abstract base class for implementations which provide retrieval of
9179 * unformatted data objects.<br>
9181 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9182 * (of the appropriate type which knows how to parse the data object) to provide a block of
9183 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9185 * Custom implementations must implement the load method as described in
9186 * {@link Roo.data.HttpProxy#load}.
9188 Roo.data.DataProxy = function(){
9192 * Fires before a network request is made to retrieve a data object.
9193 * @param {Object} This DataProxy object.
9194 * @param {Object} params The params parameter to the load function.
9199 * Fires before the load method's callback is called.
9200 * @param {Object} This DataProxy object.
9201 * @param {Object} o The data object.
9202 * @param {Object} arg The callback argument object passed to the load function.
9206 * @event loadexception
9207 * Fires if an Exception occurs during data retrieval.
9208 * @param {Object} This DataProxy object.
9209 * @param {Object} o The data object.
9210 * @param {Object} arg The callback argument object passed to the load function.
9211 * @param {Object} e The Exception.
9213 loadexception : true
9215 Roo.data.DataProxy.superclass.constructor.call(this);
9218 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9221 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9225 * Ext JS Library 1.1.1
9226 * Copyright(c) 2006-2007, Ext JS, LLC.
9228 * Originally Released Under LGPL - original licence link has changed is not relivant.
9231 * <script type="text/javascript">
9234 * @class Roo.data.MemoryProxy
9235 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9236 * to the Reader when its load method is called.
9238 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9240 Roo.data.MemoryProxy = function(data){
9244 Roo.data.MemoryProxy.superclass.constructor.call(this);
9248 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9250 * Load data from the requested source (in this case an in-memory
9251 * data object passed to the constructor), read the data object into
9252 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9253 * process that block using the passed callback.
9254 * @param {Object} params This parameter is not used by the MemoryProxy class.
9255 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9256 * object into a block of Roo.data.Records.
9257 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9258 * The function must be passed <ul>
9259 * <li>The Record block object</li>
9260 * <li>The "arg" argument from the load function</li>
9261 * <li>A boolean success indicator</li>
9263 * @param {Object} scope The scope in which to call the callback
9264 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9266 load : function(params, reader, callback, scope, arg){
9267 params = params || {};
9270 result = reader.readRecords(this.data);
9272 this.fireEvent("loadexception", this, arg, null, e);
9273 callback.call(scope, null, arg, false);
9276 callback.call(scope, result, arg, true);
9280 update : function(params, records){
9285 * Ext JS Library 1.1.1
9286 * Copyright(c) 2006-2007, Ext JS, LLC.
9288 * Originally Released Under LGPL - original licence link has changed is not relivant.
9291 * <script type="text/javascript">
9294 * @class Roo.data.HttpProxy
9295 * @extends Roo.data.DataProxy
9296 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9297 * configured to reference a certain URL.<br><br>
9299 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9300 * from which the running page was served.<br><br>
9302 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9304 * Be aware that to enable the browser to parse an XML document, the server must set
9305 * the Content-Type header in the HTTP response to "text/xml".
9307 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9308 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9309 * will be used to make the request.
9311 Roo.data.HttpProxy = function(conn){
9312 Roo.data.HttpProxy.superclass.constructor.call(this);
9313 // is conn a conn config or a real conn?
9315 this.useAjax = !conn || !conn.events;
9319 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9320 // thse are take from connection...
9323 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9326 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9327 * extra parameters to each request made by this object. (defaults to undefined)
9330 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9331 * to each request made by this object. (defaults to undefined)
9334 * @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)
9337 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9340 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9346 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9350 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9351 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9352 * a finer-grained basis than the DataProxy events.
9354 getConnection : function(){
9355 return this.useAjax ? Roo.Ajax : this.conn;
9359 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9360 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9361 * process that block using the passed callback.
9362 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9363 * for the request to the remote server.
9364 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9365 * object into a block of Roo.data.Records.
9366 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9367 * The function must be passed <ul>
9368 * <li>The Record block object</li>
9369 * <li>The "arg" argument from the load function</li>
9370 * <li>A boolean success indicator</li>
9372 * @param {Object} scope The scope in which to call the callback
9373 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9375 load : function(params, reader, callback, scope, arg){
9376 if(this.fireEvent("beforeload", this, params) !== false){
9378 params : params || {},
9380 callback : callback,
9385 callback : this.loadResponse,
9389 Roo.applyIf(o, this.conn);
9390 if(this.activeRequest){
9391 Roo.Ajax.abort(this.activeRequest);
9393 this.activeRequest = Roo.Ajax.request(o);
9395 this.conn.request(o);
9398 callback.call(scope||this, null, arg, false);
9403 loadResponse : function(o, success, response){
9404 delete this.activeRequest;
9406 this.fireEvent("loadexception", this, o, response);
9407 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9412 result = o.reader.read(response);
9414 this.fireEvent("loadexception", this, o, response, e);
9415 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9419 this.fireEvent("load", this, o, o.request.arg);
9420 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9424 update : function(dataSet){
9429 updateResponse : function(dataSet){
9434 * Ext JS Library 1.1.1
9435 * Copyright(c) 2006-2007, Ext JS, LLC.
9437 * Originally Released Under LGPL - original licence link has changed is not relivant.
9440 * <script type="text/javascript">
9444 * @class Roo.data.ScriptTagProxy
9445 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9446 * other than the originating domain of the running page.<br><br>
9448 * <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
9449 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9451 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9452 * source code that is used as the source inside a <script> tag.<br><br>
9454 * In order for the browser to process the returned data, the server must wrap the data object
9455 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9456 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9457 * depending on whether the callback name was passed:
9460 boolean scriptTag = false;
9461 String cb = request.getParameter("callback");
9464 response.setContentType("text/javascript");
9466 response.setContentType("application/x-json");
9468 Writer out = response.getWriter();
9470 out.write(cb + "(");
9472 out.print(dataBlock.toJsonString());
9479 * @param {Object} config A configuration object.
9481 Roo.data.ScriptTagProxy = function(config){
9482 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9483 Roo.apply(this, config);
9484 this.head = document.getElementsByTagName("head")[0];
9487 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9489 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9491 * @cfg {String} url The URL from which to request the data object.
9494 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9498 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9499 * the server the name of the callback function set up by the load call to process the returned data object.
9500 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9501 * javascript output which calls this named function passing the data object as its only parameter.
9503 callbackParam : "callback",
9505 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9506 * name to the request.
9511 * Load data from the configured URL, read the data object into
9512 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9513 * process that block using the passed callback.
9514 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9515 * for the request to the remote server.
9516 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9517 * object into a block of Roo.data.Records.
9518 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9519 * The function must be passed <ul>
9520 * <li>The Record block object</li>
9521 * <li>The "arg" argument from the load function</li>
9522 * <li>A boolean success indicator</li>
9524 * @param {Object} scope The scope in which to call the callback
9525 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9527 load : function(params, reader, callback, scope, arg){
9528 if(this.fireEvent("beforeload", this, params) !== false){
9530 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9533 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9535 url += "&_dc=" + (new Date().getTime());
9537 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9540 cb : "stcCallback"+transId,
9541 scriptId : "stcScript"+transId,
9545 callback : callback,
9551 window[trans.cb] = function(o){
9552 conn.handleResponse(o, trans);
9555 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9557 if(this.autoAbort !== false){
9561 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9563 var script = document.createElement("script");
9564 script.setAttribute("src", url);
9565 script.setAttribute("type", "text/javascript");
9566 script.setAttribute("id", trans.scriptId);
9567 this.head.appendChild(script);
9571 callback.call(scope||this, null, arg, false);
9576 isLoading : function(){
9577 return this.trans ? true : false;
9581 * Abort the current server request.
9584 if(this.isLoading()){
9585 this.destroyTrans(this.trans);
9590 destroyTrans : function(trans, isLoaded){
9591 this.head.removeChild(document.getElementById(trans.scriptId));
9592 clearTimeout(trans.timeoutId);
9594 window[trans.cb] = undefined;
9596 delete window[trans.cb];
9599 // if hasn't been loaded, wait for load to remove it to prevent script error
9600 window[trans.cb] = function(){
9601 window[trans.cb] = undefined;
9603 delete window[trans.cb];
9610 handleResponse : function(o, trans){
9612 this.destroyTrans(trans, true);
9615 result = trans.reader.readRecords(o);
9617 this.fireEvent("loadexception", this, o, trans.arg, e);
9618 trans.callback.call(trans.scope||window, null, trans.arg, false);
9621 this.fireEvent("load", this, o, trans.arg);
9622 trans.callback.call(trans.scope||window, result, trans.arg, true);
9626 handleFailure : function(trans){
9628 this.destroyTrans(trans, false);
9629 this.fireEvent("loadexception", this, null, trans.arg);
9630 trans.callback.call(trans.scope||window, null, trans.arg, false);
9634 * Ext JS Library 1.1.1
9635 * Copyright(c) 2006-2007, Ext JS, LLC.
9637 * Originally Released Under LGPL - original licence link has changed is not relivant.
9640 * <script type="text/javascript">
9644 * @class Roo.data.JsonReader
9645 * @extends Roo.data.DataReader
9646 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9647 * based on mappings in a provided Roo.data.Record constructor.
9649 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9650 * in the reply previously.
9655 var RecordDef = Roo.data.Record.create([
9656 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9657 {name: 'occupation'} // This field will use "occupation" as the mapping.
9659 var myReader = new Roo.data.JsonReader({
9660 totalProperty: "results", // The property which contains the total dataset size (optional)
9661 root: "rows", // The property which contains an Array of row objects
9662 id: "id" // The property within each row object that provides an ID for the record (optional)
9666 * This would consume a JSON file like this:
9668 { 'results': 2, 'rows': [
9669 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9670 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9673 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9674 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9675 * paged from the remote server.
9676 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9677 * @cfg {String} root name of the property which contains the Array of row objects.
9678 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9680 * Create a new JsonReader
9681 * @param {Object} meta Metadata configuration options
9682 * @param {Object} recordType Either an Array of field definition objects,
9683 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9685 Roo.data.JsonReader = function(meta, recordType){
9688 // set some defaults:
9690 totalProperty: 'total',
9691 successProperty : 'success',
9696 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9698 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9701 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9702 * Used by Store query builder to append _requestMeta to params.
9705 metaFromRemote : false,
9707 * This method is only used by a DataProxy which has retrieved data from a remote server.
9708 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9709 * @return {Object} data A data block which is used by an Roo.data.Store object as
9710 * a cache of Roo.data.Records.
9712 read : function(response){
9713 var json = response.responseText;
9715 var o = /* eval:var:o */ eval("("+json+")");
9717 throw {message: "JsonReader.read: Json object not found"};
9723 this.metaFromRemote = true;
9724 this.meta = o.metaData;
9725 this.recordType = Roo.data.Record.create(o.metaData.fields);
9726 this.onMetaChange(this.meta, this.recordType, o);
9728 return this.readRecords(o);
9731 // private function a store will implement
9732 onMetaChange : function(meta, recordType, o){
9739 simpleAccess: function(obj, subsc) {
9746 getJsonAccessor: function(){
9748 return function(expr) {
9750 return(re.test(expr))
9751 ? new Function("obj", "return obj." + expr)
9761 * Create a data block containing Roo.data.Records from an XML document.
9762 * @param {Object} o An object which contains an Array of row objects in the property specified
9763 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9764 * which contains the total size of the dataset.
9765 * @return {Object} data A data block which is used by an Roo.data.Store object as
9766 * a cache of Roo.data.Records.
9768 readRecords : function(o){
9770 * After any data loads, the raw JSON data is available for further custom processing.
9774 var s = this.meta, Record = this.recordType,
9775 f = Record.prototype.fields, fi = f.items, fl = f.length;
9777 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9779 if(s.totalProperty) {
9780 this.getTotal = this.getJsonAccessor(s.totalProperty);
9782 if(s.successProperty) {
9783 this.getSuccess = this.getJsonAccessor(s.successProperty);
9785 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9787 var g = this.getJsonAccessor(s.id);
9788 this.getId = function(rec) {
9790 return (r === undefined || r === "") ? null : r;
9793 this.getId = function(){return null;};
9796 for(var jj = 0; jj < fl; jj++){
9798 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9799 this.ef[jj] = this.getJsonAccessor(map);
9803 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9804 if(s.totalProperty){
9805 var vt = parseInt(this.getTotal(o), 10);
9810 if(s.successProperty){
9811 var vs = this.getSuccess(o);
9812 if(vs === false || vs === 'false'){
9817 for(var i = 0; i < c; i++){
9820 var id = this.getId(n);
9821 for(var j = 0; j < fl; j++){
9823 var v = this.ef[j](n);
9825 Roo.log('missing convert for ' + f.name);
9829 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9831 var record = new Record(values, id);
9833 records[i] = record;
9839 totalRecords : totalRecords
9844 * Ext JS Library 1.1.1
9845 * Copyright(c) 2006-2007, Ext JS, LLC.
9847 * Originally Released Under LGPL - original licence link has changed is not relivant.
9850 * <script type="text/javascript">
9854 * @class Roo.data.ArrayReader
9855 * @extends Roo.data.DataReader
9856 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9857 * Each element of that Array represents a row of data fields. The
9858 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9859 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9863 var RecordDef = Roo.data.Record.create([
9864 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9865 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9867 var myReader = new Roo.data.ArrayReader({
9868 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9872 * This would consume an Array like this:
9874 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9876 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9878 * Create a new JsonReader
9879 * @param {Object} meta Metadata configuration options.
9880 * @param {Object} recordType Either an Array of field definition objects
9881 * as specified to {@link Roo.data.Record#create},
9882 * or an {@link Roo.data.Record} object
9883 * created using {@link Roo.data.Record#create}.
9885 Roo.data.ArrayReader = function(meta, recordType){
9886 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9889 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9891 * Create a data block containing Roo.data.Records from an XML document.
9892 * @param {Object} o An Array of row objects which represents the dataset.
9893 * @return {Object} data A data block which is used by an Roo.data.Store object as
9894 * a cache of Roo.data.Records.
9896 readRecords : function(o){
9897 var sid = this.meta ? this.meta.id : null;
9898 var recordType = this.recordType, fields = recordType.prototype.fields;
9901 for(var i = 0; i < root.length; i++){
9904 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9905 for(var j = 0, jlen = fields.length; j < jlen; j++){
9906 var f = fields.items[j];
9907 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9908 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9912 var record = new recordType(values, id);
9914 records[records.length] = record;
9918 totalRecords : records.length
9927 * @class Roo.bootstrap.ComboBox
9928 * @extends Roo.bootstrap.TriggerField
9929 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9930 * @cfg {Boolean} append (true|false) default false
9931 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9932 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9933 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9935 * Create a new ComboBox.
9936 * @param {Object} config Configuration options
9938 Roo.bootstrap.ComboBox = function(config){
9939 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9943 * Fires when the dropdown list is expanded
9944 * @param {Roo.bootstrap.ComboBox} combo This combo box
9949 * Fires when the dropdown list is collapsed
9950 * @param {Roo.bootstrap.ComboBox} combo This combo box
9954 * @event beforeselect
9955 * Fires before a list item is selected. Return false to cancel the selection.
9956 * @param {Roo.bootstrap.ComboBox} combo This combo box
9957 * @param {Roo.data.Record} record The data record returned from the underlying store
9958 * @param {Number} index The index of the selected item in the dropdown list
9960 'beforeselect' : true,
9963 * Fires when a list item is selected
9964 * @param {Roo.bootstrap.ComboBox} combo This combo box
9965 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9966 * @param {Number} index The index of the selected item in the dropdown list
9970 * @event beforequery
9971 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9972 * The event object passed has these properties:
9973 * @param {Roo.bootstrap.ComboBox} combo This combo box
9974 * @param {String} query The query
9975 * @param {Boolean} forceAll true to force "all" query
9976 * @param {Boolean} cancel true to cancel the query
9977 * @param {Object} e The query event object
9979 'beforequery': true,
9982 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9983 * @param {Roo.bootstrap.ComboBox} combo This combo box
9988 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9989 * @param {Roo.bootstrap.ComboBox} combo This combo box
9990 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9995 * Fires when the remove value from the combobox array
9996 * @param {Roo.bootstrap.ComboBox} combo This combo box
10003 this.tickItems = [];
10005 this.selectedIndex = -1;
10006 if(this.mode == 'local'){
10007 if(config.queryDelay === undefined){
10008 this.queryDelay = 10;
10010 if(config.minChars === undefined){
10016 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10019 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10020 * rendering into an Roo.Editor, defaults to false)
10023 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10024 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10027 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10030 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10031 * the dropdown list (defaults to undefined, with no header element)
10035 * @cfg {String/Roo.Template} tpl The template to use to render the output
10039 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10041 listWidth: undefined,
10043 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10044 * mode = 'remote' or 'text' if mode = 'local')
10046 displayField: undefined,
10048 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10049 * mode = 'remote' or 'value' if mode = 'local').
10050 * Note: use of a valueField requires the user make a selection
10051 * in order for a value to be mapped.
10053 valueField: undefined,
10057 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10058 * field's data value (defaults to the underlying DOM element's name)
10060 hiddenName: undefined,
10062 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10066 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10068 selectedClass: 'active',
10071 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10075 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10076 * anchor positions (defaults to 'tl-bl')
10078 listAlign: 'tl-bl?',
10080 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10084 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10085 * query specified by the allQuery config option (defaults to 'query')
10087 triggerAction: 'query',
10089 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10090 * (defaults to 4, does not apply if editable = false)
10094 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10095 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10099 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10100 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10104 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10105 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10109 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10110 * when editable = true (defaults to false)
10112 selectOnFocus:false,
10114 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10116 queryParam: 'query',
10118 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10119 * when mode = 'remote' (defaults to 'Loading...')
10121 loadingText: 'Loading...',
10123 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10127 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10131 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10132 * traditional select (defaults to true)
10136 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10140 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10144 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10145 * listWidth has a higher value)
10149 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10150 * allow the user to set arbitrary text into the field (defaults to false)
10152 forceSelection:false,
10154 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10155 * if typeAhead = true (defaults to 250)
10157 typeAheadDelay : 250,
10159 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10160 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10162 valueNotFoundText : undefined,
10164 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10166 blockFocus : false,
10169 * @cfg {Boolean} disableClear Disable showing of clear button.
10171 disableClear : false,
10173 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10175 alwaysQuery : false,
10178 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10192 btnPosition : 'right',
10194 // element that contains real text value.. (when hidden is used..)
10196 getAutoCreate : function()
10203 if(!this.tickable){
10204 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10209 * ComboBox with tickable selections
10212 var align = this.labelAlign || this.parentLabelAlign();
10215 cls : 'form-group roo-combobox-tickable' //input-group
10221 cls : 'tickable-buttons',
10226 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10233 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10240 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10247 Roo.each(buttons.cn, function(c){
10249 c.cls += ' btn-' + _this.size;
10252 if (_this.disabled) {
10263 cls: 'form-hidden-field'
10267 cls: 'select2-choices',
10271 cls: 'select2-search-field',
10283 cls: 'select2-container input-group select2-container-multi',
10288 cls: 'typeahead typeahead-long dropdown-menu',
10289 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10294 if (align ==='left' && this.fieldLabel.length) {
10296 Roo.log("left and has label");
10302 cls : 'control-label col-sm-' + this.labelWidth,
10303 html : this.fieldLabel
10307 cls : "col-sm-" + (12 - this.labelWidth),
10314 } else if ( this.fieldLabel.length) {
10320 //cls : 'input-group-addon',
10321 html : this.fieldLabel
10331 Roo.log(" no label && no align");
10338 ['xs','sm','md','lg'].map(function(size){
10339 if (settings[size]) {
10340 cfg.cls += ' col-' + size + '-' + settings[size];
10349 initEvents: function()
10353 throw "can not find store for combo";
10355 this.store = Roo.factory(this.store, Roo.data);
10358 this.initTickableEvnets();
10362 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10365 if(this.hiddenName){
10367 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10369 this.hiddenField.dom.value =
10370 this.hiddenValue !== undefined ? this.hiddenValue :
10371 this.value !== undefined ? this.value : '';
10373 // prevent input submission
10374 this.el.dom.removeAttribute('name');
10375 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10380 // this.el.dom.setAttribute('autocomplete', 'off');
10383 var cls = 'x-combo-list';
10384 this.list = this.el.select('ul.dropdown-menu',true).first();
10386 //this.list = new Roo.Layer({
10387 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10393 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10394 _this.list.setWidth(lw);
10397 this.list.on('mouseover', this.onViewOver, this);
10398 this.list.on('mousemove', this.onViewMove, this);
10400 this.list.on('scroll', this.onViewScroll, this);
10403 this.list.swallowEvent('mousewheel');
10404 this.assetHeight = 0;
10407 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10408 this.assetHeight += this.header.getHeight();
10411 this.innerList = this.list.createChild({cls:cls+'-inner'});
10412 this.innerList.on('mouseover', this.onViewOver, this);
10413 this.innerList.on('mousemove', this.onViewMove, this);
10414 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10416 if(this.allowBlank && !this.pageSize && !this.disableClear){
10417 this.footer = this.list.createChild({cls:cls+'-ft'});
10418 this.pageTb = new Roo.Toolbar(this.footer);
10422 this.footer = this.list.createChild({cls:cls+'-ft'});
10423 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10424 {pageSize: this.pageSize});
10428 if (this.pageTb && this.allowBlank && !this.disableClear) {
10430 this.pageTb.add(new Roo.Toolbar.Fill(), {
10431 cls: 'x-btn-icon x-btn-clear',
10433 handler: function()
10436 _this.clearValue();
10437 _this.onSelect(false, -1);
10442 this.assetHeight += this.footer.getHeight();
10447 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10450 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10451 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10453 //this.view.wrapEl.setDisplayed(false);
10454 this.view.on('click', this.onViewClick, this);
10458 this.store.on('beforeload', this.onBeforeLoad, this);
10459 this.store.on('load', this.onLoad, this);
10460 this.store.on('loadexception', this.onLoadException, this);
10462 if(this.resizable){
10463 this.resizer = new Roo.Resizable(this.list, {
10464 pinned:true, handles:'se'
10466 this.resizer.on('resize', function(r, w, h){
10467 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10468 this.listWidth = w;
10469 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10470 this.restrictHeight();
10472 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10475 if(!this.editable){
10476 this.editable = true;
10477 this.setEditable(false);
10482 if (typeof(this.events.add.listeners) != 'undefined') {
10484 this.addicon = this.wrap.createChild(
10485 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10487 this.addicon.on('click', function(e) {
10488 this.fireEvent('add', this);
10491 if (typeof(this.events.edit.listeners) != 'undefined') {
10493 this.editicon = this.wrap.createChild(
10494 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10495 if (this.addicon) {
10496 this.editicon.setStyle('margin-left', '40px');
10498 this.editicon.on('click', function(e) {
10500 // we fire even if inothing is selected..
10501 this.fireEvent('edit', this, this.lastData );
10507 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10508 "up" : function(e){
10509 this.inKeyMode = true;
10513 "down" : function(e){
10514 if(!this.isExpanded()){
10515 this.onTriggerClick();
10517 this.inKeyMode = true;
10522 "enter" : function(e){
10523 // this.onViewClick();
10527 if(this.fireEvent("specialkey", this, e)){
10528 this.onViewClick(false);
10534 "esc" : function(e){
10538 "tab" : function(e){
10541 if(this.fireEvent("specialkey", this, e)){
10542 this.onViewClick(false);
10550 doRelay : function(foo, bar, hname){
10551 if(hname == 'down' || this.scope.isExpanded()){
10552 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10561 this.queryDelay = Math.max(this.queryDelay || 10,
10562 this.mode == 'local' ? 10 : 250);
10565 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10567 if(this.typeAhead){
10568 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10570 if(this.editable !== false){
10571 this.inputEl().on("keyup", this.onKeyUp, this);
10573 if(this.forceSelection){
10574 this.inputEl().on('blur', this.doForce, this);
10578 this.choices = this.el.select('ul.select2-choices', true).first();
10579 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10583 initTickableEvnets: function()
10585 if(this.hiddenName){
10587 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10589 this.hiddenField.dom.value =
10590 this.hiddenValue !== undefined ? this.hiddenValue :
10591 this.value !== undefined ? this.value : '';
10593 // prevent input submission
10594 this.el.dom.removeAttribute('name');
10595 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10600 this.list = this.el.select('ul.dropdown-menu',true).first();
10602 this.choices = this.el.select('ul.select2-choices', true).first();
10603 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10604 this.searchField.on("click", this.onTriggerClick, this, {preventDefault:true});
10606 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10607 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10609 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10610 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10612 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10613 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10615 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10616 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10617 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10620 this.cancelBtn.hide();
10625 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10626 _this.list.setWidth(lw);
10629 this.list.on('mouseover', this.onViewOver, this);
10630 this.list.on('mousemove', this.onViewMove, this);
10632 this.list.on('scroll', this.onViewScroll, this);
10635 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>';
10638 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10639 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10642 //this.view.wrapEl.setDisplayed(false);
10643 this.view.on('click', this.onViewClick, this);
10647 this.store.on('beforeload', this.onBeforeLoad, this);
10648 this.store.on('load', this.onLoad, this);
10649 this.store.on('loadexception', this.onLoadException, this);
10651 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10652 // "up" : function(e){
10653 // this.inKeyMode = true;
10654 // this.selectPrev();
10657 // "down" : function(e){
10658 // if(!this.isExpanded()){
10659 // this.onTriggerClick();
10661 // this.inKeyMode = true;
10662 // this.selectNext();
10666 // "enter" : function(e){
10667 //// this.onViewClick();
10669 // this.collapse();
10671 // if(this.fireEvent("specialkey", this, e)){
10672 // this.onViewClick(false);
10678 // "esc" : function(e){
10679 // this.collapse();
10682 // "tab" : function(e){
10683 // this.collapse();
10685 // if(this.fireEvent("specialkey", this, e)){
10686 // this.onViewClick(false);
10694 // doRelay : function(foo, bar, hname){
10695 // if(hname == 'down' || this.scope.isExpanded()){
10696 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10701 // forceKeyDown: true
10705 this.queryDelay = Math.max(this.queryDelay || 10,
10706 this.mode == 'local' ? 10 : 250);
10709 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10711 if(this.typeAhead){
10712 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10716 onDestroy : function(){
10718 this.view.setStore(null);
10719 this.view.el.removeAllListeners();
10720 this.view.el.remove();
10721 this.view.purgeListeners();
10724 this.list.dom.innerHTML = '';
10728 this.store.un('beforeload', this.onBeforeLoad, this);
10729 this.store.un('load', this.onLoad, this);
10730 this.store.un('loadexception', this.onLoadException, this);
10732 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10736 fireKey : function(e){
10737 if(e.isNavKeyPress() && !this.list.isVisible()){
10738 this.fireEvent("specialkey", this, e);
10743 onResize: function(w, h){
10744 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10746 // if(typeof w != 'number'){
10747 // // we do not handle it!?!?
10750 // var tw = this.trigger.getWidth();
10751 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10752 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10754 // this.inputEl().setWidth( this.adjustWidth('input', x));
10756 // //this.trigger.setStyle('left', x+'px');
10758 // if(this.list && this.listWidth === undefined){
10759 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10760 // this.list.setWidth(lw);
10761 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10769 * Allow or prevent the user from directly editing the field text. If false is passed,
10770 * the user will only be able to select from the items defined in the dropdown list. This method
10771 * is the runtime equivalent of setting the 'editable' config option at config time.
10772 * @param {Boolean} value True to allow the user to directly edit the field text
10774 setEditable : function(value){
10775 if(value == this.editable){
10778 this.editable = value;
10780 this.inputEl().dom.setAttribute('readOnly', true);
10781 this.inputEl().on('mousedown', this.onTriggerClick, this);
10782 this.inputEl().addClass('x-combo-noedit');
10784 this.inputEl().dom.setAttribute('readOnly', false);
10785 this.inputEl().un('mousedown', this.onTriggerClick, this);
10786 this.inputEl().removeClass('x-combo-noedit');
10792 onBeforeLoad : function(combo,opts){
10793 if(!this.hasFocus){
10797 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10799 this.restrictHeight();
10800 this.selectedIndex = -1;
10804 onLoad : function(){
10806 this.hasQuery = false;
10808 if(!this.hasFocus){
10812 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10813 this.loading.hide();
10816 if(this.store.getCount() > 0){
10818 this.restrictHeight();
10819 if(this.lastQuery == this.allQuery){
10820 if(this.editable && !this.tickable){
10821 this.inputEl().dom.select();
10823 if(!this.selectByValue(this.value, true) && this.autoFocus){
10824 this.select(0, true);
10827 if(this.autoFocus){
10830 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10831 this.taTask.delay(this.typeAheadDelay);
10835 this.onEmptyResults();
10841 onLoadException : function()
10843 this.hasQuery = false;
10845 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10846 this.loading.hide();
10850 Roo.log(this.store.reader.jsonData);
10851 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10853 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10859 onTypeAhead : function(){
10860 if(this.store.getCount() > 0){
10861 var r = this.store.getAt(0);
10862 var newValue = r.data[this.displayField];
10863 var len = newValue.length;
10864 var selStart = this.getRawValue().length;
10866 if(selStart != len){
10867 this.setRawValue(newValue);
10868 this.selectText(selStart, newValue.length);
10874 onSelect : function(record, index){
10876 if(this.fireEvent('beforeselect', this, record, index) !== false){
10878 this.setFromData(index > -1 ? record.data : false);
10881 this.fireEvent('select', this, record, index);
10886 * Returns the currently selected field value or empty string if no value is set.
10887 * @return {String} value The selected value
10889 getValue : function(){
10892 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10895 if(this.valueField){
10896 return typeof this.value != 'undefined' ? this.value : '';
10898 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10903 * Clears any text/value currently set in the field
10905 clearValue : function(){
10906 if(this.hiddenField){
10907 this.hiddenField.dom.value = '';
10910 this.setRawValue('');
10911 this.lastSelectionText = '';
10916 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10917 * will be displayed in the field. If the value does not match the data value of an existing item,
10918 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10919 * Otherwise the field will be blank (although the value will still be set).
10920 * @param {String} value The value to match
10922 setValue : function(v){
10929 if(this.valueField){
10930 var r = this.findRecord(this.valueField, v);
10932 text = r.data[this.displayField];
10933 }else if(this.valueNotFoundText !== undefined){
10934 text = this.valueNotFoundText;
10937 this.lastSelectionText = text;
10938 if(this.hiddenField){
10939 this.hiddenField.dom.value = v;
10941 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10945 * @property {Object} the last set data for the element
10950 * Sets the value of the field based on a object which is related to the record format for the store.
10951 * @param {Object} value the value to set as. or false on reset?
10953 setFromData : function(o){
10960 var dv = ''; // display value
10961 var vv = ''; // value value..
10963 if (this.displayField) {
10964 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10966 // this is an error condition!!!
10967 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10970 if(this.valueField){
10971 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10974 if(this.hiddenField){
10975 this.hiddenField.dom.value = vv;
10977 this.lastSelectionText = dv;
10978 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10982 // no hidden field.. - we store the value in 'value', but still display
10983 // display field!!!!
10984 this.lastSelectionText = dv;
10985 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10991 reset : function(){
10992 // overridden so that last data is reset..
10993 this.setValue(this.originalValue);
10994 this.clearInvalid();
10995 this.lastData = false;
10997 this.view.clearSelections();
11001 findRecord : function(prop, value){
11003 if(this.store.getCount() > 0){
11004 this.store.each(function(r){
11005 if(r.data[prop] == value){
11015 getName: function()
11017 // returns hidden if it's set..
11018 if (!this.rendered) {return ''};
11019 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11023 onViewMove : function(e, t){
11024 this.inKeyMode = false;
11028 onViewOver : function(e, t){
11029 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11032 var item = this.view.findItemFromChild(t);
11035 var index = this.view.indexOf(item);
11036 this.select(index, false);
11041 onViewClick : function(view, doFocus, el, e)
11043 var index = this.view.getSelectedIndexes()[0];
11045 var r = this.store.getAt(index);
11049 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11056 Roo.each(this.tickItems, function(v,k){
11058 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11059 _this.tickItems.splice(k, 1);
11069 this.tickItems.push(r.data);
11074 this.onSelect(r, index);
11076 if(doFocus !== false && !this.blockFocus){
11077 this.inputEl().focus();
11082 restrictHeight : function(){
11083 //this.innerList.dom.style.height = '';
11084 //var inner = this.innerList.dom;
11085 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11086 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11087 //this.list.beginUpdate();
11088 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11089 this.list.alignTo(this.inputEl(), this.listAlign);
11090 //this.list.endUpdate();
11094 onEmptyResults : function(){
11099 * Returns true if the dropdown list is expanded, else false.
11101 isExpanded : function(){
11102 return this.list.isVisible();
11106 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11107 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11108 * @param {String} value The data value of the item to select
11109 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11110 * selected item if it is not currently in view (defaults to true)
11111 * @return {Boolean} True if the value matched an item in the list, else false
11113 selectByValue : function(v, scrollIntoView){
11114 if(v !== undefined && v !== null){
11115 var r = this.findRecord(this.valueField || this.displayField, v);
11117 this.select(this.store.indexOf(r), scrollIntoView);
11125 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11126 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11127 * @param {Number} index The zero-based index of the list item to select
11128 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11129 * selected item if it is not currently in view (defaults to true)
11131 select : function(index, scrollIntoView){
11132 this.selectedIndex = index;
11133 this.view.select(index);
11134 if(scrollIntoView !== false){
11135 var el = this.view.getNode(index);
11137 //this.innerList.scrollChildIntoView(el, false);
11144 selectNext : function(){
11145 var ct = this.store.getCount();
11147 if(this.selectedIndex == -1){
11149 }else if(this.selectedIndex < ct-1){
11150 this.select(this.selectedIndex+1);
11156 selectPrev : function(){
11157 var ct = this.store.getCount();
11159 if(this.selectedIndex == -1){
11161 }else if(this.selectedIndex != 0){
11162 this.select(this.selectedIndex-1);
11168 onKeyUp : function(e){
11169 if(this.editable !== false && !e.isSpecialKey()){
11170 this.lastKey = e.getKey();
11171 this.dqTask.delay(this.queryDelay);
11176 validateBlur : function(){
11177 return !this.list || !this.list.isVisible();
11181 initQuery : function(){
11182 this.doQuery(this.getRawValue());
11186 doForce : function(){
11187 if(this.inputEl().dom.value.length > 0){
11188 this.inputEl().dom.value =
11189 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11195 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11196 * query allowing the query action to be canceled if needed.
11197 * @param {String} query The SQL query to execute
11198 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11199 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11200 * saved in the current store (defaults to false)
11202 doQuery : function(q, forceAll){
11204 if(q === undefined || q === null){
11209 forceAll: forceAll,
11213 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11218 forceAll = qe.forceAll;
11219 if(forceAll === true || (q.length >= this.minChars)){
11221 this.hasQuery = true;
11223 if(this.lastQuery != q || this.alwaysQuery){
11224 this.lastQuery = q;
11225 if(this.mode == 'local'){
11226 this.selectedIndex = -1;
11228 this.store.clearFilter();
11230 this.store.filter(this.displayField, q);
11234 this.store.baseParams[this.queryParam] = q;
11236 var options = {params : this.getParams(q)};
11239 options.add = true;
11240 options.params.start = this.page * this.pageSize;
11243 this.store.load(options);
11245 * this code will make the page width larger, at the beginning, the list not align correctly,
11246 * we should expand the list on onLoad
11247 * so command out it
11252 this.selectedIndex = -1;
11257 this.loadNext = false;
11261 getParams : function(q){
11263 //p[this.queryParam] = q;
11267 p.limit = this.pageSize;
11273 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11275 collapse : function(){
11276 if(!this.isExpanded()){
11284 this.cancelBtn.hide();
11285 this.trigger.show();
11288 Roo.get(document).un('mousedown', this.collapseIf, this);
11289 Roo.get(document).un('mousewheel', this.collapseIf, this);
11290 if (!this.editable) {
11291 Roo.get(document).un('keydown', this.listKeyPress, this);
11293 this.fireEvent('collapse', this);
11297 collapseIf : function(e){
11298 var in_combo = e.within(this.el);
11299 var in_list = e.within(this.list);
11301 if (in_combo || in_list) {
11302 //e.stopPropagation();
11307 this.onTickableFooterButtonClick(e, false, false);
11315 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11317 expand : function(){
11319 if(this.isExpanded() || !this.hasFocus){
11323 this.list.alignTo(this.inputEl(), this.listAlign);
11328 this.tickItems = Roo.apply([], this.item);
11331 this.cancelBtn.show();
11332 this.trigger.hide();
11336 Roo.get(document).on('mousedown', this.collapseIf, this);
11337 Roo.get(document).on('mousewheel', this.collapseIf, this);
11338 if (!this.editable) {
11339 Roo.get(document).on('keydown', this.listKeyPress, this);
11342 this.fireEvent('expand', this);
11346 // Implements the default empty TriggerField.onTriggerClick function
11347 onTriggerClick : function()
11349 Roo.log('trigger click');
11356 this.onTickableTriggerClick();
11361 this.loadNext = false;
11363 if(this.isExpanded()){
11365 if (!this.blockFocus) {
11366 this.inputEl().focus();
11370 this.hasFocus = true;
11371 if(this.triggerAction == 'all') {
11372 this.doQuery(this.allQuery, true);
11374 this.doQuery(this.getRawValue());
11376 if (!this.blockFocus) {
11377 this.inputEl().focus();
11382 onTickableTriggerClick : function()
11385 this.loadNext = false;
11386 this.hasFocus = true;
11388 if(this.triggerAction == 'all') {
11389 this.doQuery(this.allQuery, true);
11391 this.doQuery(this.getRawValue());
11395 listKeyPress : function(e)
11397 //Roo.log('listkeypress');
11398 // scroll to first matching element based on key pres..
11399 if (e.isSpecialKey()) {
11402 var k = String.fromCharCode(e.getKey()).toUpperCase();
11405 var csel = this.view.getSelectedNodes();
11406 var cselitem = false;
11408 var ix = this.view.indexOf(csel[0]);
11409 cselitem = this.store.getAt(ix);
11410 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11416 this.store.each(function(v) {
11418 // start at existing selection.
11419 if (cselitem.id == v.id) {
11425 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11426 match = this.store.indexOf(v);
11432 if (match === false) {
11433 return true; // no more action?
11436 this.view.select(match);
11437 var sn = Roo.get(this.view.getSelectedNodes()[0])
11438 //sn.scrollIntoView(sn.dom.parentNode, false);
11441 onViewScroll : function(e, t){
11443 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11447 this.hasQuery = true;
11449 this.loading = this.list.select('.loading', true).first();
11451 if(this.loading === null){
11452 this.list.createChild({
11454 cls: 'loading select2-more-results select2-active',
11455 html: 'Loading more results...'
11458 this.loading = this.list.select('.loading', true).first();
11460 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11462 this.loading.hide();
11465 this.loading.show();
11470 this.loadNext = true;
11472 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11477 addItem : function(o)
11479 var dv = ''; // display value
11481 if (this.displayField) {
11482 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11484 // this is an error condition!!!
11485 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11492 var choice = this.choices.createChild({
11494 cls: 'select2-search-choice',
11503 cls: 'select2-search-choice-close',
11508 }, this.searchField);
11510 var close = choice.select('a.select2-search-choice-close', true).first()
11512 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11520 this.inputEl().dom.value = '';
11524 onRemoveItem : function(e, _self, o)
11526 e.preventDefault();
11527 var index = this.item.indexOf(o.data) * 1;
11530 Roo.log('not this item?!');
11534 this.item.splice(index, 1);
11539 this.fireEvent('remove', this, e);
11543 syncValue : function()
11545 if(!this.item.length){
11552 Roo.each(this.item, function(i){
11553 if(_this.valueField){
11554 value.push(i[_this.valueField]);
11561 this.value = value.join(',');
11563 if(this.hiddenField){
11564 this.hiddenField.dom.value = this.value;
11568 clearItem : function()
11570 if(!this.multiple){
11576 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11583 inputEl: function ()
11586 return this.searchField;
11588 return this.el.select('input.form-control',true).first();
11592 onTickableFooterButtonClick : function(e, btn, el)
11594 e.preventDefault();
11596 if(btn && btn.name == 'cancel'){
11597 this.tickItems = Roo.apply([], this.item);
11606 Roo.each(this.tickItems, function(o){
11617 * @cfg {Boolean} grow
11621 * @cfg {Number} growMin
11625 * @cfg {Number} growMax
11635 * Ext JS Library 1.1.1
11636 * Copyright(c) 2006-2007, Ext JS, LLC.
11638 * Originally Released Under LGPL - original licence link has changed is not relivant.
11641 * <script type="text/javascript">
11646 * @extends Roo.util.Observable
11647 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11648 * This class also supports single and multi selection modes. <br>
11649 * Create a data model bound view:
11651 var store = new Roo.data.Store(...);
11653 var view = new Roo.View({
11655 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11657 singleSelect: true,
11658 selectedClass: "ydataview-selected",
11662 // listen for node click?
11663 view.on("click", function(vw, index, node, e){
11664 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11668 dataModel.load("foobar.xml");
11670 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11672 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11673 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11675 * Note: old style constructor is still suported (container, template, config)
11678 * Create a new View
11679 * @param {Object} config The config object
11682 Roo.View = function(config, depreciated_tpl, depreciated_config){
11684 this.parent = false;
11686 if (typeof(depreciated_tpl) == 'undefined') {
11687 // new way.. - universal constructor.
11688 Roo.apply(this, config);
11689 this.el = Roo.get(this.el);
11692 this.el = Roo.get(config);
11693 this.tpl = depreciated_tpl;
11694 Roo.apply(this, depreciated_config);
11696 this.wrapEl = this.el.wrap().wrap();
11697 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11700 if(typeof(this.tpl) == "string"){
11701 this.tpl = new Roo.Template(this.tpl);
11703 // support xtype ctors..
11704 this.tpl = new Roo.factory(this.tpl, Roo);
11708 this.tpl.compile();
11713 * @event beforeclick
11714 * Fires before a click is processed. Returns false to cancel the default action.
11715 * @param {Roo.View} this
11716 * @param {Number} index The index of the target node
11717 * @param {HTMLElement} node The target node
11718 * @param {Roo.EventObject} e The raw event object
11720 "beforeclick" : true,
11723 * Fires when a template node is clicked.
11724 * @param {Roo.View} this
11725 * @param {Number} index The index of the target node
11726 * @param {HTMLElement} node The target node
11727 * @param {Roo.EventObject} e The raw event object
11732 * Fires when a template node is double clicked.
11733 * @param {Roo.View} this
11734 * @param {Number} index The index of the target node
11735 * @param {HTMLElement} node The target node
11736 * @param {Roo.EventObject} e The raw event object
11740 * @event contextmenu
11741 * Fires when a template node is right clicked.
11742 * @param {Roo.View} this
11743 * @param {Number} index The index of the target node
11744 * @param {HTMLElement} node The target node
11745 * @param {Roo.EventObject} e The raw event object
11747 "contextmenu" : true,
11749 * @event selectionchange
11750 * Fires when the selected nodes change.
11751 * @param {Roo.View} this
11752 * @param {Array} selections Array of the selected nodes
11754 "selectionchange" : true,
11757 * @event beforeselect
11758 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11759 * @param {Roo.View} this
11760 * @param {HTMLElement} node The node to be selected
11761 * @param {Array} selections Array of currently selected nodes
11763 "beforeselect" : true,
11765 * @event preparedata
11766 * Fires on every row to render, to allow you to change the data.
11767 * @param {Roo.View} this
11768 * @param {Object} data to be rendered (change this)
11770 "preparedata" : true
11778 "click": this.onClick,
11779 "dblclick": this.onDblClick,
11780 "contextmenu": this.onContextMenu,
11784 this.selections = [];
11786 this.cmp = new Roo.CompositeElementLite([]);
11788 this.store = Roo.factory(this.store, Roo.data);
11789 this.setStore(this.store, true);
11792 if ( this.footer && this.footer.xtype) {
11794 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11796 this.footer.dataSource = this.store
11797 this.footer.container = fctr;
11798 this.footer = Roo.factory(this.footer, Roo);
11799 fctr.insertFirst(this.el);
11801 // this is a bit insane - as the paging toolbar seems to detach the el..
11802 // dom.parentNode.parentNode.parentNode
11803 // they get detached?
11807 Roo.View.superclass.constructor.call(this);
11812 Roo.extend(Roo.View, Roo.util.Observable, {
11815 * @cfg {Roo.data.Store} store Data store to load data from.
11820 * @cfg {String|Roo.Element} el The container element.
11825 * @cfg {String|Roo.Template} tpl The template used by this View
11829 * @cfg {String} dataName the named area of the template to use as the data area
11830 * Works with domtemplates roo-name="name"
11834 * @cfg {String} selectedClass The css class to add to selected nodes
11836 selectedClass : "x-view-selected",
11838 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11843 * @cfg {String} text to display on mask (default Loading)
11847 * @cfg {Boolean} multiSelect Allow multiple selection
11849 multiSelect : false,
11851 * @cfg {Boolean} singleSelect Allow single selection
11853 singleSelect: false,
11856 * @cfg {Boolean} toggleSelect - selecting
11858 toggleSelect : false,
11861 * @cfg {Boolean} tickable - selecting
11866 * Returns the element this view is bound to.
11867 * @return {Roo.Element}
11869 getEl : function(){
11870 return this.wrapEl;
11876 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11878 refresh : function(){
11879 Roo.log('refresh');
11882 // if we are using something like 'domtemplate', then
11883 // the what gets used is:
11884 // t.applySubtemplate(NAME, data, wrapping data..)
11885 // the outer template then get' applied with
11886 // the store 'extra data'
11887 // and the body get's added to the
11888 // roo-name="data" node?
11889 // <span class='roo-tpl-{name}'></span> ?????
11893 this.clearSelections();
11894 this.el.update("");
11896 var records = this.store.getRange();
11897 if(records.length < 1) {
11899 // is this valid?? = should it render a template??
11901 this.el.update(this.emptyText);
11905 if (this.dataName) {
11906 this.el.update(t.apply(this.store.meta)); //????
11907 el = this.el.child('.roo-tpl-' + this.dataName);
11910 for(var i = 0, len = records.length; i < len; i++){
11911 var data = this.prepareData(records[i].data, i, records[i]);
11912 this.fireEvent("preparedata", this, data, i, records[i]);
11914 var d = Roo.apply({}, data);
11917 Roo.apply(d, {'roo-id' : Roo.id()});
11921 Roo.each(this.parent.item, function(item){
11922 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11925 Roo.apply(d, {'roo-data-checked' : 'checked'});
11929 html[html.length] = Roo.util.Format.trim(
11931 t.applySubtemplate(this.dataName, d, this.store.meta) :
11938 el.update(html.join(""));
11939 this.nodes = el.dom.childNodes;
11940 this.updateIndexes(0);
11945 * Function to override to reformat the data that is sent to
11946 * the template for each node.
11947 * DEPRICATED - use the preparedata event handler.
11948 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11949 * a JSON object for an UpdateManager bound view).
11951 prepareData : function(data, index, record)
11953 this.fireEvent("preparedata", this, data, index, record);
11957 onUpdate : function(ds, record){
11958 Roo.log('on update');
11959 this.clearSelections();
11960 var index = this.store.indexOf(record);
11961 var n = this.nodes[index];
11962 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11963 n.parentNode.removeChild(n);
11964 this.updateIndexes(index, index);
11970 onAdd : function(ds, records, index)
11972 Roo.log(['on Add', ds, records, index] );
11973 this.clearSelections();
11974 if(this.nodes.length == 0){
11978 var n = this.nodes[index];
11979 for(var i = 0, len = records.length; i < len; i++){
11980 var d = this.prepareData(records[i].data, i, records[i]);
11982 this.tpl.insertBefore(n, d);
11985 this.tpl.append(this.el, d);
11988 this.updateIndexes(index);
11991 onRemove : function(ds, record, index){
11992 Roo.log('onRemove');
11993 this.clearSelections();
11994 var el = this.dataName ?
11995 this.el.child('.roo-tpl-' + this.dataName) :
11998 el.dom.removeChild(this.nodes[index]);
11999 this.updateIndexes(index);
12003 * Refresh an individual node.
12004 * @param {Number} index
12006 refreshNode : function(index){
12007 this.onUpdate(this.store, this.store.getAt(index));
12010 updateIndexes : function(startIndex, endIndex){
12011 var ns = this.nodes;
12012 startIndex = startIndex || 0;
12013 endIndex = endIndex || ns.length - 1;
12014 for(var i = startIndex; i <= endIndex; i++){
12015 ns[i].nodeIndex = i;
12020 * Changes the data store this view uses and refresh the view.
12021 * @param {Store} store
12023 setStore : function(store, initial){
12024 if(!initial && this.store){
12025 this.store.un("datachanged", this.refresh);
12026 this.store.un("add", this.onAdd);
12027 this.store.un("remove", this.onRemove);
12028 this.store.un("update", this.onUpdate);
12029 this.store.un("clear", this.refresh);
12030 this.store.un("beforeload", this.onBeforeLoad);
12031 this.store.un("load", this.onLoad);
12032 this.store.un("loadexception", this.onLoad);
12036 store.on("datachanged", this.refresh, this);
12037 store.on("add", this.onAdd, this);
12038 store.on("remove", this.onRemove, this);
12039 store.on("update", this.onUpdate, this);
12040 store.on("clear", this.refresh, this);
12041 store.on("beforeload", this.onBeforeLoad, this);
12042 store.on("load", this.onLoad, this);
12043 store.on("loadexception", this.onLoad, this);
12051 * onbeforeLoad - masks the loading area.
12054 onBeforeLoad : function(store,opts)
12056 Roo.log('onBeforeLoad');
12058 this.el.update("");
12060 this.el.mask(this.mask ? this.mask : "Loading" );
12062 onLoad : function ()
12069 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12070 * @param {HTMLElement} node
12071 * @return {HTMLElement} The template node
12073 findItemFromChild : function(node){
12074 var el = this.dataName ?
12075 this.el.child('.roo-tpl-' + this.dataName,true) :
12078 if(!node || node.parentNode == el){
12081 var p = node.parentNode;
12082 while(p && p != el){
12083 if(p.parentNode == el){
12092 onClick : function(e){
12093 var item = this.findItemFromChild(e.getTarget());
12095 var index = this.indexOf(item);
12096 if(this.onItemClick(item, index, e) !== false){
12097 this.fireEvent("click", this, index, item, e);
12100 this.clearSelections();
12105 onContextMenu : function(e){
12106 var item = this.findItemFromChild(e.getTarget());
12108 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12113 onDblClick : function(e){
12114 var item = this.findItemFromChild(e.getTarget());
12116 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12120 onItemClick : function(item, index, e)
12122 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12125 if (this.toggleSelect) {
12126 var m = this.isSelected(item) ? 'unselect' : 'select';
12129 _t[m](item, true, false);
12132 if(this.multiSelect || this.singleSelect){
12133 if(this.multiSelect && e.shiftKey && this.lastSelection){
12134 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12136 this.select(item, this.multiSelect && e.ctrlKey);
12137 this.lastSelection = item;
12140 if(!this.tickable){
12141 e.preventDefault();
12149 * Get the number of selected nodes.
12152 getSelectionCount : function(){
12153 return this.selections.length;
12157 * Get the currently selected nodes.
12158 * @return {Array} An array of HTMLElements
12160 getSelectedNodes : function(){
12161 return this.selections;
12165 * Get the indexes of the selected nodes.
12168 getSelectedIndexes : function(){
12169 var indexes = [], s = this.selections;
12170 for(var i = 0, len = s.length; i < len; i++){
12171 indexes.push(s[i].nodeIndex);
12177 * Clear all selections
12178 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12180 clearSelections : function(suppressEvent){
12181 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12182 this.cmp.elements = this.selections;
12183 this.cmp.removeClass(this.selectedClass);
12184 this.selections = [];
12185 if(!suppressEvent){
12186 this.fireEvent("selectionchange", this, this.selections);
12192 * Returns true if the passed node is selected
12193 * @param {HTMLElement/Number} node The node or node index
12194 * @return {Boolean}
12196 isSelected : function(node){
12197 var s = this.selections;
12201 node = this.getNode(node);
12202 return s.indexOf(node) !== -1;
12207 * @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
12208 * @param {Boolean} keepExisting (optional) true to keep existing selections
12209 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12211 select : function(nodeInfo, keepExisting, suppressEvent){
12212 if(nodeInfo instanceof Array){
12214 this.clearSelections(true);
12216 for(var i = 0, len = nodeInfo.length; i < len; i++){
12217 this.select(nodeInfo[i], true, true);
12221 var node = this.getNode(nodeInfo);
12222 if(!node || this.isSelected(node)){
12223 return; // already selected.
12226 this.clearSelections(true);
12228 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12229 Roo.fly(node).addClass(this.selectedClass);
12230 this.selections.push(node);
12231 if(!suppressEvent){
12232 this.fireEvent("selectionchange", this, this.selections);
12240 * @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
12241 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12242 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12244 unselect : function(nodeInfo, keepExisting, suppressEvent)
12246 if(nodeInfo instanceof Array){
12247 Roo.each(this.selections, function(s) {
12248 this.unselect(s, nodeInfo);
12252 var node = this.getNode(nodeInfo);
12253 if(!node || !this.isSelected(node)){
12254 Roo.log("not selected");
12255 return; // not selected.
12259 Roo.each(this.selections, function(s) {
12261 Roo.fly(node).removeClass(this.selectedClass);
12268 this.selections= ns;
12269 this.fireEvent("selectionchange", this, this.selections);
12273 * Gets a template node.
12274 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12275 * @return {HTMLElement} The node or null if it wasn't found
12277 getNode : function(nodeInfo){
12278 if(typeof nodeInfo == "string"){
12279 return document.getElementById(nodeInfo);
12280 }else if(typeof nodeInfo == "number"){
12281 return this.nodes[nodeInfo];
12287 * Gets a range template nodes.
12288 * @param {Number} startIndex
12289 * @param {Number} endIndex
12290 * @return {Array} An array of nodes
12292 getNodes : function(start, end){
12293 var ns = this.nodes;
12294 start = start || 0;
12295 end = typeof end == "undefined" ? ns.length - 1 : end;
12298 for(var i = start; i <= end; i++){
12302 for(var i = start; i >= end; i--){
12310 * Finds the index of the passed node
12311 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12312 * @return {Number} The index of the node or -1
12314 indexOf : function(node){
12315 node = this.getNode(node);
12316 if(typeof node.nodeIndex == "number"){
12317 return node.nodeIndex;
12319 var ns = this.nodes;
12320 for(var i = 0, len = ns.length; i < len; i++){
12331 * based on jquery fullcalendar
12335 Roo.bootstrap = Roo.bootstrap || {};
12337 * @class Roo.bootstrap.Calendar
12338 * @extends Roo.bootstrap.Component
12339 * Bootstrap Calendar class
12340 * @cfg {Boolean} loadMask (true|false) default false
12341 * @cfg {Object} header generate the user specific header of the calendar, default false
12344 * Create a new Container
12345 * @param {Object} config The config object
12350 Roo.bootstrap.Calendar = function(config){
12351 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12355 * Fires when a date is selected
12356 * @param {DatePicker} this
12357 * @param {Date} date The selected date
12361 * @event monthchange
12362 * Fires when the displayed month changes
12363 * @param {DatePicker} this
12364 * @param {Date} date The selected month
12366 'monthchange': true,
12368 * @event evententer
12369 * Fires when mouse over an event
12370 * @param {Calendar} this
12371 * @param {event} Event
12373 'evententer': true,
12375 * @event eventleave
12376 * Fires when the mouse leaves an
12377 * @param {Calendar} this
12380 'eventleave': true,
12382 * @event eventclick
12383 * Fires when the mouse click an
12384 * @param {Calendar} this
12393 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12396 * @cfg {Number} startDay
12397 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12405 getAutoCreate : function(){
12408 var fc_button = function(name, corner, style, content ) {
12409 return Roo.apply({},{
12411 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12413 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12416 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12427 style : 'width:100%',
12434 cls : 'fc-header-left',
12436 fc_button('prev', 'left', 'arrow', '‹' ),
12437 fc_button('next', 'right', 'arrow', '›' ),
12438 { tag: 'span', cls: 'fc-header-space' },
12439 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12447 cls : 'fc-header-center',
12451 cls: 'fc-header-title',
12454 html : 'month / year'
12462 cls : 'fc-header-right',
12464 /* fc_button('month', 'left', '', 'month' ),
12465 fc_button('week', '', '', 'week' ),
12466 fc_button('day', 'right', '', 'day' )
12478 header = this.header;
12481 var cal_heads = function() {
12483 // fixme - handle this.
12485 for (var i =0; i < Date.dayNames.length; i++) {
12486 var d = Date.dayNames[i];
12489 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12490 html : d.substring(0,3)
12494 ret[0].cls += ' fc-first';
12495 ret[6].cls += ' fc-last';
12498 var cal_cell = function(n) {
12501 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12506 cls: 'fc-day-number',
12510 cls: 'fc-day-content',
12514 style: 'position: relative;' // height: 17px;
12526 var cal_rows = function() {
12529 for (var r = 0; r < 6; r++) {
12536 for (var i =0; i < Date.dayNames.length; i++) {
12537 var d = Date.dayNames[i];
12538 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12541 row.cn[0].cls+=' fc-first';
12542 row.cn[0].cn[0].style = 'min-height:90px';
12543 row.cn[6].cls+=' fc-last';
12547 ret[0].cls += ' fc-first';
12548 ret[4].cls += ' fc-prev-last';
12549 ret[5].cls += ' fc-last';
12556 cls: 'fc-border-separate',
12557 style : 'width:100%',
12565 cls : 'fc-first fc-last',
12583 cls : 'fc-content',
12584 style : "position: relative;",
12587 cls : 'fc-view fc-view-month fc-grid',
12588 style : 'position: relative',
12589 unselectable : 'on',
12592 cls : 'fc-event-container',
12593 style : 'position:absolute;z-index:8;top:0;left:0;'
12611 initEvents : function()
12614 throw "can not find store for calendar";
12620 style: "text-align:center",
12624 style: "background-color:white;width:50%;margin:250 auto",
12628 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12639 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12641 var size = this.el.select('.fc-content', true).first().getSize();
12642 this.maskEl.setSize(size.width, size.height);
12643 this.maskEl.enableDisplayMode("block");
12644 if(!this.loadMask){
12645 this.maskEl.hide();
12648 this.store = Roo.factory(this.store, Roo.data);
12649 this.store.on('load', this.onLoad, this);
12650 this.store.on('beforeload', this.onBeforeLoad, this);
12654 this.cells = this.el.select('.fc-day',true);
12655 //Roo.log(this.cells);
12656 this.textNodes = this.el.query('.fc-day-number');
12657 this.cells.addClassOnOver('fc-state-hover');
12659 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12660 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12661 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12662 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12664 this.on('monthchange', this.onMonthChange, this);
12666 this.update(new Date().clearTime());
12669 resize : function() {
12670 var sz = this.el.getSize();
12672 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12673 this.el.select('.fc-day-content div',true).setHeight(34);
12678 showPrevMonth : function(e){
12679 this.update(this.activeDate.add("mo", -1));
12681 showToday : function(e){
12682 this.update(new Date().clearTime());
12685 showNextMonth : function(e){
12686 this.update(this.activeDate.add("mo", 1));
12690 showPrevYear : function(){
12691 this.update(this.activeDate.add("y", -1));
12695 showNextYear : function(){
12696 this.update(this.activeDate.add("y", 1));
12701 update : function(date)
12703 var vd = this.activeDate;
12704 this.activeDate = date;
12705 // if(vd && this.el){
12706 // var t = date.getTime();
12707 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12708 // Roo.log('using add remove');
12710 // this.fireEvent('monthchange', this, date);
12712 // this.cells.removeClass("fc-state-highlight");
12713 // this.cells.each(function(c){
12714 // if(c.dateValue == t){
12715 // c.addClass("fc-state-highlight");
12716 // setTimeout(function(){
12717 // try{c.dom.firstChild.focus();}catch(e){}
12727 var days = date.getDaysInMonth();
12729 var firstOfMonth = date.getFirstDateOfMonth();
12730 var startingPos = firstOfMonth.getDay()-this.startDay;
12732 if(startingPos < this.startDay){
12736 var pm = date.add(Date.MONTH, -1);
12737 var prevStart = pm.getDaysInMonth()-startingPos;
12739 this.cells = this.el.select('.fc-day',true);
12740 this.textNodes = this.el.query('.fc-day-number');
12741 this.cells.addClassOnOver('fc-state-hover');
12743 var cells = this.cells.elements;
12744 var textEls = this.textNodes;
12746 Roo.each(cells, function(cell){
12747 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12750 days += startingPos;
12752 // convert everything to numbers so it's fast
12753 var day = 86400000;
12754 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12757 //Roo.log(prevStart);
12759 var today = new Date().clearTime().getTime();
12760 var sel = date.clearTime().getTime();
12761 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12762 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12763 var ddMatch = this.disabledDatesRE;
12764 var ddText = this.disabledDatesText;
12765 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12766 var ddaysText = this.disabledDaysText;
12767 var format = this.format;
12769 var setCellClass = function(cal, cell){
12773 //Roo.log('set Cell Class');
12775 var t = d.getTime();
12779 cell.dateValue = t;
12781 cell.className += " fc-today";
12782 cell.className += " fc-state-highlight";
12783 cell.title = cal.todayText;
12786 // disable highlight in other month..
12787 //cell.className += " fc-state-highlight";
12792 cell.className = " fc-state-disabled";
12793 cell.title = cal.minText;
12797 cell.className = " fc-state-disabled";
12798 cell.title = cal.maxText;
12802 if(ddays.indexOf(d.getDay()) != -1){
12803 cell.title = ddaysText;
12804 cell.className = " fc-state-disabled";
12807 if(ddMatch && format){
12808 var fvalue = d.dateFormat(format);
12809 if(ddMatch.test(fvalue)){
12810 cell.title = ddText.replace("%0", fvalue);
12811 cell.className = " fc-state-disabled";
12815 if (!cell.initialClassName) {
12816 cell.initialClassName = cell.dom.className;
12819 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12824 for(; i < startingPos; i++) {
12825 textEls[i].innerHTML = (++prevStart);
12826 d.setDate(d.getDate()+1);
12828 cells[i].className = "fc-past fc-other-month";
12829 setCellClass(this, cells[i]);
12834 for(; i < days; i++){
12835 intDay = i - startingPos + 1;
12836 textEls[i].innerHTML = (intDay);
12837 d.setDate(d.getDate()+1);
12839 cells[i].className = ''; // "x-date-active";
12840 setCellClass(this, cells[i]);
12844 for(; i < 42; i++) {
12845 textEls[i].innerHTML = (++extraDays);
12846 d.setDate(d.getDate()+1);
12848 cells[i].className = "fc-future fc-other-month";
12849 setCellClass(this, cells[i]);
12852 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12854 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12856 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12857 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12859 if(totalRows != 6){
12860 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12861 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12864 this.fireEvent('monthchange', this, date);
12868 if(!this.internalRender){
12869 var main = this.el.dom.firstChild;
12870 var w = main.offsetWidth;
12871 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12872 Roo.fly(main).setWidth(w);
12873 this.internalRender = true;
12874 // opera does not respect the auto grow header center column
12875 // then, after it gets a width opera refuses to recalculate
12876 // without a second pass
12877 if(Roo.isOpera && !this.secondPass){
12878 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12879 this.secondPass = true;
12880 this.update.defer(10, this, [date]);
12887 findCell : function(dt) {
12888 dt = dt.clearTime().getTime();
12890 this.cells.each(function(c){
12891 //Roo.log("check " +c.dateValue + '?=' + dt);
12892 if(c.dateValue == dt){
12902 findCells : function(ev) {
12903 var s = ev.start.clone().clearTime().getTime();
12905 var e= ev.end.clone().clearTime().getTime();
12908 this.cells.each(function(c){
12909 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12911 if(c.dateValue > e){
12914 if(c.dateValue < s){
12923 // findBestRow: function(cells)
12927 // for (var i =0 ; i < cells.length;i++) {
12928 // ret = Math.max(cells[i].rows || 0,ret);
12935 addItem : function(ev)
12937 // look for vertical location slot in
12938 var cells = this.findCells(ev);
12940 // ev.row = this.findBestRow(cells);
12942 // work out the location.
12946 for(var i =0; i < cells.length; i++) {
12948 cells[i].row = cells[0].row;
12951 cells[i].row = cells[i].row + 1;
12961 if (crow.start.getY() == cells[i].getY()) {
12963 crow.end = cells[i];
12980 cells[0].events.push(ev);
12982 this.calevents.push(ev);
12985 clearEvents: function() {
12987 if(!this.calevents){
12991 Roo.each(this.cells.elements, function(c){
12997 Roo.each(this.calevents, function(e) {
12998 Roo.each(e.els, function(el) {
12999 el.un('mouseenter' ,this.onEventEnter, this);
13000 el.un('mouseleave' ,this.onEventLeave, this);
13005 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13011 renderEvents: function()
13015 this.cells.each(function(c) {
13024 if(c.row != c.events.length){
13025 r = 4 - (4 - (c.row - c.events.length));
13028 c.events = ev.slice(0, r);
13029 c.more = ev.slice(r);
13031 if(c.more.length && c.more.length == 1){
13032 c.events.push(c.more.pop());
13035 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13039 this.cells.each(function(c) {
13041 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13044 for (var e = 0; e < c.events.length; e++){
13045 var ev = c.events[e];
13046 var rows = ev.rows;
13048 for(var i = 0; i < rows.length; i++) {
13050 // how many rows should it span..
13053 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13054 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13056 unselectable : "on",
13059 cls: 'fc-event-inner',
13063 // cls: 'fc-event-time',
13064 // html : cells.length > 1 ? '' : ev.time
13068 cls: 'fc-event-title',
13069 html : String.format('{0}', ev.title)
13076 cls: 'ui-resizable-handle ui-resizable-e',
13077 html : '  '
13084 cfg.cls += ' fc-event-start';
13086 if ((i+1) == rows.length) {
13087 cfg.cls += ' fc-event-end';
13090 var ctr = _this.el.select('.fc-event-container',true).first();
13091 var cg = ctr.createChild(cfg);
13093 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13094 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13096 var r = (c.more.length) ? 1 : 0;
13097 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13098 cg.setWidth(ebox.right - sbox.x -2);
13100 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13101 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13102 cg.on('click', _this.onEventClick, _this, ev);
13113 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13114 style : 'position: absolute',
13115 unselectable : "on",
13118 cls: 'fc-event-inner',
13122 cls: 'fc-event-title',
13130 cls: 'ui-resizable-handle ui-resizable-e',
13131 html : '  '
13137 var ctr = _this.el.select('.fc-event-container',true).first();
13138 var cg = ctr.createChild(cfg);
13140 var sbox = c.select('.fc-day-content',true).first().getBox();
13141 var ebox = c.select('.fc-day-content',true).first().getBox();
13143 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13144 cg.setWidth(ebox.right - sbox.x -2);
13146 cg.on('click', _this.onMoreEventClick, _this, c.more);
13156 onEventEnter: function (e, el,event,d) {
13157 this.fireEvent('evententer', this, el, event);
13160 onEventLeave: function (e, el,event,d) {
13161 this.fireEvent('eventleave', this, el, event);
13164 onEventClick: function (e, el,event,d) {
13165 this.fireEvent('eventclick', this, el, event);
13168 onMonthChange: function () {
13172 onMoreEventClick: function(e, el, more)
13176 this.calpopover.placement = 'right';
13177 this.calpopover.setTitle('More');
13179 this.calpopover.setContent('');
13181 var ctr = this.calpopover.el.select('.popover-content', true).first();
13183 Roo.each(more, function(m){
13185 cls : 'fc-event-hori fc-event-draggable',
13188 var cg = ctr.createChild(cfg);
13190 cg.on('click', _this.onEventClick, _this, m);
13193 this.calpopover.show(el);
13198 onLoad: function ()
13200 this.calevents = [];
13203 if(this.store.getCount() > 0){
13204 this.store.data.each(function(d){
13207 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13208 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13209 time : d.data.start_time,
13210 title : d.data.title,
13211 description : d.data.description,
13212 venue : d.data.venue
13217 this.renderEvents();
13219 if(this.calevents.length && this.loadMask){
13220 this.maskEl.hide();
13224 onBeforeLoad: function()
13226 this.clearEvents();
13228 this.maskEl.show();
13242 * @class Roo.bootstrap.Popover
13243 * @extends Roo.bootstrap.Component
13244 * Bootstrap Popover class
13245 * @cfg {String} html contents of the popover (or false to use children..)
13246 * @cfg {String} title of popover (or false to hide)
13247 * @cfg {String} placement how it is placed
13248 * @cfg {String} trigger click || hover (or false to trigger manually)
13249 * @cfg {String} over what (parent or false to trigger manually.)
13252 * Create a new Popover
13253 * @param {Object} config The config object
13256 Roo.bootstrap.Popover = function(config){
13257 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13260 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13262 title: 'Fill in a title',
13265 placement : 'right',
13266 trigger : 'hover', // hover
13270 can_build_overlaid : false,
13272 getChildContainer : function()
13274 return this.el.select('.popover-content',true).first();
13277 getAutoCreate : function(){
13278 Roo.log('make popover?');
13280 cls : 'popover roo-dynamic',
13281 style: 'display:block',
13287 cls : 'popover-inner',
13291 cls: 'popover-title',
13295 cls : 'popover-content',
13306 setTitle: function(str)
13308 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13310 setContent: function(str)
13312 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13314 // as it get's added to the bottom of the page.
13315 onRender : function(ct, position)
13317 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13319 var cfg = Roo.apply({}, this.getAutoCreate());
13323 cfg.cls += ' ' + this.cls;
13326 cfg.style = this.style;
13328 Roo.log("adding to ")
13329 this.el = Roo.get(document.body).createChild(cfg, position);
13335 initEvents : function()
13337 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13338 this.el.enableDisplayMode('block');
13340 if (this.over === false) {
13343 if (this.triggers === false) {
13346 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13347 var triggers = this.trigger ? this.trigger.split(' ') : [];
13348 Roo.each(triggers, function(trigger) {
13350 if (trigger == 'click') {
13351 on_el.on('click', this.toggle, this);
13352 } else if (trigger != 'manual') {
13353 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13354 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13356 on_el.on(eventIn ,this.enter, this);
13357 on_el.on(eventOut, this.leave, this);
13368 toggle : function () {
13369 this.hoverState == 'in' ? this.leave() : this.enter();
13372 enter : function () {
13375 clearTimeout(this.timeout);
13377 this.hoverState = 'in'
13379 if (!this.delay || !this.delay.show) {
13384 this.timeout = setTimeout(function () {
13385 if (_t.hoverState == 'in') {
13388 }, this.delay.show)
13390 leave : function() {
13391 clearTimeout(this.timeout);
13393 this.hoverState = 'out'
13395 if (!this.delay || !this.delay.hide) {
13400 this.timeout = setTimeout(function () {
13401 if (_t.hoverState == 'out') {
13404 }, this.delay.hide)
13407 show : function (on_el)
13410 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13413 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13414 if (this.html !== false) {
13415 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13417 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13418 if (!this.title.length) {
13419 this.el.select('.popover-title',true).hide();
13422 var placement = typeof this.placement == 'function' ?
13423 this.placement.call(this, this.el, on_el) :
13426 var autoToken = /\s?auto?\s?/i;
13427 var autoPlace = autoToken.test(placement);
13429 placement = placement.replace(autoToken, '') || 'top';
13433 //this.el.setXY([0,0]);
13435 this.el.dom.style.display='block';
13436 this.el.addClass(placement);
13438 //this.el.appendTo(on_el);
13440 var p = this.getPosition();
13441 var box = this.el.getBox();
13446 var align = Roo.bootstrap.Popover.alignment[placement]
13447 this.el.alignTo(on_el, align[0],align[1]);
13448 //var arrow = this.el.select('.arrow',true).first();
13449 //arrow.set(align[2],
13451 this.el.addClass('in');
13452 this.hoverState = null;
13454 if (this.el.hasClass('fade')) {
13461 this.el.setXY([0,0]);
13462 this.el.removeClass('in');
13469 Roo.bootstrap.Popover.alignment = {
13470 'left' : ['r-l', [-10,0], 'right'],
13471 'right' : ['l-r', [10,0], 'left'],
13472 'bottom' : ['t-b', [0,10], 'top'],
13473 'top' : [ 'b-t', [0,-10], 'bottom']
13484 * @class Roo.bootstrap.Progress
13485 * @extends Roo.bootstrap.Component
13486 * Bootstrap Progress class
13487 * @cfg {Boolean} striped striped of the progress bar
13488 * @cfg {Boolean} active animated of the progress bar
13492 * Create a new Progress
13493 * @param {Object} config The config object
13496 Roo.bootstrap.Progress = function(config){
13497 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13500 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13505 getAutoCreate : function(){
13513 cfg.cls += ' progress-striped';
13517 cfg.cls += ' active';
13536 * @class Roo.bootstrap.ProgressBar
13537 * @extends Roo.bootstrap.Component
13538 * Bootstrap ProgressBar class
13539 * @cfg {Number} aria_valuenow aria-value now
13540 * @cfg {Number} aria_valuemin aria-value min
13541 * @cfg {Number} aria_valuemax aria-value max
13542 * @cfg {String} label label for the progress bar
13543 * @cfg {String} panel (success | info | warning | danger )
13544 * @cfg {String} role role of the progress bar
13545 * @cfg {String} sr_only text
13549 * Create a new ProgressBar
13550 * @param {Object} config The config object
13553 Roo.bootstrap.ProgressBar = function(config){
13554 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13557 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13561 aria_valuemax : 100,
13567 getAutoCreate : function()
13572 cls: 'progress-bar',
13573 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13585 cfg.role = this.role;
13588 if(this.aria_valuenow){
13589 cfg['aria-valuenow'] = this.aria_valuenow;
13592 if(this.aria_valuemin){
13593 cfg['aria-valuemin'] = this.aria_valuemin;
13596 if(this.aria_valuemax){
13597 cfg['aria-valuemax'] = this.aria_valuemax;
13600 if(this.label && !this.sr_only){
13601 cfg.html = this.label;
13605 cfg.cls += ' progress-bar-' + this.panel;
13611 update : function(aria_valuenow)
13613 this.aria_valuenow = aria_valuenow;
13615 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13630 * @class Roo.bootstrap.TabPanel
13631 * @extends Roo.bootstrap.Component
13632 * Bootstrap TabPanel class
13633 * @cfg {Boolean} active panel active
13634 * @cfg {String} html panel content
13635 * @cfg {String} tabId tab relate id
13636 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13640 * Create a new TabPanel
13641 * @param {Object} config The config object
13644 Roo.bootstrap.TabPanel = function(config){
13645 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13649 * Fires when the active status changes
13650 * @param {Roo.bootstrap.TabPanel} this
13651 * @param {Boolean} state the new state
13658 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13665 getAutoCreate : function(){
13669 html: this.html || ''
13673 cfg.cls += ' active';
13677 cfg.tabId = this.tabId;
13682 onRender : function(ct, position)
13684 // Roo.log("Call onRender: " + this.xtype);
13686 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13688 if (this.navId && this.tabId) {
13689 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13691 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13693 item.on('changed', function(item, state) {
13694 this.setActive(state);
13700 setActive: function(state)
13702 Roo.log("panel - set active " + this.tabId + "=" + state);
13704 this.active = state;
13706 this.el.removeClass('active');
13708 } else if (!this.el.hasClass('active')) {
13709 this.el.addClass('active');
13711 this.fireEvent('changed', this, state);
13728 * @class Roo.bootstrap.DateField
13729 * @extends Roo.bootstrap.Input
13730 * Bootstrap DateField class
13731 * @cfg {Number} weekStart default 0
13732 * @cfg {Number} weekStart default 0
13733 * @cfg {Number} viewMode default empty, (months|years)
13734 * @cfg {Number} minViewMode default empty, (months|years)
13735 * @cfg {Number} startDate default -Infinity
13736 * @cfg {Number} endDate default Infinity
13737 * @cfg {Boolean} todayHighlight default false
13738 * @cfg {Boolean} todayBtn default false
13739 * @cfg {Boolean} calendarWeeks default false
13740 * @cfg {Object} daysOfWeekDisabled default empty
13742 * @cfg {Boolean} keyboardNavigation default true
13743 * @cfg {String} language default en
13746 * Create a new DateField
13747 * @param {Object} config The config object
13750 Roo.bootstrap.DateField = function(config){
13751 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13755 * Fires when this field show.
13756 * @param {Roo.bootstrap.DateField} this
13757 * @param {Mixed} date The date value
13762 * Fires when this field hide.
13763 * @param {Roo.bootstrap.DateField} this
13764 * @param {Mixed} date The date value
13769 * Fires when select a date.
13770 * @param {Roo.bootstrap.DateField} this
13771 * @param {Mixed} date The date value
13777 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13780 * @cfg {String} format
13781 * The default date format string which can be overriden for localization support. The format must be
13782 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13786 * @cfg {String} altFormats
13787 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13788 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13790 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13798 todayHighlight : false,
13804 keyboardNavigation: true,
13806 calendarWeeks: false,
13808 startDate: -Infinity,
13812 daysOfWeekDisabled: [],
13816 UTCDate: function()
13818 return new Date(Date.UTC.apply(Date, arguments));
13821 UTCToday: function()
13823 var today = new Date();
13824 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13827 getDate: function() {
13828 var d = this.getUTCDate();
13829 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13832 getUTCDate: function() {
13836 setDate: function(d) {
13837 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13840 setUTCDate: function(d) {
13842 this.setValue(this.formatDate(this.date));
13845 onRender: function(ct, position)
13848 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13850 this.language = this.language || 'en';
13851 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13852 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13854 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13855 this.format = this.format || 'm/d/y';
13856 this.isInline = false;
13857 this.isInput = true;
13858 this.component = this.el.select('.add-on', true).first() || false;
13859 this.component = (this.component && this.component.length === 0) ? false : this.component;
13860 this.hasInput = this.component && this.inputEL().length;
13862 if (typeof(this.minViewMode === 'string')) {
13863 switch (this.minViewMode) {
13865 this.minViewMode = 1;
13868 this.minViewMode = 2;
13871 this.minViewMode = 0;
13876 if (typeof(this.viewMode === 'string')) {
13877 switch (this.viewMode) {
13890 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13892 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13894 this.picker().on('mousedown', this.onMousedown, this);
13895 this.picker().on('click', this.onClick, this);
13897 this.picker().addClass('datepicker-dropdown');
13899 this.startViewMode = this.viewMode;
13902 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13903 if(!this.calendarWeeks){
13908 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13909 v.attr('colspan', function(i, val){
13910 return parseInt(val) + 1;
13915 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13917 this.setStartDate(this.startDate);
13918 this.setEndDate(this.endDate);
13920 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13927 if(this.isInline) {
13932 picker : function()
13934 return this.el.select('.datepicker', true).first();
13937 fillDow: function()
13939 var dowCnt = this.weekStart;
13948 if(this.calendarWeeks){
13956 while (dowCnt < this.weekStart + 7) {
13960 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13964 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13967 fillMonths: function()
13970 var months = this.picker().select('>.datepicker-months td', true).first();
13972 months.dom.innerHTML = '';
13978 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13981 months.createChild(month);
13989 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13991 if (this.date < this.startDate) {
13992 this.viewDate = new Date(this.startDate);
13993 } else if (this.date > this.endDate) {
13994 this.viewDate = new Date(this.endDate);
13996 this.viewDate = new Date(this.date);
14004 var d = new Date(this.viewDate),
14005 year = d.getUTCFullYear(),
14006 month = d.getUTCMonth(),
14007 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14008 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14009 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14010 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14011 currentDate = this.date && this.date.valueOf(),
14012 today = this.UTCToday();
14014 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14016 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14018 // this.picker.select('>tfoot th.today').
14019 // .text(dates[this.language].today)
14020 // .toggle(this.todayBtn !== false);
14022 this.updateNavArrows();
14025 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14027 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14029 prevMonth.setUTCDate(day);
14031 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14033 var nextMonth = new Date(prevMonth);
14035 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14037 nextMonth = nextMonth.valueOf();
14039 var fillMonths = false;
14041 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14043 while(prevMonth.valueOf() < nextMonth) {
14046 if (prevMonth.getUTCDay() === this.weekStart) {
14048 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14056 if(this.calendarWeeks){
14057 // ISO 8601: First week contains first thursday.
14058 // ISO also states week starts on Monday, but we can be more abstract here.
14060 // Start of current week: based on weekstart/current date
14061 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14062 // Thursday of this week
14063 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14064 // First Thursday of year, year from thursday
14065 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14066 // Calendar week: ms between thursdays, div ms per day, div 7 days
14067 calWeek = (th - yth) / 864e5 / 7 + 1;
14069 fillMonths.cn.push({
14077 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14079 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14082 if (this.todayHighlight &&
14083 prevMonth.getUTCFullYear() == today.getFullYear() &&
14084 prevMonth.getUTCMonth() == today.getMonth() &&
14085 prevMonth.getUTCDate() == today.getDate()) {
14086 clsName += ' today';
14089 if (currentDate && prevMonth.valueOf() === currentDate) {
14090 clsName += ' active';
14093 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14094 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14095 clsName += ' disabled';
14098 fillMonths.cn.push({
14100 cls: 'day ' + clsName,
14101 html: prevMonth.getDate()
14104 prevMonth.setDate(prevMonth.getDate()+1);
14107 var currentYear = this.date && this.date.getUTCFullYear();
14108 var currentMonth = this.date && this.date.getUTCMonth();
14110 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14112 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14113 v.removeClass('active');
14115 if(currentYear === year && k === currentMonth){
14116 v.addClass('active');
14119 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14120 v.addClass('disabled');
14126 year = parseInt(year/10, 10) * 10;
14128 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14130 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14133 for (var i = -1; i < 11; i++) {
14134 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14136 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14144 showMode: function(dir)
14147 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14149 Roo.each(this.picker().select('>div',true).elements, function(v){
14150 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14153 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14158 if(this.isInline) return;
14160 this.picker().removeClass(['bottom', 'top']);
14162 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14164 * place to the top of element!
14168 this.picker().addClass('top');
14169 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14174 this.picker().addClass('bottom');
14176 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14179 parseDate : function(value)
14181 if(!value || value instanceof Date){
14184 var v = Date.parseDate(value, this.format);
14185 if (!v && this.useIso) {
14186 v = Date.parseDate(value, 'Y-m-d');
14188 if(!v && this.altFormats){
14189 if(!this.altFormatsArray){
14190 this.altFormatsArray = this.altFormats.split("|");
14192 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14193 v = Date.parseDate(value, this.altFormatsArray[i]);
14199 formatDate : function(date, fmt)
14201 return (!date || !(date instanceof Date)) ?
14202 date : date.dateFormat(fmt || this.format);
14205 onFocus : function()
14207 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14211 onBlur : function()
14213 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14215 var d = this.inputEl().getValue();
14226 this.picker().show();
14230 this.fireEvent('show', this, this.date);
14235 if(this.isInline) return;
14236 this.picker().hide();
14237 this.viewMode = this.startViewMode;
14240 this.fireEvent('hide', this, this.date);
14244 onMousedown: function(e)
14246 e.stopPropagation();
14247 e.preventDefault();
14252 Roo.bootstrap.DateField.superclass.keyup.call(this);
14256 setValue: function(v)
14258 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14260 var d = new Date(v);
14262 if(isNaN(d.getTime())){
14266 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14270 this.fireEvent('select', this, this.date);
14274 getValue: function()
14276 return this.formatDate(this.date);
14279 fireKey: function(e)
14281 if (!this.picker().isVisible()){
14282 if (e.keyCode == 27) // allow escape to hide and re-show picker
14286 var dateChanged = false,
14288 newDate, newViewDate;
14293 e.preventDefault();
14297 if (!this.keyboardNavigation) break;
14298 dir = e.keyCode == 37 ? -1 : 1;
14301 newDate = this.moveYear(this.date, dir);
14302 newViewDate = this.moveYear(this.viewDate, dir);
14303 } else if (e.shiftKey){
14304 newDate = this.moveMonth(this.date, dir);
14305 newViewDate = this.moveMonth(this.viewDate, dir);
14307 newDate = new Date(this.date);
14308 newDate.setUTCDate(this.date.getUTCDate() + dir);
14309 newViewDate = new Date(this.viewDate);
14310 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14312 if (this.dateWithinRange(newDate)){
14313 this.date = newDate;
14314 this.viewDate = newViewDate;
14315 this.setValue(this.formatDate(this.date));
14317 e.preventDefault();
14318 dateChanged = true;
14323 if (!this.keyboardNavigation) break;
14324 dir = e.keyCode == 38 ? -1 : 1;
14326 newDate = this.moveYear(this.date, dir);
14327 newViewDate = this.moveYear(this.viewDate, dir);
14328 } else if (e.shiftKey){
14329 newDate = this.moveMonth(this.date, dir);
14330 newViewDate = this.moveMonth(this.viewDate, dir);
14332 newDate = new Date(this.date);
14333 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14334 newViewDate = new Date(this.viewDate);
14335 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14337 if (this.dateWithinRange(newDate)){
14338 this.date = newDate;
14339 this.viewDate = newViewDate;
14340 this.setValue(this.formatDate(this.date));
14342 e.preventDefault();
14343 dateChanged = true;
14347 this.setValue(this.formatDate(this.date));
14349 e.preventDefault();
14352 this.setValue(this.formatDate(this.date));
14360 onClick: function(e)
14362 e.stopPropagation();
14363 e.preventDefault();
14365 var target = e.getTarget();
14367 if(target.nodeName.toLowerCase() === 'i'){
14368 target = Roo.get(target).dom.parentNode;
14371 var nodeName = target.nodeName;
14372 var className = target.className;
14373 var html = target.innerHTML;
14375 switch(nodeName.toLowerCase()) {
14377 switch(className) {
14383 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14384 switch(this.viewMode){
14386 this.viewDate = this.moveMonth(this.viewDate, dir);
14390 this.viewDate = this.moveYear(this.viewDate, dir);
14396 var date = new Date();
14397 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14399 this.setValue(this.formatDate(this.date));
14406 if (className.indexOf('disabled') === -1) {
14407 this.viewDate.setUTCDate(1);
14408 if (className.indexOf('month') !== -1) {
14409 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14411 var year = parseInt(html, 10) || 0;
14412 this.viewDate.setUTCFullYear(year);
14421 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14422 var day = parseInt(html, 10) || 1;
14423 var year = this.viewDate.getUTCFullYear(),
14424 month = this.viewDate.getUTCMonth();
14426 if (className.indexOf('old') !== -1) {
14433 } else if (className.indexOf('new') !== -1) {
14441 this.date = this.UTCDate(year, month, day,0,0,0,0);
14442 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14444 this.setValue(this.formatDate(this.date));
14451 setStartDate: function(startDate)
14453 this.startDate = startDate || -Infinity;
14454 if (this.startDate !== -Infinity) {
14455 this.startDate = this.parseDate(this.startDate);
14458 this.updateNavArrows();
14461 setEndDate: function(endDate)
14463 this.endDate = endDate || Infinity;
14464 if (this.endDate !== Infinity) {
14465 this.endDate = this.parseDate(this.endDate);
14468 this.updateNavArrows();
14471 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14473 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14474 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14475 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14477 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14478 return parseInt(d, 10);
14481 this.updateNavArrows();
14484 updateNavArrows: function()
14486 var d = new Date(this.viewDate),
14487 year = d.getUTCFullYear(),
14488 month = d.getUTCMonth();
14490 Roo.each(this.picker().select('.prev', true).elements, function(v){
14492 switch (this.viewMode) {
14495 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14501 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14508 Roo.each(this.picker().select('.next', true).elements, function(v){
14510 switch (this.viewMode) {
14513 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14519 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14527 moveMonth: function(date, dir)
14529 if (!dir) return date;
14530 var new_date = new Date(date.valueOf()),
14531 day = new_date.getUTCDate(),
14532 month = new_date.getUTCMonth(),
14533 mag = Math.abs(dir),
14535 dir = dir > 0 ? 1 : -1;
14538 // If going back one month, make sure month is not current month
14539 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14541 return new_date.getUTCMonth() == month;
14543 // If going forward one month, make sure month is as expected
14544 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14546 return new_date.getUTCMonth() != new_month;
14548 new_month = month + dir;
14549 new_date.setUTCMonth(new_month);
14550 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14551 if (new_month < 0 || new_month > 11)
14552 new_month = (new_month + 12) % 12;
14554 // For magnitudes >1, move one month at a time...
14555 for (var i=0; i<mag; i++)
14556 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14557 new_date = this.moveMonth(new_date, dir);
14558 // ...then reset the day, keeping it in the new month
14559 new_month = new_date.getUTCMonth();
14560 new_date.setUTCDate(day);
14562 return new_month != new_date.getUTCMonth();
14565 // Common date-resetting loop -- if date is beyond end of month, make it
14568 new_date.setUTCDate(--day);
14569 new_date.setUTCMonth(new_month);
14574 moveYear: function(date, dir)
14576 return this.moveMonth(date, dir*12);
14579 dateWithinRange: function(date)
14581 return date >= this.startDate && date <= this.endDate;
14587 this.picker().remove();
14592 Roo.apply(Roo.bootstrap.DateField, {
14603 html: '<i class="fa fa-arrow-left"/>'
14613 html: '<i class="fa fa-arrow-right"/>'
14655 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14656 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14657 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14658 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14659 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14672 navFnc: 'FullYear',
14677 navFnc: 'FullYear',
14682 Roo.apply(Roo.bootstrap.DateField, {
14686 cls: 'datepicker dropdown-menu',
14690 cls: 'datepicker-days',
14694 cls: 'table-condensed',
14696 Roo.bootstrap.DateField.head,
14700 Roo.bootstrap.DateField.footer
14707 cls: 'datepicker-months',
14711 cls: 'table-condensed',
14713 Roo.bootstrap.DateField.head,
14714 Roo.bootstrap.DateField.content,
14715 Roo.bootstrap.DateField.footer
14722 cls: 'datepicker-years',
14726 cls: 'table-condensed',
14728 Roo.bootstrap.DateField.head,
14729 Roo.bootstrap.DateField.content,
14730 Roo.bootstrap.DateField.footer
14749 * @class Roo.bootstrap.TimeField
14750 * @extends Roo.bootstrap.Input
14751 * Bootstrap DateField class
14755 * Create a new TimeField
14756 * @param {Object} config The config object
14759 Roo.bootstrap.TimeField = function(config){
14760 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14764 * Fires when this field show.
14765 * @param {Roo.bootstrap.DateField} this
14766 * @param {Mixed} date The date value
14771 * Fires when this field hide.
14772 * @param {Roo.bootstrap.DateField} this
14773 * @param {Mixed} date The date value
14778 * Fires when select a date.
14779 * @param {Roo.bootstrap.DateField} this
14780 * @param {Mixed} date The date value
14786 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14789 * @cfg {String} format
14790 * The default time format string which can be overriden for localization support. The format must be
14791 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14795 onRender: function(ct, position)
14798 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14800 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14802 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14804 this.pop = this.picker().select('>.datepicker-time',true).first();
14805 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14807 this.picker().on('mousedown', this.onMousedown, this);
14808 this.picker().on('click', this.onClick, this);
14810 this.picker().addClass('datepicker-dropdown');
14815 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14816 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14817 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14818 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14819 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14820 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14824 fireKey: function(e){
14825 if (!this.picker().isVisible()){
14826 if (e.keyCode == 27) // allow escape to hide and re-show picker
14831 e.preventDefault();
14839 this.onTogglePeriod();
14842 this.onIncrementMinutes();
14845 this.onDecrementMinutes();
14854 onClick: function(e) {
14855 e.stopPropagation();
14856 e.preventDefault();
14859 picker : function()
14861 return this.el.select('.datepicker', true).first();
14864 fillTime: function()
14866 var time = this.pop.select('tbody', true).first();
14868 time.dom.innerHTML = '';
14883 cls: 'hours-up glyphicon glyphicon-chevron-up'
14903 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14924 cls: 'timepicker-hour',
14939 cls: 'timepicker-minute',
14954 cls: 'btn btn-primary period',
14976 cls: 'hours-down glyphicon glyphicon-chevron-down'
14996 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15014 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15021 var hours = this.time.getHours();
15022 var minutes = this.time.getMinutes();
15035 hours = hours - 12;
15039 hours = '0' + hours;
15043 minutes = '0' + minutes;
15046 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15047 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15048 this.pop.select('button', true).first().dom.innerHTML = period;
15054 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15056 var cls = ['bottom'];
15058 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15065 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15070 this.picker().addClass(cls.join('-'));
15074 Roo.each(cls, function(c){
15076 _this.picker().setTop(_this.inputEl().getHeight());
15080 _this.picker().setTop(0 - _this.picker().getHeight());
15085 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15089 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15096 onFocus : function()
15098 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15102 onBlur : function()
15104 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15110 this.picker().show();
15115 this.fireEvent('show', this, this.date);
15120 this.picker().hide();
15123 this.fireEvent('hide', this, this.date);
15126 setTime : function()
15129 this.setValue(this.time.format(this.format));
15131 this.fireEvent('select', this, this.date);
15136 onMousedown: function(e){
15137 e.stopPropagation();
15138 e.preventDefault();
15141 onIncrementHours: function()
15143 Roo.log('onIncrementHours');
15144 this.time = this.time.add(Date.HOUR, 1);
15149 onDecrementHours: function()
15151 Roo.log('onDecrementHours');
15152 this.time = this.time.add(Date.HOUR, -1);
15156 onIncrementMinutes: function()
15158 Roo.log('onIncrementMinutes');
15159 this.time = this.time.add(Date.MINUTE, 1);
15163 onDecrementMinutes: function()
15165 Roo.log('onDecrementMinutes');
15166 this.time = this.time.add(Date.MINUTE, -1);
15170 onTogglePeriod: function()
15172 Roo.log('onTogglePeriod');
15173 this.time = this.time.add(Date.HOUR, 12);
15180 Roo.apply(Roo.bootstrap.TimeField, {
15210 cls: 'btn btn-info ok',
15222 Roo.apply(Roo.bootstrap.TimeField, {
15226 cls: 'datepicker dropdown-menu',
15230 cls: 'datepicker-time',
15234 cls: 'table-condensed',
15236 Roo.bootstrap.TimeField.content,
15237 Roo.bootstrap.TimeField.footer
15256 * @class Roo.bootstrap.CheckBox
15257 * @extends Roo.bootstrap.Input
15258 * Bootstrap CheckBox class
15260 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15261 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15262 * @cfg {String} boxLabel The text that appears beside the checkbox
15263 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15264 * @cfg {Boolean} checked initnal the element
15268 * Create a new CheckBox
15269 * @param {Object} config The config object
15272 Roo.bootstrap.CheckBox = function(config){
15273 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15278 * Fires when the element is checked or unchecked.
15279 * @param {Roo.bootstrap.CheckBox} this This input
15280 * @param {Boolean} checked The new checked value
15286 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15288 inputType: 'checkbox',
15295 getAutoCreate : function()
15297 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15303 cfg.cls = 'form-group checkbox' //input-group
15311 type : this.inputType,
15312 value : (!this.checked) ? this.valueOff : this.inputValue,
15313 cls : 'roo-checkbox', //'form-box',
15314 placeholder : this.placeholder || ''
15318 if (this.weight) { // Validity check?
15319 cfg.cls += " checkbox-" + this.weight;
15322 if (this.disabled) {
15323 input.disabled=true;
15327 input.checked = this.checked;
15331 input.name = this.name;
15335 input.cls += ' input-' + this.size;
15339 ['xs','sm','md','lg'].map(function(size){
15340 if (settings[size]) {
15341 cfg.cls += ' col-' + size + '-' + settings[size];
15347 var inputblock = input;
15352 if (this.before || this.after) {
15355 cls : 'input-group',
15359 inputblock.cn.push({
15361 cls : 'input-group-addon',
15365 inputblock.cn.push(input);
15367 inputblock.cn.push({
15369 cls : 'input-group-addon',
15376 if (align ==='left' && this.fieldLabel.length) {
15377 Roo.log("left and has label");
15383 cls : 'control-label col-md-' + this.labelWidth,
15384 html : this.fieldLabel
15388 cls : "col-md-" + (12 - this.labelWidth),
15395 } else if ( this.fieldLabel.length) {
15400 tag: this.boxLabel ? 'span' : 'label',
15402 cls: 'control-label box-input-label',
15403 //cls : 'input-group-addon',
15404 html : this.fieldLabel
15414 Roo.log(" no label && no align");
15415 cfg.cn = [ inputblock ] ;
15424 html: this.boxLabel
15436 * return the real input element.
15438 inputEl: function ()
15440 return this.el.select('input.roo-checkbox',true).first();
15445 return this.el.select('label.control-label',true).first();
15448 initEvents : function()
15450 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15452 this.inputEl().on('click', this.onClick, this);
15456 onClick : function()
15458 this.setChecked(!this.checked);
15461 setChecked : function(state,suppressEvent)
15463 this.checked = state;
15465 this.inputEl().dom.checked = state;
15467 if(suppressEvent !== true){
15468 this.fireEvent('check', this, state);
15471 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15475 setValue : function(v,suppressEvent)
15477 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15491 * @class Roo.bootstrap.Radio
15492 * @extends Roo.bootstrap.CheckBox
15493 * Bootstrap Radio class
15496 * Create a new Radio
15497 * @param {Object} config The config object
15500 Roo.bootstrap.Radio = function(config){
15501 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15505 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15507 inputType: 'radio',
15511 getAutoCreate : function()
15513 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15519 cfg.cls = 'form-group radio' //input-group
15524 type : this.inputType,
15525 value : (!this.checked) ? this.valueOff : this.inputValue,
15527 placeholder : this.placeholder || ''
15530 if (this.weight) { // Validity check?
15531 cfg.cls += " radio-" + this.weight;
15533 if (this.disabled) {
15534 input.disabled=true;
15538 input.checked = this.checked;
15542 input.name = this.name;
15546 input.cls += ' input-' + this.size;
15550 ['xs','sm','md','lg'].map(function(size){
15551 if (settings[size]) {
15552 cfg.cls += ' col-' + size + '-' + settings[size];
15556 var inputblock = input;
15558 if (this.before || this.after) {
15561 cls : 'input-group',
15565 inputblock.cn.push({
15567 cls : 'input-group-addon',
15571 inputblock.cn.push(input);
15573 inputblock.cn.push({
15575 cls : 'input-group-addon',
15582 if (align ==='left' && this.fieldLabel.length) {
15583 Roo.log("left and has label");
15589 cls : 'control-label col-md-' + this.labelWidth,
15590 html : this.fieldLabel
15594 cls : "col-md-" + (12 - this.labelWidth),
15601 } else if ( this.fieldLabel.length) {
15608 cls: 'control-label box-input-label',
15609 //cls : 'input-group-addon',
15610 html : this.fieldLabel
15620 Roo.log(" no label && no align");
15635 html: this.boxLabel
15642 inputEl: function ()
15644 return this.el.select('input.roo-radio',true).first();
15646 onClick : function()
15648 this.setChecked(true);
15651 setChecked : function(state,suppressEvent)
15654 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15655 v.dom.checked = false;
15659 this.checked = state;
15660 this.inputEl().dom.checked = state;
15662 if(suppressEvent !== true){
15663 this.fireEvent('check', this, state);
15666 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15670 getGroupValue : function()
15673 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15674 if(v.dom.checked == true){
15675 value = v.dom.value;
15683 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15684 * @return {Mixed} value The field value
15686 getValue : function(){
15687 return this.getGroupValue();
15693 //<script type="text/javascript">
15696 * Based Ext JS Library 1.1.1
15697 * Copyright(c) 2006-2007, Ext JS, LLC.
15703 * @class Roo.HtmlEditorCore
15704 * @extends Roo.Component
15705 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15707 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15710 Roo.HtmlEditorCore = function(config){
15713 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15716 * @event initialize
15717 * Fires when the editor is fully initialized (including the iframe)
15718 * @param {Roo.HtmlEditorCore} this
15723 * Fires when the editor is first receives the focus. Any insertion must wait
15724 * until after this event.
15725 * @param {Roo.HtmlEditorCore} this
15729 * @event beforesync
15730 * Fires before the textarea is updated with content from the editor iframe. Return false
15731 * to cancel the sync.
15732 * @param {Roo.HtmlEditorCore} this
15733 * @param {String} html
15737 * @event beforepush
15738 * Fires before the iframe editor is updated with content from the textarea. Return false
15739 * to cancel the push.
15740 * @param {Roo.HtmlEditorCore} this
15741 * @param {String} html
15746 * Fires when the textarea is updated with content from the editor iframe.
15747 * @param {Roo.HtmlEditorCore} this
15748 * @param {String} html
15753 * Fires when the iframe editor is updated with content from the textarea.
15754 * @param {Roo.HtmlEditorCore} this
15755 * @param {String} html
15760 * @event editorevent
15761 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15762 * @param {Roo.HtmlEditorCore} this
15770 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15774 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15780 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15785 * @cfg {Number} height (in pixels)
15789 * @cfg {Number} width (in pixels)
15794 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15797 stylesheets: false,
15802 // private properties
15803 validationEvent : false,
15805 initialized : false,
15807 sourceEditMode : false,
15808 onFocus : Roo.emptyFn,
15810 hideMode:'offsets',
15818 * Protected method that will not generally be called directly. It
15819 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15820 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15822 getDocMarkup : function(){
15825 Roo.log(this.stylesheets);
15827 // inherit styels from page...??
15828 if (this.stylesheets === false) {
15830 Roo.get(document.head).select('style').each(function(node) {
15831 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15834 Roo.get(document.head).select('link').each(function(node) {
15835 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15838 } else if (!this.stylesheets.length) {
15840 st = '<style type="text/css">' +
15841 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15844 Roo.each(this.stylesheets, function(s) {
15845 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15850 st += '<style type="text/css">' +
15851 'IMG { cursor: pointer } ' +
15855 return '<html><head>' + st +
15856 //<style type="text/css">' +
15857 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15859 ' </head><body class="roo-htmleditor-body"></body></html>';
15863 onRender : function(ct, position)
15866 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15867 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15870 this.el.dom.style.border = '0 none';
15871 this.el.dom.setAttribute('tabIndex', -1);
15872 this.el.addClass('x-hidden hide');
15876 if(Roo.isIE){ // fix IE 1px bogus margin
15877 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15881 this.frameId = Roo.id();
15885 var iframe = this.owner.wrap.createChild({
15887 cls: 'form-control', // bootstrap..
15889 name: this.frameId,
15890 frameBorder : 'no',
15891 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15896 this.iframe = iframe.dom;
15898 this.assignDocWin();
15900 this.doc.designMode = 'on';
15903 this.doc.write(this.getDocMarkup());
15907 var task = { // must defer to wait for browser to be ready
15909 //console.log("run task?" + this.doc.readyState);
15910 this.assignDocWin();
15911 if(this.doc.body || this.doc.readyState == 'complete'){
15913 this.doc.designMode="on";
15917 Roo.TaskMgr.stop(task);
15918 this.initEditor.defer(10, this);
15925 Roo.TaskMgr.start(task);
15932 onResize : function(w, h)
15934 Roo.log('resize: ' +w + ',' + h );
15935 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15939 if(typeof w == 'number'){
15941 this.iframe.style.width = w + 'px';
15943 if(typeof h == 'number'){
15945 this.iframe.style.height = h + 'px';
15947 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15954 * Toggles the editor between standard and source edit mode.
15955 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15957 toggleSourceEdit : function(sourceEditMode){
15959 this.sourceEditMode = sourceEditMode === true;
15961 if(this.sourceEditMode){
15963 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15966 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15967 //this.iframe.className = '';
15970 //this.setSize(this.owner.wrap.getSize());
15971 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15978 * Protected method that will not generally be called directly. If you need/want
15979 * custom HTML cleanup, this is the method you should override.
15980 * @param {String} html The HTML to be cleaned
15981 * return {String} The cleaned HTML
15983 cleanHtml : function(html){
15984 html = String(html);
15985 if(html.length > 5){
15986 if(Roo.isSafari){ // strip safari nonsense
15987 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15990 if(html == ' '){
15997 * HTML Editor -> Textarea
15998 * Protected method that will not generally be called directly. Syncs the contents
15999 * of the editor iframe with the textarea.
16001 syncValue : function(){
16002 if(this.initialized){
16003 var bd = (this.doc.body || this.doc.documentElement);
16004 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16005 var html = bd.innerHTML;
16007 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16008 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16010 html = '<div style="'+m[0]+'">' + html + '</div>';
16013 html = this.cleanHtml(html);
16014 // fix up the special chars.. normaly like back quotes in word...
16015 // however we do not want to do this with chinese..
16016 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16017 var cc = b.charCodeAt();
16019 (cc >= 0x4E00 && cc < 0xA000 ) ||
16020 (cc >= 0x3400 && cc < 0x4E00 ) ||
16021 (cc >= 0xf900 && cc < 0xfb00 )
16027 if(this.owner.fireEvent('beforesync', this, html) !== false){
16028 this.el.dom.value = html;
16029 this.owner.fireEvent('sync', this, html);
16035 * Protected method that will not generally be called directly. Pushes the value of the textarea
16036 * into the iframe editor.
16038 pushValue : function(){
16039 if(this.initialized){
16040 var v = this.el.dom.value.trim();
16042 // if(v.length < 1){
16046 if(this.owner.fireEvent('beforepush', this, v) !== false){
16047 var d = (this.doc.body || this.doc.documentElement);
16049 this.cleanUpPaste();
16050 this.el.dom.value = d.innerHTML;
16051 this.owner.fireEvent('push', this, v);
16057 deferFocus : function(){
16058 this.focus.defer(10, this);
16062 focus : function(){
16063 if(this.win && !this.sourceEditMode){
16070 assignDocWin: function()
16072 var iframe = this.iframe;
16075 this.doc = iframe.contentWindow.document;
16076 this.win = iframe.contentWindow;
16078 if (!Roo.get(this.frameId)) {
16081 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16082 this.win = Roo.get(this.frameId).dom.contentWindow;
16087 initEditor : function(){
16088 //console.log("INIT EDITOR");
16089 this.assignDocWin();
16093 this.doc.designMode="on";
16095 this.doc.write(this.getDocMarkup());
16098 var dbody = (this.doc.body || this.doc.documentElement);
16099 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16100 // this copies styles from the containing element into thsi one..
16101 // not sure why we need all of this..
16102 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16104 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16105 //ss['background-attachment'] = 'fixed'; // w3c
16106 dbody.bgProperties = 'fixed'; // ie
16107 //Roo.DomHelper.applyStyles(dbody, ss);
16108 Roo.EventManager.on(this.doc, {
16109 //'mousedown': this.onEditorEvent,
16110 'mouseup': this.onEditorEvent,
16111 'dblclick': this.onEditorEvent,
16112 'click': this.onEditorEvent,
16113 'keyup': this.onEditorEvent,
16118 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16120 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16121 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16123 this.initialized = true;
16125 this.owner.fireEvent('initialize', this);
16130 onDestroy : function(){
16136 //for (var i =0; i < this.toolbars.length;i++) {
16137 // // fixme - ask toolbars for heights?
16138 // this.toolbars[i].onDestroy();
16141 //this.wrap.dom.innerHTML = '';
16142 //this.wrap.remove();
16147 onFirstFocus : function(){
16149 this.assignDocWin();
16152 this.activated = true;
16155 if(Roo.isGecko){ // prevent silly gecko errors
16157 var s = this.win.getSelection();
16158 if(!s.focusNode || s.focusNode.nodeType != 3){
16159 var r = s.getRangeAt(0);
16160 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16165 this.execCmd('useCSS', true);
16166 this.execCmd('styleWithCSS', false);
16169 this.owner.fireEvent('activate', this);
16173 adjustFont: function(btn){
16174 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16175 //if(Roo.isSafari){ // safari
16178 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16179 if(Roo.isSafari){ // safari
16180 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16181 v = (v < 10) ? 10 : v;
16182 v = (v > 48) ? 48 : v;
16183 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16188 v = Math.max(1, v+adjust);
16190 this.execCmd('FontSize', v );
16193 onEditorEvent : function(e){
16194 this.owner.fireEvent('editorevent', this, e);
16195 // this.updateToolbar();
16196 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16199 insertTag : function(tg)
16201 // could be a bit smarter... -> wrap the current selected tRoo..
16202 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16204 range = this.createRange(this.getSelection());
16205 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16206 wrappingNode.appendChild(range.extractContents());
16207 range.insertNode(wrappingNode);
16214 this.execCmd("formatblock", tg);
16218 insertText : function(txt)
16222 var range = this.createRange();
16223 range.deleteContents();
16224 //alert(Sender.getAttribute('label'));
16226 range.insertNode(this.doc.createTextNode(txt));
16232 * Executes a Midas editor command on the editor document and performs necessary focus and
16233 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16234 * @param {String} cmd The Midas command
16235 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16237 relayCmd : function(cmd, value){
16239 this.execCmd(cmd, value);
16240 this.owner.fireEvent('editorevent', this);
16241 //this.updateToolbar();
16242 this.owner.deferFocus();
16246 * Executes a Midas editor command directly on the editor document.
16247 * For visual commands, you should use {@link #relayCmd} instead.
16248 * <b>This should only be called after the editor is initialized.</b>
16249 * @param {String} cmd The Midas command
16250 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16252 execCmd : function(cmd, value){
16253 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16260 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16262 * @param {String} text | dom node..
16264 insertAtCursor : function(text)
16269 if(!this.activated){
16275 var r = this.doc.selection.createRange();
16286 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16290 // from jquery ui (MIT licenced)
16292 var win = this.win;
16294 if (win.getSelection && win.getSelection().getRangeAt) {
16295 range = win.getSelection().getRangeAt(0);
16296 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16297 range.insertNode(node);
16298 } else if (win.document.selection && win.document.selection.createRange) {
16299 // no firefox support
16300 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16301 win.document.selection.createRange().pasteHTML(txt);
16303 // no firefox support
16304 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16305 this.execCmd('InsertHTML', txt);
16314 mozKeyPress : function(e){
16316 var c = e.getCharCode(), cmd;
16319 c = String.fromCharCode(c).toLowerCase();
16333 this.cleanUpPaste.defer(100, this);
16341 e.preventDefault();
16349 fixKeys : function(){ // load time branching for fastest keydown performance
16351 return function(e){
16352 var k = e.getKey(), r;
16355 r = this.doc.selection.createRange();
16358 r.pasteHTML('    ');
16365 r = this.doc.selection.createRange();
16367 var target = r.parentElement();
16368 if(!target || target.tagName.toLowerCase() != 'li'){
16370 r.pasteHTML('<br />');
16376 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16377 this.cleanUpPaste.defer(100, this);
16383 }else if(Roo.isOpera){
16384 return function(e){
16385 var k = e.getKey();
16389 this.execCmd('InsertHTML','    ');
16392 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16393 this.cleanUpPaste.defer(100, this);
16398 }else if(Roo.isSafari){
16399 return function(e){
16400 var k = e.getKey();
16404 this.execCmd('InsertText','\t');
16408 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16409 this.cleanUpPaste.defer(100, this);
16417 getAllAncestors: function()
16419 var p = this.getSelectedNode();
16422 a.push(p); // push blank onto stack..
16423 p = this.getParentElement();
16427 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16431 a.push(this.doc.body);
16435 lastSelNode : false,
16438 getSelection : function()
16440 this.assignDocWin();
16441 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16444 getSelectedNode: function()
16446 // this may only work on Gecko!!!
16448 // should we cache this!!!!
16453 var range = this.createRange(this.getSelection()).cloneRange();
16456 var parent = range.parentElement();
16458 var testRange = range.duplicate();
16459 testRange.moveToElementText(parent);
16460 if (testRange.inRange(range)) {
16463 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16466 parent = parent.parentElement;
16471 // is ancestor a text element.
16472 var ac = range.commonAncestorContainer;
16473 if (ac.nodeType == 3) {
16474 ac = ac.parentNode;
16477 var ar = ac.childNodes;
16480 var other_nodes = [];
16481 var has_other_nodes = false;
16482 for (var i=0;i<ar.length;i++) {
16483 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16486 // fullly contained node.
16488 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16493 // probably selected..
16494 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16495 other_nodes.push(ar[i]);
16499 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16504 has_other_nodes = true;
16506 if (!nodes.length && other_nodes.length) {
16507 nodes= other_nodes;
16509 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16515 createRange: function(sel)
16517 // this has strange effects when using with
16518 // top toolbar - not sure if it's a great idea.
16519 //this.editor.contentWindow.focus();
16520 if (typeof sel != "undefined") {
16522 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16524 return this.doc.createRange();
16527 return this.doc.createRange();
16530 getParentElement: function()
16533 this.assignDocWin();
16534 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16536 var range = this.createRange(sel);
16539 var p = range.commonAncestorContainer;
16540 while (p.nodeType == 3) { // text node
16551 * Range intersection.. the hard stuff...
16555 * [ -- selected range --- ]
16559 * if end is before start or hits it. fail.
16560 * if start is after end or hits it fail.
16562 * if either hits (but other is outside. - then it's not
16568 // @see http://www.thismuchiknow.co.uk/?p=64.
16569 rangeIntersectsNode : function(range, node)
16571 var nodeRange = node.ownerDocument.createRange();
16573 nodeRange.selectNode(node);
16575 nodeRange.selectNodeContents(node);
16578 var rangeStartRange = range.cloneRange();
16579 rangeStartRange.collapse(true);
16581 var rangeEndRange = range.cloneRange();
16582 rangeEndRange.collapse(false);
16584 var nodeStartRange = nodeRange.cloneRange();
16585 nodeStartRange.collapse(true);
16587 var nodeEndRange = nodeRange.cloneRange();
16588 nodeEndRange.collapse(false);
16590 return rangeStartRange.compareBoundaryPoints(
16591 Range.START_TO_START, nodeEndRange) == -1 &&
16592 rangeEndRange.compareBoundaryPoints(
16593 Range.START_TO_START, nodeStartRange) == 1;
16597 rangeCompareNode : function(range, node)
16599 var nodeRange = node.ownerDocument.createRange();
16601 nodeRange.selectNode(node);
16603 nodeRange.selectNodeContents(node);
16607 range.collapse(true);
16609 nodeRange.collapse(true);
16611 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16612 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16614 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16616 var nodeIsBefore = ss == 1;
16617 var nodeIsAfter = ee == -1;
16619 if (nodeIsBefore && nodeIsAfter)
16621 if (!nodeIsBefore && nodeIsAfter)
16622 return 1; //right trailed.
16624 if (nodeIsBefore && !nodeIsAfter)
16625 return 2; // left trailed.
16630 // private? - in a new class?
16631 cleanUpPaste : function()
16633 // cleans up the whole document..
16634 Roo.log('cleanuppaste');
16636 this.cleanUpChildren(this.doc.body);
16637 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16638 if (clean != this.doc.body.innerHTML) {
16639 this.doc.body.innerHTML = clean;
16644 cleanWordChars : function(input) {// change the chars to hex code
16645 var he = Roo.HtmlEditorCore;
16647 var output = input;
16648 Roo.each(he.swapCodes, function(sw) {
16649 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16651 output = output.replace(swapper, sw[1]);
16658 cleanUpChildren : function (n)
16660 if (!n.childNodes.length) {
16663 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16664 this.cleanUpChild(n.childNodes[i]);
16671 cleanUpChild : function (node)
16674 //console.log(node);
16675 if (node.nodeName == "#text") {
16676 // clean up silly Windows -- stuff?
16679 if (node.nodeName == "#comment") {
16680 node.parentNode.removeChild(node);
16681 // clean up silly Windows -- stuff?
16685 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16687 node.parentNode.removeChild(node);
16692 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16694 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16695 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16697 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16698 // remove_keep_children = true;
16701 if (remove_keep_children) {
16702 this.cleanUpChildren(node);
16703 // inserts everything just before this node...
16704 while (node.childNodes.length) {
16705 var cn = node.childNodes[0];
16706 node.removeChild(cn);
16707 node.parentNode.insertBefore(cn, node);
16709 node.parentNode.removeChild(node);
16713 if (!node.attributes || !node.attributes.length) {
16714 this.cleanUpChildren(node);
16718 function cleanAttr(n,v)
16721 if (v.match(/^\./) || v.match(/^\//)) {
16724 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16727 if (v.match(/^#/)) {
16730 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16731 node.removeAttribute(n);
16735 function cleanStyle(n,v)
16737 if (v.match(/expression/)) { //XSS?? should we even bother..
16738 node.removeAttribute(n);
16741 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16742 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16745 var parts = v.split(/;/);
16748 Roo.each(parts, function(p) {
16749 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16753 var l = p.split(':').shift().replace(/\s+/g,'');
16754 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16756 if ( cblack.indexOf(l) > -1) {
16757 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16758 //node.removeAttribute(n);
16762 // only allow 'c whitelisted system attributes'
16763 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16764 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16765 //node.removeAttribute(n);
16775 if (clean.length) {
16776 node.setAttribute(n, clean.join(';'));
16778 node.removeAttribute(n);
16784 for (var i = node.attributes.length-1; i > -1 ; i--) {
16785 var a = node.attributes[i];
16788 if (a.name.toLowerCase().substr(0,2)=='on') {
16789 node.removeAttribute(a.name);
16792 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16793 node.removeAttribute(a.name);
16796 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16797 cleanAttr(a.name,a.value); // fixme..
16800 if (a.name == 'style') {
16801 cleanStyle(a.name,a.value);
16804 /// clean up MS crap..
16805 // tecnically this should be a list of valid class'es..
16808 if (a.name == 'class') {
16809 if (a.value.match(/^Mso/)) {
16810 node.className = '';
16813 if (a.value.match(/body/)) {
16814 node.className = '';
16825 this.cleanUpChildren(node);
16830 * Clean up MS wordisms...
16832 cleanWord : function(node)
16835 var cleanWordChildren = function()
16837 if (!node.childNodes.length) {
16840 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16841 _t.cleanWord(node.childNodes[i]);
16847 this.cleanWord(this.doc.body);
16850 if (node.nodeName == "#text") {
16851 // clean up silly Windows -- stuff?
16854 if (node.nodeName == "#comment") {
16855 node.parentNode.removeChild(node);
16856 // clean up silly Windows -- stuff?
16860 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16861 node.parentNode.removeChild(node);
16865 // remove - but keep children..
16866 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16867 while (node.childNodes.length) {
16868 var cn = node.childNodes[0];
16869 node.removeChild(cn);
16870 node.parentNode.insertBefore(cn, node);
16872 node.parentNode.removeChild(node);
16873 cleanWordChildren();
16877 if (node.className.length) {
16879 var cn = node.className.split(/\W+/);
16881 Roo.each(cn, function(cls) {
16882 if (cls.match(/Mso[a-zA-Z]+/)) {
16887 node.className = cna.length ? cna.join(' ') : '';
16889 node.removeAttribute("class");
16893 if (node.hasAttribute("lang")) {
16894 node.removeAttribute("lang");
16897 if (node.hasAttribute("style")) {
16899 var styles = node.getAttribute("style").split(";");
16901 Roo.each(styles, function(s) {
16902 if (!s.match(/:/)) {
16905 var kv = s.split(":");
16906 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16909 // what ever is left... we allow.
16912 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16913 if (!nstyle.length) {
16914 node.removeAttribute('style');
16918 cleanWordChildren();
16922 domToHTML : function(currentElement, depth, nopadtext) {
16924 depth = depth || 0;
16925 nopadtext = nopadtext || false;
16927 if (!currentElement) {
16928 return this.domToHTML(this.doc.body);
16931 //Roo.log(currentElement);
16933 var allText = false;
16934 var nodeName = currentElement.nodeName;
16935 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16937 if (nodeName == '#text') {
16938 return currentElement.nodeValue;
16943 if (nodeName != 'BODY') {
16946 // Prints the node tagName, such as <A>, <IMG>, etc
16949 for(i = 0; i < currentElement.attributes.length;i++) {
16951 var aname = currentElement.attributes.item(i).name;
16952 if (!currentElement.attributes.item(i).value.length) {
16955 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16958 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16967 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16970 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16975 // Traverse the tree
16977 var currentElementChild = currentElement.childNodes.item(i);
16978 var allText = true;
16979 var innerHTML = '';
16981 while (currentElementChild) {
16982 // Formatting code (indent the tree so it looks nice on the screen)
16983 var nopad = nopadtext;
16984 if (lastnode == 'SPAN') {
16988 if (currentElementChild.nodeName == '#text') {
16989 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16990 if (!nopad && toadd.length > 80) {
16991 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16993 innerHTML += toadd;
16996 currentElementChild = currentElement.childNodes.item(i);
17002 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17004 // Recursively traverse the tree structure of the child node
17005 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17006 lastnode = currentElementChild.nodeName;
17008 currentElementChild=currentElement.childNodes.item(i);
17014 // The remaining code is mostly for formatting the tree
17015 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17020 ret+= "</"+tagName+">";
17026 // hide stuff that is not compatible
17040 * @event specialkey
17044 * @cfg {String} fieldClass @hide
17047 * @cfg {String} focusClass @hide
17050 * @cfg {String} autoCreate @hide
17053 * @cfg {String} inputType @hide
17056 * @cfg {String} invalidClass @hide
17059 * @cfg {String} invalidText @hide
17062 * @cfg {String} msgFx @hide
17065 * @cfg {String} validateOnBlur @hide
17069 Roo.HtmlEditorCore.white = [
17070 'area', 'br', 'img', 'input', 'hr', 'wbr',
17072 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17073 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17074 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17075 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17076 'table', 'ul', 'xmp',
17078 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17081 'dir', 'menu', 'ol', 'ul', 'dl',
17087 Roo.HtmlEditorCore.black = [
17088 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17090 'base', 'basefont', 'bgsound', 'blink', 'body',
17091 'frame', 'frameset', 'head', 'html', 'ilayer',
17092 'iframe', 'layer', 'link', 'meta', 'object',
17093 'script', 'style' ,'title', 'xml' // clean later..
17095 Roo.HtmlEditorCore.clean = [
17096 'script', 'style', 'title', 'xml'
17098 Roo.HtmlEditorCore.remove = [
17103 Roo.HtmlEditorCore.ablack = [
17107 Roo.HtmlEditorCore.aclean = [
17108 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17112 Roo.HtmlEditorCore.pwhite= [
17113 'http', 'https', 'mailto'
17116 // white listed style attributes.
17117 Roo.HtmlEditorCore.cwhite= [
17118 // 'text-align', /// default is to allow most things..
17124 // black listed style attributes.
17125 Roo.HtmlEditorCore.cblack= [
17126 // 'font-size' -- this can be set by the project
17130 Roo.HtmlEditorCore.swapCodes =[
17149 * @class Roo.bootstrap.HtmlEditor
17150 * @extends Roo.bootstrap.TextArea
17151 * Bootstrap HtmlEditor class
17154 * Create a new HtmlEditor
17155 * @param {Object} config The config object
17158 Roo.bootstrap.HtmlEditor = function(config){
17159 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17160 if (!this.toolbars) {
17161 this.toolbars = [];
17163 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17166 * @event initialize
17167 * Fires when the editor is fully initialized (including the iframe)
17168 * @param {HtmlEditor} this
17173 * Fires when the editor is first receives the focus. Any insertion must wait
17174 * until after this event.
17175 * @param {HtmlEditor} this
17179 * @event beforesync
17180 * Fires before the textarea is updated with content from the editor iframe. Return false
17181 * to cancel the sync.
17182 * @param {HtmlEditor} this
17183 * @param {String} html
17187 * @event beforepush
17188 * Fires before the iframe editor is updated with content from the textarea. Return false
17189 * to cancel the push.
17190 * @param {HtmlEditor} this
17191 * @param {String} html
17196 * Fires when the textarea is updated with content from the editor iframe.
17197 * @param {HtmlEditor} this
17198 * @param {String} html
17203 * Fires when the iframe editor is updated with content from the textarea.
17204 * @param {HtmlEditor} this
17205 * @param {String} html
17209 * @event editmodechange
17210 * Fires when the editor switches edit modes
17211 * @param {HtmlEditor} this
17212 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17214 editmodechange: true,
17216 * @event editorevent
17217 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17218 * @param {HtmlEditor} this
17222 * @event firstfocus
17223 * Fires when on first focus - needed by toolbars..
17224 * @param {HtmlEditor} this
17229 * Auto save the htmlEditor value as a file into Events
17230 * @param {HtmlEditor} this
17234 * @event savedpreview
17235 * preview the saved version of htmlEditor
17236 * @param {HtmlEditor} this
17243 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17247 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17252 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17257 * @cfg {Number} height (in pixels)
17261 * @cfg {Number} width (in pixels)
17266 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17269 stylesheets: false,
17274 // private properties
17275 validationEvent : false,
17277 initialized : false,
17280 onFocus : Roo.emptyFn,
17282 hideMode:'offsets',
17285 tbContainer : false,
17287 toolbarContainer :function() {
17288 return this.wrap.select('.x-html-editor-tb',true).first();
17292 * Protected method that will not generally be called directly. It
17293 * is called when the editor creates its toolbar. Override this method if you need to
17294 * add custom toolbar buttons.
17295 * @param {HtmlEditor} editor
17297 createToolbar : function(){
17299 Roo.log("create toolbars");
17301 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17302 this.toolbars[0].render(this.toolbarContainer());
17306 // if (!editor.toolbars || !editor.toolbars.length) {
17307 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17310 // for (var i =0 ; i < editor.toolbars.length;i++) {
17311 // editor.toolbars[i] = Roo.factory(
17312 // typeof(editor.toolbars[i]) == 'string' ?
17313 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17314 // Roo.bootstrap.HtmlEditor);
17315 // editor.toolbars[i].init(editor);
17321 onRender : function(ct, position)
17323 // Roo.log("Call onRender: " + this.xtype);
17325 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17327 this.wrap = this.inputEl().wrap({
17328 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17331 this.editorcore.onRender(ct, position);
17333 if (this.resizable) {
17334 this.resizeEl = new Roo.Resizable(this.wrap, {
17338 minHeight : this.height,
17339 height: this.height,
17340 handles : this.resizable,
17343 resize : function(r, w, h) {
17344 _t.onResize(w,h); // -something
17350 this.createToolbar(this);
17353 if(!this.width && this.resizable){
17354 this.setSize(this.wrap.getSize());
17356 if (this.resizeEl) {
17357 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17358 // should trigger onReize..
17364 onResize : function(w, h)
17366 Roo.log('resize: ' +w + ',' + h );
17367 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17371 if(this.inputEl() ){
17372 if(typeof w == 'number'){
17373 var aw = w - this.wrap.getFrameWidth('lr');
17374 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17377 if(typeof h == 'number'){
17378 var tbh = -11; // fixme it needs to tool bar size!
17379 for (var i =0; i < this.toolbars.length;i++) {
17380 // fixme - ask toolbars for heights?
17381 tbh += this.toolbars[i].el.getHeight();
17382 //if (this.toolbars[i].footer) {
17383 // tbh += this.toolbars[i].footer.el.getHeight();
17391 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17392 ah -= 5; // knock a few pixes off for look..
17393 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17397 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17398 this.editorcore.onResize(ew,eh);
17403 * Toggles the editor between standard and source edit mode.
17404 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17406 toggleSourceEdit : function(sourceEditMode)
17408 this.editorcore.toggleSourceEdit(sourceEditMode);
17410 if(this.editorcore.sourceEditMode){
17411 Roo.log('editor - showing textarea');
17414 // Roo.log(this.syncValue());
17416 this.inputEl().removeClass(['hide', 'x-hidden']);
17417 this.inputEl().dom.removeAttribute('tabIndex');
17418 this.inputEl().focus();
17420 Roo.log('editor - hiding textarea');
17422 // Roo.log(this.pushValue());
17425 this.inputEl().addClass(['hide', 'x-hidden']);
17426 this.inputEl().dom.setAttribute('tabIndex', -1);
17427 //this.deferFocus();
17430 if(this.resizable){
17431 this.setSize(this.wrap.getSize());
17434 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17437 // private (for BoxComponent)
17438 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17440 // private (for BoxComponent)
17441 getResizeEl : function(){
17445 // private (for BoxComponent)
17446 getPositionEl : function(){
17451 initEvents : function(){
17452 this.originalValue = this.getValue();
17456 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17459 // markInvalid : Roo.emptyFn,
17461 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17464 // clearInvalid : Roo.emptyFn,
17466 setValue : function(v){
17467 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17468 this.editorcore.pushValue();
17473 deferFocus : function(){
17474 this.focus.defer(10, this);
17478 focus : function(){
17479 this.editorcore.focus();
17485 onDestroy : function(){
17491 for (var i =0; i < this.toolbars.length;i++) {
17492 // fixme - ask toolbars for heights?
17493 this.toolbars[i].onDestroy();
17496 this.wrap.dom.innerHTML = '';
17497 this.wrap.remove();
17502 onFirstFocus : function(){
17503 //Roo.log("onFirstFocus");
17504 this.editorcore.onFirstFocus();
17505 for (var i =0; i < this.toolbars.length;i++) {
17506 this.toolbars[i].onFirstFocus();
17512 syncValue : function()
17514 this.editorcore.syncValue();
17517 pushValue : function()
17519 this.editorcore.pushValue();
17523 // hide stuff that is not compatible
17537 * @event specialkey
17541 * @cfg {String} fieldClass @hide
17544 * @cfg {String} focusClass @hide
17547 * @cfg {String} autoCreate @hide
17550 * @cfg {String} inputType @hide
17553 * @cfg {String} invalidClass @hide
17556 * @cfg {String} invalidText @hide
17559 * @cfg {String} msgFx @hide
17562 * @cfg {String} validateOnBlur @hide
17571 Roo.namespace('Roo.bootstrap.htmleditor');
17573 * @class Roo.bootstrap.HtmlEditorToolbar1
17578 new Roo.bootstrap.HtmlEditor({
17581 new Roo.bootstrap.HtmlEditorToolbar1({
17582 disable : { fonts: 1 , format: 1, ..., ... , ...],
17588 * @cfg {Object} disable List of elements to disable..
17589 * @cfg {Array} btns List of additional buttons.
17593 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17596 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17599 Roo.apply(this, config);
17601 // default disabled, based on 'good practice'..
17602 this.disable = this.disable || {};
17603 Roo.applyIf(this.disable, {
17606 specialElements : true
17608 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17610 this.editor = config.editor;
17611 this.editorcore = config.editor.editorcore;
17613 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17615 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17616 // dont call parent... till later.
17618 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17623 editorcore : false,
17628 "h1","h2","h3","h4","h5","h6",
17630 "abbr", "acronym", "address", "cite", "samp", "var",
17634 onRender : function(ct, position)
17636 // Roo.log("Call onRender: " + this.xtype);
17638 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17640 this.el.dom.style.marginBottom = '0';
17642 var editorcore = this.editorcore;
17643 var editor= this.editor;
17646 var btn = function(id,cmd , toggle, handler){
17648 var event = toggle ? 'toggle' : 'click';
17653 xns: Roo.bootstrap,
17656 enableToggle:toggle !== false,
17658 pressed : toggle ? false : null,
17661 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17662 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17671 xns: Roo.bootstrap,
17672 glyphicon : 'font',
17676 xns: Roo.bootstrap,
17680 Roo.each(this.formats, function(f) {
17681 style.menu.items.push({
17683 xns: Roo.bootstrap,
17684 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17689 editorcore.insertTag(this.tagname);
17696 children.push(style);
17699 btn('bold',false,true);
17700 btn('italic',false,true);
17701 btn('align-left', 'justifyleft',true);
17702 btn('align-center', 'justifycenter',true);
17703 btn('align-right' , 'justifyright',true);
17704 btn('link', false, false, function(btn) {
17705 //Roo.log("create link?");
17706 var url = prompt(this.createLinkText, this.defaultLinkValue);
17707 if(url && url != 'http:/'+'/'){
17708 this.editorcore.relayCmd('createlink', url);
17711 btn('list','insertunorderedlist',true);
17712 btn('pencil', false,true, function(btn){
17715 this.toggleSourceEdit(btn.pressed);
17721 xns: Roo.bootstrap,
17726 xns: Roo.bootstrap,
17731 cog.menu.items.push({
17733 xns: Roo.bootstrap,
17734 html : Clean styles,
17739 editorcore.insertTag(this.tagname);
17748 this.xtype = 'NavSimplebar';
17750 for(var i=0;i< children.length;i++) {
17752 this.buttons.add(this.addxtypeChild(children[i]));
17756 editor.on('editorevent', this.updateToolbar, this);
17758 onBtnClick : function(id)
17760 this.editorcore.relayCmd(id);
17761 this.editorcore.focus();
17765 * Protected method that will not generally be called directly. It triggers
17766 * a toolbar update by reading the markup state of the current selection in the editor.
17768 updateToolbar: function(){
17770 if(!this.editorcore.activated){
17771 this.editor.onFirstFocus(); // is this neeed?
17775 var btns = this.buttons;
17776 var doc = this.editorcore.doc;
17777 btns.get('bold').setActive(doc.queryCommandState('bold'));
17778 btns.get('italic').setActive(doc.queryCommandState('italic'));
17779 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17781 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17782 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17783 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17785 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17786 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17789 var ans = this.editorcore.getAllAncestors();
17790 if (this.formatCombo) {
17793 var store = this.formatCombo.store;
17794 this.formatCombo.setValue("");
17795 for (var i =0; i < ans.length;i++) {
17796 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17798 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17806 // hides menus... - so this cant be on a menu...
17807 Roo.bootstrap.MenuMgr.hideAll();
17809 Roo.bootstrap.MenuMgr.hideAll();
17810 //this.editorsyncValue();
17812 onFirstFocus: function() {
17813 this.buttons.each(function(item){
17817 toggleSourceEdit : function(sourceEditMode){
17820 if(sourceEditMode){
17821 Roo.log("disabling buttons");
17822 this.buttons.each( function(item){
17823 if(item.cmd != 'pencil'){
17829 Roo.log("enabling buttons");
17830 if(this.editorcore.initialized){
17831 this.buttons.each( function(item){
17837 Roo.log("calling toggole on editor");
17838 // tell the editor that it's been pressed..
17839 this.editor.toggleSourceEdit(sourceEditMode);
17849 * @class Roo.bootstrap.Table.AbstractSelectionModel
17850 * @extends Roo.util.Observable
17851 * Abstract base class for grid SelectionModels. It provides the interface that should be
17852 * implemented by descendant classes. This class should not be directly instantiated.
17855 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17856 this.locked = false;
17857 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17861 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17862 /** @ignore Called by the grid automatically. Do not call directly. */
17863 init : function(grid){
17869 * Locks the selections.
17872 this.locked = true;
17876 * Unlocks the selections.
17878 unlock : function(){
17879 this.locked = false;
17883 * Returns true if the selections are locked.
17884 * @return {Boolean}
17886 isLocked : function(){
17887 return this.locked;
17891 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17892 * @class Roo.bootstrap.Table.RowSelectionModel
17893 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17894 * It supports multiple selections and keyboard selection/navigation.
17896 * @param {Object} config
17899 Roo.bootstrap.Table.RowSelectionModel = function(config){
17900 Roo.apply(this, config);
17901 this.selections = new Roo.util.MixedCollection(false, function(o){
17906 this.lastActive = false;
17910 * @event selectionchange
17911 * Fires when the selection changes
17912 * @param {SelectionModel} this
17914 "selectionchange" : true,
17916 * @event afterselectionchange
17917 * Fires after the selection changes (eg. by key press or clicking)
17918 * @param {SelectionModel} this
17920 "afterselectionchange" : true,
17922 * @event beforerowselect
17923 * Fires when a row is selected being selected, return false to cancel.
17924 * @param {SelectionModel} this
17925 * @param {Number} rowIndex The selected index
17926 * @param {Boolean} keepExisting False if other selections will be cleared
17928 "beforerowselect" : true,
17931 * Fires when a row is selected.
17932 * @param {SelectionModel} this
17933 * @param {Number} rowIndex The selected index
17934 * @param {Roo.data.Record} r The record
17936 "rowselect" : true,
17938 * @event rowdeselect
17939 * Fires when a row is deselected.
17940 * @param {SelectionModel} this
17941 * @param {Number} rowIndex The selected index
17943 "rowdeselect" : true
17945 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17946 this.locked = false;
17949 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17951 * @cfg {Boolean} singleSelect
17952 * True to allow selection of only one row at a time (defaults to false)
17954 singleSelect : false,
17957 initEvents : function(){
17959 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17960 this.grid.on("mousedown", this.handleMouseDown, this);
17961 }else{ // allow click to work like normal
17962 this.grid.on("rowclick", this.handleDragableRowClick, this);
17965 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17966 "up" : function(e){
17968 this.selectPrevious(e.shiftKey);
17969 }else if(this.last !== false && this.lastActive !== false){
17970 var last = this.last;
17971 this.selectRange(this.last, this.lastActive-1);
17972 this.grid.getView().focusRow(this.lastActive);
17973 if(last !== false){
17977 this.selectFirstRow();
17979 this.fireEvent("afterselectionchange", this);
17981 "down" : function(e){
17983 this.selectNext(e.shiftKey);
17984 }else if(this.last !== false && this.lastActive !== false){
17985 var last = this.last;
17986 this.selectRange(this.last, this.lastActive+1);
17987 this.grid.getView().focusRow(this.lastActive);
17988 if(last !== false){
17992 this.selectFirstRow();
17994 this.fireEvent("afterselectionchange", this);
17999 var view = this.grid.view;
18000 view.on("refresh", this.onRefresh, this);
18001 view.on("rowupdated", this.onRowUpdated, this);
18002 view.on("rowremoved", this.onRemove, this);
18006 onRefresh : function(){
18007 var ds = this.grid.dataSource, i, v = this.grid.view;
18008 var s = this.selections;
18009 s.each(function(r){
18010 if((i = ds.indexOfId(r.id)) != -1){
18019 onRemove : function(v, index, r){
18020 this.selections.remove(r);
18024 onRowUpdated : function(v, index, r){
18025 if(this.isSelected(r)){
18026 v.onRowSelect(index);
18032 * @param {Array} records The records to select
18033 * @param {Boolean} keepExisting (optional) True to keep existing selections
18035 selectRecords : function(records, keepExisting){
18037 this.clearSelections();
18039 var ds = this.grid.dataSource;
18040 for(var i = 0, len = records.length; i < len; i++){
18041 this.selectRow(ds.indexOf(records[i]), true);
18046 * Gets the number of selected rows.
18049 getCount : function(){
18050 return this.selections.length;
18054 * Selects the first row in the grid.
18056 selectFirstRow : function(){
18061 * Select the last row.
18062 * @param {Boolean} keepExisting (optional) True to keep existing selections
18064 selectLastRow : function(keepExisting){
18065 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18069 * Selects the row immediately following the last selected row.
18070 * @param {Boolean} keepExisting (optional) True to keep existing selections
18072 selectNext : function(keepExisting){
18073 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18074 this.selectRow(this.last+1, keepExisting);
18075 this.grid.getView().focusRow(this.last);
18080 * Selects the row that precedes the last selected row.
18081 * @param {Boolean} keepExisting (optional) True to keep existing selections
18083 selectPrevious : function(keepExisting){
18085 this.selectRow(this.last-1, keepExisting);
18086 this.grid.getView().focusRow(this.last);
18091 * Returns the selected records
18092 * @return {Array} Array of selected records
18094 getSelections : function(){
18095 return [].concat(this.selections.items);
18099 * Returns the first selected record.
18102 getSelected : function(){
18103 return this.selections.itemAt(0);
18108 * Clears all selections.
18110 clearSelections : function(fast){
18111 if(this.locked) return;
18113 var ds = this.grid.dataSource;
18114 var s = this.selections;
18115 s.each(function(r){
18116 this.deselectRow(ds.indexOfId(r.id));
18120 this.selections.clear();
18127 * Selects all rows.
18129 selectAll : function(){
18130 if(this.locked) return;
18131 this.selections.clear();
18132 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18133 this.selectRow(i, true);
18138 * Returns True if there is a selection.
18139 * @return {Boolean}
18141 hasSelection : function(){
18142 return this.selections.length > 0;
18146 * Returns True if the specified row is selected.
18147 * @param {Number/Record} record The record or index of the record to check
18148 * @return {Boolean}
18150 isSelected : function(index){
18151 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18152 return (r && this.selections.key(r.id) ? true : false);
18156 * Returns True if the specified record id is selected.
18157 * @param {String} id The id of record to check
18158 * @return {Boolean}
18160 isIdSelected : function(id){
18161 return (this.selections.key(id) ? true : false);
18165 handleMouseDown : function(e, t){
18166 var view = this.grid.getView(), rowIndex;
18167 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18170 if(e.shiftKey && this.last !== false){
18171 var last = this.last;
18172 this.selectRange(last, rowIndex, e.ctrlKey);
18173 this.last = last; // reset the last
18174 view.focusRow(rowIndex);
18176 var isSelected = this.isSelected(rowIndex);
18177 if(e.button !== 0 && isSelected){
18178 view.focusRow(rowIndex);
18179 }else if(e.ctrlKey && isSelected){
18180 this.deselectRow(rowIndex);
18181 }else if(!isSelected){
18182 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18183 view.focusRow(rowIndex);
18186 this.fireEvent("afterselectionchange", this);
18189 handleDragableRowClick : function(grid, rowIndex, e)
18191 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18192 this.selectRow(rowIndex, false);
18193 grid.view.focusRow(rowIndex);
18194 this.fireEvent("afterselectionchange", this);
18199 * Selects multiple rows.
18200 * @param {Array} rows Array of the indexes of the row to select
18201 * @param {Boolean} keepExisting (optional) True to keep existing selections
18203 selectRows : function(rows, keepExisting){
18205 this.clearSelections();
18207 for(var i = 0, len = rows.length; i < len; i++){
18208 this.selectRow(rows[i], true);
18213 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18214 * @param {Number} startRow The index of the first row in the range
18215 * @param {Number} endRow The index of the last row in the range
18216 * @param {Boolean} keepExisting (optional) True to retain existing selections
18218 selectRange : function(startRow, endRow, keepExisting){
18219 if(this.locked) return;
18221 this.clearSelections();
18223 if(startRow <= endRow){
18224 for(var i = startRow; i <= endRow; i++){
18225 this.selectRow(i, true);
18228 for(var i = startRow; i >= endRow; i--){
18229 this.selectRow(i, true);
18235 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18236 * @param {Number} startRow The index of the first row in the range
18237 * @param {Number} endRow The index of the last row in the range
18239 deselectRange : function(startRow, endRow, preventViewNotify){
18240 if(this.locked) return;
18241 for(var i = startRow; i <= endRow; i++){
18242 this.deselectRow(i, preventViewNotify);
18248 * @param {Number} row The index of the row to select
18249 * @param {Boolean} keepExisting (optional) True to keep existing selections
18251 selectRow : function(index, keepExisting, preventViewNotify){
18252 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18253 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18254 if(!keepExisting || this.singleSelect){
18255 this.clearSelections();
18257 var r = this.grid.dataSource.getAt(index);
18258 this.selections.add(r);
18259 this.last = this.lastActive = index;
18260 if(!preventViewNotify){
18261 this.grid.getView().onRowSelect(index);
18263 this.fireEvent("rowselect", this, index, r);
18264 this.fireEvent("selectionchange", this);
18270 * @param {Number} row The index of the row to deselect
18272 deselectRow : function(index, preventViewNotify){
18273 if(this.locked) return;
18274 if(this.last == index){
18277 if(this.lastActive == index){
18278 this.lastActive = false;
18280 var r = this.grid.dataSource.getAt(index);
18281 this.selections.remove(r);
18282 if(!preventViewNotify){
18283 this.grid.getView().onRowDeselect(index);
18285 this.fireEvent("rowdeselect", this, index);
18286 this.fireEvent("selectionchange", this);
18290 restoreLast : function(){
18292 this.last = this._last;
18297 acceptsNav : function(row, col, cm){
18298 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18302 onEditorKey : function(field, e){
18303 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18308 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18310 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18312 }else if(k == e.ENTER && !e.ctrlKey){
18316 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18318 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18320 }else if(k == e.ESC){
18324 g.startEditing(newCell[0], newCell[1]);
18329 * Ext JS Library 1.1.1
18330 * Copyright(c) 2006-2007, Ext JS, LLC.
18332 * Originally Released Under LGPL - original licence link has changed is not relivant.
18335 * <script type="text/javascript">
18339 * @class Roo.bootstrap.PagingToolbar
18341 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18343 * Create a new PagingToolbar
18344 * @param {Object} config The config object
18346 Roo.bootstrap.PagingToolbar = function(config)
18348 // old args format still supported... - xtype is prefered..
18349 // created from xtype...
18350 var ds = config.dataSource;
18351 this.toolbarItems = [];
18352 if (config.items) {
18353 this.toolbarItems = config.items;
18354 // config.items = [];
18357 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18364 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18368 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18370 * @cfg {Roo.data.Store} dataSource
18371 * The underlying data store providing the paged data
18374 * @cfg {String/HTMLElement/Element} container
18375 * container The id or element that will contain the toolbar
18378 * @cfg {Boolean} displayInfo
18379 * True to display the displayMsg (defaults to false)
18382 * @cfg {Number} pageSize
18383 * The number of records to display per page (defaults to 20)
18387 * @cfg {String} displayMsg
18388 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18390 displayMsg : 'Displaying {0} - {1} of {2}',
18392 * @cfg {String} emptyMsg
18393 * The message to display when no records are found (defaults to "No data to display")
18395 emptyMsg : 'No data to display',
18397 * Customizable piece of the default paging text (defaults to "Page")
18400 beforePageText : "Page",
18402 * Customizable piece of the default paging text (defaults to "of %0")
18405 afterPageText : "of {0}",
18407 * Customizable piece of the default paging text (defaults to "First Page")
18410 firstText : "First Page",
18412 * Customizable piece of the default paging text (defaults to "Previous Page")
18415 prevText : "Previous Page",
18417 * Customizable piece of the default paging text (defaults to "Next Page")
18420 nextText : "Next Page",
18422 * Customizable piece of the default paging text (defaults to "Last Page")
18425 lastText : "Last Page",
18427 * Customizable piece of the default paging text (defaults to "Refresh")
18430 refreshText : "Refresh",
18434 onRender : function(ct, position)
18436 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18437 this.navgroup.parentId = this.id;
18438 this.navgroup.onRender(this.el, null);
18439 // add the buttons to the navgroup
18441 if(this.displayInfo){
18442 Roo.log(this.el.select('ul.navbar-nav',true).first());
18443 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18444 this.displayEl = this.el.select('.x-paging-info', true).first();
18445 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18446 // this.displayEl = navel.el.select('span',true).first();
18452 Roo.each(_this.buttons, function(e){
18453 Roo.factory(e).onRender(_this.el, null);
18457 Roo.each(_this.toolbarItems, function(e) {
18458 _this.navgroup.addItem(e);
18461 this.first = this.navgroup.addItem({
18462 tooltip: this.firstText,
18464 icon : 'fa fa-backward',
18466 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18469 this.prev = this.navgroup.addItem({
18470 tooltip: this.prevText,
18472 icon : 'fa fa-step-backward',
18474 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18476 //this.addSeparator();
18479 var field = this.navgroup.addItem( {
18481 cls : 'x-paging-position',
18483 html : this.beforePageText +
18484 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18485 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18488 this.field = field.el.select('input', true).first();
18489 this.field.on("keydown", this.onPagingKeydown, this);
18490 this.field.on("focus", function(){this.dom.select();});
18493 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18494 //this.field.setHeight(18);
18495 //this.addSeparator();
18496 this.next = this.navgroup.addItem({
18497 tooltip: this.nextText,
18499 html : ' <i class="fa fa-step-forward">',
18501 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18503 this.last = this.navgroup.addItem({
18504 tooltip: this.lastText,
18505 icon : 'fa fa-forward',
18508 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18510 //this.addSeparator();
18511 this.loading = this.navgroup.addItem({
18512 tooltip: this.refreshText,
18513 icon: 'fa fa-refresh',
18515 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18521 updateInfo : function(){
18522 if(this.displayEl){
18523 var count = this.ds.getCount();
18524 var msg = count == 0 ?
18528 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18530 this.displayEl.update(msg);
18535 onLoad : function(ds, r, o){
18536 this.cursor = o.params ? o.params.start : 0;
18537 var d = this.getPageData(),
18541 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18542 this.field.dom.value = ap;
18543 this.first.setDisabled(ap == 1);
18544 this.prev.setDisabled(ap == 1);
18545 this.next.setDisabled(ap == ps);
18546 this.last.setDisabled(ap == ps);
18547 this.loading.enable();
18552 getPageData : function(){
18553 var total = this.ds.getTotalCount();
18556 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18557 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18562 onLoadError : function(){
18563 this.loading.enable();
18567 onPagingKeydown : function(e){
18568 var k = e.getKey();
18569 var d = this.getPageData();
18571 var v = this.field.dom.value, pageNum;
18572 if(!v || isNaN(pageNum = parseInt(v, 10))){
18573 this.field.dom.value = d.activePage;
18576 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18577 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18580 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))
18582 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18583 this.field.dom.value = pageNum;
18584 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18587 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18589 var v = this.field.dom.value, pageNum;
18590 var increment = (e.shiftKey) ? 10 : 1;
18591 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18593 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18594 this.field.dom.value = d.activePage;
18597 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18599 this.field.dom.value = parseInt(v, 10) + increment;
18600 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18601 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18608 beforeLoad : function(){
18610 this.loading.disable();
18615 onClick : function(which){
18622 ds.load({params:{start: 0, limit: this.pageSize}});
18625 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18628 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18631 var total = ds.getTotalCount();
18632 var extra = total % this.pageSize;
18633 var lastStart = extra ? (total - extra) : total-this.pageSize;
18634 ds.load({params:{start: lastStart, limit: this.pageSize}});
18637 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18643 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18644 * @param {Roo.data.Store} store The data store to unbind
18646 unbind : function(ds){
18647 ds.un("beforeload", this.beforeLoad, this);
18648 ds.un("load", this.onLoad, this);
18649 ds.un("loadexception", this.onLoadError, this);
18650 ds.un("remove", this.updateInfo, this);
18651 ds.un("add", this.updateInfo, this);
18652 this.ds = undefined;
18656 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18657 * @param {Roo.data.Store} store The data store to bind
18659 bind : function(ds){
18660 ds.on("beforeload", this.beforeLoad, this);
18661 ds.on("load", this.onLoad, this);
18662 ds.on("loadexception", this.onLoadError, this);
18663 ds.on("remove", this.updateInfo, this);
18664 ds.on("add", this.updateInfo, this);
18675 * @class Roo.bootstrap.MessageBar
18676 * @extends Roo.bootstrap.Component
18677 * Bootstrap MessageBar class
18678 * @cfg {String} html contents of the MessageBar
18679 * @cfg {String} weight (info | success | warning | danger) default info
18680 * @cfg {String} beforeClass insert the bar before the given class
18681 * @cfg {Boolean} closable (true | false) default false
18682 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18685 * Create a new Element
18686 * @param {Object} config The config object
18689 Roo.bootstrap.MessageBar = function(config){
18690 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18693 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18699 beforeClass: 'bootstrap-sticky-wrap',
18701 getAutoCreate : function(){
18705 cls: 'alert alert-dismissable alert-' + this.weight,
18710 html: this.html || ''
18716 cfg.cls += ' alert-messages-fixed';
18730 onRender : function(ct, position)
18732 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18735 var cfg = Roo.apply({}, this.getAutoCreate());
18739 cfg.cls += ' ' + this.cls;
18742 cfg.style = this.style;
18744 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18746 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18749 this.el.select('>button.close').on('click', this.hide, this);
18755 if (!this.rendered) {
18761 this.fireEvent('show', this);
18767 if (!this.rendered) {
18773 this.fireEvent('hide', this);
18776 update : function()
18778 // var e = this.el.dom.firstChild;
18780 // if(this.closable){
18781 // e = e.nextSibling;
18784 // e.data = this.html || '';
18786 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18802 * @class Roo.bootstrap.Graph
18803 * @extends Roo.bootstrap.Component
18804 * Bootstrap Graph class
18808 @cfg {String} graphtype bar | vbar | pie
18809 @cfg {number} g_x coodinator | centre x (pie)
18810 @cfg {number} g_y coodinator | centre y (pie)
18811 @cfg {number} g_r radius (pie)
18812 @cfg {number} g_height height of the chart (respected by all elements in the set)
18813 @cfg {number} g_width width of the chart (respected by all elements in the set)
18814 @cfg {Object} title The title of the chart
18817 -opts (object) options for the chart
18819 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18820 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18822 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.
18823 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18825 o stretch (boolean)
18827 -opts (object) options for the pie
18830 o startAngle (number)
18831 o endAngle (number)
18835 * Create a new Input
18836 * @param {Object} config The config object
18839 Roo.bootstrap.Graph = function(config){
18840 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18846 * The img click event for the img.
18847 * @param {Roo.EventObject} e
18853 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18864 //g_colors: this.colors,
18871 getAutoCreate : function(){
18882 onRender : function(ct,position){
18883 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18884 this.raphael = Raphael(this.el.dom);
18886 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18887 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18888 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18889 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18891 r.text(160, 10, "Single Series Chart").attr(txtattr);
18892 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18893 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18894 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18896 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18897 r.barchart(330, 10, 300, 220, data1);
18898 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18899 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18902 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18903 // r.barchart(30, 30, 560, 250, xdata, {
18904 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18905 // axis : "0 0 1 1",
18906 // axisxlabels : xdata
18907 // //yvalues : cols,
18910 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18912 // this.load(null,xdata,{
18913 // axis : "0 0 1 1",
18914 // axisxlabels : xdata
18919 load : function(graphtype,xdata,opts){
18920 this.raphael.clear();
18922 graphtype = this.graphtype;
18927 var r = this.raphael,
18928 fin = function () {
18929 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18931 fout = function () {
18932 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18934 pfin = function() {
18935 this.sector.stop();
18936 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18939 this.label[0].stop();
18940 this.label[0].attr({ r: 7.5 });
18941 this.label[1].attr({ "font-weight": 800 });
18944 pfout = function() {
18945 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18948 this.label[0].animate({ r: 5 }, 500, "bounce");
18949 this.label[1].attr({ "font-weight": 400 });
18955 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18958 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18961 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18962 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18964 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18971 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18976 setTitle: function(o)
18981 initEvents: function() {
18984 this.el.on('click', this.onClick, this);
18988 onClick : function(e)
18990 Roo.log('img onclick');
18991 this.fireEvent('click', this, e);
19003 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19006 * @class Roo.bootstrap.dash.NumberBox
19007 * @extends Roo.bootstrap.Component
19008 * Bootstrap NumberBox class
19009 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19010 * @cfg {String} headline Box headline
19011 * @cfg {String} content Box content
19012 * @cfg {String} icon Box icon
19013 * @cfg {String} footer Footer text
19014 * @cfg {String} fhref Footer href
19017 * Create a new NumberBox
19018 * @param {Object} config The config object
19022 Roo.bootstrap.dash.NumberBox = function(config){
19023 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19027 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19037 getAutoCreate : function(){
19041 cls : 'small-box bg-' + this.bgcolor,
19049 cls : 'roo-headline',
19050 html : this.headline
19054 cls : 'roo-content',
19055 html : this.content
19069 cls : 'ion ' + this.icon
19078 cls : 'small-box-footer',
19079 href : this.fhref || '#',
19083 cfg.cn.push(footer);
19090 onRender : function(ct,position){
19091 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19098 setHeadline: function (value)
19100 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19103 setFooter: function (value, href)
19105 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19108 this.el.select('a.small-box-footer',true).first().attr('href', href);
19113 setContent: function (value)
19115 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19118 initEvents: function()
19132 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19135 * @class Roo.bootstrap.dash.TabBox
19136 * @extends Roo.bootstrap.Component
19137 * Bootstrap TabBox class
19138 * @cfg {String} title Title of the TabBox
19139 * @cfg {String} icon Icon of the TabBox
19142 * Create a new TabBox
19143 * @param {Object} config The config object
19147 Roo.bootstrap.dash.TabBox = function(config){
19148 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19153 * When a pane is added
19154 * @param {Roo.bootstrap.dash.TabPane} pane
19161 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19166 getChildContainer : function()
19168 return this.el.select('.tab-content', true).first();
19171 getAutoCreate : function(){
19175 cls: 'pull-left header',
19183 cls: 'fa ' + this.icon
19190 cls: 'nav-tabs-custom',
19194 cls: 'nav nav-tabs pull-right',
19201 cls: 'tab-content no-padding',
19209 initEvents : function()
19211 //Roo.log('add add pane handler');
19212 this.on('addpane', this.onAddPane, this);
19215 * Updates the box title
19216 * @param {String} html to set the title to.
19218 setTitle : function(value)
19220 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19222 onAddPane : function(pane)
19224 //Roo.log('addpane');
19226 // tabs are rendere left to right..
19227 var ctr = this.el.select('.nav-tabs', true).first();
19230 var existing = ctr.select('.nav-tab',true);
19231 var qty = existing.getCount();;
19234 var tab = ctr.createChild({
19236 cls : 'nav-tab' + (qty ? '' : ' active'),
19244 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19247 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19249 pane.el.addClass('active');
19254 onTabClick : function(ev,un,ob,pane)
19256 //Roo.log('tab - prev default');
19257 ev.preventDefault();
19260 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19261 pane.tab.addClass('active');
19262 //Roo.log(pane.title);
19263 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19264 // technically we should have a deactivate event.. but maybe add later.
19265 // and it should not de-activate the selected tab...
19267 pane.el.addClass('active');
19268 pane.fireEvent('activate');
19283 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19285 * @class Roo.bootstrap.TabPane
19286 * @extends Roo.bootstrap.Component
19287 * Bootstrap TabPane class
19288 * @cfg {Boolean} active (false | true) Default false
19289 * @cfg {String} title title of panel
19293 * Create a new TabPane
19294 * @param {Object} config The config object
19297 Roo.bootstrap.dash.TabPane = function(config){
19298 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19302 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19307 // the tabBox that this is attached to.
19310 getAutoCreate : function()
19318 cfg.cls += ' active';
19323 initEvents : function()
19325 //Roo.log('trigger add pane handler');
19326 this.parent().fireEvent('addpane', this)
19330 * Updates the tab title
19331 * @param {String} html to set the title to.
19333 setTitle: function(str)
19339 this.tab.select('a'.true).first().dom.innerHTML = str;
19356 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19359 * @class Roo.bootstrap.menu.Menu
19360 * @extends Roo.bootstrap.Component
19361 * Bootstrap Menu class - container for Menu
19362 * @cfg {String} html Text of the menu
19363 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19364 * @cfg {String} icon Font awesome icon
19365 * @cfg {String} pos Menu align to (top | bottom) default bottom
19369 * Create a new Menu
19370 * @param {Object} config The config object
19374 Roo.bootstrap.menu.Menu = function(config){
19375 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19379 * @event beforeshow
19380 * Fires before this menu is displayed
19381 * @param {Roo.bootstrap.menu.Menu} this
19385 * @event beforehide
19386 * Fires before this menu is hidden
19387 * @param {Roo.bootstrap.menu.Menu} this
19392 * Fires after this menu is displayed
19393 * @param {Roo.bootstrap.menu.Menu} this
19398 * Fires after this menu is hidden
19399 * @param {Roo.bootstrap.menu.Menu} this
19404 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19405 * @param {Roo.bootstrap.menu.Menu} this
19406 * @param {Roo.EventObject} e
19413 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19417 weight : 'default',
19422 getChildContainer : function() {
19423 if(this.isSubMenu){
19427 return this.el.select('ul.dropdown-menu', true).first();
19430 getAutoCreate : function()
19435 cls : 'roo-menu-text',
19443 cls : 'fa ' + this.icon
19454 cls : 'dropdown-button btn btn-' + this.weight,
19459 cls : 'dropdown-toggle btn btn-' + this.weight,
19469 cls : 'dropdown-menu'
19475 if(this.pos == 'top'){
19476 cfg.cls += ' dropup';
19479 if(this.isSubMenu){
19482 cls : 'dropdown-menu'
19489 onRender : function(ct, position)
19491 this.isSubMenu = ct.hasClass('dropdown-submenu');
19493 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19496 initEvents : function()
19498 if(this.isSubMenu){
19502 this.hidden = true;
19504 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19505 this.triggerEl.on('click', this.onTriggerPress, this);
19507 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19508 this.buttonEl.on('click', this.onClick, this);
19514 if(this.isSubMenu){
19518 return this.el.select('ul.dropdown-menu', true).first();
19521 onClick : function(e)
19523 this.fireEvent("click", this, e);
19526 onTriggerPress : function(e)
19528 if (this.isVisible()) {
19535 isVisible : function(){
19536 return !this.hidden;
19541 this.fireEvent("beforeshow", this);
19543 this.hidden = false;
19544 this.el.addClass('open');
19546 Roo.get(document).on("mouseup", this.onMouseUp, this);
19548 this.fireEvent("show", this);
19555 this.fireEvent("beforehide", this);
19557 this.hidden = true;
19558 this.el.removeClass('open');
19560 Roo.get(document).un("mouseup", this.onMouseUp);
19562 this.fireEvent("hide", this);
19565 onMouseUp : function()
19579 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19582 * @class Roo.bootstrap.menu.Item
19583 * @extends Roo.bootstrap.Component
19584 * Bootstrap MenuItem class
19585 * @cfg {Boolean} submenu (true | false) default false
19586 * @cfg {String} html text of the item
19587 * @cfg {String} href the link
19588 * @cfg {Boolean} disable (true | false) default false
19589 * @cfg {Boolean} preventDefault (true | false) default true
19590 * @cfg {String} icon Font awesome icon
19591 * @cfg {String} pos Submenu align to (left | right) default right
19595 * Create a new Item
19596 * @param {Object} config The config object
19600 Roo.bootstrap.menu.Item = function(config){
19601 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19605 * Fires when the mouse is hovering over this menu
19606 * @param {Roo.bootstrap.menu.Item} this
19607 * @param {Roo.EventObject} e
19612 * Fires when the mouse exits this menu
19613 * @param {Roo.bootstrap.menu.Item} this
19614 * @param {Roo.EventObject} e
19620 * The raw click event for the entire grid.
19621 * @param {Roo.EventObject} e
19627 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19632 preventDefault: true,
19637 getAutoCreate : function()
19642 cls : 'roo-menu-item-text',
19650 cls : 'fa ' + this.icon
19659 href : this.href || '#',
19666 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19670 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19672 if(this.pos == 'left'){
19673 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19680 initEvents : function()
19682 this.el.on('mouseover', this.onMouseOver, this);
19683 this.el.on('mouseout', this.onMouseOut, this);
19685 this.el.select('a', true).first().on('click', this.onClick, this);
19689 onClick : function(e)
19691 if(this.preventDefault){
19692 e.preventDefault();
19695 this.fireEvent("click", this, e);
19698 onMouseOver : function(e)
19700 if(this.submenu && this.pos == 'left'){
19701 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19704 this.fireEvent("mouseover", this, e);
19707 onMouseOut : function(e)
19709 this.fireEvent("mouseout", this, e);
19721 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19724 * @class Roo.bootstrap.menu.Separator
19725 * @extends Roo.bootstrap.Component
19726 * Bootstrap Separator class
19729 * Create a new Separator
19730 * @param {Object} config The config object
19734 Roo.bootstrap.menu.Separator = function(config){
19735 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19738 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19740 getAutoCreate : function(){