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);
3181 Roo.bootstrap.NavGroup.register(this);
3185 * Fires when the active item changes
3186 * @param {Roo.bootstrap.NavGroup} this
3187 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3188 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3195 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3206 getAutoCreate : function()
3208 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3215 if (['tabs','pills'].indexOf(this.type)!==-1) {
3216 cfg.cls += ' nav-' + this.type
3218 if (this.type!=='nav') {
3219 Roo.log('nav type must be nav/tabs/pills')
3221 cfg.cls += ' navbar-nav'
3224 if (this.parent().sidebar) {
3227 cls: 'dashboard-menu sidebar-menu'
3233 if (this.form === true) {
3239 if (this.align === 'right') {
3240 cfg.cls += ' navbar-right';
3242 cfg.cls += ' navbar-left';
3246 if (this.align === 'right') {
3247 cfg.cls += ' navbar-right';
3251 cfg.cls += ' navbar-inverse';
3259 * sets the active Navigation item
3260 * @param {Roo.bootstrap.NavItem} the new current navitem
3262 setActiveItem : function(item)
3265 Roo.each(this.navItems, function(v){
3270 v.setActive(false, true);
3277 item.setActive(true, true);
3278 this.fireEvent('changed', this, item, prev);
3283 * gets the active Navigation item
3284 * @return {Roo.bootstrap.NavItem} the current navitem
3286 getActive : function()
3290 Roo.each(this.navItems, function(v){
3301 * adds a Navigation item
3302 * @param {Roo.bootstrap.NavItem} the navitem to add
3304 addItem : function(cfg)
3306 var cn = new Roo.bootstrap.NavItem(cfg);
3308 cn.parentId = this.id;
3309 cn.onRender(this.el, null);
3313 * register a Navigation item
3314 * @param {Roo.bootstrap.NavItem} the navitem to add
3316 register : function(item)
3318 this.navItems.push( item);
3319 item.navId = this.navId;
3324 getNavItem: function(tabId)
3327 Roo.each(this.navItems, function(e) {
3328 if (e.tabId == tabId) {
3344 Roo.apply(Roo.bootstrap.NavGroup, {
3348 * register a Navigation Group
3349 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3351 register : function(navgrp)
3353 this.groups[navgrp.navId] = navgrp;
3357 * fetch a Navigation Group based on the navigation ID
3358 * @param {string} the navgroup to add
3359 * @returns {Roo.bootstrap.NavGroup} the navgroup
3361 get: function(navId) {
3362 if (typeof(this.groups[navId]) == 'undefined') {
3364 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3366 return this.groups[navId] ;
3381 * @class Roo.bootstrap.NavItem
3382 * @extends Roo.bootstrap.Component
3383 * Bootstrap Navbar.NavItem class
3384 * @cfg {String} href link to
3385 * @cfg {String} html content of button
3386 * @cfg {String} badge text inside badge
3387 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3388 * @cfg {String} glyphicon name of glyphicon
3389 * @cfg {String} icon name of font awesome icon
3390 * @cfg {Boolean} active Is item active
3391 * @cfg {Boolean} disabled Is item disabled
3393 * @cfg {Boolean} preventDefault (true | false) default false
3394 * @cfg {String} tabId the tab that this item activates.
3395 * @cfg {String} tagtype (a|span) render as a href or span?
3398 * Create a new Navbar Item
3399 * @param {Object} config The config object
3401 Roo.bootstrap.NavItem = function(config){
3402 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3407 * The raw click event for the entire grid.
3408 * @param {Roo.EventObject} e
3413 * Fires when the active item active state changes
3414 * @param {Roo.bootstrap.NavItem} this
3415 * @param {boolean} state the new state
3423 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3431 preventDefault : false,
3436 getAutoCreate : function(){
3444 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3446 if (this.disabled) {
3447 cfg.cls += ' disabled';
3450 if (this.href || this.html || this.glyphicon || this.icon) {
3454 href : this.href || "#",
3455 html: this.html || ''
3460 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3463 if(this.glyphicon) {
3464 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3469 cfg.cn[0].html += " <span class='caret'></span>";
3473 if (this.badge !== '') {
3475 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3483 initEvents: function() {
3484 // Roo.log('init events?');
3485 // Roo.log(this.el.dom);
3486 if (typeof (this.menu) != 'undefined') {
3487 this.menu.parentType = this.xtype;
3488 this.menu.triggerEl = this.el;
3489 this.addxtype(Roo.apply({}, this.menu));
3493 this.el.select('a',true).on('click', this.onClick, this);
3494 // at this point parent should be available..
3495 this.parent().register(this);
3498 onClick : function(e)
3501 if(this.preventDefault){
3504 if (this.disabled) {
3507 Roo.log("fire event clicked");
3508 if(this.fireEvent('click', this, e) === false){
3512 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3513 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3514 this.parent().setActiveItem(this);
3522 isActive: function () {
3525 setActive : function(state, fire)
3527 this.active = state;
3529 this.el.removeClass('active');
3530 } else if (!this.el.hasClass('active')) {
3531 this.el.addClass('active');
3534 this.fireEvent('changed', this, state);
3539 // this should not be here...
3540 setDisabled : function(state)
3542 this.disabled = state;
3544 this.el.removeClass('disabled');
3545 } else if (!this.el.hasClass('disabled')) {
3546 this.el.addClass('disabled');
3559 * <span> icon </span>
3560 * <span> text </span>
3561 * <span>badge </span>
3565 * @class Roo.bootstrap.NavSidebarItem
3566 * @extends Roo.bootstrap.NavItem
3567 * Bootstrap Navbar.NavSidebarItem class
3569 * Create a new Navbar Button
3570 * @param {Object} config The config object
3572 Roo.bootstrap.NavSidebarItem = function(config){
3573 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3578 * The raw click event for the entire grid.
3579 * @param {Roo.EventObject} e
3584 * Fires when the active item active state changes
3585 * @param {Roo.bootstrap.NavSidebarItem} this
3586 * @param {boolean} state the new state
3594 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3597 getAutoCreate : function(){
3602 href : this.href || '#',
3614 html : this.html || ''
3619 cfg.cls += ' active';
3623 if (this.glyphicon || this.icon) {
3624 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3625 a.cn.push({ tag : 'i', cls : c }) ;
3630 if (this.badge !== '') {
3631 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3635 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3636 a.cls += 'dropdown-toggle treeview' ;
3660 * @class Roo.bootstrap.Row
3661 * @extends Roo.bootstrap.Component
3662 * Bootstrap Row class (contains columns...)
3666 * @param {Object} config The config object
3669 Roo.bootstrap.Row = function(config){
3670 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3673 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3675 getAutoCreate : function(){
3694 * @class Roo.bootstrap.Element
3695 * @extends Roo.bootstrap.Component
3696 * Bootstrap Element class
3697 * @cfg {String} html contents of the element
3698 * @cfg {String} tag tag of the element
3699 * @cfg {String} cls class of the element
3702 * Create a new Element
3703 * @param {Object} config The config object
3706 Roo.bootstrap.Element = function(config){
3707 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3710 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3717 getAutoCreate : function(){
3742 * @class Roo.bootstrap.Pagination
3743 * @extends Roo.bootstrap.Component
3744 * Bootstrap Pagination class
3745 * @cfg {String} size xs | sm | md | lg
3746 * @cfg {Boolean} inverse false | true
3749 * Create a new Pagination
3750 * @param {Object} config The config object
3753 Roo.bootstrap.Pagination = function(config){
3754 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3757 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3763 getAutoCreate : function(){
3769 cfg.cls += ' inverse';
3775 cfg.cls += " " + this.cls;
3793 * @class Roo.bootstrap.PaginationItem
3794 * @extends Roo.bootstrap.Component
3795 * Bootstrap PaginationItem class
3796 * @cfg {String} html text
3797 * @cfg {String} href the link
3798 * @cfg {Boolean} preventDefault (true | false) default true
3799 * @cfg {Boolean} active (true | false) default false
3803 * Create a new PaginationItem
3804 * @param {Object} config The config object
3808 Roo.bootstrap.PaginationItem = function(config){
3809 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3814 * The raw click event for the entire grid.
3815 * @param {Roo.EventObject} e
3821 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3825 preventDefault: true,
3829 getAutoCreate : function(){
3835 href : this.href ? this.href : '#',
3836 html : this.html ? this.html : ''
3846 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3852 initEvents: function() {
3854 this.el.on('click', this.onClick, this);
3857 onClick : function(e)
3859 Roo.log('PaginationItem on click ');
3860 if(this.preventDefault){
3864 this.fireEvent('click', this, e);
3880 * @class Roo.bootstrap.Slider
3881 * @extends Roo.bootstrap.Component
3882 * Bootstrap Slider class
3885 * Create a new Slider
3886 * @param {Object} config The config object
3889 Roo.bootstrap.Slider = function(config){
3890 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3893 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3895 getAutoCreate : function(){
3899 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3903 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3915 * Ext JS Library 1.1.1
3916 * Copyright(c) 2006-2007, Ext JS, LLC.
3918 * Originally Released Under LGPL - original licence link has changed is not relivant.
3921 * <script type="text/javascript">
3926 * @class Roo.grid.ColumnModel
3927 * @extends Roo.util.Observable
3928 * This is the default implementation of a ColumnModel used by the Grid. It defines
3929 * the columns in the grid.
3932 var colModel = new Roo.grid.ColumnModel([
3933 {header: "Ticker", width: 60, sortable: true, locked: true},
3934 {header: "Company Name", width: 150, sortable: true},
3935 {header: "Market Cap.", width: 100, sortable: true},
3936 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3937 {header: "Employees", width: 100, sortable: true, resizable: false}
3942 * The config options listed for this class are options which may appear in each
3943 * individual column definition.
3944 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3946 * @param {Object} config An Array of column config objects. See this class's
3947 * config objects for details.
3949 Roo.grid.ColumnModel = function(config){
3951 * The config passed into the constructor
3953 this.config = config;
3956 // if no id, create one
3957 // if the column does not have a dataIndex mapping,
3958 // map it to the order it is in the config
3959 for(var i = 0, len = config.length; i < len; i++){
3961 if(typeof c.dataIndex == "undefined"){
3964 if(typeof c.renderer == "string"){
3965 c.renderer = Roo.util.Format[c.renderer];
3967 if(typeof c.id == "undefined"){
3970 if(c.editor && c.editor.xtype){
3971 c.editor = Roo.factory(c.editor, Roo.grid);
3973 if(c.editor && c.editor.isFormField){
3974 c.editor = new Roo.grid.GridEditor(c.editor);
3976 this.lookup[c.id] = c;
3980 * The width of columns which have no width specified (defaults to 100)
3983 this.defaultWidth = 100;
3986 * Default sortable of columns which have no sortable specified (defaults to false)
3989 this.defaultSortable = false;
3993 * @event widthchange
3994 * Fires when the width of a column changes.
3995 * @param {ColumnModel} this
3996 * @param {Number} columnIndex The column index
3997 * @param {Number} newWidth The new width
3999 "widthchange": true,
4001 * @event headerchange
4002 * Fires when the text of a header changes.
4003 * @param {ColumnModel} this
4004 * @param {Number} columnIndex The column index
4005 * @param {Number} newText The new header text
4007 "headerchange": true,
4009 * @event hiddenchange
4010 * Fires when a column is hidden or "unhidden".
4011 * @param {ColumnModel} this
4012 * @param {Number} columnIndex The column index
4013 * @param {Boolean} hidden true if hidden, false otherwise
4015 "hiddenchange": true,
4017 * @event columnmoved
4018 * Fires when a column is moved.
4019 * @param {ColumnModel} this
4020 * @param {Number} oldIndex
4021 * @param {Number} newIndex
4023 "columnmoved" : true,
4025 * @event columlockchange
4026 * Fires when a column's locked state is changed
4027 * @param {ColumnModel} this
4028 * @param {Number} colIndex
4029 * @param {Boolean} locked true if locked
4031 "columnlockchange" : true
4033 Roo.grid.ColumnModel.superclass.constructor.call(this);
4035 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4037 * @cfg {String} header The header text to display in the Grid view.
4040 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4041 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4042 * specified, the column's index is used as an index into the Record's data Array.
4045 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4046 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4049 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4050 * Defaults to the value of the {@link #defaultSortable} property.
4051 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4054 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4057 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4060 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4063 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4066 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4067 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4068 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4069 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4072 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4075 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4079 * Returns the id of the column at the specified index.
4080 * @param {Number} index The column index
4081 * @return {String} the id
4083 getColumnId : function(index){
4084 return this.config[index].id;
4088 * Returns the column for a specified id.
4089 * @param {String} id The column id
4090 * @return {Object} the column
4092 getColumnById : function(id){
4093 return this.lookup[id];
4098 * Returns the column for a specified dataIndex.
4099 * @param {String} dataIndex The column dataIndex
4100 * @return {Object|Boolean} the column or false if not found
4102 getColumnByDataIndex: function(dataIndex){
4103 var index = this.findColumnIndex(dataIndex);
4104 return index > -1 ? this.config[index] : false;
4108 * Returns the index for a specified column id.
4109 * @param {String} id The column id
4110 * @return {Number} the index, or -1 if not found
4112 getIndexById : function(id){
4113 for(var i = 0, len = this.config.length; i < len; i++){
4114 if(this.config[i].id == id){
4122 * Returns the index for a specified column dataIndex.
4123 * @param {String} dataIndex The column dataIndex
4124 * @return {Number} the index, or -1 if not found
4127 findColumnIndex : function(dataIndex){
4128 for(var i = 0, len = this.config.length; i < len; i++){
4129 if(this.config[i].dataIndex == dataIndex){
4137 moveColumn : function(oldIndex, newIndex){
4138 var c = this.config[oldIndex];
4139 this.config.splice(oldIndex, 1);
4140 this.config.splice(newIndex, 0, c);
4141 this.dataMap = null;
4142 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4145 isLocked : function(colIndex){
4146 return this.config[colIndex].locked === true;
4149 setLocked : function(colIndex, value, suppressEvent){
4150 if(this.isLocked(colIndex) == value){
4153 this.config[colIndex].locked = value;
4155 this.fireEvent("columnlockchange", this, colIndex, value);
4159 getTotalLockedWidth : function(){
4161 for(var i = 0; i < this.config.length; i++){
4162 if(this.isLocked(i) && !this.isHidden(i)){
4163 this.totalWidth += this.getColumnWidth(i);
4169 getLockedCount : function(){
4170 for(var i = 0, len = this.config.length; i < len; i++){
4171 if(!this.isLocked(i)){
4178 * Returns the number of columns.
4181 getColumnCount : function(visibleOnly){
4182 if(visibleOnly === true){
4184 for(var i = 0, len = this.config.length; i < len; i++){
4185 if(!this.isHidden(i)){
4191 return this.config.length;
4195 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4196 * @param {Function} fn
4197 * @param {Object} scope (optional)
4198 * @return {Array} result
4200 getColumnsBy : function(fn, scope){
4202 for(var i = 0, len = this.config.length; i < len; i++){
4203 var c = this.config[i];
4204 if(fn.call(scope||this, c, i) === true){
4212 * Returns true if the specified column is sortable.
4213 * @param {Number} col The column index
4216 isSortable : function(col){
4217 if(typeof this.config[col].sortable == "undefined"){
4218 return this.defaultSortable;
4220 return this.config[col].sortable;
4224 * Returns the rendering (formatting) function defined for the column.
4225 * @param {Number} col The column index.
4226 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4228 getRenderer : function(col){
4229 if(!this.config[col].renderer){
4230 return Roo.grid.ColumnModel.defaultRenderer;
4232 return this.config[col].renderer;
4236 * Sets the rendering (formatting) function for a column.
4237 * @param {Number} col The column index
4238 * @param {Function} fn The function to use to process the cell's raw data
4239 * to return HTML markup for the grid view. The render function is called with
4240 * the following parameters:<ul>
4241 * <li>Data value.</li>
4242 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4243 * <li>css A CSS style string to apply to the table cell.</li>
4244 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4245 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4246 * <li>Row index</li>
4247 * <li>Column index</li>
4248 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4250 setRenderer : function(col, fn){
4251 this.config[col].renderer = fn;
4255 * Returns the width for the specified column.
4256 * @param {Number} col The column index
4259 getColumnWidth : function(col){
4260 return this.config[col].width * 1 || this.defaultWidth;
4264 * Sets the width for a column.
4265 * @param {Number} col The column index
4266 * @param {Number} width The new width
4268 setColumnWidth : function(col, width, suppressEvent){
4269 this.config[col].width = width;
4270 this.totalWidth = null;
4272 this.fireEvent("widthchange", this, col, width);
4277 * Returns the total width of all columns.
4278 * @param {Boolean} includeHidden True to include hidden column widths
4281 getTotalWidth : function(includeHidden){
4282 if(!this.totalWidth){
4283 this.totalWidth = 0;
4284 for(var i = 0, len = this.config.length; i < len; i++){
4285 if(includeHidden || !this.isHidden(i)){
4286 this.totalWidth += this.getColumnWidth(i);
4290 return this.totalWidth;
4294 * Returns the header for the specified column.
4295 * @param {Number} col The column index
4298 getColumnHeader : function(col){
4299 return this.config[col].header;
4303 * Sets the header for a column.
4304 * @param {Number} col The column index
4305 * @param {String} header The new header
4307 setColumnHeader : function(col, header){
4308 this.config[col].header = header;
4309 this.fireEvent("headerchange", this, col, header);
4313 * Returns the tooltip for the specified column.
4314 * @param {Number} col The column index
4317 getColumnTooltip : function(col){
4318 return this.config[col].tooltip;
4321 * Sets the tooltip for a column.
4322 * @param {Number} col The column index
4323 * @param {String} tooltip The new tooltip
4325 setColumnTooltip : function(col, tooltip){
4326 this.config[col].tooltip = tooltip;
4330 * Returns the dataIndex for the specified column.
4331 * @param {Number} col The column index
4334 getDataIndex : function(col){
4335 return this.config[col].dataIndex;
4339 * Sets the dataIndex for a column.
4340 * @param {Number} col The column index
4341 * @param {Number} dataIndex The new dataIndex
4343 setDataIndex : function(col, dataIndex){
4344 this.config[col].dataIndex = dataIndex;
4350 * Returns true if the cell is editable.
4351 * @param {Number} colIndex The column index
4352 * @param {Number} rowIndex The row index
4355 isCellEditable : function(colIndex, rowIndex){
4356 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4360 * Returns the editor defined for the cell/column.
4361 * return false or null to disable editing.
4362 * @param {Number} colIndex The column index
4363 * @param {Number} rowIndex The row index
4366 getCellEditor : function(colIndex, rowIndex){
4367 return this.config[colIndex].editor;
4371 * Sets if a column is editable.
4372 * @param {Number} col The column index
4373 * @param {Boolean} editable True if the column is editable
4375 setEditable : function(col, editable){
4376 this.config[col].editable = editable;
4381 * Returns true if the column is hidden.
4382 * @param {Number} colIndex The column index
4385 isHidden : function(colIndex){
4386 return this.config[colIndex].hidden;
4391 * Returns true if the column width cannot be changed
4393 isFixed : function(colIndex){
4394 return this.config[colIndex].fixed;
4398 * Returns true if the column can be resized
4401 isResizable : function(colIndex){
4402 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4405 * Sets if a column is hidden.
4406 * @param {Number} colIndex The column index
4407 * @param {Boolean} hidden True if the column is hidden
4409 setHidden : function(colIndex, hidden){
4410 this.config[colIndex].hidden = hidden;
4411 this.totalWidth = null;
4412 this.fireEvent("hiddenchange", this, colIndex, hidden);
4416 * Sets the editor for a column.
4417 * @param {Number} col The column index
4418 * @param {Object} editor The editor object
4420 setEditor : function(col, editor){
4421 this.config[col].editor = editor;
4425 Roo.grid.ColumnModel.defaultRenderer = function(value){
4426 if(typeof value == "string" && value.length < 1){
4432 // Alias for backwards compatibility
4433 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4436 * Ext JS Library 1.1.1
4437 * Copyright(c) 2006-2007, Ext JS, LLC.
4439 * Originally Released Under LGPL - original licence link has changed is not relivant.
4442 * <script type="text/javascript">
4446 * @class Roo.LoadMask
4447 * A simple utility class for generically masking elements while loading data. If the element being masked has
4448 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4449 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4450 * element's UpdateManager load indicator and will be destroyed after the initial load.
4452 * Create a new LoadMask
4453 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4454 * @param {Object} config The config object
4456 Roo.LoadMask = function(el, config){
4457 this.el = Roo.get(el);
4458 Roo.apply(this, config);
4460 this.store.on('beforeload', this.onBeforeLoad, this);
4461 this.store.on('load', this.onLoad, this);
4462 this.store.on('loadexception', this.onLoadException, this);
4463 this.removeMask = false;
4465 var um = this.el.getUpdateManager();
4466 um.showLoadIndicator = false; // disable the default indicator
4467 um.on('beforeupdate', this.onBeforeLoad, this);
4468 um.on('update', this.onLoad, this);
4469 um.on('failure', this.onLoad, this);
4470 this.removeMask = true;
4474 Roo.LoadMask.prototype = {
4476 * @cfg {Boolean} removeMask
4477 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4478 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4482 * The text to display in a centered loading message box (defaults to 'Loading...')
4486 * @cfg {String} msgCls
4487 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4489 msgCls : 'x-mask-loading',
4492 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4498 * Disables the mask to prevent it from being displayed
4500 disable : function(){
4501 this.disabled = true;
4505 * Enables the mask so that it can be displayed
4507 enable : function(){
4508 this.disabled = false;
4511 onLoadException : function()
4515 if (typeof(arguments[3]) != 'undefined') {
4516 Roo.MessageBox.alert("Error loading",arguments[3]);
4520 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4521 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4530 this.el.unmask(this.removeMask);
4535 this.el.unmask(this.removeMask);
4539 onBeforeLoad : function(){
4541 this.el.mask(this.msg, this.msgCls);
4546 destroy : function(){
4548 this.store.un('beforeload', this.onBeforeLoad, this);
4549 this.store.un('load', this.onLoad, this);
4550 this.store.un('loadexception', this.onLoadException, this);
4552 var um = this.el.getUpdateManager();
4553 um.un('beforeupdate', this.onBeforeLoad, this);
4554 um.un('update', this.onLoad, this);
4555 um.un('failure', this.onLoad, this);
4566 * @class Roo.bootstrap.Table
4567 * @extends Roo.bootstrap.Component
4568 * Bootstrap Table class
4569 * @cfg {String} cls table class
4570 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4571 * @cfg {String} bgcolor Specifies the background color for a table
4572 * @cfg {Number} border Specifies whether the table cells should have borders or not
4573 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4574 * @cfg {Number} cellspacing Specifies the space between cells
4575 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4576 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4577 * @cfg {String} sortable Specifies that the table should be sortable
4578 * @cfg {String} summary Specifies a summary of the content of a table
4579 * @cfg {Number} width Specifies the width of a table
4580 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4582 * @cfg {boolean} striped Should the rows be alternative striped
4583 * @cfg {boolean} bordered Add borders to the table
4584 * @cfg {boolean} hover Add hover highlighting
4585 * @cfg {boolean} condensed Format condensed
4586 * @cfg {boolean} responsive Format condensed
4587 * @cfg {Boolean} loadMask (true|false) default false
4588 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4589 * @cfg {Boolean} thead (true|false) generate thead, default true
4590 * @cfg {Boolean} RowSelection (true|false) default false
4591 * @cfg {Boolean} CellSelection (true|false) default false
4593 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4597 * Create a new Table
4598 * @param {Object} config The config object
4601 Roo.bootstrap.Table = function(config){
4602 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4605 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4606 this.sm = this.selModel;
4607 this.sm.xmodule = this.xmodule || false;
4609 if (this.cm && typeof(this.cm.config) == 'undefined') {
4610 this.colModel = new Roo.grid.ColumnModel(this.cm);
4611 this.cm = this.colModel;
4612 this.cm.xmodule = this.xmodule || false;
4615 this.store= Roo.factory(this.store, Roo.data);
4616 this.ds = this.store;
4617 this.ds.xmodule = this.xmodule || false;
4620 if (this.footer && this.store) {
4621 this.footer.dataSource = this.ds;
4622 this.footer = Roo.factory(this.footer);
4629 * Fires when a cell is clicked
4630 * @param {Roo.bootstrap.Table} this
4631 * @param {Roo.Element} el
4632 * @param {Number} rowIndex
4633 * @param {Number} columnIndex
4634 * @param {Roo.EventObject} e
4638 * @event celldblclick
4639 * Fires when a cell is double clicked
4640 * @param {Roo.bootstrap.Table} this
4641 * @param {Roo.Element} el
4642 * @param {Number} rowIndex
4643 * @param {Number} columnIndex
4644 * @param {Roo.EventObject} e
4646 "celldblclick" : true,
4649 * Fires when a row is clicked
4650 * @param {Roo.bootstrap.Table} this
4651 * @param {Roo.Element} el
4652 * @param {Number} rowIndex
4653 * @param {Roo.EventObject} e
4657 * @event rowdblclick
4658 * Fires when a row is double clicked
4659 * @param {Roo.bootstrap.Table} this
4660 * @param {Roo.Element} el
4661 * @param {Number} rowIndex
4662 * @param {Roo.EventObject} e
4664 "rowdblclick" : true,
4667 * Fires when a mouseover occur
4668 * @param {Roo.bootstrap.Table} this
4669 * @param {Roo.Element} el
4670 * @param {Number} rowIndex
4671 * @param {Number} columnIndex
4672 * @param {Roo.EventObject} e
4677 * Fires when a mouseout occur
4678 * @param {Roo.bootstrap.Table} this
4679 * @param {Roo.Element} el
4680 * @param {Number} rowIndex
4681 * @param {Number} columnIndex
4682 * @param {Roo.EventObject} e
4687 * Fires when a row is rendered, so you can change add a style to it.
4688 * @param {Roo.bootstrap.Table} this
4689 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4696 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4720 RowSelection : false,
4721 CellSelection : false,
4724 // Roo.Element - the tbody
4727 getAutoCreate : function(){
4728 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4737 cfg.cls += ' table-striped';
4741 cfg.cls += ' table-hover';
4743 if (this.bordered) {
4744 cfg.cls += ' table-bordered';
4746 if (this.condensed) {
4747 cfg.cls += ' table-condensed';
4749 if (this.responsive) {
4750 cfg.cls += ' table-responsive';
4754 cfg.cls+= ' ' +this.cls;
4757 // this lot should be simplifed...
4760 cfg.align=this.align;
4763 cfg.bgcolor=this.bgcolor;
4766 cfg.border=this.border;
4768 if (this.cellpadding) {
4769 cfg.cellpadding=this.cellpadding;
4771 if (this.cellspacing) {
4772 cfg.cellspacing=this.cellspacing;
4775 cfg.frame=this.frame;
4778 cfg.rules=this.rules;
4780 if (this.sortable) {
4781 cfg.sortable=this.sortable;
4784 cfg.summary=this.summary;
4787 cfg.width=this.width;
4790 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4793 if(this.store || this.cm){
4795 cfg.cn.push(this.renderHeader());
4798 cfg.cn.push(this.renderBody());
4801 cfg.cn.push(this.renderFooter());
4804 cfg.cls+= ' TableGrid';
4807 return { cn : [ cfg ] };
4810 initEvents : function()
4812 if(!this.store || !this.cm){
4816 //Roo.log('initEvents with ds!!!!');
4818 this.mainBody = this.el.select('tbody', true).first();
4823 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4824 e.on('click', _this.sort, _this);
4827 this.el.on("click", this.onClick, this);
4828 this.el.on("dblclick", this.onDblClick, this);
4830 this.parent().el.setStyle('position', 'relative');
4832 this.footer.parentId = this.id;
4833 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4836 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4838 this.store.on('load', this.onLoad, this);
4839 this.store.on('beforeload', this.onBeforeLoad, this);
4840 this.store.on('update', this.onUpdate, this);
4844 onMouseover : function(e, el)
4846 var cell = Roo.get(el);
4852 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4853 cell = cell.findParent('td', false, true);
4856 var row = cell.findParent('tr', false, true);
4857 var cellIndex = cell.dom.cellIndex;
4858 var rowIndex = row.dom.rowIndex - 1; // start from 0
4860 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4864 onMouseout : function(e, el)
4866 var cell = Roo.get(el);
4872 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4873 cell = cell.findParent('td', false, true);
4876 var row = cell.findParent('tr', false, true);
4877 var cellIndex = cell.dom.cellIndex;
4878 var rowIndex = row.dom.rowIndex - 1; // start from 0
4880 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4884 onClick : function(e, el)
4886 var cell = Roo.get(el);
4888 if(!cell || (!this.CellSelection && !this.RowSelection)){
4893 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4894 cell = cell.findParent('td', false, true);
4897 var row = cell.findParent('tr', false, true);
4898 var cellIndex = cell.dom.cellIndex;
4899 var rowIndex = row.dom.rowIndex - 1;
4901 if(this.CellSelection){
4902 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4905 if(this.RowSelection){
4906 this.fireEvent('rowclick', this, row, rowIndex, e);
4912 onDblClick : function(e,el)
4914 var cell = Roo.get(el);
4916 if(!cell || (!this.CellSelection && !this.RowSelection)){
4920 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4921 cell = cell.findParent('td', false, true);
4924 var row = cell.findParent('tr', false, true);
4925 var cellIndex = cell.dom.cellIndex;
4926 var rowIndex = row.dom.rowIndex - 1;
4928 if(this.CellSelection){
4929 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4932 if(this.RowSelection){
4933 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4937 sort : function(e,el)
4939 var col = Roo.get(el)
4941 if(!col.hasClass('sortable')){
4945 var sort = col.attr('sort');
4948 if(col.hasClass('glyphicon-arrow-up')){
4952 this.store.sortInfo = {field : sort, direction : dir};
4955 Roo.log("calling footer first");
4956 this.footer.onClick('first');
4959 this.store.load({ params : { start : 0 } });
4963 renderHeader : function()
4972 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4974 var config = cm.config[i];
4979 html: cm.getColumnHeader(i)
4982 if(typeof(config.hidden) != 'undefined' && config.hidden){
4983 c.style += ' display:none;';
4986 if(typeof(config.dataIndex) != 'undefined'){
4987 c.sort = config.dataIndex;
4990 if(typeof(config.sortable) != 'undefined' && config.sortable){
4994 // if(typeof(config.align) != 'undefined' && config.align.length){
4995 // c.style += ' text-align:' + config.align + ';';
4998 if(typeof(config.width) != 'undefined'){
4999 c.style += ' width:' + config.width + 'px;';
5008 renderBody : function()
5018 colspan : this.cm.getColumnCount()
5028 renderFooter : function()
5038 colspan : this.cm.getColumnCount()
5052 Roo.log('ds onload');
5057 var ds = this.store;
5059 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5060 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5062 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5063 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5066 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5067 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5071 var tbody = this.mainBody;
5075 if(ds.getCount() > 0){
5076 ds.data.each(function(d,rowIndex){
5077 var row = this.renderRow(cm, ds, rowIndex);
5079 tbody.createChild(row);
5083 if(row.cellObjects.length){
5084 Roo.each(row.cellObjects, function(r){
5085 _this.renderCellObject(r);
5092 Roo.each(this.el.select('tbody td', true).elements, function(e){
5093 e.on('mouseover', _this.onMouseover, _this);
5096 Roo.each(this.el.select('tbody td', true).elements, function(e){
5097 e.on('mouseout', _this.onMouseout, _this);
5100 //if(this.loadMask){
5101 // this.maskEl.hide();
5106 onUpdate : function(ds,record)
5108 this.refreshRow(record);
5110 onRemove : function(ds, record, index, isUpdate){
5111 if(isUpdate !== true){
5112 this.fireEvent("beforerowremoved", this, index, record);
5114 var bt = this.mainBody.dom;
5116 bt.removeChild(bt.rows[index]);
5119 if(isUpdate !== true){
5120 //this.stripeRows(index);
5121 //this.syncRowHeights(index, index);
5123 this.fireEvent("rowremoved", this, index, record);
5128 refreshRow : function(record){
5129 var ds = this.store, index;
5130 if(typeof record == 'number'){
5132 record = ds.getAt(index);
5134 index = ds.indexOf(record);
5136 this.insertRow(ds, index, true);
5137 this.onRemove(ds, record, index+1, true);
5138 //this.syncRowHeights(index, index);
5140 this.fireEvent("rowupdated", this, index, record);
5143 insertRow : function(dm, rowIndex, isUpdate){
5146 this.fireEvent("beforerowsinserted", this, rowIndex);
5148 //var s = this.getScrollState();
5149 var row = this.renderRow(this.cm, this.store, rowIndex);
5150 // insert before rowIndex..
5151 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5156 if(row.cellObjects.length){
5157 Roo.each(row.cellObjects, function(r){
5158 _this.renderCellObject(r);
5163 this.fireEvent("rowsinserted", this, rowIndex);
5164 //this.syncRowHeights(firstRow, lastRow);
5165 //this.stripeRows(firstRow);
5172 getRowDom : function(rowIndex)
5174 // not sure if I need to check this.. but let's do it anyway..
5175 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5176 this.mainBody.dom.rows[rowIndex] : false
5178 // returns the object tree for a tr..
5181 renderRow : function(cm, ds, rowIndex) {
5183 var d = ds.getAt(rowIndex);
5190 var cellObjects = [];
5192 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5193 var config = cm.config[i];
5195 var renderer = cm.getRenderer(i);
5199 if(typeof(renderer) !== 'undefined'){
5200 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5202 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5203 // and are rendered into the cells after the row is rendered - using the id for the element.
5205 if(typeof(value) === 'object'){
5215 rowIndex : rowIndex,
5220 this.fireEvent('rowclass', this, rowcfg);
5224 cls : rowcfg.rowClass,
5226 html: (typeof(value) === 'object') ? '' : value
5233 if(typeof(config.hidden) != 'undefined' && config.hidden){
5234 td.style += ' display:none;';
5237 if(typeof(config.align) != 'undefined' && config.align.length){
5238 td.style += ' text-align:' + config.align + ';';
5241 if(typeof(config.width) != 'undefined'){
5242 td.style += ' width:' + config.width + 'px;';
5249 row.cellObjects = cellObjects;
5257 onBeforeLoad : function()
5259 //Roo.log('ds onBeforeLoad');
5263 //if(this.loadMask){
5264 // this.maskEl.show();
5270 this.el.select('tbody', true).first().dom.innerHTML = '';
5273 getSelectionModel : function(){
5275 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5277 return this.selModel;
5280 * Render the Roo.bootstrap object from renderder
5282 renderCellObject : function(r)
5286 var t = r.cfg.render(r.container);
5289 Roo.each(r.cfg.cn, function(c){
5291 container: t.getChildContainer(),
5294 _this.renderCellObject(child);
5311 * @class Roo.bootstrap.TableCell
5312 * @extends Roo.bootstrap.Component
5313 * Bootstrap TableCell class
5314 * @cfg {String} html cell contain text
5315 * @cfg {String} cls cell class
5316 * @cfg {String} tag cell tag (td|th) default td
5317 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5318 * @cfg {String} align Aligns the content in a cell
5319 * @cfg {String} axis Categorizes cells
5320 * @cfg {String} bgcolor Specifies the background color of a cell
5321 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5322 * @cfg {Number} colspan Specifies the number of columns a cell should span
5323 * @cfg {String} headers Specifies one or more header cells a cell is related to
5324 * @cfg {Number} height Sets the height of a cell
5325 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5326 * @cfg {Number} rowspan Sets the number of rows a cell should span
5327 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5328 * @cfg {String} valign Vertical aligns the content in a cell
5329 * @cfg {Number} width Specifies the width of a cell
5332 * Create a new TableCell
5333 * @param {Object} config The config object
5336 Roo.bootstrap.TableCell = function(config){
5337 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5340 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5360 getAutoCreate : function(){
5361 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5381 cfg.align=this.align
5387 cfg.bgcolor=this.bgcolor
5390 cfg.charoff=this.charoff
5393 cfg.colspan=this.colspan
5396 cfg.headers=this.headers
5399 cfg.height=this.height
5402 cfg.nowrap=this.nowrap
5405 cfg.rowspan=this.rowspan
5408 cfg.scope=this.scope
5411 cfg.valign=this.valign
5414 cfg.width=this.width
5433 * @class Roo.bootstrap.TableRow
5434 * @extends Roo.bootstrap.Component
5435 * Bootstrap TableRow class
5436 * @cfg {String} cls row class
5437 * @cfg {String} align Aligns the content in a table row
5438 * @cfg {String} bgcolor Specifies a background color for a table row
5439 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5440 * @cfg {String} valign Vertical aligns the content in a table row
5443 * Create a new TableRow
5444 * @param {Object} config The config object
5447 Roo.bootstrap.TableRow = function(config){
5448 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5451 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5459 getAutoCreate : function(){
5460 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5470 cfg.align = this.align;
5473 cfg.bgcolor = this.bgcolor;
5476 cfg.charoff = this.charoff;
5479 cfg.valign = this.valign;
5497 * @class Roo.bootstrap.TableBody
5498 * @extends Roo.bootstrap.Component
5499 * Bootstrap TableBody class
5500 * @cfg {String} cls element class
5501 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5502 * @cfg {String} align Aligns the content inside the element
5503 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5504 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5507 * Create a new TableBody
5508 * @param {Object} config The config object
5511 Roo.bootstrap.TableBody = function(config){
5512 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5515 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5523 getAutoCreate : function(){
5524 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5538 cfg.align = this.align;
5541 cfg.charoff = this.charoff;
5544 cfg.valign = this.valign;
5551 // initEvents : function()
5558 // this.store = Roo.factory(this.store, Roo.data);
5559 // this.store.on('load', this.onLoad, this);
5561 // this.store.load();
5565 // onLoad: function ()
5567 // this.fireEvent('load', this);
5577 * Ext JS Library 1.1.1
5578 * Copyright(c) 2006-2007, Ext JS, LLC.
5580 * Originally Released Under LGPL - original licence link has changed is not relivant.
5583 * <script type="text/javascript">
5586 // as we use this in bootstrap.
5587 Roo.namespace('Roo.form');
5589 * @class Roo.form.Action
5590 * Internal Class used to handle form actions
5592 * @param {Roo.form.BasicForm} el The form element or its id
5593 * @param {Object} config Configuration options
5598 // define the action interface
5599 Roo.form.Action = function(form, options){
5601 this.options = options || {};
5604 * Client Validation Failed
5607 Roo.form.Action.CLIENT_INVALID = 'client';
5609 * Server Validation Failed
5612 Roo.form.Action.SERVER_INVALID = 'server';
5614 * Connect to Server Failed
5617 Roo.form.Action.CONNECT_FAILURE = 'connect';
5619 * Reading Data from Server Failed
5622 Roo.form.Action.LOAD_FAILURE = 'load';
5624 Roo.form.Action.prototype = {
5626 failureType : undefined,
5627 response : undefined,
5631 run : function(options){
5636 success : function(response){
5641 handleResponse : function(response){
5645 // default connection failure
5646 failure : function(response){
5648 this.response = response;
5649 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5650 this.form.afterAction(this, false);
5653 processResponse : function(response){
5654 this.response = response;
5655 if(!response.responseText){
5658 this.result = this.handleResponse(response);
5662 // utility functions used internally
5663 getUrl : function(appendParams){
5664 var url = this.options.url || this.form.url || this.form.el.dom.action;
5666 var p = this.getParams();
5668 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5674 getMethod : function(){
5675 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5678 getParams : function(){
5679 var bp = this.form.baseParams;
5680 var p = this.options.params;
5682 if(typeof p == "object"){
5683 p = Roo.urlEncode(Roo.applyIf(p, bp));
5684 }else if(typeof p == 'string' && bp){
5685 p += '&' + Roo.urlEncode(bp);
5688 p = Roo.urlEncode(bp);
5693 createCallback : function(){
5695 success: this.success,
5696 failure: this.failure,
5698 timeout: (this.form.timeout*1000),
5699 upload: this.form.fileUpload ? this.success : undefined
5704 Roo.form.Action.Submit = function(form, options){
5705 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5708 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5711 haveProgress : false,
5712 uploadComplete : false,
5714 // uploadProgress indicator.
5715 uploadProgress : function()
5717 if (!this.form.progressUrl) {
5721 if (!this.haveProgress) {
5722 Roo.MessageBox.progress("Uploading", "Uploading");
5724 if (this.uploadComplete) {
5725 Roo.MessageBox.hide();
5729 this.haveProgress = true;
5731 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5733 var c = new Roo.data.Connection();
5735 url : this.form.progressUrl,
5740 success : function(req){
5741 //console.log(data);
5745 rdata = Roo.decode(req.responseText)
5747 Roo.log("Invalid data from server..");
5751 if (!rdata || !rdata.success) {
5753 Roo.MessageBox.alert(Roo.encode(rdata));
5756 var data = rdata.data;
5758 if (this.uploadComplete) {
5759 Roo.MessageBox.hide();
5764 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5765 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5768 this.uploadProgress.defer(2000,this);
5771 failure: function(data) {
5772 Roo.log('progress url failed ');
5783 // run get Values on the form, so it syncs any secondary forms.
5784 this.form.getValues();
5786 var o = this.options;
5787 var method = this.getMethod();
5788 var isPost = method == 'POST';
5789 if(o.clientValidation === false || this.form.isValid()){
5791 if (this.form.progressUrl) {
5792 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5793 (new Date() * 1) + '' + Math.random());
5798 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5799 form:this.form.el.dom,
5800 url:this.getUrl(!isPost),
5802 params:isPost ? this.getParams() : null,
5803 isUpload: this.form.fileUpload
5806 this.uploadProgress();
5808 }else if (o.clientValidation !== false){ // client validation failed
5809 this.failureType = Roo.form.Action.CLIENT_INVALID;
5810 this.form.afterAction(this, false);
5814 success : function(response)
5816 this.uploadComplete= true;
5817 if (this.haveProgress) {
5818 Roo.MessageBox.hide();
5822 var result = this.processResponse(response);
5823 if(result === true || result.success){
5824 this.form.afterAction(this, true);
5828 this.form.markInvalid(result.errors);
5829 this.failureType = Roo.form.Action.SERVER_INVALID;
5831 this.form.afterAction(this, false);
5833 failure : function(response)
5835 this.uploadComplete= true;
5836 if (this.haveProgress) {
5837 Roo.MessageBox.hide();
5840 this.response = response;
5841 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5842 this.form.afterAction(this, false);
5845 handleResponse : function(response){
5846 if(this.form.errorReader){
5847 var rs = this.form.errorReader.read(response);
5850 for(var i = 0, len = rs.records.length; i < len; i++) {
5851 var r = rs.records[i];
5855 if(errors.length < 1){
5859 success : rs.success,
5865 ret = Roo.decode(response.responseText);
5869 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5879 Roo.form.Action.Load = function(form, options){
5880 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5881 this.reader = this.form.reader;
5884 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5889 Roo.Ajax.request(Roo.apply(
5890 this.createCallback(), {
5891 method:this.getMethod(),
5892 url:this.getUrl(false),
5893 params:this.getParams()
5897 success : function(response){
5899 var result = this.processResponse(response);
5900 if(result === true || !result.success || !result.data){
5901 this.failureType = Roo.form.Action.LOAD_FAILURE;
5902 this.form.afterAction(this, false);
5905 this.form.clearInvalid();
5906 this.form.setValues(result.data);
5907 this.form.afterAction(this, true);
5910 handleResponse : function(response){
5911 if(this.form.reader){
5912 var rs = this.form.reader.read(response);
5913 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5915 success : rs.success,
5919 return Roo.decode(response.responseText);
5923 Roo.form.Action.ACTION_TYPES = {
5924 'load' : Roo.form.Action.Load,
5925 'submit' : Roo.form.Action.Submit
5934 * @class Roo.bootstrap.Form
5935 * @extends Roo.bootstrap.Component
5936 * Bootstrap Form class
5937 * @cfg {String} method GET | POST (default POST)
5938 * @cfg {String} labelAlign top | left (default top)
5939 * @cfg {String} align left | right - for navbars
5944 * @param {Object} config The config object
5948 Roo.bootstrap.Form = function(config){
5949 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5952 * @event clientvalidation
5953 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5954 * @param {Form} this
5955 * @param {Boolean} valid true if the form has passed client-side validation
5957 clientvalidation: true,
5959 * @event beforeaction
5960 * Fires before any action is performed. Return false to cancel the action.
5961 * @param {Form} this
5962 * @param {Action} action The action to be performed
5966 * @event actionfailed
5967 * Fires when an action fails.
5968 * @param {Form} this
5969 * @param {Action} action The action that failed
5971 actionfailed : true,
5973 * @event actioncomplete
5974 * Fires when an action is completed.
5975 * @param {Form} this
5976 * @param {Action} action The action that completed
5978 actioncomplete : true
5983 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5986 * @cfg {String} method
5987 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5992 * The URL to use for form actions if one isn't supplied in the action options.
5995 * @cfg {Boolean} fileUpload
5996 * Set to true if this form is a file upload.
6000 * @cfg {Object} baseParams
6001 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6005 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6009 * @cfg {Sting} align (left|right) for navbar forms
6014 activeAction : null,
6017 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6018 * element by passing it or its id or mask the form itself by passing in true.
6021 waitMsgTarget : false,
6026 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6027 * element by passing it or its id or mask the form itself by passing in true.
6031 getAutoCreate : function(){
6035 method : this.method || 'POST',
6036 id : this.id || Roo.id(),
6039 if (this.parent().xtype.match(/^Nav/)) {
6040 cfg.cls = 'navbar-form navbar-' + this.align;
6044 if (this.labelAlign == 'left' ) {
6045 cfg.cls += ' form-horizontal';
6051 initEvents : function()
6053 this.el.on('submit', this.onSubmit, this);
6054 // this was added as random key presses on the form where triggering form submit.
6055 this.el.on('keypress', function(e) {
6056 if (e.getCharCode() != 13) {
6059 // we might need to allow it for textareas.. and some other items.
6060 // check e.getTarget().
6062 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6066 Roo.log("keypress blocked");
6074 onSubmit : function(e){
6079 * Returns true if client-side validation on the form is successful.
6082 isValid : function(){
6083 var items = this.getItems();
6085 items.each(function(f){
6094 * Returns true if any fields in this form have changed since their original load.
6097 isDirty : function(){
6099 var items = this.getItems();
6100 items.each(function(f){
6110 * Performs a predefined action (submit or load) or custom actions you define on this form.
6111 * @param {String} actionName The name of the action type
6112 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6113 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6114 * accept other config options):
6116 Property Type Description
6117 ---------------- --------------- ----------------------------------------------------------------------------------
6118 url String The url for the action (defaults to the form's url)
6119 method String The form method to use (defaults to the form's method, or POST if not defined)
6120 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6121 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6122 validate the form on the client (defaults to false)
6124 * @return {BasicForm} this
6126 doAction : function(action, options){
6127 if(typeof action == 'string'){
6128 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6130 if(this.fireEvent('beforeaction', this, action) !== false){
6131 this.beforeAction(action);
6132 action.run.defer(100, action);
6138 beforeAction : function(action){
6139 var o = action.options;
6141 // not really supported yet.. ??
6143 //if(this.waitMsgTarget === true){
6144 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6145 //}else if(this.waitMsgTarget){
6146 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6147 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6149 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6155 afterAction : function(action, success){
6156 this.activeAction = null;
6157 var o = action.options;
6159 //if(this.waitMsgTarget === true){
6161 //}else if(this.waitMsgTarget){
6162 // this.waitMsgTarget.unmask();
6164 // Roo.MessageBox.updateProgress(1);
6165 // Roo.MessageBox.hide();
6172 Roo.callback(o.success, o.scope, [this, action]);
6173 this.fireEvent('actioncomplete', this, action);
6177 // failure condition..
6178 // we have a scenario where updates need confirming.
6179 // eg. if a locking scenario exists..
6180 // we look for { errors : { needs_confirm : true }} in the response.
6182 (typeof(action.result) != 'undefined') &&
6183 (typeof(action.result.errors) != 'undefined') &&
6184 (typeof(action.result.errors.needs_confirm) != 'undefined')
6187 Roo.log("not supported yet");
6190 Roo.MessageBox.confirm(
6191 "Change requires confirmation",
6192 action.result.errorMsg,
6197 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6207 Roo.callback(o.failure, o.scope, [this, action]);
6208 // show an error message if no failed handler is set..
6209 if (!this.hasListener('actionfailed')) {
6210 Roo.log("need to add dialog support");
6212 Roo.MessageBox.alert("Error",
6213 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6214 action.result.errorMsg :
6215 "Saving Failed, please check your entries or try again"
6220 this.fireEvent('actionfailed', this, action);
6225 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6226 * @param {String} id The value to search for
6229 findField : function(id){
6230 var items = this.getItems();
6231 var field = items.get(id);
6233 items.each(function(f){
6234 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6241 return field || null;
6244 * Mark fields in this form invalid in bulk.
6245 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6246 * @return {BasicForm} this
6248 markInvalid : function(errors){
6249 if(errors instanceof Array){
6250 for(var i = 0, len = errors.length; i < len; i++){
6251 var fieldError = errors[i];
6252 var f = this.findField(fieldError.id);
6254 f.markInvalid(fieldError.msg);
6260 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6261 field.markInvalid(errors[id]);
6265 //Roo.each(this.childForms || [], function (f) {
6266 // f.markInvalid(errors);
6273 * Set values for fields in this form in bulk.
6274 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6275 * @return {BasicForm} this
6277 setValues : function(values){
6278 if(values instanceof Array){ // array of objects
6279 for(var i = 0, len = values.length; i < len; i++){
6281 var f = this.findField(v.id);
6283 f.setValue(v.value);
6284 if(this.trackResetOnLoad){
6285 f.originalValue = f.getValue();
6289 }else{ // object hash
6292 if(typeof values[id] != 'function' && (field = this.findField(id))){
6294 if (field.setFromData &&
6296 field.displayField &&
6297 // combos' with local stores can
6298 // be queried via setValue()
6299 // to set their value..
6300 (field.store && !field.store.isLocal)
6304 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6305 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6306 field.setFromData(sd);
6309 field.setValue(values[id]);
6313 if(this.trackResetOnLoad){
6314 field.originalValue = field.getValue();
6320 //Roo.each(this.childForms || [], function (f) {
6321 // f.setValues(values);
6328 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6329 * they are returned as an array.
6330 * @param {Boolean} asString
6333 getValues : function(asString){
6334 //if (this.childForms) {
6335 // copy values from the child forms
6336 // Roo.each(this.childForms, function (f) {
6337 // this.setValues(f.getValues());
6343 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6344 if(asString === true){
6347 return Roo.urlDecode(fs);
6351 * Returns the fields in this form as an object with key/value pairs.
6352 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6355 getFieldValues : function(with_hidden)
6357 var items = this.getItems();
6359 items.each(function(f){
6363 var v = f.getValue();
6364 if (f.inputType =='radio') {
6365 if (typeof(ret[f.getName()]) == 'undefined') {
6366 ret[f.getName()] = ''; // empty..
6369 if (!f.el.dom.checked) {
6377 // not sure if this supported any more..
6378 if ((typeof(v) == 'object') && f.getRawValue) {
6379 v = f.getRawValue() ; // dates..
6381 // combo boxes where name != hiddenName...
6382 if (f.name != f.getName()) {
6383 ret[f.name] = f.getRawValue();
6385 ret[f.getName()] = v;
6392 * Clears all invalid messages in this form.
6393 * @return {BasicForm} this
6395 clearInvalid : function(){
6396 var items = this.getItems();
6398 items.each(function(f){
6409 * @return {BasicForm} this
6412 var items = this.getItems();
6413 items.each(function(f){
6417 Roo.each(this.childForms || [], function (f) {
6424 getItems : function()
6426 var r=new Roo.util.MixedCollection(false, function(o){
6427 return o.id || (o.id = Roo.id());
6429 var iter = function(el) {
6436 Roo.each(el.items,function(e) {
6455 * Ext JS Library 1.1.1
6456 * Copyright(c) 2006-2007, Ext JS, LLC.
6458 * Originally Released Under LGPL - original licence link has changed is not relivant.
6461 * <script type="text/javascript">
6464 * @class Roo.form.VTypes
6465 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6468 Roo.form.VTypes = function(){
6469 // closure these in so they are only created once.
6470 var alpha = /^[a-zA-Z_]+$/;
6471 var alphanum = /^[a-zA-Z0-9_]+$/;
6472 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6473 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6475 // All these messages and functions are configurable
6478 * The function used to validate email addresses
6479 * @param {String} value The email address
6481 'email' : function(v){
6482 return email.test(v);
6485 * The error text to display when the email validation function returns false
6488 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6490 * The keystroke filter mask to be applied on email input
6493 'emailMask' : /[a-z0-9_\.\-@]/i,
6496 * The function used to validate URLs
6497 * @param {String} value The URL
6499 'url' : function(v){
6503 * The error text to display when the url validation function returns false
6506 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6509 * The function used to validate alpha values
6510 * @param {String} value The value
6512 'alpha' : function(v){
6513 return alpha.test(v);
6516 * The error text to display when the alpha validation function returns false
6519 'alphaText' : 'This field should only contain letters and _',
6521 * The keystroke filter mask to be applied on alpha input
6524 'alphaMask' : /[a-z_]/i,
6527 * The function used to validate alphanumeric values
6528 * @param {String} value The value
6530 'alphanum' : function(v){
6531 return alphanum.test(v);
6534 * The error text to display when the alphanumeric validation function returns false
6537 'alphanumText' : 'This field should only contain letters, numbers and _',
6539 * The keystroke filter mask to be applied on alphanumeric input
6542 'alphanumMask' : /[a-z0-9_]/i
6552 * @class Roo.bootstrap.Input
6553 * @extends Roo.bootstrap.Component
6554 * Bootstrap Input class
6555 * @cfg {Boolean} disabled is it disabled
6556 * @cfg {String} fieldLabel - the label associated
6557 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6558 * @cfg {String} name name of the input
6559 * @cfg {string} fieldLabel - the label associated
6560 * @cfg {string} inputType - input / file submit ...
6561 * @cfg {string} placeholder - placeholder to put in text.
6562 * @cfg {string} before - input group add on before
6563 * @cfg {string} after - input group add on after
6564 * @cfg {string} size - (lg|sm) or leave empty..
6565 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6566 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6567 * @cfg {Number} md colspan out of 12 for computer-sized screens
6568 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6569 * @cfg {string} value default value of the input
6570 * @cfg {Number} labelWidth set the width of label (0-12)
6571 * @cfg {String} labelAlign (top|left)
6572 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6573 * @cfg {String} align (left|center|right) Default left
6577 * Create a new Input
6578 * @param {Object} config The config object
6581 Roo.bootstrap.Input = function(config){
6582 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6587 * Fires when this field receives input focus.
6588 * @param {Roo.form.Field} this
6593 * Fires when this field loses input focus.
6594 * @param {Roo.form.Field} this
6599 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6600 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6601 * @param {Roo.form.Field} this
6602 * @param {Roo.EventObject} e The event object
6607 * Fires just before the field blurs if the field value has changed.
6608 * @param {Roo.form.Field} this
6609 * @param {Mixed} newValue The new value
6610 * @param {Mixed} oldValue The original value
6615 * Fires after the field has been marked as invalid.
6616 * @param {Roo.form.Field} this
6617 * @param {String} msg The validation message
6622 * Fires after the field has been validated with no errors.
6623 * @param {Roo.form.Field} this
6628 * Fires after the key up
6629 * @param {Roo.form.Field} this
6630 * @param {Roo.EventObject} e The event Object
6636 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6638 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6639 automatic validation (defaults to "keyup").
6641 validationEvent : "keyup",
6643 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6645 validateOnBlur : true,
6647 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6649 validationDelay : 250,
6651 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6653 focusClass : "x-form-focus", // not needed???
6657 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6659 invalidClass : "has-error",
6662 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6664 selectOnFocus : false,
6667 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6671 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6676 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6678 disableKeyFilter : false,
6681 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6685 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6689 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6691 blankText : "This field is required",
6694 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6698 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6700 maxLength : Number.MAX_VALUE,
6702 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6704 minLengthText : "The minimum length for this field is {0}",
6706 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6708 maxLengthText : "The maximum length for this field is {0}",
6712 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6713 * If available, this function will be called only after the basic validators all return true, and will be passed the
6714 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6718 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6719 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6720 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6724 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6747 formatedValue : false,
6749 parentLabelAlign : function()
6752 while (parent.parent()) {
6753 parent = parent.parent();
6754 if (typeof(parent.labelAlign) !='undefined') {
6755 return parent.labelAlign;
6762 getAutoCreate : function(){
6764 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6770 if(this.inputType != 'hidden'){
6771 cfg.cls = 'form-group' //input-group
6777 type : this.inputType,
6779 cls : 'form-control',
6780 placeholder : this.placeholder || ''
6785 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6788 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6789 input.maxLength = this.maxLength;
6792 if (this.disabled) {
6793 input.disabled=true;
6796 if (this.readOnly) {
6797 input.readonly=true;
6801 input.name = this.name;
6804 input.cls += ' input-' + this.size;
6807 ['xs','sm','md','lg'].map(function(size){
6808 if (settings[size]) {
6809 cfg.cls += ' col-' + size + '-' + settings[size];
6813 var inputblock = input;
6815 if (this.before || this.after) {
6818 cls : 'input-group',
6821 if (this.before && typeof(this.before) == 'string') {
6823 inputblock.cn.push({
6825 cls : 'roo-input-before input-group-addon',
6829 if (this.before && typeof(this.before) == 'object') {
6830 this.before = Roo.factory(this.before);
6831 Roo.log(this.before);
6832 inputblock.cn.push({
6834 cls : 'roo-input-before input-group-' +
6835 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6839 inputblock.cn.push(input);
6841 if (this.after && typeof(this.after) == 'string') {
6842 inputblock.cn.push({
6844 cls : 'roo-input-after input-group-addon',
6848 if (this.after && typeof(this.after) == 'object') {
6849 this.after = Roo.factory(this.after);
6850 Roo.log(this.after);
6851 inputblock.cn.push({
6853 cls : 'roo-input-after input-group-' +
6854 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6859 if (align ==='left' && this.fieldLabel.length) {
6860 Roo.log("left and has label");
6866 cls : 'control-label col-sm-' + this.labelWidth,
6867 html : this.fieldLabel
6871 cls : "col-sm-" + (12 - this.labelWidth),
6878 } else if ( this.fieldLabel.length) {
6884 //cls : 'input-group-addon',
6885 html : this.fieldLabel
6895 Roo.log(" no label && no align");
6904 Roo.log('input-parentType: ' + this.parentType);
6906 if (this.parentType === 'Navbar' && this.parent().bar) {
6907 cfg.cls += ' navbar-form';
6915 * return the real input element.
6917 inputEl: function ()
6919 return this.el.select('input.form-control',true).first();
6921 setDisabled : function(v)
6923 var i = this.inputEl().dom;
6925 i.removeAttribute('disabled');
6929 i.setAttribute('disabled','true');
6931 initEvents : function()
6934 this.inputEl().on("keydown" , this.fireKey, this);
6935 this.inputEl().on("focus", this.onFocus, this);
6936 this.inputEl().on("blur", this.onBlur, this);
6938 this.inputEl().relayEvent('keyup', this);
6940 // reference to original value for reset
6941 this.originalValue = this.getValue();
6942 //Roo.form.TextField.superclass.initEvents.call(this);
6943 if(this.validationEvent == 'keyup'){
6944 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6945 this.inputEl().on('keyup', this.filterValidation, this);
6947 else if(this.validationEvent !== false){
6948 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6951 if(this.selectOnFocus){
6952 this.on("focus", this.preFocus, this);
6955 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6956 this.inputEl().on("keypress", this.filterKeys, this);
6959 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6960 this.el.on("click", this.autoSize, this);
6963 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6964 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6967 if (typeof(this.before) == 'object') {
6968 this.before.render(this.el.select('.roo-input-before',true).first());
6970 if (typeof(this.after) == 'object') {
6971 this.after.render(this.el.select('.roo-input-after',true).first());
6976 filterValidation : function(e){
6977 if(!e.isNavKeyPress()){
6978 this.validationTask.delay(this.validationDelay);
6982 * Validates the field value
6983 * @return {Boolean} True if the value is valid, else false
6985 validate : function(){
6986 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6987 if(this.disabled || this.validateValue(this.getRawValue())){
6988 this.clearInvalid();
6996 * Validates a value according to the field's validation rules and marks the field as invalid
6997 * if the validation fails
6998 * @param {Mixed} value The value to validate
6999 * @return {Boolean} True if the value is valid, else false
7001 validateValue : function(value){
7002 if(value.length < 1) { // if it's blank
7003 if(this.allowBlank){
7004 this.clearInvalid();
7007 this.markInvalid(this.blankText);
7011 if(value.length < this.minLength){
7012 this.markInvalid(String.format(this.minLengthText, this.minLength));
7015 if(value.length > this.maxLength){
7016 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7020 var vt = Roo.form.VTypes;
7021 if(!vt[this.vtype](value, this)){
7022 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7026 if(typeof this.validator == "function"){
7027 var msg = this.validator(value);
7029 this.markInvalid(msg);
7033 if(this.regex && !this.regex.test(value)){
7034 this.markInvalid(this.regexText);
7043 fireKey : function(e){
7044 //Roo.log('field ' + e.getKey());
7045 if(e.isNavKeyPress()){
7046 this.fireEvent("specialkey", this, e);
7049 focus : function (selectText){
7051 this.inputEl().focus();
7052 if(selectText === true){
7053 this.inputEl().dom.select();
7059 onFocus : function(){
7060 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7061 // this.el.addClass(this.focusClass);
7064 this.hasFocus = true;
7065 this.startValue = this.getValue();
7066 this.fireEvent("focus", this);
7070 beforeBlur : Roo.emptyFn,
7074 onBlur : function(){
7076 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7077 //this.el.removeClass(this.focusClass);
7079 this.hasFocus = false;
7080 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7083 var v = this.getValue();
7084 if(String(v) !== String(this.startValue)){
7085 this.fireEvent('change', this, v, this.startValue);
7087 this.fireEvent("blur", this);
7091 * Resets the current field value to the originally loaded value and clears any validation messages
7094 this.setValue(this.originalValue);
7095 this.clearInvalid();
7098 * Returns the name of the field
7099 * @return {Mixed} name The name field
7101 getName: function(){
7105 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7106 * @return {Mixed} value The field value
7108 getValue : function(){
7110 var v = this.inputEl().getValue();
7115 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7116 * @return {Mixed} value The field value
7118 getRawValue : function(){
7119 var v = this.inputEl().getValue();
7125 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7126 * @param {Mixed} value The value to set
7128 setRawValue : function(v){
7129 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7132 selectText : function(start, end){
7133 var v = this.getRawValue();
7135 start = start === undefined ? 0 : start;
7136 end = end === undefined ? v.length : end;
7137 var d = this.inputEl().dom;
7138 if(d.setSelectionRange){
7139 d.setSelectionRange(start, end);
7140 }else if(d.createTextRange){
7141 var range = d.createTextRange();
7142 range.moveStart("character", start);
7143 range.moveEnd("character", v.length-end);
7150 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7151 * @param {Mixed} value The value to set
7153 setValue : function(v){
7156 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7162 processValue : function(value){
7163 if(this.stripCharsRe){
7164 var newValue = value.replace(this.stripCharsRe, '');
7165 if(newValue !== value){
7166 this.setRawValue(newValue);
7173 preFocus : function(){
7175 if(this.selectOnFocus){
7176 this.inputEl().dom.select();
7179 filterKeys : function(e){
7181 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7184 var c = e.getCharCode(), cc = String.fromCharCode(c);
7185 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7188 if(!this.maskRe.test(cc)){
7193 * Clear any invalid styles/messages for this field
7195 clearInvalid : function(){
7197 if(!this.el || this.preventMark){ // not rendered
7200 this.el.removeClass(this.invalidClass);
7202 switch(this.msgTarget){
7204 this.el.dom.qtip = '';
7207 this.el.dom.title = '';
7211 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7216 this.errorIcon.dom.qtip = '';
7217 this.errorIcon.hide();
7218 this.un('resize', this.alignErrorIcon, this);
7222 var t = Roo.getDom(this.msgTarget);
7224 t.style.display = 'none';
7228 this.fireEvent('valid', this);
7231 * Mark this field as invalid
7232 * @param {String} msg The validation message
7234 markInvalid : function(msg){
7235 if(!this.el || this.preventMark){ // not rendered
7238 this.el.addClass(this.invalidClass);
7240 msg = msg || this.invalidText;
7241 switch(this.msgTarget){
7243 this.el.dom.qtip = msg;
7244 this.el.dom.qclass = 'x-form-invalid-tip';
7245 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7246 Roo.QuickTips.enable();
7250 this.el.dom.title = msg;
7254 var elp = this.el.findParent('.x-form-element', 5, true);
7255 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7256 this.errorEl.setWidth(elp.getWidth(true)-20);
7258 this.errorEl.update(msg);
7259 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7262 if(!this.errorIcon){
7263 var elp = this.el.findParent('.x-form-element', 5, true);
7264 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7266 this.alignErrorIcon();
7267 this.errorIcon.dom.qtip = msg;
7268 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7269 this.errorIcon.show();
7270 this.on('resize', this.alignErrorIcon, this);
7273 var t = Roo.getDom(this.msgTarget);
7275 t.style.display = this.msgDisplay;
7279 this.fireEvent('invalid', this, msg);
7282 SafariOnKeyDown : function(event)
7284 // this is a workaround for a password hang bug on chrome/ webkit.
7286 var isSelectAll = false;
7288 if(this.inputEl().dom.selectionEnd > 0){
7289 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7291 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7292 event.preventDefault();
7297 if(isSelectAll){ // backspace and delete key
7299 event.preventDefault();
7300 // this is very hacky as keydown always get's upper case.
7302 var cc = String.fromCharCode(event.getCharCode());
7303 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7307 adjustWidth : function(tag, w){
7308 tag = tag.toLowerCase();
7309 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7310 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7314 if(tag == 'textarea'){
7317 }else if(Roo.isOpera){
7321 if(tag == 'textarea'){
7340 * @class Roo.bootstrap.TextArea
7341 * @extends Roo.bootstrap.Input
7342 * Bootstrap TextArea class
7343 * @cfg {Number} cols Specifies the visible width of a text area
7344 * @cfg {Number} rows Specifies the visible number of lines in a text area
7345 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7346 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7347 * @cfg {string} html text
7350 * Create a new TextArea
7351 * @param {Object} config The config object
7354 Roo.bootstrap.TextArea = function(config){
7355 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7359 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7369 getAutoCreate : function(){
7371 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7382 value : this.value || '',
7383 html: this.html || '',
7384 cls : 'form-control',
7385 placeholder : this.placeholder || ''
7389 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7390 input.maxLength = this.maxLength;
7394 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7398 input.cols = this.cols;
7401 if (this.readOnly) {
7402 input.readonly = true;
7406 input.name = this.name;
7410 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7414 ['xs','sm','md','lg'].map(function(size){
7415 if (settings[size]) {
7416 cfg.cls += ' col-' + size + '-' + settings[size];
7420 var inputblock = input;
7422 if (this.before || this.after) {
7425 cls : 'input-group',
7429 inputblock.cn.push({
7431 cls : 'input-group-addon',
7435 inputblock.cn.push(input);
7437 inputblock.cn.push({
7439 cls : 'input-group-addon',
7446 if (align ==='left' && this.fieldLabel.length) {
7447 Roo.log("left and has label");
7453 cls : 'control-label col-sm-' + this.labelWidth,
7454 html : this.fieldLabel
7458 cls : "col-sm-" + (12 - this.labelWidth),
7465 } else if ( this.fieldLabel.length) {
7471 //cls : 'input-group-addon',
7472 html : this.fieldLabel
7482 Roo.log(" no label && no align");
7492 if (this.disabled) {
7493 input.disabled=true;
7500 * return the real textarea element.
7502 inputEl: function ()
7504 return this.el.select('textarea.form-control',true).first();
7512 * trigger field - base class for combo..
7517 * @class Roo.bootstrap.TriggerField
7518 * @extends Roo.bootstrap.Input
7519 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7520 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7521 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7522 * for which you can provide a custom implementation. For example:
7524 var trigger = new Roo.bootstrap.TriggerField();
7525 trigger.onTriggerClick = myTriggerFn;
7526 trigger.applyTo('my-field');
7529 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7530 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7531 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7532 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7534 * Create a new TriggerField.
7535 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7536 * to the base TextField)
7538 Roo.bootstrap.TriggerField = function(config){
7539 this.mimicing = false;
7540 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7543 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7545 * @cfg {String} triggerClass A CSS class to apply to the trigger
7548 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7552 /** @cfg {Boolean} grow @hide */
7553 /** @cfg {Number} growMin @hide */
7554 /** @cfg {Number} growMax @hide */
7560 autoSize: Roo.emptyFn,
7567 actionMode : 'wrap',
7571 getAutoCreate : function(){
7573 var parent = this.parent();
7575 var align = this.labelAlign || this.parentLabelAlign();
7580 cls: 'form-group' //input-group
7587 type : this.inputType,
7588 cls : 'form-control',
7589 autocomplete: 'off',
7590 placeholder : this.placeholder || ''
7594 input.name = this.name;
7597 input.cls += ' input-' + this.size;
7600 if (this.disabled) {
7601 input.disabled=true;
7604 var inputblock = input;
7606 if (this.before || this.after) {
7609 cls : 'input-group',
7613 inputblock.cn.push({
7615 cls : 'input-group-addon',
7619 inputblock.cn.push(input);
7621 inputblock.cn.push({
7623 cls : 'input-group-addon',
7636 cls: 'form-hidden-field'
7644 Roo.log('multiple');
7652 cls: 'form-hidden-field'
7656 cls: 'select2-choices',
7660 cls: 'select2-search-field',
7673 cls: 'select2-container input-group',
7678 cls: 'typeahead typeahead-long dropdown-menu',
7679 style: 'display:none'
7687 cls : 'input-group-addon btn dropdown-toggle',
7695 cls: 'combobox-clear',
7709 combobox.cls += ' select2-container-multi';
7712 if (align ==='left' && this.fieldLabel.length) {
7714 Roo.log("left and has label");
7720 cls : 'control-label col-sm-' + this.labelWidth,
7721 html : this.fieldLabel
7725 cls : "col-sm-" + (12 - this.labelWidth),
7732 } else if ( this.fieldLabel.length) {
7738 //cls : 'input-group-addon',
7739 html : this.fieldLabel
7749 Roo.log(" no label && no align");
7756 ['xs','sm','md','lg'].map(function(size){
7757 if (settings[size]) {
7758 cfg.cls += ' col-' + size + '-' + settings[size];
7769 onResize : function(w, h){
7770 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7771 // if(typeof w == 'number'){
7772 // var x = w - this.trigger.getWidth();
7773 // this.inputEl().setWidth(this.adjustWidth('input', x));
7774 // this.trigger.setStyle('left', x+'px');
7779 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7782 getResizeEl : function(){
7783 return this.inputEl();
7787 getPositionEl : function(){
7788 return this.inputEl();
7792 alignErrorIcon : function(){
7793 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7797 initEvents : function(){
7799 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7800 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7802 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7803 if(this.hideTrigger){
7804 this.trigger.setDisplayed(false);
7806 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7810 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7813 //this.trigger.addClassOnOver('x-form-trigger-over');
7814 //this.trigger.addClassOnClick('x-form-trigger-click');
7817 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7822 initTrigger : function(){
7827 onDestroy : function(){
7829 this.trigger.removeAllListeners();
7830 // this.trigger.remove();
7833 // this.wrap.remove();
7835 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7839 onFocus : function(){
7840 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7843 this.wrap.addClass('x-trigger-wrap-focus');
7844 this.mimicing = true;
7845 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7846 if(this.monitorTab){
7847 this.el.on("keydown", this.checkTab, this);
7854 checkTab : function(e){
7855 if(e.getKey() == e.TAB){
7861 onBlur : function(){
7866 mimicBlur : function(e, t){
7868 if(!this.wrap.contains(t) && this.validateBlur()){
7875 triggerBlur : function(){
7876 this.mimicing = false;
7877 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7878 if(this.monitorTab){
7879 this.el.un("keydown", this.checkTab, this);
7881 //this.wrap.removeClass('x-trigger-wrap-focus');
7882 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7886 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7887 validateBlur : function(e, t){
7892 onDisable : function(){
7893 this.inputEl().dom.disabled = true;
7894 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7896 // this.wrap.addClass('x-item-disabled');
7901 onEnable : function(){
7902 this.inputEl().dom.disabled = false;
7903 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7905 // this.el.removeClass('x-item-disabled');
7910 onShow : function(){
7911 var ae = this.getActionEl();
7914 ae.dom.style.display = '';
7915 ae.dom.style.visibility = 'visible';
7921 onHide : function(){
7922 var ae = this.getActionEl();
7923 ae.dom.style.display = 'none';
7927 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7928 * by an implementing function.
7930 * @param {EventObject} e
7932 onTriggerClick : Roo.emptyFn
7936 * Ext JS Library 1.1.1
7937 * Copyright(c) 2006-2007, Ext JS, LLC.
7939 * Originally Released Under LGPL - original licence link has changed is not relivant.
7942 * <script type="text/javascript">
7947 * @class Roo.data.SortTypes
7949 * Defines the default sorting (casting?) comparison functions used when sorting data.
7951 Roo.data.SortTypes = {
7953 * Default sort that does nothing
7954 * @param {Mixed} s The value being converted
7955 * @return {Mixed} The comparison value
7962 * The regular expression used to strip tags
7966 stripTagsRE : /<\/?[^>]+>/gi,
7969 * Strips all HTML tags to sort on text only
7970 * @param {Mixed} s The value being converted
7971 * @return {String} The comparison value
7973 asText : function(s){
7974 return String(s).replace(this.stripTagsRE, "");
7978 * Strips all HTML tags to sort on text only - Case insensitive
7979 * @param {Mixed} s The value being converted
7980 * @return {String} The comparison value
7982 asUCText : function(s){
7983 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7987 * Case insensitive string
7988 * @param {Mixed} s The value being converted
7989 * @return {String} The comparison value
7991 asUCString : function(s) {
7992 return String(s).toUpperCase();
7997 * @param {Mixed} s The value being converted
7998 * @return {Number} The comparison value
8000 asDate : function(s) {
8004 if(s instanceof Date){
8007 return Date.parse(String(s));
8012 * @param {Mixed} s The value being converted
8013 * @return {Float} The comparison value
8015 asFloat : function(s) {
8016 var val = parseFloat(String(s).replace(/,/g, ""));
8017 if(isNaN(val)) val = 0;
8023 * @param {Mixed} s The value being converted
8024 * @return {Number} The comparison value
8026 asInt : function(s) {
8027 var val = parseInt(String(s).replace(/,/g, ""));
8028 if(isNaN(val)) val = 0;
8033 * Ext JS Library 1.1.1
8034 * Copyright(c) 2006-2007, Ext JS, LLC.
8036 * Originally Released Under LGPL - original licence link has changed is not relivant.
8039 * <script type="text/javascript">
8043 * @class Roo.data.Record
8044 * Instances of this class encapsulate both record <em>definition</em> information, and record
8045 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8046 * to access Records cached in an {@link Roo.data.Store} object.<br>
8048 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8049 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8052 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8054 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8055 * {@link #create}. The parameters are the same.
8056 * @param {Array} data An associative Array of data values keyed by the field name.
8057 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8058 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8059 * not specified an integer id is generated.
8061 Roo.data.Record = function(data, id){
8062 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8067 * Generate a constructor for a specific record layout.
8068 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8069 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8070 * Each field definition object may contain the following properties: <ul>
8071 * <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,
8072 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8073 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8074 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8075 * is being used, then this is a string containing the javascript expression to reference the data relative to
8076 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8077 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8078 * this may be omitted.</p></li>
8079 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8080 * <ul><li>auto (Default, implies no conversion)</li>
8085 * <li>date</li></ul></p></li>
8086 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8087 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8088 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8089 * by the Reader into an object that will be stored in the Record. It is passed the
8090 * following parameters:<ul>
8091 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8093 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8095 * <br>usage:<br><pre><code>
8096 var TopicRecord = Roo.data.Record.create(
8097 {name: 'title', mapping: 'topic_title'},
8098 {name: 'author', mapping: 'username'},
8099 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8100 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8101 {name: 'lastPoster', mapping: 'user2'},
8102 {name: 'excerpt', mapping: 'post_text'}
8105 var myNewRecord = new TopicRecord({
8106 title: 'Do my job please',
8109 lastPost: new Date(),
8110 lastPoster: 'Animal',
8111 excerpt: 'No way dude!'
8113 myStore.add(myNewRecord);
8118 Roo.data.Record.create = function(o){
8120 f.superclass.constructor.apply(this, arguments);
8122 Roo.extend(f, Roo.data.Record);
8123 var p = f.prototype;
8124 p.fields = new Roo.util.MixedCollection(false, function(field){
8127 for(var i = 0, len = o.length; i < len; i++){
8128 p.fields.add(new Roo.data.Field(o[i]));
8130 f.getField = function(name){
8131 return p.fields.get(name);
8136 Roo.data.Record.AUTO_ID = 1000;
8137 Roo.data.Record.EDIT = 'edit';
8138 Roo.data.Record.REJECT = 'reject';
8139 Roo.data.Record.COMMIT = 'commit';
8141 Roo.data.Record.prototype = {
8143 * Readonly flag - true if this record has been modified.
8152 join : function(store){
8157 * Set the named field to the specified value.
8158 * @param {String} name The name of the field to set.
8159 * @param {Object} value The value to set the field to.
8161 set : function(name, value){
8162 if(this.data[name] == value){
8169 if(typeof this.modified[name] == 'undefined'){
8170 this.modified[name] = this.data[name];
8172 this.data[name] = value;
8173 if(!this.editing && this.store){
8174 this.store.afterEdit(this);
8179 * Get the value of the named field.
8180 * @param {String} name The name of the field to get the value of.
8181 * @return {Object} The value of the field.
8183 get : function(name){
8184 return this.data[name];
8188 beginEdit : function(){
8189 this.editing = true;
8194 cancelEdit : function(){
8195 this.editing = false;
8196 delete this.modified;
8200 endEdit : function(){
8201 this.editing = false;
8202 if(this.dirty && this.store){
8203 this.store.afterEdit(this);
8208 * Usually called by the {@link Roo.data.Store} which owns the Record.
8209 * Rejects all changes made to the Record since either creation, or the last commit operation.
8210 * Modified fields are reverted to their original values.
8212 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8213 * of reject operations.
8215 reject : function(){
8216 var m = this.modified;
8218 if(typeof m[n] != "function"){
8219 this.data[n] = m[n];
8223 delete this.modified;
8224 this.editing = false;
8226 this.store.afterReject(this);
8231 * Usually called by the {@link Roo.data.Store} which owns the Record.
8232 * Commits all changes made to the Record since either creation, or the last commit operation.
8234 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8235 * of commit operations.
8237 commit : function(){
8239 delete this.modified;
8240 this.editing = false;
8242 this.store.afterCommit(this);
8247 hasError : function(){
8248 return this.error != null;
8252 clearError : function(){
8257 * Creates a copy of this record.
8258 * @param {String} id (optional) A new record id if you don't want to use this record's id
8261 copy : function(newId) {
8262 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8266 * Ext JS Library 1.1.1
8267 * Copyright(c) 2006-2007, Ext JS, LLC.
8269 * Originally Released Under LGPL - original licence link has changed is not relivant.
8272 * <script type="text/javascript">
8278 * @class Roo.data.Store
8279 * @extends Roo.util.Observable
8280 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8281 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8283 * 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
8284 * has no knowledge of the format of the data returned by the Proxy.<br>
8286 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8287 * instances from the data object. These records are cached and made available through accessor functions.
8289 * Creates a new Store.
8290 * @param {Object} config A config object containing the objects needed for the Store to access data,
8291 * and read the data into Records.
8293 Roo.data.Store = function(config){
8294 this.data = new Roo.util.MixedCollection(false);
8295 this.data.getKey = function(o){
8298 this.baseParams = {};
8305 "multisort" : "_multisort"
8308 if(config && config.data){
8309 this.inlineData = config.data;
8313 Roo.apply(this, config);
8315 if(this.reader){ // reader passed
8316 this.reader = Roo.factory(this.reader, Roo.data);
8317 this.reader.xmodule = this.xmodule || false;
8318 if(!this.recordType){
8319 this.recordType = this.reader.recordType;
8321 if(this.reader.onMetaChange){
8322 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8326 if(this.recordType){
8327 this.fields = this.recordType.prototype.fields;
8333 * @event datachanged
8334 * Fires when the data cache has changed, and a widget which is using this Store
8335 * as a Record cache should refresh its view.
8336 * @param {Store} this
8341 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8342 * @param {Store} this
8343 * @param {Object} meta The JSON metadata
8348 * Fires when Records have been added to the Store
8349 * @param {Store} this
8350 * @param {Roo.data.Record[]} records The array of Records added
8351 * @param {Number} index The index at which the record(s) were added
8356 * Fires when a Record has been removed from the Store
8357 * @param {Store} this
8358 * @param {Roo.data.Record} record The Record that was removed
8359 * @param {Number} index The index at which the record was removed
8364 * Fires when a Record has been updated
8365 * @param {Store} this
8366 * @param {Roo.data.Record} record The Record that was updated
8367 * @param {String} operation The update operation being performed. Value may be one of:
8369 Roo.data.Record.EDIT
8370 Roo.data.Record.REJECT
8371 Roo.data.Record.COMMIT
8377 * Fires when the data cache has been cleared.
8378 * @param {Store} this
8383 * Fires before a request is made for a new data object. If the beforeload handler returns false
8384 * the load action will be canceled.
8385 * @param {Store} this
8386 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8390 * @event beforeloadadd
8391 * Fires after a new set of Records has been loaded.
8392 * @param {Store} this
8393 * @param {Roo.data.Record[]} records The Records that were loaded
8394 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8396 beforeloadadd : true,
8399 * Fires after a new set of Records has been loaded, before they are added to the store.
8400 * @param {Store} this
8401 * @param {Roo.data.Record[]} records The Records that were loaded
8402 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8403 * @params {Object} return from reader
8407 * @event loadexception
8408 * Fires if an exception occurs in the Proxy during loading.
8409 * Called with the signature of the Proxy's "loadexception" event.
8410 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8413 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8414 * @param {Object} load options
8415 * @param {Object} jsonData from your request (normally this contains the Exception)
8417 loadexception : true
8421 this.proxy = Roo.factory(this.proxy, Roo.data);
8422 this.proxy.xmodule = this.xmodule || false;
8423 this.relayEvents(this.proxy, ["loadexception"]);
8425 this.sortToggle = {};
8426 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8428 Roo.data.Store.superclass.constructor.call(this);
8430 if(this.inlineData){
8431 this.loadData(this.inlineData);
8432 delete this.inlineData;
8436 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8438 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8439 * without a remote query - used by combo/forms at present.
8443 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8446 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8449 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8450 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8453 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8454 * on any HTTP request
8457 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8460 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8464 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8465 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8470 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8471 * loaded or when a record is removed. (defaults to false).
8473 pruneModifiedRecords : false,
8479 * Add Records to the Store and fires the add event.
8480 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8482 add : function(records){
8483 records = [].concat(records);
8484 for(var i = 0, len = records.length; i < len; i++){
8485 records[i].join(this);
8487 var index = this.data.length;
8488 this.data.addAll(records);
8489 this.fireEvent("add", this, records, index);
8493 * Remove a Record from the Store and fires the remove event.
8494 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8496 remove : function(record){
8497 var index = this.data.indexOf(record);
8498 this.data.removeAt(index);
8499 if(this.pruneModifiedRecords){
8500 this.modified.remove(record);
8502 this.fireEvent("remove", this, record, index);
8506 * Remove all Records from the Store and fires the clear event.
8508 removeAll : function(){
8510 if(this.pruneModifiedRecords){
8513 this.fireEvent("clear", this);
8517 * Inserts Records to the Store at the given index and fires the add event.
8518 * @param {Number} index The start index at which to insert the passed Records.
8519 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8521 insert : function(index, records){
8522 records = [].concat(records);
8523 for(var i = 0, len = records.length; i < len; i++){
8524 this.data.insert(index, records[i]);
8525 records[i].join(this);
8527 this.fireEvent("add", this, records, index);
8531 * Get the index within the cache of the passed Record.
8532 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8533 * @return {Number} The index of the passed Record. Returns -1 if not found.
8535 indexOf : function(record){
8536 return this.data.indexOf(record);
8540 * Get the index within the cache of the Record with the passed id.
8541 * @param {String} id The id of the Record to find.
8542 * @return {Number} The index of the Record. Returns -1 if not found.
8544 indexOfId : function(id){
8545 return this.data.indexOfKey(id);
8549 * Get the Record with the specified id.
8550 * @param {String} id The id of the Record to find.
8551 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8553 getById : function(id){
8554 return this.data.key(id);
8558 * Get the Record at the specified index.
8559 * @param {Number} index The index of the Record to find.
8560 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8562 getAt : function(index){
8563 return this.data.itemAt(index);
8567 * Returns a range of Records between specified indices.
8568 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8569 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8570 * @return {Roo.data.Record[]} An array of Records
8572 getRange : function(start, end){
8573 return this.data.getRange(start, end);
8577 storeOptions : function(o){
8578 o = Roo.apply({}, o);
8581 this.lastOptions = o;
8585 * Loads the Record cache from the configured Proxy using the configured Reader.
8587 * If using remote paging, then the first load call must specify the <em>start</em>
8588 * and <em>limit</em> properties in the options.params property to establish the initial
8589 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8591 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8592 * and this call will return before the new data has been loaded. Perform any post-processing
8593 * in a callback function, or in a "load" event handler.</strong>
8595 * @param {Object} options An object containing properties which control loading options:<ul>
8596 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8597 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8598 * passed the following arguments:<ul>
8599 * <li>r : Roo.data.Record[]</li>
8600 * <li>options: Options object from the load call</li>
8601 * <li>success: Boolean success indicator</li></ul></li>
8602 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8603 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8606 load : function(options){
8607 options = options || {};
8608 if(this.fireEvent("beforeload", this, options) !== false){
8609 this.storeOptions(options);
8610 var p = Roo.apply(options.params || {}, this.baseParams);
8611 // if meta was not loaded from remote source.. try requesting it.
8612 if (!this.reader.metaFromRemote) {
8615 if(this.sortInfo && this.remoteSort){
8616 var pn = this.paramNames;
8617 p[pn["sort"]] = this.sortInfo.field;
8618 p[pn["dir"]] = this.sortInfo.direction;
8620 if (this.multiSort) {
8621 var pn = this.paramNames;
8622 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8625 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8630 * Reloads the Record cache from the configured Proxy using the configured Reader and
8631 * the options from the last load operation performed.
8632 * @param {Object} options (optional) An object containing properties which may override the options
8633 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8634 * the most recently used options are reused).
8636 reload : function(options){
8637 this.load(Roo.applyIf(options||{}, this.lastOptions));
8641 // Called as a callback by the Reader during a load operation.
8642 loadRecords : function(o, options, success){
8643 if(!o || success === false){
8644 if(success !== false){
8645 this.fireEvent("load", this, [], options, o);
8647 if(options.callback){
8648 options.callback.call(options.scope || this, [], options, false);
8652 // if data returned failure - throw an exception.
8653 if (o.success === false) {
8654 // show a message if no listener is registered.
8655 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8656 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8658 // loadmask wil be hooked into this..
8659 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8662 var r = o.records, t = o.totalRecords || r.length;
8664 this.fireEvent("beforeloadadd", this, r, options, o);
8666 if(!options || options.add !== true){
8667 if(this.pruneModifiedRecords){
8670 for(var i = 0, len = r.length; i < len; i++){
8674 this.data = this.snapshot;
8675 delete this.snapshot;
8678 this.data.addAll(r);
8679 this.totalLength = t;
8681 this.fireEvent("datachanged", this);
8683 this.totalLength = Math.max(t, this.data.length+r.length);
8686 this.fireEvent("load", this, r, options, o);
8687 if(options.callback){
8688 options.callback.call(options.scope || this, r, options, true);
8694 * Loads data from a passed data block. A Reader which understands the format of the data
8695 * must have been configured in the constructor.
8696 * @param {Object} data The data block from which to read the Records. The format of the data expected
8697 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8698 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8700 loadData : function(o, append){
8701 var r = this.reader.readRecords(o);
8702 this.loadRecords(r, {add: append}, true);
8706 * Gets the number of cached records.
8708 * <em>If using paging, this may not be the total size of the dataset. If the data object
8709 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8710 * the data set size</em>
8712 getCount : function(){
8713 return this.data.length || 0;
8717 * Gets the total number of records in the dataset as returned by the server.
8719 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8720 * the dataset size</em>
8722 getTotalCount : function(){
8723 return this.totalLength || 0;
8727 * Returns the sort state of the Store as an object with two properties:
8729 field {String} The name of the field by which the Records are sorted
8730 direction {String} The sort order, "ASC" or "DESC"
8733 getSortState : function(){
8734 return this.sortInfo;
8738 applySort : function(){
8739 if(this.sortInfo && !this.remoteSort){
8740 var s = this.sortInfo, f = s.field;
8741 var st = this.fields.get(f).sortType;
8742 var fn = function(r1, r2){
8743 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8744 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8746 this.data.sort(s.direction, fn);
8747 if(this.snapshot && this.snapshot != this.data){
8748 this.snapshot.sort(s.direction, fn);
8754 * Sets the default sort column and order to be used by the next load operation.
8755 * @param {String} fieldName The name of the field to sort by.
8756 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8758 setDefaultSort : function(field, dir){
8759 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8764 * If remote sorting is used, the sort is performed on the server, and the cache is
8765 * reloaded. If local sorting is used, the cache is sorted internally.
8766 * @param {String} fieldName The name of the field to sort by.
8767 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8769 sort : function(fieldName, dir){
8770 var f = this.fields.get(fieldName);
8772 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8774 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8775 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8780 this.sortToggle[f.name] = dir;
8781 this.sortInfo = {field: f.name, direction: dir};
8782 if(!this.remoteSort){
8784 this.fireEvent("datachanged", this);
8786 this.load(this.lastOptions);
8791 * Calls the specified function for each of the Records in the cache.
8792 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8793 * Returning <em>false</em> aborts and exits the iteration.
8794 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8796 each : function(fn, scope){
8797 this.data.each(fn, scope);
8801 * Gets all records modified since the last commit. Modified records are persisted across load operations
8802 * (e.g., during paging).
8803 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8805 getModifiedRecords : function(){
8806 return this.modified;
8810 createFilterFn : function(property, value, anyMatch){
8811 if(!value.exec){ // not a regex
8812 value = String(value);
8813 if(value.length == 0){
8816 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8819 return value.test(r.data[property]);
8824 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8825 * @param {String} property A field on your records
8826 * @param {Number} start The record index to start at (defaults to 0)
8827 * @param {Number} end The last record index to include (defaults to length - 1)
8828 * @return {Number} The sum
8830 sum : function(property, start, end){
8831 var rs = this.data.items, v = 0;
8833 end = (end || end === 0) ? end : rs.length-1;
8835 for(var i = start; i <= end; i++){
8836 v += (rs[i].data[property] || 0);
8842 * Filter the records by a specified property.
8843 * @param {String} field A field on your records
8844 * @param {String/RegExp} value Either a string that the field
8845 * should start with or a RegExp to test against the field
8846 * @param {Boolean} anyMatch True to match any part not just the beginning
8848 filter : function(property, value, anyMatch){
8849 var fn = this.createFilterFn(property, value, anyMatch);
8850 return fn ? this.filterBy(fn) : this.clearFilter();
8854 * Filter by a function. The specified function will be called with each
8855 * record in this data source. If the function returns true the record is included,
8856 * otherwise it is filtered.
8857 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8858 * @param {Object} scope (optional) The scope of the function (defaults to this)
8860 filterBy : function(fn, scope){
8861 this.snapshot = this.snapshot || this.data;
8862 this.data = this.queryBy(fn, scope||this);
8863 this.fireEvent("datachanged", this);
8867 * Query the records by a specified property.
8868 * @param {String} field A field on your records
8869 * @param {String/RegExp} value Either a string that the field
8870 * should start with or a RegExp to test against the field
8871 * @param {Boolean} anyMatch True to match any part not just the beginning
8872 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8874 query : function(property, value, anyMatch){
8875 var fn = this.createFilterFn(property, value, anyMatch);
8876 return fn ? this.queryBy(fn) : this.data.clone();
8880 * Query by a function. The specified function will be called with each
8881 * record in this data source. If the function returns true the record is included
8883 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8884 * @param {Object} scope (optional) The scope of the function (defaults to this)
8885 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8887 queryBy : function(fn, scope){
8888 var data = this.snapshot || this.data;
8889 return data.filterBy(fn, scope||this);
8893 * Collects unique values for a particular dataIndex from this store.
8894 * @param {String} dataIndex The property to collect
8895 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8896 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8897 * @return {Array} An array of the unique values
8899 collect : function(dataIndex, allowNull, bypassFilter){
8900 var d = (bypassFilter === true && this.snapshot) ?
8901 this.snapshot.items : this.data.items;
8902 var v, sv, r = [], l = {};
8903 for(var i = 0, len = d.length; i < len; i++){
8904 v = d[i].data[dataIndex];
8906 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8915 * Revert to a view of the Record cache with no filtering applied.
8916 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8918 clearFilter : function(suppressEvent){
8919 if(this.snapshot && this.snapshot != this.data){
8920 this.data = this.snapshot;
8921 delete this.snapshot;
8922 if(suppressEvent !== true){
8923 this.fireEvent("datachanged", this);
8929 afterEdit : function(record){
8930 if(this.modified.indexOf(record) == -1){
8931 this.modified.push(record);
8933 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8937 afterReject : function(record){
8938 this.modified.remove(record);
8939 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8943 afterCommit : function(record){
8944 this.modified.remove(record);
8945 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8949 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8950 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8952 commitChanges : function(){
8953 var m = this.modified.slice(0);
8955 for(var i = 0, len = m.length; i < len; i++){
8961 * Cancel outstanding changes on all changed records.
8963 rejectChanges : function(){
8964 var m = this.modified.slice(0);
8966 for(var i = 0, len = m.length; i < len; i++){
8971 onMetaChange : function(meta, rtype, o){
8972 this.recordType = rtype;
8973 this.fields = rtype.prototype.fields;
8974 delete this.snapshot;
8975 this.sortInfo = meta.sortInfo || this.sortInfo;
8977 this.fireEvent('metachange', this, this.reader.meta);
8980 moveIndex : function(data, type)
8982 var index = this.indexOf(data);
8984 var newIndex = index + type;
8988 this.insert(newIndex, data);
8993 * Ext JS Library 1.1.1
8994 * Copyright(c) 2006-2007, Ext JS, LLC.
8996 * Originally Released Under LGPL - original licence link has changed is not relivant.
8999 * <script type="text/javascript">
9003 * @class Roo.data.SimpleStore
9004 * @extends Roo.data.Store
9005 * Small helper class to make creating Stores from Array data easier.
9006 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9007 * @cfg {Array} fields An array of field definition objects, or field name strings.
9008 * @cfg {Array} data The multi-dimensional array of data
9010 * @param {Object} config
9012 Roo.data.SimpleStore = function(config){
9013 Roo.data.SimpleStore.superclass.constructor.call(this, {
9015 reader: new Roo.data.ArrayReader({
9018 Roo.data.Record.create(config.fields)
9020 proxy : new Roo.data.MemoryProxy(config.data)
9024 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9026 * Ext JS Library 1.1.1
9027 * Copyright(c) 2006-2007, Ext JS, LLC.
9029 * Originally Released Under LGPL - original licence link has changed is not relivant.
9032 * <script type="text/javascript">
9037 * @extends Roo.data.Store
9038 * @class Roo.data.JsonStore
9039 * Small helper class to make creating Stores for JSON data easier. <br/>
9041 var store = new Roo.data.JsonStore({
9042 url: 'get-images.php',
9044 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9047 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9048 * JsonReader and HttpProxy (unless inline data is provided).</b>
9049 * @cfg {Array} fields An array of field definition objects, or field name strings.
9051 * @param {Object} config
9053 Roo.data.JsonStore = function(c){
9054 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9055 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9056 reader: new Roo.data.JsonReader(c, c.fields)
9059 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9061 * Ext JS Library 1.1.1
9062 * Copyright(c) 2006-2007, Ext JS, LLC.
9064 * Originally Released Under LGPL - original licence link has changed is not relivant.
9067 * <script type="text/javascript">
9071 Roo.data.Field = function(config){
9072 if(typeof config == "string"){
9073 config = {name: config};
9075 Roo.apply(this, config);
9081 var st = Roo.data.SortTypes;
9082 // named sortTypes are supported, here we look them up
9083 if(typeof this.sortType == "string"){
9084 this.sortType = st[this.sortType];
9087 // set default sortType for strings and dates
9091 this.sortType = st.asUCString;
9094 this.sortType = st.asDate;
9097 this.sortType = st.none;
9102 var stripRe = /[\$,%]/g;
9104 // prebuilt conversion function for this field, instead of
9105 // switching every time we're reading a value
9107 var cv, dateFormat = this.dateFormat;
9112 cv = function(v){ return v; };
9115 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9119 return v !== undefined && v !== null && v !== '' ?
9120 parseInt(String(v).replace(stripRe, ""), 10) : '';
9125 return v !== undefined && v !== null && v !== '' ?
9126 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9131 cv = function(v){ return v === true || v === "true" || v == 1; };
9138 if(v instanceof Date){
9142 if(dateFormat == "timestamp"){
9143 return new Date(v*1000);
9145 return Date.parseDate(v, dateFormat);
9147 var parsed = Date.parse(v);
9148 return parsed ? new Date(parsed) : null;
9157 Roo.data.Field.prototype = {
9165 * Ext JS Library 1.1.1
9166 * Copyright(c) 2006-2007, Ext JS, LLC.
9168 * Originally Released Under LGPL - original licence link has changed is not relivant.
9171 * <script type="text/javascript">
9174 // Base class for reading structured data from a data source. This class is intended to be
9175 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9178 * @class Roo.data.DataReader
9179 * Base class for reading structured data from a data source. This class is intended to be
9180 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9183 Roo.data.DataReader = function(meta, recordType){
9187 this.recordType = recordType instanceof Array ?
9188 Roo.data.Record.create(recordType) : recordType;
9191 Roo.data.DataReader.prototype = {
9193 * Create an empty record
9194 * @param {Object} data (optional) - overlay some values
9195 * @return {Roo.data.Record} record created.
9197 newRow : function(d) {
9199 this.recordType.prototype.fields.each(function(c) {
9201 case 'int' : da[c.name] = 0; break;
9202 case 'date' : da[c.name] = new Date(); break;
9203 case 'float' : da[c.name] = 0.0; break;
9204 case 'boolean' : da[c.name] = false; break;
9205 default : da[c.name] = ""; break;
9209 return new this.recordType(Roo.apply(da, d));
9214 * Ext JS Library 1.1.1
9215 * Copyright(c) 2006-2007, Ext JS, LLC.
9217 * Originally Released Under LGPL - original licence link has changed is not relivant.
9220 * <script type="text/javascript">
9224 * @class Roo.data.DataProxy
9225 * @extends Roo.data.Observable
9226 * This class is an abstract base class for implementations which provide retrieval of
9227 * unformatted data objects.<br>
9229 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9230 * (of the appropriate type which knows how to parse the data object) to provide a block of
9231 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9233 * Custom implementations must implement the load method as described in
9234 * {@link Roo.data.HttpProxy#load}.
9236 Roo.data.DataProxy = function(){
9240 * Fires before a network request is made to retrieve a data object.
9241 * @param {Object} This DataProxy object.
9242 * @param {Object} params The params parameter to the load function.
9247 * Fires before the load method's callback is called.
9248 * @param {Object} This DataProxy object.
9249 * @param {Object} o The data object.
9250 * @param {Object} arg The callback argument object passed to the load function.
9254 * @event loadexception
9255 * Fires if an Exception occurs during data retrieval.
9256 * @param {Object} This DataProxy object.
9257 * @param {Object} o The data object.
9258 * @param {Object} arg The callback argument object passed to the load function.
9259 * @param {Object} e The Exception.
9261 loadexception : true
9263 Roo.data.DataProxy.superclass.constructor.call(this);
9266 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9269 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9273 * Ext JS Library 1.1.1
9274 * Copyright(c) 2006-2007, Ext JS, LLC.
9276 * Originally Released Under LGPL - original licence link has changed is not relivant.
9279 * <script type="text/javascript">
9282 * @class Roo.data.MemoryProxy
9283 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9284 * to the Reader when its load method is called.
9286 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9288 Roo.data.MemoryProxy = function(data){
9292 Roo.data.MemoryProxy.superclass.constructor.call(this);
9296 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9298 * Load data from the requested source (in this case an in-memory
9299 * data object passed to the constructor), read the data object into
9300 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9301 * process that block using the passed callback.
9302 * @param {Object} params This parameter is not used by the MemoryProxy class.
9303 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9304 * object into a block of Roo.data.Records.
9305 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9306 * The function must be passed <ul>
9307 * <li>The Record block object</li>
9308 * <li>The "arg" argument from the load function</li>
9309 * <li>A boolean success indicator</li>
9311 * @param {Object} scope The scope in which to call the callback
9312 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9314 load : function(params, reader, callback, scope, arg){
9315 params = params || {};
9318 result = reader.readRecords(this.data);
9320 this.fireEvent("loadexception", this, arg, null, e);
9321 callback.call(scope, null, arg, false);
9324 callback.call(scope, result, arg, true);
9328 update : function(params, records){
9333 * Ext JS Library 1.1.1
9334 * Copyright(c) 2006-2007, Ext JS, LLC.
9336 * Originally Released Under LGPL - original licence link has changed is not relivant.
9339 * <script type="text/javascript">
9342 * @class Roo.data.HttpProxy
9343 * @extends Roo.data.DataProxy
9344 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9345 * configured to reference a certain URL.<br><br>
9347 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9348 * from which the running page was served.<br><br>
9350 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9352 * Be aware that to enable the browser to parse an XML document, the server must set
9353 * the Content-Type header in the HTTP response to "text/xml".
9355 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9356 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9357 * will be used to make the request.
9359 Roo.data.HttpProxy = function(conn){
9360 Roo.data.HttpProxy.superclass.constructor.call(this);
9361 // is conn a conn config or a real conn?
9363 this.useAjax = !conn || !conn.events;
9367 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9368 // thse are take from connection...
9371 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9374 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9375 * extra parameters to each request made by this object. (defaults to undefined)
9378 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9379 * to each request made by this object. (defaults to undefined)
9382 * @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)
9385 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9388 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9394 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9398 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9399 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9400 * a finer-grained basis than the DataProxy events.
9402 getConnection : function(){
9403 return this.useAjax ? Roo.Ajax : this.conn;
9407 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9408 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9409 * process that block using the passed callback.
9410 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9411 * for the request to the remote server.
9412 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9413 * object into a block of Roo.data.Records.
9414 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9415 * The function must be passed <ul>
9416 * <li>The Record block object</li>
9417 * <li>The "arg" argument from the load function</li>
9418 * <li>A boolean success indicator</li>
9420 * @param {Object} scope The scope in which to call the callback
9421 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9423 load : function(params, reader, callback, scope, arg){
9424 if(this.fireEvent("beforeload", this, params) !== false){
9426 params : params || {},
9428 callback : callback,
9433 callback : this.loadResponse,
9437 Roo.applyIf(o, this.conn);
9438 if(this.activeRequest){
9439 Roo.Ajax.abort(this.activeRequest);
9441 this.activeRequest = Roo.Ajax.request(o);
9443 this.conn.request(o);
9446 callback.call(scope||this, null, arg, false);
9451 loadResponse : function(o, success, response){
9452 delete this.activeRequest;
9454 this.fireEvent("loadexception", this, o, response);
9455 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9460 result = o.reader.read(response);
9462 this.fireEvent("loadexception", this, o, response, e);
9463 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9467 this.fireEvent("load", this, o, o.request.arg);
9468 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9472 update : function(dataSet){
9477 updateResponse : function(dataSet){
9482 * Ext JS Library 1.1.1
9483 * Copyright(c) 2006-2007, Ext JS, LLC.
9485 * Originally Released Under LGPL - original licence link has changed is not relivant.
9488 * <script type="text/javascript">
9492 * @class Roo.data.ScriptTagProxy
9493 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9494 * other than the originating domain of the running page.<br><br>
9496 * <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
9497 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9499 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9500 * source code that is used as the source inside a <script> tag.<br><br>
9502 * In order for the browser to process the returned data, the server must wrap the data object
9503 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9504 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9505 * depending on whether the callback name was passed:
9508 boolean scriptTag = false;
9509 String cb = request.getParameter("callback");
9512 response.setContentType("text/javascript");
9514 response.setContentType("application/x-json");
9516 Writer out = response.getWriter();
9518 out.write(cb + "(");
9520 out.print(dataBlock.toJsonString());
9527 * @param {Object} config A configuration object.
9529 Roo.data.ScriptTagProxy = function(config){
9530 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9531 Roo.apply(this, config);
9532 this.head = document.getElementsByTagName("head")[0];
9535 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9537 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9539 * @cfg {String} url The URL from which to request the data object.
9542 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9546 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9547 * the server the name of the callback function set up by the load call to process the returned data object.
9548 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9549 * javascript output which calls this named function passing the data object as its only parameter.
9551 callbackParam : "callback",
9553 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9554 * name to the request.
9559 * Load data from the configured URL, read the data object into
9560 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9561 * process that block using the passed callback.
9562 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9563 * for the request to the remote server.
9564 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9565 * object into a block of Roo.data.Records.
9566 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9567 * The function must be passed <ul>
9568 * <li>The Record block object</li>
9569 * <li>The "arg" argument from the load function</li>
9570 * <li>A boolean success indicator</li>
9572 * @param {Object} scope The scope in which to call the callback
9573 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9575 load : function(params, reader, callback, scope, arg){
9576 if(this.fireEvent("beforeload", this, params) !== false){
9578 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9581 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9583 url += "&_dc=" + (new Date().getTime());
9585 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9588 cb : "stcCallback"+transId,
9589 scriptId : "stcScript"+transId,
9593 callback : callback,
9599 window[trans.cb] = function(o){
9600 conn.handleResponse(o, trans);
9603 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9605 if(this.autoAbort !== false){
9609 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9611 var script = document.createElement("script");
9612 script.setAttribute("src", url);
9613 script.setAttribute("type", "text/javascript");
9614 script.setAttribute("id", trans.scriptId);
9615 this.head.appendChild(script);
9619 callback.call(scope||this, null, arg, false);
9624 isLoading : function(){
9625 return this.trans ? true : false;
9629 * Abort the current server request.
9632 if(this.isLoading()){
9633 this.destroyTrans(this.trans);
9638 destroyTrans : function(trans, isLoaded){
9639 this.head.removeChild(document.getElementById(trans.scriptId));
9640 clearTimeout(trans.timeoutId);
9642 window[trans.cb] = undefined;
9644 delete window[trans.cb];
9647 // if hasn't been loaded, wait for load to remove it to prevent script error
9648 window[trans.cb] = function(){
9649 window[trans.cb] = undefined;
9651 delete window[trans.cb];
9658 handleResponse : function(o, trans){
9660 this.destroyTrans(trans, true);
9663 result = trans.reader.readRecords(o);
9665 this.fireEvent("loadexception", this, o, trans.arg, e);
9666 trans.callback.call(trans.scope||window, null, trans.arg, false);
9669 this.fireEvent("load", this, o, trans.arg);
9670 trans.callback.call(trans.scope||window, result, trans.arg, true);
9674 handleFailure : function(trans){
9676 this.destroyTrans(trans, false);
9677 this.fireEvent("loadexception", this, null, trans.arg);
9678 trans.callback.call(trans.scope||window, null, trans.arg, false);
9682 * Ext JS Library 1.1.1
9683 * Copyright(c) 2006-2007, Ext JS, LLC.
9685 * Originally Released Under LGPL - original licence link has changed is not relivant.
9688 * <script type="text/javascript">
9692 * @class Roo.data.JsonReader
9693 * @extends Roo.data.DataReader
9694 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9695 * based on mappings in a provided Roo.data.Record constructor.
9697 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9698 * in the reply previously.
9703 var RecordDef = Roo.data.Record.create([
9704 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9705 {name: 'occupation'} // This field will use "occupation" as the mapping.
9707 var myReader = new Roo.data.JsonReader({
9708 totalProperty: "results", // The property which contains the total dataset size (optional)
9709 root: "rows", // The property which contains an Array of row objects
9710 id: "id" // The property within each row object that provides an ID for the record (optional)
9714 * This would consume a JSON file like this:
9716 { 'results': 2, 'rows': [
9717 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9718 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9721 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9722 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9723 * paged from the remote server.
9724 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9725 * @cfg {String} root name of the property which contains the Array of row objects.
9726 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9728 * Create a new JsonReader
9729 * @param {Object} meta Metadata configuration options
9730 * @param {Object} recordType Either an Array of field definition objects,
9731 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9733 Roo.data.JsonReader = function(meta, recordType){
9736 // set some defaults:
9738 totalProperty: 'total',
9739 successProperty : 'success',
9744 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9746 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9749 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9750 * Used by Store query builder to append _requestMeta to params.
9753 metaFromRemote : false,
9755 * This method is only used by a DataProxy which has retrieved data from a remote server.
9756 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9757 * @return {Object} data A data block which is used by an Roo.data.Store object as
9758 * a cache of Roo.data.Records.
9760 read : function(response){
9761 var json = response.responseText;
9763 var o = /* eval:var:o */ eval("("+json+")");
9765 throw {message: "JsonReader.read: Json object not found"};
9771 this.metaFromRemote = true;
9772 this.meta = o.metaData;
9773 this.recordType = Roo.data.Record.create(o.metaData.fields);
9774 this.onMetaChange(this.meta, this.recordType, o);
9776 return this.readRecords(o);
9779 // private function a store will implement
9780 onMetaChange : function(meta, recordType, o){
9787 simpleAccess: function(obj, subsc) {
9794 getJsonAccessor: function(){
9796 return function(expr) {
9798 return(re.test(expr))
9799 ? new Function("obj", "return obj." + expr)
9809 * Create a data block containing Roo.data.Records from an XML document.
9810 * @param {Object} o An object which contains an Array of row objects in the property specified
9811 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9812 * which contains the total size of the dataset.
9813 * @return {Object} data A data block which is used by an Roo.data.Store object as
9814 * a cache of Roo.data.Records.
9816 readRecords : function(o){
9818 * After any data loads, the raw JSON data is available for further custom processing.
9822 var s = this.meta, Record = this.recordType,
9823 f = Record.prototype.fields, fi = f.items, fl = f.length;
9825 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9827 if(s.totalProperty) {
9828 this.getTotal = this.getJsonAccessor(s.totalProperty);
9830 if(s.successProperty) {
9831 this.getSuccess = this.getJsonAccessor(s.successProperty);
9833 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9835 var g = this.getJsonAccessor(s.id);
9836 this.getId = function(rec) {
9838 return (r === undefined || r === "") ? null : r;
9841 this.getId = function(){return null;};
9844 for(var jj = 0; jj < fl; jj++){
9846 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9847 this.ef[jj] = this.getJsonAccessor(map);
9851 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9852 if(s.totalProperty){
9853 var vt = parseInt(this.getTotal(o), 10);
9858 if(s.successProperty){
9859 var vs = this.getSuccess(o);
9860 if(vs === false || vs === 'false'){
9865 for(var i = 0; i < c; i++){
9868 var id = this.getId(n);
9869 for(var j = 0; j < fl; j++){
9871 var v = this.ef[j](n);
9873 Roo.log('missing convert for ' + f.name);
9877 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9879 var record = new Record(values, id);
9881 records[i] = record;
9887 totalRecords : totalRecords
9892 * Ext JS Library 1.1.1
9893 * Copyright(c) 2006-2007, Ext JS, LLC.
9895 * Originally Released Under LGPL - original licence link has changed is not relivant.
9898 * <script type="text/javascript">
9902 * @class Roo.data.ArrayReader
9903 * @extends Roo.data.DataReader
9904 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9905 * Each element of that Array represents a row of data fields. The
9906 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9907 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9911 var RecordDef = Roo.data.Record.create([
9912 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9913 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9915 var myReader = new Roo.data.ArrayReader({
9916 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9920 * This would consume an Array like this:
9922 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9924 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9926 * Create a new JsonReader
9927 * @param {Object} meta Metadata configuration options.
9928 * @param {Object} recordType Either an Array of field definition objects
9929 * as specified to {@link Roo.data.Record#create},
9930 * or an {@link Roo.data.Record} object
9931 * created using {@link Roo.data.Record#create}.
9933 Roo.data.ArrayReader = function(meta, recordType){
9934 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9937 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9939 * Create a data block containing Roo.data.Records from an XML document.
9940 * @param {Object} o An Array of row objects which represents the dataset.
9941 * @return {Object} data A data block which is used by an Roo.data.Store object as
9942 * a cache of Roo.data.Records.
9944 readRecords : function(o){
9945 var sid = this.meta ? this.meta.id : null;
9946 var recordType = this.recordType, fields = recordType.prototype.fields;
9949 for(var i = 0; i < root.length; i++){
9952 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9953 for(var j = 0, jlen = fields.length; j < jlen; j++){
9954 var f = fields.items[j];
9955 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9956 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9960 var record = new recordType(values, id);
9962 records[records.length] = record;
9966 totalRecords : records.length
9975 * @class Roo.bootstrap.ComboBox
9976 * @extends Roo.bootstrap.TriggerField
9977 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9978 * @cfg {Boolean} append (true|false) default false
9979 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9980 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9981 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9983 * Create a new ComboBox.
9984 * @param {Object} config Configuration options
9986 Roo.bootstrap.ComboBox = function(config){
9987 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9991 * Fires when the dropdown list is expanded
9992 * @param {Roo.bootstrap.ComboBox} combo This combo box
9997 * Fires when the dropdown list is collapsed
9998 * @param {Roo.bootstrap.ComboBox} combo This combo box
10002 * @event beforeselect
10003 * Fires before a list item is selected. Return false to cancel the selection.
10004 * @param {Roo.bootstrap.ComboBox} combo This combo box
10005 * @param {Roo.data.Record} record The data record returned from the underlying store
10006 * @param {Number} index The index of the selected item in the dropdown list
10008 'beforeselect' : true,
10011 * Fires when a list item is selected
10012 * @param {Roo.bootstrap.ComboBox} combo This combo box
10013 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10014 * @param {Number} index The index of the selected item in the dropdown list
10018 * @event beforequery
10019 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10020 * The event object passed has these properties:
10021 * @param {Roo.bootstrap.ComboBox} combo This combo box
10022 * @param {String} query The query
10023 * @param {Boolean} forceAll true to force "all" query
10024 * @param {Boolean} cancel true to cancel the query
10025 * @param {Object} e The query event object
10027 'beforequery': true,
10030 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10031 * @param {Roo.bootstrap.ComboBox} combo This combo box
10036 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10037 * @param {Roo.bootstrap.ComboBox} combo This combo box
10038 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10043 * Fires when the remove value from the combobox array
10044 * @param {Roo.bootstrap.ComboBox} combo This combo box
10051 this.tickItems = [];
10053 this.selectedIndex = -1;
10054 if(this.mode == 'local'){
10055 if(config.queryDelay === undefined){
10056 this.queryDelay = 10;
10058 if(config.minChars === undefined){
10064 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10067 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10068 * rendering into an Roo.Editor, defaults to false)
10071 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10072 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10075 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10078 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10079 * the dropdown list (defaults to undefined, with no header element)
10083 * @cfg {String/Roo.Template} tpl The template to use to render the output
10087 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10089 listWidth: undefined,
10091 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10092 * mode = 'remote' or 'text' if mode = 'local')
10094 displayField: undefined,
10096 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10097 * mode = 'remote' or 'value' if mode = 'local').
10098 * Note: use of a valueField requires the user make a selection
10099 * in order for a value to be mapped.
10101 valueField: undefined,
10105 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10106 * field's data value (defaults to the underlying DOM element's name)
10108 hiddenName: undefined,
10110 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10114 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10116 selectedClass: 'active',
10119 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10123 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10124 * anchor positions (defaults to 'tl-bl')
10126 listAlign: 'tl-bl?',
10128 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10132 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10133 * query specified by the allQuery config option (defaults to 'query')
10135 triggerAction: 'query',
10137 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10138 * (defaults to 4, does not apply if editable = false)
10142 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10143 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10147 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10148 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10152 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10153 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10157 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10158 * when editable = true (defaults to false)
10160 selectOnFocus:false,
10162 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10164 queryParam: 'query',
10166 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10167 * when mode = 'remote' (defaults to 'Loading...')
10169 loadingText: 'Loading...',
10171 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10175 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10179 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10180 * traditional select (defaults to true)
10184 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10188 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10192 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10193 * listWidth has a higher value)
10197 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10198 * allow the user to set arbitrary text into the field (defaults to false)
10200 forceSelection:false,
10202 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10203 * if typeAhead = true (defaults to 250)
10205 typeAheadDelay : 250,
10207 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10208 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10210 valueNotFoundText : undefined,
10212 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10214 blockFocus : false,
10217 * @cfg {Boolean} disableClear Disable showing of clear button.
10219 disableClear : false,
10221 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10223 alwaysQuery : false,
10226 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10240 btnPosition : 'right',
10242 // element that contains real text value.. (when hidden is used..)
10244 getAutoCreate : function()
10251 if(!this.tickable){
10252 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10257 * ComboBox with tickable selections
10260 var align = this.labelAlign || this.parentLabelAlign();
10263 cls : 'form-group roo-combobox-tickable' //input-group
10269 cls : 'tickable-buttons',
10274 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10281 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10288 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10295 Roo.each(buttons.cn, function(c){
10297 c.cls += ' btn-' + _this.size;
10300 if (_this.disabled) {
10311 cls: 'form-hidden-field'
10315 cls: 'select2-choices',
10319 cls: 'select2-search-field',
10331 cls: 'select2-container input-group select2-container-multi',
10336 cls: 'typeahead typeahead-long dropdown-menu',
10337 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10342 if (align ==='left' && this.fieldLabel.length) {
10344 Roo.log("left and has label");
10350 cls : 'control-label col-sm-' + this.labelWidth,
10351 html : this.fieldLabel
10355 cls : "col-sm-" + (12 - this.labelWidth),
10362 } else if ( this.fieldLabel.length) {
10368 //cls : 'input-group-addon',
10369 html : this.fieldLabel
10379 Roo.log(" no label && no align");
10386 ['xs','sm','md','lg'].map(function(size){
10387 if (settings[size]) {
10388 cfg.cls += ' col-' + size + '-' + settings[size];
10397 initEvents: function()
10401 throw "can not find store for combo";
10403 this.store = Roo.factory(this.store, Roo.data);
10406 this.initTickableEvnets();
10410 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10413 if(this.hiddenName){
10415 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10417 this.hiddenField.dom.value =
10418 this.hiddenValue !== undefined ? this.hiddenValue :
10419 this.value !== undefined ? this.value : '';
10421 // prevent input submission
10422 this.el.dom.removeAttribute('name');
10423 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10428 // this.el.dom.setAttribute('autocomplete', 'off');
10431 var cls = 'x-combo-list';
10432 this.list = this.el.select('ul.dropdown-menu',true).first();
10434 //this.list = new Roo.Layer({
10435 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10441 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10442 _this.list.setWidth(lw);
10445 this.list.on('mouseover', this.onViewOver, this);
10446 this.list.on('mousemove', this.onViewMove, this);
10448 this.list.on('scroll', this.onViewScroll, this);
10451 this.list.swallowEvent('mousewheel');
10452 this.assetHeight = 0;
10455 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10456 this.assetHeight += this.header.getHeight();
10459 this.innerList = this.list.createChild({cls:cls+'-inner'});
10460 this.innerList.on('mouseover', this.onViewOver, this);
10461 this.innerList.on('mousemove', this.onViewMove, this);
10462 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10464 if(this.allowBlank && !this.pageSize && !this.disableClear){
10465 this.footer = this.list.createChild({cls:cls+'-ft'});
10466 this.pageTb = new Roo.Toolbar(this.footer);
10470 this.footer = this.list.createChild({cls:cls+'-ft'});
10471 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10472 {pageSize: this.pageSize});
10476 if (this.pageTb && this.allowBlank && !this.disableClear) {
10478 this.pageTb.add(new Roo.Toolbar.Fill(), {
10479 cls: 'x-btn-icon x-btn-clear',
10481 handler: function()
10484 _this.clearValue();
10485 _this.onSelect(false, -1);
10490 this.assetHeight += this.footer.getHeight();
10495 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10498 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10499 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10501 //this.view.wrapEl.setDisplayed(false);
10502 this.view.on('click', this.onViewClick, this);
10506 this.store.on('beforeload', this.onBeforeLoad, this);
10507 this.store.on('load', this.onLoad, this);
10508 this.store.on('loadexception', this.onLoadException, this);
10510 if(this.resizable){
10511 this.resizer = new Roo.Resizable(this.list, {
10512 pinned:true, handles:'se'
10514 this.resizer.on('resize', function(r, w, h){
10515 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10516 this.listWidth = w;
10517 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10518 this.restrictHeight();
10520 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10523 if(!this.editable){
10524 this.editable = true;
10525 this.setEditable(false);
10530 if (typeof(this.events.add.listeners) != 'undefined') {
10532 this.addicon = this.wrap.createChild(
10533 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10535 this.addicon.on('click', function(e) {
10536 this.fireEvent('add', this);
10539 if (typeof(this.events.edit.listeners) != 'undefined') {
10541 this.editicon = this.wrap.createChild(
10542 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10543 if (this.addicon) {
10544 this.editicon.setStyle('margin-left', '40px');
10546 this.editicon.on('click', function(e) {
10548 // we fire even if inothing is selected..
10549 this.fireEvent('edit', this, this.lastData );
10555 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10556 "up" : function(e){
10557 this.inKeyMode = true;
10561 "down" : function(e){
10562 if(!this.isExpanded()){
10563 this.onTriggerClick();
10565 this.inKeyMode = true;
10570 "enter" : function(e){
10571 // this.onViewClick();
10575 if(this.fireEvent("specialkey", this, e)){
10576 this.onViewClick(false);
10582 "esc" : function(e){
10586 "tab" : function(e){
10589 if(this.fireEvent("specialkey", this, e)){
10590 this.onViewClick(false);
10598 doRelay : function(foo, bar, hname){
10599 if(hname == 'down' || this.scope.isExpanded()){
10600 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10609 this.queryDelay = Math.max(this.queryDelay || 10,
10610 this.mode == 'local' ? 10 : 250);
10613 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10615 if(this.typeAhead){
10616 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10618 if(this.editable !== false){
10619 this.inputEl().on("keyup", this.onKeyUp, this);
10621 if(this.forceSelection){
10622 this.inputEl().on('blur', this.doForce, this);
10626 this.choices = this.el.select('ul.select2-choices', true).first();
10627 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10631 initTickableEvnets: function()
10633 if(this.hiddenName){
10635 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10637 this.hiddenField.dom.value =
10638 this.hiddenValue !== undefined ? this.hiddenValue :
10639 this.value !== undefined ? this.value : '';
10641 // prevent input submission
10642 this.el.dom.removeAttribute('name');
10643 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10648 this.list = this.el.select('ul.dropdown-menu',true).first();
10650 this.choices = this.el.select('ul.select2-choices', true).first();
10651 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10653 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10655 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10656 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10658 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10659 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10661 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10662 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10664 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10665 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10666 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10669 this.cancelBtn.hide();
10674 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10675 _this.list.setWidth(lw);
10678 this.list.on('mouseover', this.onViewOver, this);
10679 this.list.on('mousemove', this.onViewMove, this);
10681 this.list.on('scroll', this.onViewScroll, this);
10684 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>';
10687 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10688 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10691 //this.view.wrapEl.setDisplayed(false);
10692 this.view.on('click', this.onViewClick, this);
10696 this.store.on('beforeload', this.onBeforeLoad, this);
10697 this.store.on('load', this.onLoad, this);
10698 this.store.on('loadexception', this.onLoadException, this);
10700 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10701 // "up" : function(e){
10702 // this.inKeyMode = true;
10703 // this.selectPrev();
10706 // "down" : function(e){
10707 // if(!this.isExpanded()){
10708 // this.onTriggerClick();
10710 // this.inKeyMode = true;
10711 // this.selectNext();
10715 // "enter" : function(e){
10716 //// this.onViewClick();
10718 // this.collapse();
10720 // if(this.fireEvent("specialkey", this, e)){
10721 // this.onViewClick(false);
10727 // "esc" : function(e){
10728 // this.collapse();
10731 // "tab" : function(e){
10732 // this.collapse();
10734 // if(this.fireEvent("specialkey", this, e)){
10735 // this.onViewClick(false);
10743 // doRelay : function(foo, bar, hname){
10744 // if(hname == 'down' || this.scope.isExpanded()){
10745 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10750 // forceKeyDown: true
10754 this.queryDelay = Math.max(this.queryDelay || 10,
10755 this.mode == 'local' ? 10 : 250);
10758 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10760 if(this.typeAhead){
10761 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10765 onDestroy : function(){
10767 this.view.setStore(null);
10768 this.view.el.removeAllListeners();
10769 this.view.el.remove();
10770 this.view.purgeListeners();
10773 this.list.dom.innerHTML = '';
10777 this.store.un('beforeload', this.onBeforeLoad, this);
10778 this.store.un('load', this.onLoad, this);
10779 this.store.un('loadexception', this.onLoadException, this);
10781 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10785 fireKey : function(e){
10786 if(e.isNavKeyPress() && !this.list.isVisible()){
10787 this.fireEvent("specialkey", this, e);
10792 onResize: function(w, h){
10793 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10795 // if(typeof w != 'number'){
10796 // // we do not handle it!?!?
10799 // var tw = this.trigger.getWidth();
10800 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10801 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10803 // this.inputEl().setWidth( this.adjustWidth('input', x));
10805 // //this.trigger.setStyle('left', x+'px');
10807 // if(this.list && this.listWidth === undefined){
10808 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10809 // this.list.setWidth(lw);
10810 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10818 * Allow or prevent the user from directly editing the field text. If false is passed,
10819 * the user will only be able to select from the items defined in the dropdown list. This method
10820 * is the runtime equivalent of setting the 'editable' config option at config time.
10821 * @param {Boolean} value True to allow the user to directly edit the field text
10823 setEditable : function(value){
10824 if(value == this.editable){
10827 this.editable = value;
10829 this.inputEl().dom.setAttribute('readOnly', true);
10830 this.inputEl().on('mousedown', this.onTriggerClick, this);
10831 this.inputEl().addClass('x-combo-noedit');
10833 this.inputEl().dom.setAttribute('readOnly', false);
10834 this.inputEl().un('mousedown', this.onTriggerClick, this);
10835 this.inputEl().removeClass('x-combo-noedit');
10841 onBeforeLoad : function(combo,opts){
10842 if(!this.hasFocus){
10846 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10848 this.restrictHeight();
10849 this.selectedIndex = -1;
10853 onLoad : function(){
10855 this.hasQuery = false;
10857 if(!this.hasFocus){
10861 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10862 this.loading.hide();
10865 if(this.store.getCount() > 0){
10867 this.restrictHeight();
10868 if(this.lastQuery == this.allQuery){
10869 if(this.editable && !this.tickable){
10870 this.inputEl().dom.select();
10872 if(!this.selectByValue(this.value, true) && this.autoFocus){
10873 this.select(0, true);
10876 if(this.autoFocus){
10879 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10880 this.taTask.delay(this.typeAheadDelay);
10884 this.onEmptyResults();
10890 onLoadException : function()
10892 this.hasQuery = false;
10894 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10895 this.loading.hide();
10899 Roo.log(this.store.reader.jsonData);
10900 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10902 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10908 onTypeAhead : function(){
10909 if(this.store.getCount() > 0){
10910 var r = this.store.getAt(0);
10911 var newValue = r.data[this.displayField];
10912 var len = newValue.length;
10913 var selStart = this.getRawValue().length;
10915 if(selStart != len){
10916 this.setRawValue(newValue);
10917 this.selectText(selStart, newValue.length);
10923 onSelect : function(record, index){
10925 if(this.fireEvent('beforeselect', this, record, index) !== false){
10927 this.setFromData(index > -1 ? record.data : false);
10930 this.fireEvent('select', this, record, index);
10935 * Returns the currently selected field value or empty string if no value is set.
10936 * @return {String} value The selected value
10938 getValue : function(){
10941 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10944 if(this.valueField){
10945 return typeof this.value != 'undefined' ? this.value : '';
10947 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10952 * Clears any text/value currently set in the field
10954 clearValue : function(){
10955 if(this.hiddenField){
10956 this.hiddenField.dom.value = '';
10959 this.setRawValue('');
10960 this.lastSelectionText = '';
10965 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10966 * will be displayed in the field. If the value does not match the data value of an existing item,
10967 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10968 * Otherwise the field will be blank (although the value will still be set).
10969 * @param {String} value The value to match
10971 setValue : function(v){
10978 if(this.valueField){
10979 var r = this.findRecord(this.valueField, v);
10981 text = r.data[this.displayField];
10982 }else if(this.valueNotFoundText !== undefined){
10983 text = this.valueNotFoundText;
10986 this.lastSelectionText = text;
10987 if(this.hiddenField){
10988 this.hiddenField.dom.value = v;
10990 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10994 * @property {Object} the last set data for the element
10999 * Sets the value of the field based on a object which is related to the record format for the store.
11000 * @param {Object} value the value to set as. or false on reset?
11002 setFromData : function(o){
11009 var dv = ''; // display value
11010 var vv = ''; // value value..
11012 if (this.displayField) {
11013 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11015 // this is an error condition!!!
11016 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11019 if(this.valueField){
11020 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11023 if(this.hiddenField){
11024 this.hiddenField.dom.value = vv;
11026 this.lastSelectionText = dv;
11027 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11031 // no hidden field.. - we store the value in 'value', but still display
11032 // display field!!!!
11033 this.lastSelectionText = dv;
11034 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11040 reset : function(){
11041 // overridden so that last data is reset..
11042 this.setValue(this.originalValue);
11043 this.clearInvalid();
11044 this.lastData = false;
11046 this.view.clearSelections();
11050 findRecord : function(prop, value){
11052 if(this.store.getCount() > 0){
11053 this.store.each(function(r){
11054 if(r.data[prop] == value){
11064 getName: function()
11066 // returns hidden if it's set..
11067 if (!this.rendered) {return ''};
11068 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11072 onViewMove : function(e, t){
11073 this.inKeyMode = false;
11077 onViewOver : function(e, t){
11078 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11081 var item = this.view.findItemFromChild(t);
11084 var index = this.view.indexOf(item);
11085 this.select(index, false);
11090 onViewClick : function(view, doFocus, el, e)
11092 var index = this.view.getSelectedIndexes()[0];
11094 var r = this.store.getAt(index);
11098 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11105 Roo.each(this.tickItems, function(v,k){
11107 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11108 _this.tickItems.splice(k, 1);
11118 this.tickItems.push(r.data);
11123 this.onSelect(r, index);
11125 if(doFocus !== false && !this.blockFocus){
11126 this.inputEl().focus();
11131 restrictHeight : function(){
11132 //this.innerList.dom.style.height = '';
11133 //var inner = this.innerList.dom;
11134 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11135 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11136 //this.list.beginUpdate();
11137 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11138 this.list.alignTo(this.inputEl(), this.listAlign);
11139 //this.list.endUpdate();
11143 onEmptyResults : function(){
11148 * Returns true if the dropdown list is expanded, else false.
11150 isExpanded : function(){
11151 return this.list.isVisible();
11155 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11156 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11157 * @param {String} value The data value of the item to select
11158 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11159 * selected item if it is not currently in view (defaults to true)
11160 * @return {Boolean} True if the value matched an item in the list, else false
11162 selectByValue : function(v, scrollIntoView){
11163 if(v !== undefined && v !== null){
11164 var r = this.findRecord(this.valueField || this.displayField, v);
11166 this.select(this.store.indexOf(r), scrollIntoView);
11174 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11175 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11176 * @param {Number} index The zero-based index of the list item to select
11177 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11178 * selected item if it is not currently in view (defaults to true)
11180 select : function(index, scrollIntoView){
11181 this.selectedIndex = index;
11182 this.view.select(index);
11183 if(scrollIntoView !== false){
11184 var el = this.view.getNode(index);
11186 //this.innerList.scrollChildIntoView(el, false);
11193 selectNext : function(){
11194 var ct = this.store.getCount();
11196 if(this.selectedIndex == -1){
11198 }else if(this.selectedIndex < ct-1){
11199 this.select(this.selectedIndex+1);
11205 selectPrev : function(){
11206 var ct = this.store.getCount();
11208 if(this.selectedIndex == -1){
11210 }else if(this.selectedIndex != 0){
11211 this.select(this.selectedIndex-1);
11217 onKeyUp : function(e){
11218 if(this.editable !== false && !e.isSpecialKey()){
11219 this.lastKey = e.getKey();
11220 this.dqTask.delay(this.queryDelay);
11225 validateBlur : function(){
11226 return !this.list || !this.list.isVisible();
11230 initQuery : function(){
11231 this.doQuery(this.getRawValue());
11235 doForce : function(){
11236 if(this.inputEl().dom.value.length > 0){
11237 this.inputEl().dom.value =
11238 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11244 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11245 * query allowing the query action to be canceled if needed.
11246 * @param {String} query The SQL query to execute
11247 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11248 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11249 * saved in the current store (defaults to false)
11251 doQuery : function(q, forceAll){
11253 if(q === undefined || q === null){
11258 forceAll: forceAll,
11262 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11267 forceAll = qe.forceAll;
11268 if(forceAll === true || (q.length >= this.minChars)){
11270 this.hasQuery = true;
11272 if(this.lastQuery != q || this.alwaysQuery){
11273 this.lastQuery = q;
11274 if(this.mode == 'local'){
11275 this.selectedIndex = -1;
11277 this.store.clearFilter();
11279 this.store.filter(this.displayField, q);
11283 this.store.baseParams[this.queryParam] = q;
11285 var options = {params : this.getParams(q)};
11288 options.add = true;
11289 options.params.start = this.page * this.pageSize;
11292 this.store.load(options);
11294 * this code will make the page width larger, at the beginning, the list not align correctly,
11295 * we should expand the list on onLoad
11296 * so command out it
11301 this.selectedIndex = -1;
11306 this.loadNext = false;
11310 getParams : function(q){
11312 //p[this.queryParam] = q;
11316 p.limit = this.pageSize;
11322 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11324 collapse : function(){
11325 if(!this.isExpanded()){
11329 this.hasFocus = false;
11335 this.cancelBtn.hide();
11336 this.trigger.show();
11339 Roo.get(document).un('mousedown', this.collapseIf, this);
11340 Roo.get(document).un('mousewheel', this.collapseIf, this);
11341 if (!this.editable) {
11342 Roo.get(document).un('keydown', this.listKeyPress, this);
11344 this.fireEvent('collapse', this);
11348 collapseIf : function(e){
11349 var in_combo = e.within(this.el);
11350 var in_list = e.within(this.list);
11352 if (in_combo || in_list) {
11353 //e.stopPropagation();
11358 this.onTickableFooterButtonClick(e, false, false);
11366 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11368 expand : function(){
11370 if(this.isExpanded() || !this.hasFocus){
11374 this.list.alignTo(this.inputEl(), this.listAlign);
11379 this.tickItems = Roo.apply([], this.item);
11382 this.cancelBtn.show();
11383 this.trigger.hide();
11387 Roo.get(document).on('mousedown', this.collapseIf, this);
11388 Roo.get(document).on('mousewheel', this.collapseIf, this);
11389 if (!this.editable) {
11390 Roo.get(document).on('keydown', this.listKeyPress, this);
11393 this.fireEvent('expand', this);
11397 // Implements the default empty TriggerField.onTriggerClick function
11398 onTriggerClick : function(e)
11400 Roo.log('trigger click');
11407 this.loadNext = false;
11409 if(this.isExpanded()){
11411 if (!this.blockFocus) {
11412 this.inputEl().focus();
11416 this.hasFocus = true;
11417 if(this.triggerAction == 'all') {
11418 this.doQuery(this.allQuery, true);
11420 this.doQuery(this.getRawValue());
11422 if (!this.blockFocus) {
11423 this.inputEl().focus();
11428 onTickableTriggerClick : function(e)
11435 this.loadNext = false;
11436 this.hasFocus = true;
11438 if(this.triggerAction == 'all') {
11439 this.doQuery(this.allQuery, true);
11441 this.doQuery(this.getRawValue());
11445 onSearchFieldClick : function(e)
11447 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11452 this.loadNext = false;
11453 this.hasFocus = true;
11455 if(this.triggerAction == 'all') {
11456 this.doQuery(this.allQuery, true);
11458 this.doQuery(this.getRawValue());
11462 listKeyPress : function(e)
11464 //Roo.log('listkeypress');
11465 // scroll to first matching element based on key pres..
11466 if (e.isSpecialKey()) {
11469 var k = String.fromCharCode(e.getKey()).toUpperCase();
11472 var csel = this.view.getSelectedNodes();
11473 var cselitem = false;
11475 var ix = this.view.indexOf(csel[0]);
11476 cselitem = this.store.getAt(ix);
11477 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11483 this.store.each(function(v) {
11485 // start at existing selection.
11486 if (cselitem.id == v.id) {
11492 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11493 match = this.store.indexOf(v);
11499 if (match === false) {
11500 return true; // no more action?
11503 this.view.select(match);
11504 var sn = Roo.get(this.view.getSelectedNodes()[0])
11505 //sn.scrollIntoView(sn.dom.parentNode, false);
11508 onViewScroll : function(e, t){
11510 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11514 this.hasQuery = true;
11516 this.loading = this.list.select('.loading', true).first();
11518 if(this.loading === null){
11519 this.list.createChild({
11521 cls: 'loading select2-more-results select2-active',
11522 html: 'Loading more results...'
11525 this.loading = this.list.select('.loading', true).first();
11527 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11529 this.loading.hide();
11532 this.loading.show();
11537 this.loadNext = true;
11539 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11544 addItem : function(o)
11546 var dv = ''; // display value
11548 if (this.displayField) {
11549 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11551 // this is an error condition!!!
11552 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11559 var choice = this.choices.createChild({
11561 cls: 'select2-search-choice',
11570 cls: 'select2-search-choice-close',
11575 }, this.searchField);
11577 var close = choice.select('a.select2-search-choice-close', true).first()
11579 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11587 this.inputEl().dom.value = '';
11591 onRemoveItem : function(e, _self, o)
11593 e.preventDefault();
11594 var index = this.item.indexOf(o.data) * 1;
11597 Roo.log('not this item?!');
11601 this.item.splice(index, 1);
11606 this.fireEvent('remove', this, e);
11610 syncValue : function()
11612 if(!this.item.length){
11619 Roo.each(this.item, function(i){
11620 if(_this.valueField){
11621 value.push(i[_this.valueField]);
11628 this.value = value.join(',');
11630 if(this.hiddenField){
11631 this.hiddenField.dom.value = this.value;
11635 clearItem : function()
11637 if(!this.multiple){
11643 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11650 inputEl: function ()
11653 return this.searchField;
11655 return this.el.select('input.form-control',true).first();
11659 onTickableFooterButtonClick : function(e, btn, el)
11661 e.preventDefault();
11663 if(btn && btn.name == 'cancel'){
11664 this.tickItems = Roo.apply([], this.item);
11673 Roo.each(this.tickItems, function(o){
11684 * @cfg {Boolean} grow
11688 * @cfg {Number} growMin
11692 * @cfg {Number} growMax
11702 * Ext JS Library 1.1.1
11703 * Copyright(c) 2006-2007, Ext JS, LLC.
11705 * Originally Released Under LGPL - original licence link has changed is not relivant.
11708 * <script type="text/javascript">
11713 * @extends Roo.util.Observable
11714 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11715 * This class also supports single and multi selection modes. <br>
11716 * Create a data model bound view:
11718 var store = new Roo.data.Store(...);
11720 var view = new Roo.View({
11722 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11724 singleSelect: true,
11725 selectedClass: "ydataview-selected",
11729 // listen for node click?
11730 view.on("click", function(vw, index, node, e){
11731 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11735 dataModel.load("foobar.xml");
11737 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11739 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11740 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11742 * Note: old style constructor is still suported (container, template, config)
11745 * Create a new View
11746 * @param {Object} config The config object
11749 Roo.View = function(config, depreciated_tpl, depreciated_config){
11751 this.parent = false;
11753 if (typeof(depreciated_tpl) == 'undefined') {
11754 // new way.. - universal constructor.
11755 Roo.apply(this, config);
11756 this.el = Roo.get(this.el);
11759 this.el = Roo.get(config);
11760 this.tpl = depreciated_tpl;
11761 Roo.apply(this, depreciated_config);
11763 this.wrapEl = this.el.wrap().wrap();
11764 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11767 if(typeof(this.tpl) == "string"){
11768 this.tpl = new Roo.Template(this.tpl);
11770 // support xtype ctors..
11771 this.tpl = new Roo.factory(this.tpl, Roo);
11775 this.tpl.compile();
11780 * @event beforeclick
11781 * Fires before a click is processed. Returns false to cancel the default action.
11782 * @param {Roo.View} this
11783 * @param {Number} index The index of the target node
11784 * @param {HTMLElement} node The target node
11785 * @param {Roo.EventObject} e The raw event object
11787 "beforeclick" : true,
11790 * Fires when a template node is clicked.
11791 * @param {Roo.View} this
11792 * @param {Number} index The index of the target node
11793 * @param {HTMLElement} node The target node
11794 * @param {Roo.EventObject} e The raw event object
11799 * Fires when a template node is double clicked.
11800 * @param {Roo.View} this
11801 * @param {Number} index The index of the target node
11802 * @param {HTMLElement} node The target node
11803 * @param {Roo.EventObject} e The raw event object
11807 * @event contextmenu
11808 * Fires when a template node is right clicked.
11809 * @param {Roo.View} this
11810 * @param {Number} index The index of the target node
11811 * @param {HTMLElement} node The target node
11812 * @param {Roo.EventObject} e The raw event object
11814 "contextmenu" : true,
11816 * @event selectionchange
11817 * Fires when the selected nodes change.
11818 * @param {Roo.View} this
11819 * @param {Array} selections Array of the selected nodes
11821 "selectionchange" : true,
11824 * @event beforeselect
11825 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11826 * @param {Roo.View} this
11827 * @param {HTMLElement} node The node to be selected
11828 * @param {Array} selections Array of currently selected nodes
11830 "beforeselect" : true,
11832 * @event preparedata
11833 * Fires on every row to render, to allow you to change the data.
11834 * @param {Roo.View} this
11835 * @param {Object} data to be rendered (change this)
11837 "preparedata" : true
11845 "click": this.onClick,
11846 "dblclick": this.onDblClick,
11847 "contextmenu": this.onContextMenu,
11851 this.selections = [];
11853 this.cmp = new Roo.CompositeElementLite([]);
11855 this.store = Roo.factory(this.store, Roo.data);
11856 this.setStore(this.store, true);
11859 if ( this.footer && this.footer.xtype) {
11861 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11863 this.footer.dataSource = this.store
11864 this.footer.container = fctr;
11865 this.footer = Roo.factory(this.footer, Roo);
11866 fctr.insertFirst(this.el);
11868 // this is a bit insane - as the paging toolbar seems to detach the el..
11869 // dom.parentNode.parentNode.parentNode
11870 // they get detached?
11874 Roo.View.superclass.constructor.call(this);
11879 Roo.extend(Roo.View, Roo.util.Observable, {
11882 * @cfg {Roo.data.Store} store Data store to load data from.
11887 * @cfg {String|Roo.Element} el The container element.
11892 * @cfg {String|Roo.Template} tpl The template used by this View
11896 * @cfg {String} dataName the named area of the template to use as the data area
11897 * Works with domtemplates roo-name="name"
11901 * @cfg {String} selectedClass The css class to add to selected nodes
11903 selectedClass : "x-view-selected",
11905 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11910 * @cfg {String} text to display on mask (default Loading)
11914 * @cfg {Boolean} multiSelect Allow multiple selection
11916 multiSelect : false,
11918 * @cfg {Boolean} singleSelect Allow single selection
11920 singleSelect: false,
11923 * @cfg {Boolean} toggleSelect - selecting
11925 toggleSelect : false,
11928 * @cfg {Boolean} tickable - selecting
11933 * Returns the element this view is bound to.
11934 * @return {Roo.Element}
11936 getEl : function(){
11937 return this.wrapEl;
11943 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11945 refresh : function(){
11946 Roo.log('refresh');
11949 // if we are using something like 'domtemplate', then
11950 // the what gets used is:
11951 // t.applySubtemplate(NAME, data, wrapping data..)
11952 // the outer template then get' applied with
11953 // the store 'extra data'
11954 // and the body get's added to the
11955 // roo-name="data" node?
11956 // <span class='roo-tpl-{name}'></span> ?????
11960 this.clearSelections();
11961 this.el.update("");
11963 var records = this.store.getRange();
11964 if(records.length < 1) {
11966 // is this valid?? = should it render a template??
11968 this.el.update(this.emptyText);
11972 if (this.dataName) {
11973 this.el.update(t.apply(this.store.meta)); //????
11974 el = this.el.child('.roo-tpl-' + this.dataName);
11977 for(var i = 0, len = records.length; i < len; i++){
11978 var data = this.prepareData(records[i].data, i, records[i]);
11979 this.fireEvent("preparedata", this, data, i, records[i]);
11981 var d = Roo.apply({}, data);
11984 Roo.apply(d, {'roo-id' : Roo.id()});
11988 Roo.each(this.parent.item, function(item){
11989 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11992 Roo.apply(d, {'roo-data-checked' : 'checked'});
11996 html[html.length] = Roo.util.Format.trim(
11998 t.applySubtemplate(this.dataName, d, this.store.meta) :
12005 el.update(html.join(""));
12006 this.nodes = el.dom.childNodes;
12007 this.updateIndexes(0);
12012 * Function to override to reformat the data that is sent to
12013 * the template for each node.
12014 * DEPRICATED - use the preparedata event handler.
12015 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12016 * a JSON object for an UpdateManager bound view).
12018 prepareData : function(data, index, record)
12020 this.fireEvent("preparedata", this, data, index, record);
12024 onUpdate : function(ds, record){
12025 Roo.log('on update');
12026 this.clearSelections();
12027 var index = this.store.indexOf(record);
12028 var n = this.nodes[index];
12029 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12030 n.parentNode.removeChild(n);
12031 this.updateIndexes(index, index);
12037 onAdd : function(ds, records, index)
12039 Roo.log(['on Add', ds, records, index] );
12040 this.clearSelections();
12041 if(this.nodes.length == 0){
12045 var n = this.nodes[index];
12046 for(var i = 0, len = records.length; i < len; i++){
12047 var d = this.prepareData(records[i].data, i, records[i]);
12049 this.tpl.insertBefore(n, d);
12052 this.tpl.append(this.el, d);
12055 this.updateIndexes(index);
12058 onRemove : function(ds, record, index){
12059 Roo.log('onRemove');
12060 this.clearSelections();
12061 var el = this.dataName ?
12062 this.el.child('.roo-tpl-' + this.dataName) :
12065 el.dom.removeChild(this.nodes[index]);
12066 this.updateIndexes(index);
12070 * Refresh an individual node.
12071 * @param {Number} index
12073 refreshNode : function(index){
12074 this.onUpdate(this.store, this.store.getAt(index));
12077 updateIndexes : function(startIndex, endIndex){
12078 var ns = this.nodes;
12079 startIndex = startIndex || 0;
12080 endIndex = endIndex || ns.length - 1;
12081 for(var i = startIndex; i <= endIndex; i++){
12082 ns[i].nodeIndex = i;
12087 * Changes the data store this view uses and refresh the view.
12088 * @param {Store} store
12090 setStore : function(store, initial){
12091 if(!initial && this.store){
12092 this.store.un("datachanged", this.refresh);
12093 this.store.un("add", this.onAdd);
12094 this.store.un("remove", this.onRemove);
12095 this.store.un("update", this.onUpdate);
12096 this.store.un("clear", this.refresh);
12097 this.store.un("beforeload", this.onBeforeLoad);
12098 this.store.un("load", this.onLoad);
12099 this.store.un("loadexception", this.onLoad);
12103 store.on("datachanged", this.refresh, this);
12104 store.on("add", this.onAdd, this);
12105 store.on("remove", this.onRemove, this);
12106 store.on("update", this.onUpdate, this);
12107 store.on("clear", this.refresh, this);
12108 store.on("beforeload", this.onBeforeLoad, this);
12109 store.on("load", this.onLoad, this);
12110 store.on("loadexception", this.onLoad, this);
12118 * onbeforeLoad - masks the loading area.
12121 onBeforeLoad : function(store,opts)
12123 Roo.log('onBeforeLoad');
12125 this.el.update("");
12127 this.el.mask(this.mask ? this.mask : "Loading" );
12129 onLoad : function ()
12136 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12137 * @param {HTMLElement} node
12138 * @return {HTMLElement} The template node
12140 findItemFromChild : function(node){
12141 var el = this.dataName ?
12142 this.el.child('.roo-tpl-' + this.dataName,true) :
12145 if(!node || node.parentNode == el){
12148 var p = node.parentNode;
12149 while(p && p != el){
12150 if(p.parentNode == el){
12159 onClick : function(e){
12160 var item = this.findItemFromChild(e.getTarget());
12162 var index = this.indexOf(item);
12163 if(this.onItemClick(item, index, e) !== false){
12164 this.fireEvent("click", this, index, item, e);
12167 this.clearSelections();
12172 onContextMenu : function(e){
12173 var item = this.findItemFromChild(e.getTarget());
12175 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12180 onDblClick : function(e){
12181 var item = this.findItemFromChild(e.getTarget());
12183 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12187 onItemClick : function(item, index, e)
12189 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12192 if (this.toggleSelect) {
12193 var m = this.isSelected(item) ? 'unselect' : 'select';
12196 _t[m](item, true, false);
12199 if(this.multiSelect || this.singleSelect){
12200 if(this.multiSelect && e.shiftKey && this.lastSelection){
12201 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12203 this.select(item, this.multiSelect && e.ctrlKey);
12204 this.lastSelection = item;
12207 if(!this.tickable){
12208 e.preventDefault();
12216 * Get the number of selected nodes.
12219 getSelectionCount : function(){
12220 return this.selections.length;
12224 * Get the currently selected nodes.
12225 * @return {Array} An array of HTMLElements
12227 getSelectedNodes : function(){
12228 return this.selections;
12232 * Get the indexes of the selected nodes.
12235 getSelectedIndexes : function(){
12236 var indexes = [], s = this.selections;
12237 for(var i = 0, len = s.length; i < len; i++){
12238 indexes.push(s[i].nodeIndex);
12244 * Clear all selections
12245 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12247 clearSelections : function(suppressEvent){
12248 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12249 this.cmp.elements = this.selections;
12250 this.cmp.removeClass(this.selectedClass);
12251 this.selections = [];
12252 if(!suppressEvent){
12253 this.fireEvent("selectionchange", this, this.selections);
12259 * Returns true if the passed node is selected
12260 * @param {HTMLElement/Number} node The node or node index
12261 * @return {Boolean}
12263 isSelected : function(node){
12264 var s = this.selections;
12268 node = this.getNode(node);
12269 return s.indexOf(node) !== -1;
12274 * @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
12275 * @param {Boolean} keepExisting (optional) true to keep existing selections
12276 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12278 select : function(nodeInfo, keepExisting, suppressEvent){
12279 if(nodeInfo instanceof Array){
12281 this.clearSelections(true);
12283 for(var i = 0, len = nodeInfo.length; i < len; i++){
12284 this.select(nodeInfo[i], true, true);
12288 var node = this.getNode(nodeInfo);
12289 if(!node || this.isSelected(node)){
12290 return; // already selected.
12293 this.clearSelections(true);
12295 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12296 Roo.fly(node).addClass(this.selectedClass);
12297 this.selections.push(node);
12298 if(!suppressEvent){
12299 this.fireEvent("selectionchange", this, this.selections);
12307 * @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
12308 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12309 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12311 unselect : function(nodeInfo, keepExisting, suppressEvent)
12313 if(nodeInfo instanceof Array){
12314 Roo.each(this.selections, function(s) {
12315 this.unselect(s, nodeInfo);
12319 var node = this.getNode(nodeInfo);
12320 if(!node || !this.isSelected(node)){
12321 Roo.log("not selected");
12322 return; // not selected.
12326 Roo.each(this.selections, function(s) {
12328 Roo.fly(node).removeClass(this.selectedClass);
12335 this.selections= ns;
12336 this.fireEvent("selectionchange", this, this.selections);
12340 * Gets a template node.
12341 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12342 * @return {HTMLElement} The node or null if it wasn't found
12344 getNode : function(nodeInfo){
12345 if(typeof nodeInfo == "string"){
12346 return document.getElementById(nodeInfo);
12347 }else if(typeof nodeInfo == "number"){
12348 return this.nodes[nodeInfo];
12354 * Gets a range template nodes.
12355 * @param {Number} startIndex
12356 * @param {Number} endIndex
12357 * @return {Array} An array of nodes
12359 getNodes : function(start, end){
12360 var ns = this.nodes;
12361 start = start || 0;
12362 end = typeof end == "undefined" ? ns.length - 1 : end;
12365 for(var i = start; i <= end; i++){
12369 for(var i = start; i >= end; i--){
12377 * Finds the index of the passed node
12378 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12379 * @return {Number} The index of the node or -1
12381 indexOf : function(node){
12382 node = this.getNode(node);
12383 if(typeof node.nodeIndex == "number"){
12384 return node.nodeIndex;
12386 var ns = this.nodes;
12387 for(var i = 0, len = ns.length; i < len; i++){
12398 * based on jquery fullcalendar
12402 Roo.bootstrap = Roo.bootstrap || {};
12404 * @class Roo.bootstrap.Calendar
12405 * @extends Roo.bootstrap.Component
12406 * Bootstrap Calendar class
12407 * @cfg {Boolean} loadMask (true|false) default false
12408 * @cfg {Object} header generate the user specific header of the calendar, default false
12411 * Create a new Container
12412 * @param {Object} config The config object
12417 Roo.bootstrap.Calendar = function(config){
12418 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12422 * Fires when a date is selected
12423 * @param {DatePicker} this
12424 * @param {Date} date The selected date
12428 * @event monthchange
12429 * Fires when the displayed month changes
12430 * @param {DatePicker} this
12431 * @param {Date} date The selected month
12433 'monthchange': true,
12435 * @event evententer
12436 * Fires when mouse over an event
12437 * @param {Calendar} this
12438 * @param {event} Event
12440 'evententer': true,
12442 * @event eventleave
12443 * Fires when the mouse leaves an
12444 * @param {Calendar} this
12447 'eventleave': true,
12449 * @event eventclick
12450 * Fires when the mouse click an
12451 * @param {Calendar} this
12460 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12463 * @cfg {Number} startDay
12464 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12472 getAutoCreate : function(){
12475 var fc_button = function(name, corner, style, content ) {
12476 return Roo.apply({},{
12478 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12480 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12483 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12494 style : 'width:100%',
12501 cls : 'fc-header-left',
12503 fc_button('prev', 'left', 'arrow', '‹' ),
12504 fc_button('next', 'right', 'arrow', '›' ),
12505 { tag: 'span', cls: 'fc-header-space' },
12506 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12514 cls : 'fc-header-center',
12518 cls: 'fc-header-title',
12521 html : 'month / year'
12529 cls : 'fc-header-right',
12531 /* fc_button('month', 'left', '', 'month' ),
12532 fc_button('week', '', '', 'week' ),
12533 fc_button('day', 'right', '', 'day' )
12545 header = this.header;
12548 var cal_heads = function() {
12550 // fixme - handle this.
12552 for (var i =0; i < Date.dayNames.length; i++) {
12553 var d = Date.dayNames[i];
12556 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12557 html : d.substring(0,3)
12561 ret[0].cls += ' fc-first';
12562 ret[6].cls += ' fc-last';
12565 var cal_cell = function(n) {
12568 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12573 cls: 'fc-day-number',
12577 cls: 'fc-day-content',
12581 style: 'position: relative;' // height: 17px;
12593 var cal_rows = function() {
12596 for (var r = 0; r < 6; r++) {
12603 for (var i =0; i < Date.dayNames.length; i++) {
12604 var d = Date.dayNames[i];
12605 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12608 row.cn[0].cls+=' fc-first';
12609 row.cn[0].cn[0].style = 'min-height:90px';
12610 row.cn[6].cls+=' fc-last';
12614 ret[0].cls += ' fc-first';
12615 ret[4].cls += ' fc-prev-last';
12616 ret[5].cls += ' fc-last';
12623 cls: 'fc-border-separate',
12624 style : 'width:100%',
12632 cls : 'fc-first fc-last',
12650 cls : 'fc-content',
12651 style : "position: relative;",
12654 cls : 'fc-view fc-view-month fc-grid',
12655 style : 'position: relative',
12656 unselectable : 'on',
12659 cls : 'fc-event-container',
12660 style : 'position:absolute;z-index:8;top:0;left:0;'
12678 initEvents : function()
12681 throw "can not find store for calendar";
12687 style: "text-align:center",
12691 style: "background-color:white;width:50%;margin:250 auto",
12695 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12706 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12708 var size = this.el.select('.fc-content', true).first().getSize();
12709 this.maskEl.setSize(size.width, size.height);
12710 this.maskEl.enableDisplayMode("block");
12711 if(!this.loadMask){
12712 this.maskEl.hide();
12715 this.store = Roo.factory(this.store, Roo.data);
12716 this.store.on('load', this.onLoad, this);
12717 this.store.on('beforeload', this.onBeforeLoad, this);
12721 this.cells = this.el.select('.fc-day',true);
12722 //Roo.log(this.cells);
12723 this.textNodes = this.el.query('.fc-day-number');
12724 this.cells.addClassOnOver('fc-state-hover');
12726 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12727 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12728 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12729 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12731 this.on('monthchange', this.onMonthChange, this);
12733 this.update(new Date().clearTime());
12736 resize : function() {
12737 var sz = this.el.getSize();
12739 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12740 this.el.select('.fc-day-content div',true).setHeight(34);
12745 showPrevMonth : function(e){
12746 this.update(this.activeDate.add("mo", -1));
12748 showToday : function(e){
12749 this.update(new Date().clearTime());
12752 showNextMonth : function(e){
12753 this.update(this.activeDate.add("mo", 1));
12757 showPrevYear : function(){
12758 this.update(this.activeDate.add("y", -1));
12762 showNextYear : function(){
12763 this.update(this.activeDate.add("y", 1));
12768 update : function(date)
12770 var vd = this.activeDate;
12771 this.activeDate = date;
12772 // if(vd && this.el){
12773 // var t = date.getTime();
12774 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12775 // Roo.log('using add remove');
12777 // this.fireEvent('monthchange', this, date);
12779 // this.cells.removeClass("fc-state-highlight");
12780 // this.cells.each(function(c){
12781 // if(c.dateValue == t){
12782 // c.addClass("fc-state-highlight");
12783 // setTimeout(function(){
12784 // try{c.dom.firstChild.focus();}catch(e){}
12794 var days = date.getDaysInMonth();
12796 var firstOfMonth = date.getFirstDateOfMonth();
12797 var startingPos = firstOfMonth.getDay()-this.startDay;
12799 if(startingPos < this.startDay){
12803 var pm = date.add(Date.MONTH, -1);
12804 var prevStart = pm.getDaysInMonth()-startingPos;
12806 this.cells = this.el.select('.fc-day',true);
12807 this.textNodes = this.el.query('.fc-day-number');
12808 this.cells.addClassOnOver('fc-state-hover');
12810 var cells = this.cells.elements;
12811 var textEls = this.textNodes;
12813 Roo.each(cells, function(cell){
12814 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12817 days += startingPos;
12819 // convert everything to numbers so it's fast
12820 var day = 86400000;
12821 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12824 //Roo.log(prevStart);
12826 var today = new Date().clearTime().getTime();
12827 var sel = date.clearTime().getTime();
12828 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12829 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12830 var ddMatch = this.disabledDatesRE;
12831 var ddText = this.disabledDatesText;
12832 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12833 var ddaysText = this.disabledDaysText;
12834 var format = this.format;
12836 var setCellClass = function(cal, cell){
12840 //Roo.log('set Cell Class');
12842 var t = d.getTime();
12846 cell.dateValue = t;
12848 cell.className += " fc-today";
12849 cell.className += " fc-state-highlight";
12850 cell.title = cal.todayText;
12853 // disable highlight in other month..
12854 //cell.className += " fc-state-highlight";
12859 cell.className = " fc-state-disabled";
12860 cell.title = cal.minText;
12864 cell.className = " fc-state-disabled";
12865 cell.title = cal.maxText;
12869 if(ddays.indexOf(d.getDay()) != -1){
12870 cell.title = ddaysText;
12871 cell.className = " fc-state-disabled";
12874 if(ddMatch && format){
12875 var fvalue = d.dateFormat(format);
12876 if(ddMatch.test(fvalue)){
12877 cell.title = ddText.replace("%0", fvalue);
12878 cell.className = " fc-state-disabled";
12882 if (!cell.initialClassName) {
12883 cell.initialClassName = cell.dom.className;
12886 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12891 for(; i < startingPos; i++) {
12892 textEls[i].innerHTML = (++prevStart);
12893 d.setDate(d.getDate()+1);
12895 cells[i].className = "fc-past fc-other-month";
12896 setCellClass(this, cells[i]);
12901 for(; i < days; i++){
12902 intDay = i - startingPos + 1;
12903 textEls[i].innerHTML = (intDay);
12904 d.setDate(d.getDate()+1);
12906 cells[i].className = ''; // "x-date-active";
12907 setCellClass(this, cells[i]);
12911 for(; i < 42; i++) {
12912 textEls[i].innerHTML = (++extraDays);
12913 d.setDate(d.getDate()+1);
12915 cells[i].className = "fc-future fc-other-month";
12916 setCellClass(this, cells[i]);
12919 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12921 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12923 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12924 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12926 if(totalRows != 6){
12927 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12928 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12931 this.fireEvent('monthchange', this, date);
12935 if(!this.internalRender){
12936 var main = this.el.dom.firstChild;
12937 var w = main.offsetWidth;
12938 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12939 Roo.fly(main).setWidth(w);
12940 this.internalRender = true;
12941 // opera does not respect the auto grow header center column
12942 // then, after it gets a width opera refuses to recalculate
12943 // without a second pass
12944 if(Roo.isOpera && !this.secondPass){
12945 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12946 this.secondPass = true;
12947 this.update.defer(10, this, [date]);
12954 findCell : function(dt) {
12955 dt = dt.clearTime().getTime();
12957 this.cells.each(function(c){
12958 //Roo.log("check " +c.dateValue + '?=' + dt);
12959 if(c.dateValue == dt){
12969 findCells : function(ev) {
12970 var s = ev.start.clone().clearTime().getTime();
12972 var e= ev.end.clone().clearTime().getTime();
12975 this.cells.each(function(c){
12976 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12978 if(c.dateValue > e){
12981 if(c.dateValue < s){
12990 // findBestRow: function(cells)
12994 // for (var i =0 ; i < cells.length;i++) {
12995 // ret = Math.max(cells[i].rows || 0,ret);
13002 addItem : function(ev)
13004 // look for vertical location slot in
13005 var cells = this.findCells(ev);
13007 // ev.row = this.findBestRow(cells);
13009 // work out the location.
13013 for(var i =0; i < cells.length; i++) {
13015 cells[i].row = cells[0].row;
13018 cells[i].row = cells[i].row + 1;
13028 if (crow.start.getY() == cells[i].getY()) {
13030 crow.end = cells[i];
13047 cells[0].events.push(ev);
13049 this.calevents.push(ev);
13052 clearEvents: function() {
13054 if(!this.calevents){
13058 Roo.each(this.cells.elements, function(c){
13064 Roo.each(this.calevents, function(e) {
13065 Roo.each(e.els, function(el) {
13066 el.un('mouseenter' ,this.onEventEnter, this);
13067 el.un('mouseleave' ,this.onEventLeave, this);
13072 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13078 renderEvents: function()
13082 this.cells.each(function(c) {
13091 if(c.row != c.events.length){
13092 r = 4 - (4 - (c.row - c.events.length));
13095 c.events = ev.slice(0, r);
13096 c.more = ev.slice(r);
13098 if(c.more.length && c.more.length == 1){
13099 c.events.push(c.more.pop());
13102 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13106 this.cells.each(function(c) {
13108 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13111 for (var e = 0; e < c.events.length; e++){
13112 var ev = c.events[e];
13113 var rows = ev.rows;
13115 for(var i = 0; i < rows.length; i++) {
13117 // how many rows should it span..
13120 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13121 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13123 unselectable : "on",
13126 cls: 'fc-event-inner',
13130 // cls: 'fc-event-time',
13131 // html : cells.length > 1 ? '' : ev.time
13135 cls: 'fc-event-title',
13136 html : String.format('{0}', ev.title)
13143 cls: 'ui-resizable-handle ui-resizable-e',
13144 html : '  '
13151 cfg.cls += ' fc-event-start';
13153 if ((i+1) == rows.length) {
13154 cfg.cls += ' fc-event-end';
13157 var ctr = _this.el.select('.fc-event-container',true).first();
13158 var cg = ctr.createChild(cfg);
13160 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13161 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13163 var r = (c.more.length) ? 1 : 0;
13164 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13165 cg.setWidth(ebox.right - sbox.x -2);
13167 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13168 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13169 cg.on('click', _this.onEventClick, _this, ev);
13180 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13181 style : 'position: absolute',
13182 unselectable : "on",
13185 cls: 'fc-event-inner',
13189 cls: 'fc-event-title',
13197 cls: 'ui-resizable-handle ui-resizable-e',
13198 html : '  '
13204 var ctr = _this.el.select('.fc-event-container',true).first();
13205 var cg = ctr.createChild(cfg);
13207 var sbox = c.select('.fc-day-content',true).first().getBox();
13208 var ebox = c.select('.fc-day-content',true).first().getBox();
13210 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13211 cg.setWidth(ebox.right - sbox.x -2);
13213 cg.on('click', _this.onMoreEventClick, _this, c.more);
13223 onEventEnter: function (e, el,event,d) {
13224 this.fireEvent('evententer', this, el, event);
13227 onEventLeave: function (e, el,event,d) {
13228 this.fireEvent('eventleave', this, el, event);
13231 onEventClick: function (e, el,event,d) {
13232 this.fireEvent('eventclick', this, el, event);
13235 onMonthChange: function () {
13239 onMoreEventClick: function(e, el, more)
13243 this.calpopover.placement = 'right';
13244 this.calpopover.setTitle('More');
13246 this.calpopover.setContent('');
13248 var ctr = this.calpopover.el.select('.popover-content', true).first();
13250 Roo.each(more, function(m){
13252 cls : 'fc-event-hori fc-event-draggable',
13255 var cg = ctr.createChild(cfg);
13257 cg.on('click', _this.onEventClick, _this, m);
13260 this.calpopover.show(el);
13265 onLoad: function ()
13267 this.calevents = [];
13270 if(this.store.getCount() > 0){
13271 this.store.data.each(function(d){
13274 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13275 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13276 time : d.data.start_time,
13277 title : d.data.title,
13278 description : d.data.description,
13279 venue : d.data.venue
13284 this.renderEvents();
13286 if(this.calevents.length && this.loadMask){
13287 this.maskEl.hide();
13291 onBeforeLoad: function()
13293 this.clearEvents();
13295 this.maskEl.show();
13309 * @class Roo.bootstrap.Popover
13310 * @extends Roo.bootstrap.Component
13311 * Bootstrap Popover class
13312 * @cfg {String} html contents of the popover (or false to use children..)
13313 * @cfg {String} title of popover (or false to hide)
13314 * @cfg {String} placement how it is placed
13315 * @cfg {String} trigger click || hover (or false to trigger manually)
13316 * @cfg {String} over what (parent or false to trigger manually.)
13319 * Create a new Popover
13320 * @param {Object} config The config object
13323 Roo.bootstrap.Popover = function(config){
13324 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13327 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13329 title: 'Fill in a title',
13332 placement : 'right',
13333 trigger : 'hover', // hover
13337 can_build_overlaid : false,
13339 getChildContainer : function()
13341 return this.el.select('.popover-content',true).first();
13344 getAutoCreate : function(){
13345 Roo.log('make popover?');
13347 cls : 'popover roo-dynamic',
13348 style: 'display:block',
13354 cls : 'popover-inner',
13358 cls: 'popover-title',
13362 cls : 'popover-content',
13373 setTitle: function(str)
13375 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13377 setContent: function(str)
13379 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13381 // as it get's added to the bottom of the page.
13382 onRender : function(ct, position)
13384 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13386 var cfg = Roo.apply({}, this.getAutoCreate());
13390 cfg.cls += ' ' + this.cls;
13393 cfg.style = this.style;
13395 Roo.log("adding to ")
13396 this.el = Roo.get(document.body).createChild(cfg, position);
13402 initEvents : function()
13404 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13405 this.el.enableDisplayMode('block');
13407 if (this.over === false) {
13410 if (this.triggers === false) {
13413 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13414 var triggers = this.trigger ? this.trigger.split(' ') : [];
13415 Roo.each(triggers, function(trigger) {
13417 if (trigger == 'click') {
13418 on_el.on('click', this.toggle, this);
13419 } else if (trigger != 'manual') {
13420 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13421 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13423 on_el.on(eventIn ,this.enter, this);
13424 on_el.on(eventOut, this.leave, this);
13435 toggle : function () {
13436 this.hoverState == 'in' ? this.leave() : this.enter();
13439 enter : function () {
13442 clearTimeout(this.timeout);
13444 this.hoverState = 'in'
13446 if (!this.delay || !this.delay.show) {
13451 this.timeout = setTimeout(function () {
13452 if (_t.hoverState == 'in') {
13455 }, this.delay.show)
13457 leave : function() {
13458 clearTimeout(this.timeout);
13460 this.hoverState = 'out'
13462 if (!this.delay || !this.delay.hide) {
13467 this.timeout = setTimeout(function () {
13468 if (_t.hoverState == 'out') {
13471 }, this.delay.hide)
13474 show : function (on_el)
13477 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13480 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13481 if (this.html !== false) {
13482 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13484 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13485 if (!this.title.length) {
13486 this.el.select('.popover-title',true).hide();
13489 var placement = typeof this.placement == 'function' ?
13490 this.placement.call(this, this.el, on_el) :
13493 var autoToken = /\s?auto?\s?/i;
13494 var autoPlace = autoToken.test(placement);
13496 placement = placement.replace(autoToken, '') || 'top';
13500 //this.el.setXY([0,0]);
13502 this.el.dom.style.display='block';
13503 this.el.addClass(placement);
13505 //this.el.appendTo(on_el);
13507 var p = this.getPosition();
13508 var box = this.el.getBox();
13513 var align = Roo.bootstrap.Popover.alignment[placement]
13514 this.el.alignTo(on_el, align[0],align[1]);
13515 //var arrow = this.el.select('.arrow',true).first();
13516 //arrow.set(align[2],
13518 this.el.addClass('in');
13519 this.hoverState = null;
13521 if (this.el.hasClass('fade')) {
13528 this.el.setXY([0,0]);
13529 this.el.removeClass('in');
13536 Roo.bootstrap.Popover.alignment = {
13537 'left' : ['r-l', [-10,0], 'right'],
13538 'right' : ['l-r', [10,0], 'left'],
13539 'bottom' : ['t-b', [0,10], 'top'],
13540 'top' : [ 'b-t', [0,-10], 'bottom']
13551 * @class Roo.bootstrap.Progress
13552 * @extends Roo.bootstrap.Component
13553 * Bootstrap Progress class
13554 * @cfg {Boolean} striped striped of the progress bar
13555 * @cfg {Boolean} active animated of the progress bar
13559 * Create a new Progress
13560 * @param {Object} config The config object
13563 Roo.bootstrap.Progress = function(config){
13564 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13567 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13572 getAutoCreate : function(){
13580 cfg.cls += ' progress-striped';
13584 cfg.cls += ' active';
13603 * @class Roo.bootstrap.ProgressBar
13604 * @extends Roo.bootstrap.Component
13605 * Bootstrap ProgressBar class
13606 * @cfg {Number} aria_valuenow aria-value now
13607 * @cfg {Number} aria_valuemin aria-value min
13608 * @cfg {Number} aria_valuemax aria-value max
13609 * @cfg {String} label label for the progress bar
13610 * @cfg {String} panel (success | info | warning | danger )
13611 * @cfg {String} role role of the progress bar
13612 * @cfg {String} sr_only text
13616 * Create a new ProgressBar
13617 * @param {Object} config The config object
13620 Roo.bootstrap.ProgressBar = function(config){
13621 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13624 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13628 aria_valuemax : 100,
13634 getAutoCreate : function()
13639 cls: 'progress-bar',
13640 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13652 cfg.role = this.role;
13655 if(this.aria_valuenow){
13656 cfg['aria-valuenow'] = this.aria_valuenow;
13659 if(this.aria_valuemin){
13660 cfg['aria-valuemin'] = this.aria_valuemin;
13663 if(this.aria_valuemax){
13664 cfg['aria-valuemax'] = this.aria_valuemax;
13667 if(this.label && !this.sr_only){
13668 cfg.html = this.label;
13672 cfg.cls += ' progress-bar-' + this.panel;
13678 update : function(aria_valuenow)
13680 this.aria_valuenow = aria_valuenow;
13682 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13697 * @class Roo.bootstrap.TabGroup
13698 * @extends Roo.bootstrap.Column
13699 * Bootstrap Column class
13700 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13703 * Create a new TabGroup
13704 * @param {Object} config The config object
13707 Roo.bootstrap.TabGroup = function(config){
13708 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13710 this.navId = Roo.id();
13713 Roo.bootstrap.TabGroup.register(this);
13717 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13720 getAutoCreate : function(){
13721 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13723 cfg.cls += ' tab-content';
13729 * register a Navigation item
13730 * @param {Roo.bootstrap.NavItem} the navitem to add
13732 register : function(item)
13734 this.tabs.push( item);
13735 item.navId = this.navId; // not really needed..
13739 getActivePanel : function()
13742 Roo.each(this.tabs, function(t) {
13752 getPanelByName : function(n)
13755 Roo.each(this.tabs, function(t) {
13756 if (t.tabId == n) {
13764 indexOfPanel : function(p)
13767 Roo.each(this.tabs, function(t,i) {
13768 if (t.tabId == p.tabId) {
13776 showPanel : function (pan)
13778 if (typeof(pan) == 'pnumber') {
13779 pan = this.tabs[pan];
13781 if (typeof(pan) == 'string') {
13782 pan = this.getPanelByName(pan);
13784 if (pan.tabId == this.getActivePanel().tabId) {
13787 this.getActivePanel().setActive(false);
13788 pan.setActive(true);
13791 showNextPanel : function()
13793 var i = this.indexOfPanel(this.getActivePanel());
13794 if (i > this.tabs.length) {
13797 this.showPanel(this.tabs[i+1]);
13799 showPrevPanel : function()
13801 var i = this.indexOfPanel(this.getActivePanel());
13805 this.showPanel(this.tabs[i-1]);
13816 Roo.apply(Roo.bootstrap.TabGroup, {
13820 * register a Navigation Group
13821 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13823 register : function(navgrp)
13825 this.groups[navgrp.navId] = navgrp;
13829 * fetch a Navigation Group based on the navigation ID
13830 * if one does not exist , it will get created.
13831 * @param {string} the navgroup to add
13832 * @returns {Roo.bootstrap.NavGroup} the navgroup
13834 get: function(navId) {
13835 if (typeof(this.groups[navId]) == 'undefined') {
13836 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13838 return this.groups[navId] ;
13853 * @class Roo.bootstrap.TabPanel
13854 * @extends Roo.bootstrap.Component
13855 * Bootstrap TabPanel class
13856 * @cfg {Boolean} active panel active
13857 * @cfg {String} html panel content
13858 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
13859 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13863 * Create a new TabPanel
13864 * @param {Object} config The config object
13867 Roo.bootstrap.TabPanel = function(config){
13868 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13872 * Fires when the active status changes
13873 * @param {Roo.bootstrap.TabPanel} this
13874 * @param {Boolean} state the new state
13879 this.tabId = this.tabId || Roo.id();
13883 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13890 getAutoCreate : function(){
13894 html: this.html || ''
13898 cfg.cls += ' active';
13902 cfg.tabId = this.tabId;
13908 initEvents: function()
13910 Roo.log('-------- init events on tab panel ---------');
13912 var p = this.parent();
13913 this.navId = this.navId || p.navId;
13915 if (typeof(this.navId) != 'undefined') {
13916 // not really needed.. but just in case.. parent should be a NavGroup.
13917 var tg = Roo.bootstrap.TabGroup.get(this.navId);
13918 Roo.log(['register', tg, this]);
13924 onRender : function(ct, position)
13926 // Roo.log("Call onRender: " + this.xtype);
13928 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13930 // registration with navgroups..
13931 if (this.navId && this.tabId) {
13932 var grp = Roo.bootstrap.NavGroup.get(this.navId);
13935 var item = grp.getNavItem(this.tabId);
13937 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13939 item.on('changed', function(item, state) {
13940 this.setActive(state);
13949 setActive: function(state)
13951 Roo.log("panel - set active " + this.tabId + "=" + state);
13953 this.active = state;
13955 this.el.removeClass('active');
13957 } else if (!this.el.hasClass('active')) {
13958 this.el.addClass('active');
13960 this.fireEvent('changed', this, state);
13977 * @class Roo.bootstrap.DateField
13978 * @extends Roo.bootstrap.Input
13979 * Bootstrap DateField class
13980 * @cfg {Number} weekStart default 0
13981 * @cfg {Number} weekStart default 0
13982 * @cfg {Number} viewMode default empty, (months|years)
13983 * @cfg {Number} minViewMode default empty, (months|years)
13984 * @cfg {Number} startDate default -Infinity
13985 * @cfg {Number} endDate default Infinity
13986 * @cfg {Boolean} todayHighlight default false
13987 * @cfg {Boolean} todayBtn default false
13988 * @cfg {Boolean} calendarWeeks default false
13989 * @cfg {Object} daysOfWeekDisabled default empty
13991 * @cfg {Boolean} keyboardNavigation default true
13992 * @cfg {String} language default en
13995 * Create a new DateField
13996 * @param {Object} config The config object
13999 Roo.bootstrap.DateField = function(config){
14000 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14004 * Fires when this field show.
14005 * @param {Roo.bootstrap.DateField} this
14006 * @param {Mixed} date The date value
14011 * Fires when this field hide.
14012 * @param {Roo.bootstrap.DateField} this
14013 * @param {Mixed} date The date value
14018 * Fires when select a date.
14019 * @param {Roo.bootstrap.DateField} this
14020 * @param {Mixed} date The date value
14026 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14029 * @cfg {String} format
14030 * The default date format string which can be overriden for localization support. The format must be
14031 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14035 * @cfg {String} altFormats
14036 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14037 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14039 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14047 todayHighlight : false,
14053 keyboardNavigation: true,
14055 calendarWeeks: false,
14057 startDate: -Infinity,
14061 daysOfWeekDisabled: [],
14065 UTCDate: function()
14067 return new Date(Date.UTC.apply(Date, arguments));
14070 UTCToday: function()
14072 var today = new Date();
14073 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14076 getDate: function() {
14077 var d = this.getUTCDate();
14078 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14081 getUTCDate: function() {
14085 setDate: function(d) {
14086 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14089 setUTCDate: function(d) {
14091 this.setValue(this.formatDate(this.date));
14094 onRender: function(ct, position)
14097 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14099 this.language = this.language || 'en';
14100 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14101 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14103 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14104 this.format = this.format || 'm/d/y';
14105 this.isInline = false;
14106 this.isInput = true;
14107 this.component = this.el.select('.add-on', true).first() || false;
14108 this.component = (this.component && this.component.length === 0) ? false : this.component;
14109 this.hasInput = this.component && this.inputEL().length;
14111 if (typeof(this.minViewMode === 'string')) {
14112 switch (this.minViewMode) {
14114 this.minViewMode = 1;
14117 this.minViewMode = 2;
14120 this.minViewMode = 0;
14125 if (typeof(this.viewMode === 'string')) {
14126 switch (this.viewMode) {
14139 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14141 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14143 this.picker().on('mousedown', this.onMousedown, this);
14144 this.picker().on('click', this.onClick, this);
14146 this.picker().addClass('datepicker-dropdown');
14148 this.startViewMode = this.viewMode;
14151 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14152 if(!this.calendarWeeks){
14157 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14158 v.attr('colspan', function(i, val){
14159 return parseInt(val) + 1;
14164 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14166 this.setStartDate(this.startDate);
14167 this.setEndDate(this.endDate);
14169 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14176 if(this.isInline) {
14181 picker : function()
14183 return this.el.select('.datepicker', true).first();
14186 fillDow: function()
14188 var dowCnt = this.weekStart;
14197 if(this.calendarWeeks){
14205 while (dowCnt < this.weekStart + 7) {
14209 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14213 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14216 fillMonths: function()
14219 var months = this.picker().select('>.datepicker-months td', true).first();
14221 months.dom.innerHTML = '';
14227 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14230 months.createChild(month);
14238 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14240 if (this.date < this.startDate) {
14241 this.viewDate = new Date(this.startDate);
14242 } else if (this.date > this.endDate) {
14243 this.viewDate = new Date(this.endDate);
14245 this.viewDate = new Date(this.date);
14253 var d = new Date(this.viewDate),
14254 year = d.getUTCFullYear(),
14255 month = d.getUTCMonth(),
14256 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14257 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14258 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14259 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14260 currentDate = this.date && this.date.valueOf(),
14261 today = this.UTCToday();
14263 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14265 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14267 // this.picker.select('>tfoot th.today').
14268 // .text(dates[this.language].today)
14269 // .toggle(this.todayBtn !== false);
14271 this.updateNavArrows();
14274 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14276 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14278 prevMonth.setUTCDate(day);
14280 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14282 var nextMonth = new Date(prevMonth);
14284 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14286 nextMonth = nextMonth.valueOf();
14288 var fillMonths = false;
14290 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14292 while(prevMonth.valueOf() < nextMonth) {
14295 if (prevMonth.getUTCDay() === this.weekStart) {
14297 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14305 if(this.calendarWeeks){
14306 // ISO 8601: First week contains first thursday.
14307 // ISO also states week starts on Monday, but we can be more abstract here.
14309 // Start of current week: based on weekstart/current date
14310 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14311 // Thursday of this week
14312 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14313 // First Thursday of year, year from thursday
14314 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14315 // Calendar week: ms between thursdays, div ms per day, div 7 days
14316 calWeek = (th - yth) / 864e5 / 7 + 1;
14318 fillMonths.cn.push({
14326 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14328 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14331 if (this.todayHighlight &&
14332 prevMonth.getUTCFullYear() == today.getFullYear() &&
14333 prevMonth.getUTCMonth() == today.getMonth() &&
14334 prevMonth.getUTCDate() == today.getDate()) {
14335 clsName += ' today';
14338 if (currentDate && prevMonth.valueOf() === currentDate) {
14339 clsName += ' active';
14342 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14343 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14344 clsName += ' disabled';
14347 fillMonths.cn.push({
14349 cls: 'day ' + clsName,
14350 html: prevMonth.getDate()
14353 prevMonth.setDate(prevMonth.getDate()+1);
14356 var currentYear = this.date && this.date.getUTCFullYear();
14357 var currentMonth = this.date && this.date.getUTCMonth();
14359 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14361 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14362 v.removeClass('active');
14364 if(currentYear === year && k === currentMonth){
14365 v.addClass('active');
14368 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14369 v.addClass('disabled');
14375 year = parseInt(year/10, 10) * 10;
14377 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14379 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14382 for (var i = -1; i < 11; i++) {
14383 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14385 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14393 showMode: function(dir)
14396 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14398 Roo.each(this.picker().select('>div',true).elements, function(v){
14399 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14402 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14407 if(this.isInline) return;
14409 this.picker().removeClass(['bottom', 'top']);
14411 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14413 * place to the top of element!
14417 this.picker().addClass('top');
14418 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14423 this.picker().addClass('bottom');
14425 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14428 parseDate : function(value)
14430 if(!value || value instanceof Date){
14433 var v = Date.parseDate(value, this.format);
14434 if (!v && this.useIso) {
14435 v = Date.parseDate(value, 'Y-m-d');
14437 if(!v && this.altFormats){
14438 if(!this.altFormatsArray){
14439 this.altFormatsArray = this.altFormats.split("|");
14441 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14442 v = Date.parseDate(value, this.altFormatsArray[i]);
14448 formatDate : function(date, fmt)
14450 return (!date || !(date instanceof Date)) ?
14451 date : date.dateFormat(fmt || this.format);
14454 onFocus : function()
14456 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14460 onBlur : function()
14462 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14464 var d = this.inputEl().getValue();
14475 this.picker().show();
14479 this.fireEvent('show', this, this.date);
14484 if(this.isInline) return;
14485 this.picker().hide();
14486 this.viewMode = this.startViewMode;
14489 this.fireEvent('hide', this, this.date);
14493 onMousedown: function(e)
14495 e.stopPropagation();
14496 e.preventDefault();
14501 Roo.bootstrap.DateField.superclass.keyup.call(this);
14505 setValue: function(v)
14507 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14509 var d = new Date(v);
14511 if(isNaN(d.getTime())){
14515 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14519 this.fireEvent('select', this, this.date);
14523 getValue: function()
14525 return this.formatDate(this.date);
14528 fireKey: function(e)
14530 if (!this.picker().isVisible()){
14531 if (e.keyCode == 27) // allow escape to hide and re-show picker
14535 var dateChanged = false,
14537 newDate, newViewDate;
14542 e.preventDefault();
14546 if (!this.keyboardNavigation) break;
14547 dir = e.keyCode == 37 ? -1 : 1;
14550 newDate = this.moveYear(this.date, dir);
14551 newViewDate = this.moveYear(this.viewDate, dir);
14552 } else if (e.shiftKey){
14553 newDate = this.moveMonth(this.date, dir);
14554 newViewDate = this.moveMonth(this.viewDate, dir);
14556 newDate = new Date(this.date);
14557 newDate.setUTCDate(this.date.getUTCDate() + dir);
14558 newViewDate = new Date(this.viewDate);
14559 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14561 if (this.dateWithinRange(newDate)){
14562 this.date = newDate;
14563 this.viewDate = newViewDate;
14564 this.setValue(this.formatDate(this.date));
14566 e.preventDefault();
14567 dateChanged = true;
14572 if (!this.keyboardNavigation) break;
14573 dir = e.keyCode == 38 ? -1 : 1;
14575 newDate = this.moveYear(this.date, dir);
14576 newViewDate = this.moveYear(this.viewDate, dir);
14577 } else if (e.shiftKey){
14578 newDate = this.moveMonth(this.date, dir);
14579 newViewDate = this.moveMonth(this.viewDate, dir);
14581 newDate = new Date(this.date);
14582 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14583 newViewDate = new Date(this.viewDate);
14584 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14586 if (this.dateWithinRange(newDate)){
14587 this.date = newDate;
14588 this.viewDate = newViewDate;
14589 this.setValue(this.formatDate(this.date));
14591 e.preventDefault();
14592 dateChanged = true;
14596 this.setValue(this.formatDate(this.date));
14598 e.preventDefault();
14601 this.setValue(this.formatDate(this.date));
14609 onClick: function(e)
14611 e.stopPropagation();
14612 e.preventDefault();
14614 var target = e.getTarget();
14616 if(target.nodeName.toLowerCase() === 'i'){
14617 target = Roo.get(target).dom.parentNode;
14620 var nodeName = target.nodeName;
14621 var className = target.className;
14622 var html = target.innerHTML;
14624 switch(nodeName.toLowerCase()) {
14626 switch(className) {
14632 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14633 switch(this.viewMode){
14635 this.viewDate = this.moveMonth(this.viewDate, dir);
14639 this.viewDate = this.moveYear(this.viewDate, dir);
14645 var date = new Date();
14646 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14648 this.setValue(this.formatDate(this.date));
14655 if (className.indexOf('disabled') === -1) {
14656 this.viewDate.setUTCDate(1);
14657 if (className.indexOf('month') !== -1) {
14658 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14660 var year = parseInt(html, 10) || 0;
14661 this.viewDate.setUTCFullYear(year);
14670 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14671 var day = parseInt(html, 10) || 1;
14672 var year = this.viewDate.getUTCFullYear(),
14673 month = this.viewDate.getUTCMonth();
14675 if (className.indexOf('old') !== -1) {
14682 } else if (className.indexOf('new') !== -1) {
14690 this.date = this.UTCDate(year, month, day,0,0,0,0);
14691 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14693 this.setValue(this.formatDate(this.date));
14700 setStartDate: function(startDate)
14702 this.startDate = startDate || -Infinity;
14703 if (this.startDate !== -Infinity) {
14704 this.startDate = this.parseDate(this.startDate);
14707 this.updateNavArrows();
14710 setEndDate: function(endDate)
14712 this.endDate = endDate || Infinity;
14713 if (this.endDate !== Infinity) {
14714 this.endDate = this.parseDate(this.endDate);
14717 this.updateNavArrows();
14720 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14722 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14723 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14724 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14726 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14727 return parseInt(d, 10);
14730 this.updateNavArrows();
14733 updateNavArrows: function()
14735 var d = new Date(this.viewDate),
14736 year = d.getUTCFullYear(),
14737 month = d.getUTCMonth();
14739 Roo.each(this.picker().select('.prev', true).elements, function(v){
14741 switch (this.viewMode) {
14744 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14750 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14757 Roo.each(this.picker().select('.next', true).elements, function(v){
14759 switch (this.viewMode) {
14762 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14768 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14776 moveMonth: function(date, dir)
14778 if (!dir) return date;
14779 var new_date = new Date(date.valueOf()),
14780 day = new_date.getUTCDate(),
14781 month = new_date.getUTCMonth(),
14782 mag = Math.abs(dir),
14784 dir = dir > 0 ? 1 : -1;
14787 // If going back one month, make sure month is not current month
14788 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14790 return new_date.getUTCMonth() == month;
14792 // If going forward one month, make sure month is as expected
14793 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14795 return new_date.getUTCMonth() != new_month;
14797 new_month = month + dir;
14798 new_date.setUTCMonth(new_month);
14799 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14800 if (new_month < 0 || new_month > 11)
14801 new_month = (new_month + 12) % 12;
14803 // For magnitudes >1, move one month at a time...
14804 for (var i=0; i<mag; i++)
14805 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14806 new_date = this.moveMonth(new_date, dir);
14807 // ...then reset the day, keeping it in the new month
14808 new_month = new_date.getUTCMonth();
14809 new_date.setUTCDate(day);
14811 return new_month != new_date.getUTCMonth();
14814 // Common date-resetting loop -- if date is beyond end of month, make it
14817 new_date.setUTCDate(--day);
14818 new_date.setUTCMonth(new_month);
14823 moveYear: function(date, dir)
14825 return this.moveMonth(date, dir*12);
14828 dateWithinRange: function(date)
14830 return date >= this.startDate && date <= this.endDate;
14836 this.picker().remove();
14841 Roo.apply(Roo.bootstrap.DateField, {
14852 html: '<i class="fa fa-arrow-left"/>'
14862 html: '<i class="fa fa-arrow-right"/>'
14904 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14905 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14906 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14907 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14908 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14921 navFnc: 'FullYear',
14926 navFnc: 'FullYear',
14931 Roo.apply(Roo.bootstrap.DateField, {
14935 cls: 'datepicker dropdown-menu',
14939 cls: 'datepicker-days',
14943 cls: 'table-condensed',
14945 Roo.bootstrap.DateField.head,
14949 Roo.bootstrap.DateField.footer
14956 cls: 'datepicker-months',
14960 cls: 'table-condensed',
14962 Roo.bootstrap.DateField.head,
14963 Roo.bootstrap.DateField.content,
14964 Roo.bootstrap.DateField.footer
14971 cls: 'datepicker-years',
14975 cls: 'table-condensed',
14977 Roo.bootstrap.DateField.head,
14978 Roo.bootstrap.DateField.content,
14979 Roo.bootstrap.DateField.footer
14998 * @class Roo.bootstrap.TimeField
14999 * @extends Roo.bootstrap.Input
15000 * Bootstrap DateField class
15004 * Create a new TimeField
15005 * @param {Object} config The config object
15008 Roo.bootstrap.TimeField = function(config){
15009 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15013 * Fires when this field show.
15014 * @param {Roo.bootstrap.DateField} this
15015 * @param {Mixed} date The date value
15020 * Fires when this field hide.
15021 * @param {Roo.bootstrap.DateField} this
15022 * @param {Mixed} date The date value
15027 * Fires when select a date.
15028 * @param {Roo.bootstrap.DateField} this
15029 * @param {Mixed} date The date value
15035 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15038 * @cfg {String} format
15039 * The default time format string which can be overriden for localization support. The format must be
15040 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15044 onRender: function(ct, position)
15047 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15049 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15051 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15053 this.pop = this.picker().select('>.datepicker-time',true).first();
15054 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15056 this.picker().on('mousedown', this.onMousedown, this);
15057 this.picker().on('click', this.onClick, this);
15059 this.picker().addClass('datepicker-dropdown');
15064 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15065 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15066 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15067 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15068 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15069 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15073 fireKey: function(e){
15074 if (!this.picker().isVisible()){
15075 if (e.keyCode == 27) // allow escape to hide and re-show picker
15080 e.preventDefault();
15088 this.onTogglePeriod();
15091 this.onIncrementMinutes();
15094 this.onDecrementMinutes();
15103 onClick: function(e) {
15104 e.stopPropagation();
15105 e.preventDefault();
15108 picker : function()
15110 return this.el.select('.datepicker', true).first();
15113 fillTime: function()
15115 var time = this.pop.select('tbody', true).first();
15117 time.dom.innerHTML = '';
15132 cls: 'hours-up glyphicon glyphicon-chevron-up'
15152 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15173 cls: 'timepicker-hour',
15188 cls: 'timepicker-minute',
15203 cls: 'btn btn-primary period',
15225 cls: 'hours-down glyphicon glyphicon-chevron-down'
15245 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15263 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15270 var hours = this.time.getHours();
15271 var minutes = this.time.getMinutes();
15284 hours = hours - 12;
15288 hours = '0' + hours;
15292 minutes = '0' + minutes;
15295 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15296 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15297 this.pop.select('button', true).first().dom.innerHTML = period;
15303 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15305 var cls = ['bottom'];
15307 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15314 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15319 this.picker().addClass(cls.join('-'));
15323 Roo.each(cls, function(c){
15325 _this.picker().setTop(_this.inputEl().getHeight());
15329 _this.picker().setTop(0 - _this.picker().getHeight());
15334 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15338 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15345 onFocus : function()
15347 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15351 onBlur : function()
15353 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15359 this.picker().show();
15364 this.fireEvent('show', this, this.date);
15369 this.picker().hide();
15372 this.fireEvent('hide', this, this.date);
15375 setTime : function()
15378 this.setValue(this.time.format(this.format));
15380 this.fireEvent('select', this, this.date);
15385 onMousedown: function(e){
15386 e.stopPropagation();
15387 e.preventDefault();
15390 onIncrementHours: function()
15392 Roo.log('onIncrementHours');
15393 this.time = this.time.add(Date.HOUR, 1);
15398 onDecrementHours: function()
15400 Roo.log('onDecrementHours');
15401 this.time = this.time.add(Date.HOUR, -1);
15405 onIncrementMinutes: function()
15407 Roo.log('onIncrementMinutes');
15408 this.time = this.time.add(Date.MINUTE, 1);
15412 onDecrementMinutes: function()
15414 Roo.log('onDecrementMinutes');
15415 this.time = this.time.add(Date.MINUTE, -1);
15419 onTogglePeriod: function()
15421 Roo.log('onTogglePeriod');
15422 this.time = this.time.add(Date.HOUR, 12);
15429 Roo.apply(Roo.bootstrap.TimeField, {
15459 cls: 'btn btn-info ok',
15471 Roo.apply(Roo.bootstrap.TimeField, {
15475 cls: 'datepicker dropdown-menu',
15479 cls: 'datepicker-time',
15483 cls: 'table-condensed',
15485 Roo.bootstrap.TimeField.content,
15486 Roo.bootstrap.TimeField.footer
15505 * @class Roo.bootstrap.CheckBox
15506 * @extends Roo.bootstrap.Input
15507 * Bootstrap CheckBox class
15509 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15510 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15511 * @cfg {String} boxLabel The text that appears beside the checkbox
15512 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15513 * @cfg {Boolean} checked initnal the element
15517 * Create a new CheckBox
15518 * @param {Object} config The config object
15521 Roo.bootstrap.CheckBox = function(config){
15522 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15527 * Fires when the element is checked or unchecked.
15528 * @param {Roo.bootstrap.CheckBox} this This input
15529 * @param {Boolean} checked The new checked value
15535 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15537 inputType: 'checkbox',
15544 getAutoCreate : function()
15546 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15552 cfg.cls = 'form-group checkbox' //input-group
15560 type : this.inputType,
15561 value : (!this.checked) ? this.valueOff : this.inputValue,
15562 cls : 'roo-checkbox', //'form-box',
15563 placeholder : this.placeholder || ''
15567 if (this.weight) { // Validity check?
15568 cfg.cls += " checkbox-" + this.weight;
15571 if (this.disabled) {
15572 input.disabled=true;
15576 input.checked = this.checked;
15580 input.name = this.name;
15584 input.cls += ' input-' + this.size;
15588 ['xs','sm','md','lg'].map(function(size){
15589 if (settings[size]) {
15590 cfg.cls += ' col-' + size + '-' + settings[size];
15596 var inputblock = input;
15601 if (this.before || this.after) {
15604 cls : 'input-group',
15608 inputblock.cn.push({
15610 cls : 'input-group-addon',
15614 inputblock.cn.push(input);
15616 inputblock.cn.push({
15618 cls : 'input-group-addon',
15625 if (align ==='left' && this.fieldLabel.length) {
15626 Roo.log("left and has label");
15632 cls : 'control-label col-md-' + this.labelWidth,
15633 html : this.fieldLabel
15637 cls : "col-md-" + (12 - this.labelWidth),
15644 } else if ( this.fieldLabel.length) {
15649 tag: this.boxLabel ? 'span' : 'label',
15651 cls: 'control-label box-input-label',
15652 //cls : 'input-group-addon',
15653 html : this.fieldLabel
15663 Roo.log(" no label && no align");
15664 cfg.cn = [ inputblock ] ;
15673 html: this.boxLabel
15685 * return the real input element.
15687 inputEl: function ()
15689 return this.el.select('input.roo-checkbox',true).first();
15694 return this.el.select('label.control-label',true).first();
15697 initEvents : function()
15699 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15701 this.inputEl().on('click', this.onClick, this);
15705 onClick : function()
15707 this.setChecked(!this.checked);
15710 setChecked : function(state,suppressEvent)
15712 this.checked = state;
15714 this.inputEl().dom.checked = state;
15716 if(suppressEvent !== true){
15717 this.fireEvent('check', this, state);
15720 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15724 setValue : function(v,suppressEvent)
15726 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15740 * @class Roo.bootstrap.Radio
15741 * @extends Roo.bootstrap.CheckBox
15742 * Bootstrap Radio class
15745 * Create a new Radio
15746 * @param {Object} config The config object
15749 Roo.bootstrap.Radio = function(config){
15750 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15754 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15756 inputType: 'radio',
15760 getAutoCreate : function()
15762 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15768 cfg.cls = 'form-group radio' //input-group
15773 type : this.inputType,
15774 value : (!this.checked) ? this.valueOff : this.inputValue,
15776 placeholder : this.placeholder || ''
15779 if (this.weight) { // Validity check?
15780 cfg.cls += " radio-" + this.weight;
15782 if (this.disabled) {
15783 input.disabled=true;
15787 input.checked = this.checked;
15791 input.name = this.name;
15795 input.cls += ' input-' + this.size;
15799 ['xs','sm','md','lg'].map(function(size){
15800 if (settings[size]) {
15801 cfg.cls += ' col-' + size + '-' + settings[size];
15805 var inputblock = input;
15807 if (this.before || this.after) {
15810 cls : 'input-group',
15814 inputblock.cn.push({
15816 cls : 'input-group-addon',
15820 inputblock.cn.push(input);
15822 inputblock.cn.push({
15824 cls : 'input-group-addon',
15831 if (align ==='left' && this.fieldLabel.length) {
15832 Roo.log("left and has label");
15838 cls : 'control-label col-md-' + this.labelWidth,
15839 html : this.fieldLabel
15843 cls : "col-md-" + (12 - this.labelWidth),
15850 } else if ( this.fieldLabel.length) {
15857 cls: 'control-label box-input-label',
15858 //cls : 'input-group-addon',
15859 html : this.fieldLabel
15869 Roo.log(" no label && no align");
15884 html: this.boxLabel
15891 inputEl: function ()
15893 return this.el.select('input.roo-radio',true).first();
15895 onClick : function()
15897 this.setChecked(true);
15900 setChecked : function(state,suppressEvent)
15903 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15904 v.dom.checked = false;
15908 this.checked = state;
15909 this.inputEl().dom.checked = state;
15911 if(suppressEvent !== true){
15912 this.fireEvent('check', this, state);
15915 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15919 getGroupValue : function()
15922 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15923 if(v.dom.checked == true){
15924 value = v.dom.value;
15932 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15933 * @return {Mixed} value The field value
15935 getValue : function(){
15936 return this.getGroupValue();
15942 //<script type="text/javascript">
15945 * Based Ext JS Library 1.1.1
15946 * Copyright(c) 2006-2007, Ext JS, LLC.
15952 * @class Roo.HtmlEditorCore
15953 * @extends Roo.Component
15954 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15956 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15959 Roo.HtmlEditorCore = function(config){
15962 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15965 * @event initialize
15966 * Fires when the editor is fully initialized (including the iframe)
15967 * @param {Roo.HtmlEditorCore} this
15972 * Fires when the editor is first receives the focus. Any insertion must wait
15973 * until after this event.
15974 * @param {Roo.HtmlEditorCore} this
15978 * @event beforesync
15979 * Fires before the textarea is updated with content from the editor iframe. Return false
15980 * to cancel the sync.
15981 * @param {Roo.HtmlEditorCore} this
15982 * @param {String} html
15986 * @event beforepush
15987 * Fires before the iframe editor is updated with content from the textarea. Return false
15988 * to cancel the push.
15989 * @param {Roo.HtmlEditorCore} this
15990 * @param {String} html
15995 * Fires when the textarea is updated with content from the editor iframe.
15996 * @param {Roo.HtmlEditorCore} this
15997 * @param {String} html
16002 * Fires when the iframe editor is updated with content from the textarea.
16003 * @param {Roo.HtmlEditorCore} this
16004 * @param {String} html
16009 * @event editorevent
16010 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16011 * @param {Roo.HtmlEditorCore} this
16019 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16023 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16029 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16034 * @cfg {Number} height (in pixels)
16038 * @cfg {Number} width (in pixels)
16043 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16046 stylesheets: false,
16051 // private properties
16052 validationEvent : false,
16054 initialized : false,
16056 sourceEditMode : false,
16057 onFocus : Roo.emptyFn,
16059 hideMode:'offsets',
16067 * Protected method that will not generally be called directly. It
16068 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16069 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16071 getDocMarkup : function(){
16074 Roo.log(this.stylesheets);
16076 // inherit styels from page...??
16077 if (this.stylesheets === false) {
16079 Roo.get(document.head).select('style').each(function(node) {
16080 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16083 Roo.get(document.head).select('link').each(function(node) {
16084 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16087 } else if (!this.stylesheets.length) {
16089 st = '<style type="text/css">' +
16090 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16093 Roo.each(this.stylesheets, function(s) {
16094 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16099 st += '<style type="text/css">' +
16100 'IMG { cursor: pointer } ' +
16104 return '<html><head>' + st +
16105 //<style type="text/css">' +
16106 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16108 ' </head><body class="roo-htmleditor-body"></body></html>';
16112 onRender : function(ct, position)
16115 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16116 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16119 this.el.dom.style.border = '0 none';
16120 this.el.dom.setAttribute('tabIndex', -1);
16121 this.el.addClass('x-hidden hide');
16125 if(Roo.isIE){ // fix IE 1px bogus margin
16126 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16130 this.frameId = Roo.id();
16134 var iframe = this.owner.wrap.createChild({
16136 cls: 'form-control', // bootstrap..
16138 name: this.frameId,
16139 frameBorder : 'no',
16140 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16145 this.iframe = iframe.dom;
16147 this.assignDocWin();
16149 this.doc.designMode = 'on';
16152 this.doc.write(this.getDocMarkup());
16156 var task = { // must defer to wait for browser to be ready
16158 //console.log("run task?" + this.doc.readyState);
16159 this.assignDocWin();
16160 if(this.doc.body || this.doc.readyState == 'complete'){
16162 this.doc.designMode="on";
16166 Roo.TaskMgr.stop(task);
16167 this.initEditor.defer(10, this);
16174 Roo.TaskMgr.start(task);
16181 onResize : function(w, h)
16183 Roo.log('resize: ' +w + ',' + h );
16184 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16188 if(typeof w == 'number'){
16190 this.iframe.style.width = w + 'px';
16192 if(typeof h == 'number'){
16194 this.iframe.style.height = h + 'px';
16196 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16203 * Toggles the editor between standard and source edit mode.
16204 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16206 toggleSourceEdit : function(sourceEditMode){
16208 this.sourceEditMode = sourceEditMode === true;
16210 if(this.sourceEditMode){
16212 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16215 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16216 //this.iframe.className = '';
16219 //this.setSize(this.owner.wrap.getSize());
16220 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16227 * Protected method that will not generally be called directly. If you need/want
16228 * custom HTML cleanup, this is the method you should override.
16229 * @param {String} html The HTML to be cleaned
16230 * return {String} The cleaned HTML
16232 cleanHtml : function(html){
16233 html = String(html);
16234 if(html.length > 5){
16235 if(Roo.isSafari){ // strip safari nonsense
16236 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16239 if(html == ' '){
16246 * HTML Editor -> Textarea
16247 * Protected method that will not generally be called directly. Syncs the contents
16248 * of the editor iframe with the textarea.
16250 syncValue : function(){
16251 if(this.initialized){
16252 var bd = (this.doc.body || this.doc.documentElement);
16253 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16254 var html = bd.innerHTML;
16256 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16257 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16259 html = '<div style="'+m[0]+'">' + html + '</div>';
16262 html = this.cleanHtml(html);
16263 // fix up the special chars.. normaly like back quotes in word...
16264 // however we do not want to do this with chinese..
16265 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16266 var cc = b.charCodeAt();
16268 (cc >= 0x4E00 && cc < 0xA000 ) ||
16269 (cc >= 0x3400 && cc < 0x4E00 ) ||
16270 (cc >= 0xf900 && cc < 0xfb00 )
16276 if(this.owner.fireEvent('beforesync', this, html) !== false){
16277 this.el.dom.value = html;
16278 this.owner.fireEvent('sync', this, html);
16284 * Protected method that will not generally be called directly. Pushes the value of the textarea
16285 * into the iframe editor.
16287 pushValue : function(){
16288 if(this.initialized){
16289 var v = this.el.dom.value.trim();
16291 // if(v.length < 1){
16295 if(this.owner.fireEvent('beforepush', this, v) !== false){
16296 var d = (this.doc.body || this.doc.documentElement);
16298 this.cleanUpPaste();
16299 this.el.dom.value = d.innerHTML;
16300 this.owner.fireEvent('push', this, v);
16306 deferFocus : function(){
16307 this.focus.defer(10, this);
16311 focus : function(){
16312 if(this.win && !this.sourceEditMode){
16319 assignDocWin: function()
16321 var iframe = this.iframe;
16324 this.doc = iframe.contentWindow.document;
16325 this.win = iframe.contentWindow;
16327 if (!Roo.get(this.frameId)) {
16330 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16331 this.win = Roo.get(this.frameId).dom.contentWindow;
16336 initEditor : function(){
16337 //console.log("INIT EDITOR");
16338 this.assignDocWin();
16342 this.doc.designMode="on";
16344 this.doc.write(this.getDocMarkup());
16347 var dbody = (this.doc.body || this.doc.documentElement);
16348 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16349 // this copies styles from the containing element into thsi one..
16350 // not sure why we need all of this..
16351 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16353 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16354 //ss['background-attachment'] = 'fixed'; // w3c
16355 dbody.bgProperties = 'fixed'; // ie
16356 //Roo.DomHelper.applyStyles(dbody, ss);
16357 Roo.EventManager.on(this.doc, {
16358 //'mousedown': this.onEditorEvent,
16359 'mouseup': this.onEditorEvent,
16360 'dblclick': this.onEditorEvent,
16361 'click': this.onEditorEvent,
16362 'keyup': this.onEditorEvent,
16367 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16369 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16370 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16372 this.initialized = true;
16374 this.owner.fireEvent('initialize', this);
16379 onDestroy : function(){
16385 //for (var i =0; i < this.toolbars.length;i++) {
16386 // // fixme - ask toolbars for heights?
16387 // this.toolbars[i].onDestroy();
16390 //this.wrap.dom.innerHTML = '';
16391 //this.wrap.remove();
16396 onFirstFocus : function(){
16398 this.assignDocWin();
16401 this.activated = true;
16404 if(Roo.isGecko){ // prevent silly gecko errors
16406 var s = this.win.getSelection();
16407 if(!s.focusNode || s.focusNode.nodeType != 3){
16408 var r = s.getRangeAt(0);
16409 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16414 this.execCmd('useCSS', true);
16415 this.execCmd('styleWithCSS', false);
16418 this.owner.fireEvent('activate', this);
16422 adjustFont: function(btn){
16423 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16424 //if(Roo.isSafari){ // safari
16427 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16428 if(Roo.isSafari){ // safari
16429 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16430 v = (v < 10) ? 10 : v;
16431 v = (v > 48) ? 48 : v;
16432 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16437 v = Math.max(1, v+adjust);
16439 this.execCmd('FontSize', v );
16442 onEditorEvent : function(e){
16443 this.owner.fireEvent('editorevent', this, e);
16444 // this.updateToolbar();
16445 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16448 insertTag : function(tg)
16450 // could be a bit smarter... -> wrap the current selected tRoo..
16451 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16453 range = this.createRange(this.getSelection());
16454 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16455 wrappingNode.appendChild(range.extractContents());
16456 range.insertNode(wrappingNode);
16463 this.execCmd("formatblock", tg);
16467 insertText : function(txt)
16471 var range = this.createRange();
16472 range.deleteContents();
16473 //alert(Sender.getAttribute('label'));
16475 range.insertNode(this.doc.createTextNode(txt));
16481 * Executes a Midas editor command on the editor document and performs necessary focus and
16482 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16483 * @param {String} cmd The Midas command
16484 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16486 relayCmd : function(cmd, value){
16488 this.execCmd(cmd, value);
16489 this.owner.fireEvent('editorevent', this);
16490 //this.updateToolbar();
16491 this.owner.deferFocus();
16495 * Executes a Midas editor command directly on the editor document.
16496 * For visual commands, you should use {@link #relayCmd} instead.
16497 * <b>This should only be called after the editor is initialized.</b>
16498 * @param {String} cmd The Midas command
16499 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16501 execCmd : function(cmd, value){
16502 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16509 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16511 * @param {String} text | dom node..
16513 insertAtCursor : function(text)
16518 if(!this.activated){
16524 var r = this.doc.selection.createRange();
16535 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16539 // from jquery ui (MIT licenced)
16541 var win = this.win;
16543 if (win.getSelection && win.getSelection().getRangeAt) {
16544 range = win.getSelection().getRangeAt(0);
16545 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16546 range.insertNode(node);
16547 } else if (win.document.selection && win.document.selection.createRange) {
16548 // no firefox support
16549 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16550 win.document.selection.createRange().pasteHTML(txt);
16552 // no firefox support
16553 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16554 this.execCmd('InsertHTML', txt);
16563 mozKeyPress : function(e){
16565 var c = e.getCharCode(), cmd;
16568 c = String.fromCharCode(c).toLowerCase();
16582 this.cleanUpPaste.defer(100, this);
16590 e.preventDefault();
16598 fixKeys : function(){ // load time branching for fastest keydown performance
16600 return function(e){
16601 var k = e.getKey(), r;
16604 r = this.doc.selection.createRange();
16607 r.pasteHTML('    ');
16614 r = this.doc.selection.createRange();
16616 var target = r.parentElement();
16617 if(!target || target.tagName.toLowerCase() != 'li'){
16619 r.pasteHTML('<br />');
16625 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16626 this.cleanUpPaste.defer(100, this);
16632 }else if(Roo.isOpera){
16633 return function(e){
16634 var k = e.getKey();
16638 this.execCmd('InsertHTML','    ');
16641 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16642 this.cleanUpPaste.defer(100, this);
16647 }else if(Roo.isSafari){
16648 return function(e){
16649 var k = e.getKey();
16653 this.execCmd('InsertText','\t');
16657 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16658 this.cleanUpPaste.defer(100, this);
16666 getAllAncestors: function()
16668 var p = this.getSelectedNode();
16671 a.push(p); // push blank onto stack..
16672 p = this.getParentElement();
16676 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16680 a.push(this.doc.body);
16684 lastSelNode : false,
16687 getSelection : function()
16689 this.assignDocWin();
16690 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16693 getSelectedNode: function()
16695 // this may only work on Gecko!!!
16697 // should we cache this!!!!
16702 var range = this.createRange(this.getSelection()).cloneRange();
16705 var parent = range.parentElement();
16707 var testRange = range.duplicate();
16708 testRange.moveToElementText(parent);
16709 if (testRange.inRange(range)) {
16712 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16715 parent = parent.parentElement;
16720 // is ancestor a text element.
16721 var ac = range.commonAncestorContainer;
16722 if (ac.nodeType == 3) {
16723 ac = ac.parentNode;
16726 var ar = ac.childNodes;
16729 var other_nodes = [];
16730 var has_other_nodes = false;
16731 for (var i=0;i<ar.length;i++) {
16732 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16735 // fullly contained node.
16737 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16742 // probably selected..
16743 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16744 other_nodes.push(ar[i]);
16748 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16753 has_other_nodes = true;
16755 if (!nodes.length && other_nodes.length) {
16756 nodes= other_nodes;
16758 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16764 createRange: function(sel)
16766 // this has strange effects when using with
16767 // top toolbar - not sure if it's a great idea.
16768 //this.editor.contentWindow.focus();
16769 if (typeof sel != "undefined") {
16771 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16773 return this.doc.createRange();
16776 return this.doc.createRange();
16779 getParentElement: function()
16782 this.assignDocWin();
16783 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16785 var range = this.createRange(sel);
16788 var p = range.commonAncestorContainer;
16789 while (p.nodeType == 3) { // text node
16800 * Range intersection.. the hard stuff...
16804 * [ -- selected range --- ]
16808 * if end is before start or hits it. fail.
16809 * if start is after end or hits it fail.
16811 * if either hits (but other is outside. - then it's not
16817 // @see http://www.thismuchiknow.co.uk/?p=64.
16818 rangeIntersectsNode : function(range, node)
16820 var nodeRange = node.ownerDocument.createRange();
16822 nodeRange.selectNode(node);
16824 nodeRange.selectNodeContents(node);
16827 var rangeStartRange = range.cloneRange();
16828 rangeStartRange.collapse(true);
16830 var rangeEndRange = range.cloneRange();
16831 rangeEndRange.collapse(false);
16833 var nodeStartRange = nodeRange.cloneRange();
16834 nodeStartRange.collapse(true);
16836 var nodeEndRange = nodeRange.cloneRange();
16837 nodeEndRange.collapse(false);
16839 return rangeStartRange.compareBoundaryPoints(
16840 Range.START_TO_START, nodeEndRange) == -1 &&
16841 rangeEndRange.compareBoundaryPoints(
16842 Range.START_TO_START, nodeStartRange) == 1;
16846 rangeCompareNode : function(range, node)
16848 var nodeRange = node.ownerDocument.createRange();
16850 nodeRange.selectNode(node);
16852 nodeRange.selectNodeContents(node);
16856 range.collapse(true);
16858 nodeRange.collapse(true);
16860 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16861 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16863 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16865 var nodeIsBefore = ss == 1;
16866 var nodeIsAfter = ee == -1;
16868 if (nodeIsBefore && nodeIsAfter)
16870 if (!nodeIsBefore && nodeIsAfter)
16871 return 1; //right trailed.
16873 if (nodeIsBefore && !nodeIsAfter)
16874 return 2; // left trailed.
16879 // private? - in a new class?
16880 cleanUpPaste : function()
16882 // cleans up the whole document..
16883 Roo.log('cleanuppaste');
16885 this.cleanUpChildren(this.doc.body);
16886 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16887 if (clean != this.doc.body.innerHTML) {
16888 this.doc.body.innerHTML = clean;
16893 cleanWordChars : function(input) {// change the chars to hex code
16894 var he = Roo.HtmlEditorCore;
16896 var output = input;
16897 Roo.each(he.swapCodes, function(sw) {
16898 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16900 output = output.replace(swapper, sw[1]);
16907 cleanUpChildren : function (n)
16909 if (!n.childNodes.length) {
16912 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16913 this.cleanUpChild(n.childNodes[i]);
16920 cleanUpChild : function (node)
16923 //console.log(node);
16924 if (node.nodeName == "#text") {
16925 // clean up silly Windows -- stuff?
16928 if (node.nodeName == "#comment") {
16929 node.parentNode.removeChild(node);
16930 // clean up silly Windows -- stuff?
16934 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16936 node.parentNode.removeChild(node);
16941 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16943 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16944 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16946 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16947 // remove_keep_children = true;
16950 if (remove_keep_children) {
16951 this.cleanUpChildren(node);
16952 // inserts everything just before this node...
16953 while (node.childNodes.length) {
16954 var cn = node.childNodes[0];
16955 node.removeChild(cn);
16956 node.parentNode.insertBefore(cn, node);
16958 node.parentNode.removeChild(node);
16962 if (!node.attributes || !node.attributes.length) {
16963 this.cleanUpChildren(node);
16967 function cleanAttr(n,v)
16970 if (v.match(/^\./) || v.match(/^\//)) {
16973 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16976 if (v.match(/^#/)) {
16979 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16980 node.removeAttribute(n);
16984 function cleanStyle(n,v)
16986 if (v.match(/expression/)) { //XSS?? should we even bother..
16987 node.removeAttribute(n);
16990 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16991 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16994 var parts = v.split(/;/);
16997 Roo.each(parts, function(p) {
16998 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17002 var l = p.split(':').shift().replace(/\s+/g,'');
17003 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17005 if ( cblack.indexOf(l) > -1) {
17006 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17007 //node.removeAttribute(n);
17011 // only allow 'c whitelisted system attributes'
17012 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17013 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17014 //node.removeAttribute(n);
17024 if (clean.length) {
17025 node.setAttribute(n, clean.join(';'));
17027 node.removeAttribute(n);
17033 for (var i = node.attributes.length-1; i > -1 ; i--) {
17034 var a = node.attributes[i];
17037 if (a.name.toLowerCase().substr(0,2)=='on') {
17038 node.removeAttribute(a.name);
17041 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17042 node.removeAttribute(a.name);
17045 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17046 cleanAttr(a.name,a.value); // fixme..
17049 if (a.name == 'style') {
17050 cleanStyle(a.name,a.value);
17053 /// clean up MS crap..
17054 // tecnically this should be a list of valid class'es..
17057 if (a.name == 'class') {
17058 if (a.value.match(/^Mso/)) {
17059 node.className = '';
17062 if (a.value.match(/body/)) {
17063 node.className = '';
17074 this.cleanUpChildren(node);
17079 * Clean up MS wordisms...
17081 cleanWord : function(node)
17084 var cleanWordChildren = function()
17086 if (!node.childNodes.length) {
17089 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17090 _t.cleanWord(node.childNodes[i]);
17096 this.cleanWord(this.doc.body);
17099 if (node.nodeName == "#text") {
17100 // clean up silly Windows -- stuff?
17103 if (node.nodeName == "#comment") {
17104 node.parentNode.removeChild(node);
17105 // clean up silly Windows -- stuff?
17109 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17110 node.parentNode.removeChild(node);
17114 // remove - but keep children..
17115 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17116 while (node.childNodes.length) {
17117 var cn = node.childNodes[0];
17118 node.removeChild(cn);
17119 node.parentNode.insertBefore(cn, node);
17121 node.parentNode.removeChild(node);
17122 cleanWordChildren();
17126 if (node.className.length) {
17128 var cn = node.className.split(/\W+/);
17130 Roo.each(cn, function(cls) {
17131 if (cls.match(/Mso[a-zA-Z]+/)) {
17136 node.className = cna.length ? cna.join(' ') : '';
17138 node.removeAttribute("class");
17142 if (node.hasAttribute("lang")) {
17143 node.removeAttribute("lang");
17146 if (node.hasAttribute("style")) {
17148 var styles = node.getAttribute("style").split(";");
17150 Roo.each(styles, function(s) {
17151 if (!s.match(/:/)) {
17154 var kv = s.split(":");
17155 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17158 // what ever is left... we allow.
17161 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17162 if (!nstyle.length) {
17163 node.removeAttribute('style');
17167 cleanWordChildren();
17171 domToHTML : function(currentElement, depth, nopadtext) {
17173 depth = depth || 0;
17174 nopadtext = nopadtext || false;
17176 if (!currentElement) {
17177 return this.domToHTML(this.doc.body);
17180 //Roo.log(currentElement);
17182 var allText = false;
17183 var nodeName = currentElement.nodeName;
17184 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17186 if (nodeName == '#text') {
17187 return currentElement.nodeValue;
17192 if (nodeName != 'BODY') {
17195 // Prints the node tagName, such as <A>, <IMG>, etc
17198 for(i = 0; i < currentElement.attributes.length;i++) {
17200 var aname = currentElement.attributes.item(i).name;
17201 if (!currentElement.attributes.item(i).value.length) {
17204 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17207 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17216 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17219 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17224 // Traverse the tree
17226 var currentElementChild = currentElement.childNodes.item(i);
17227 var allText = true;
17228 var innerHTML = '';
17230 while (currentElementChild) {
17231 // Formatting code (indent the tree so it looks nice on the screen)
17232 var nopad = nopadtext;
17233 if (lastnode == 'SPAN') {
17237 if (currentElementChild.nodeName == '#text') {
17238 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17239 if (!nopad && toadd.length > 80) {
17240 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17242 innerHTML += toadd;
17245 currentElementChild = currentElement.childNodes.item(i);
17251 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17253 // Recursively traverse the tree structure of the child node
17254 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17255 lastnode = currentElementChild.nodeName;
17257 currentElementChild=currentElement.childNodes.item(i);
17263 // The remaining code is mostly for formatting the tree
17264 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17269 ret+= "</"+tagName+">";
17275 // hide stuff that is not compatible
17289 * @event specialkey
17293 * @cfg {String} fieldClass @hide
17296 * @cfg {String} focusClass @hide
17299 * @cfg {String} autoCreate @hide
17302 * @cfg {String} inputType @hide
17305 * @cfg {String} invalidClass @hide
17308 * @cfg {String} invalidText @hide
17311 * @cfg {String} msgFx @hide
17314 * @cfg {String} validateOnBlur @hide
17318 Roo.HtmlEditorCore.white = [
17319 'area', 'br', 'img', 'input', 'hr', 'wbr',
17321 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17322 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17323 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17324 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17325 'table', 'ul', 'xmp',
17327 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17330 'dir', 'menu', 'ol', 'ul', 'dl',
17336 Roo.HtmlEditorCore.black = [
17337 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17339 'base', 'basefont', 'bgsound', 'blink', 'body',
17340 'frame', 'frameset', 'head', 'html', 'ilayer',
17341 'iframe', 'layer', 'link', 'meta', 'object',
17342 'script', 'style' ,'title', 'xml' // clean later..
17344 Roo.HtmlEditorCore.clean = [
17345 'script', 'style', 'title', 'xml'
17347 Roo.HtmlEditorCore.remove = [
17352 Roo.HtmlEditorCore.ablack = [
17356 Roo.HtmlEditorCore.aclean = [
17357 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17361 Roo.HtmlEditorCore.pwhite= [
17362 'http', 'https', 'mailto'
17365 // white listed style attributes.
17366 Roo.HtmlEditorCore.cwhite= [
17367 // 'text-align', /// default is to allow most things..
17373 // black listed style attributes.
17374 Roo.HtmlEditorCore.cblack= [
17375 // 'font-size' -- this can be set by the project
17379 Roo.HtmlEditorCore.swapCodes =[
17398 * @class Roo.bootstrap.HtmlEditor
17399 * @extends Roo.bootstrap.TextArea
17400 * Bootstrap HtmlEditor class
17403 * Create a new HtmlEditor
17404 * @param {Object} config The config object
17407 Roo.bootstrap.HtmlEditor = function(config){
17408 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17409 if (!this.toolbars) {
17410 this.toolbars = [];
17412 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17415 * @event initialize
17416 * Fires when the editor is fully initialized (including the iframe)
17417 * @param {HtmlEditor} this
17422 * Fires when the editor is first receives the focus. Any insertion must wait
17423 * until after this event.
17424 * @param {HtmlEditor} this
17428 * @event beforesync
17429 * Fires before the textarea is updated with content from the editor iframe. Return false
17430 * to cancel the sync.
17431 * @param {HtmlEditor} this
17432 * @param {String} html
17436 * @event beforepush
17437 * Fires before the iframe editor is updated with content from the textarea. Return false
17438 * to cancel the push.
17439 * @param {HtmlEditor} this
17440 * @param {String} html
17445 * Fires when the textarea is updated with content from the editor iframe.
17446 * @param {HtmlEditor} this
17447 * @param {String} html
17452 * Fires when the iframe editor is updated with content from the textarea.
17453 * @param {HtmlEditor} this
17454 * @param {String} html
17458 * @event editmodechange
17459 * Fires when the editor switches edit modes
17460 * @param {HtmlEditor} this
17461 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17463 editmodechange: true,
17465 * @event editorevent
17466 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17467 * @param {HtmlEditor} this
17471 * @event firstfocus
17472 * Fires when on first focus - needed by toolbars..
17473 * @param {HtmlEditor} this
17478 * Auto save the htmlEditor value as a file into Events
17479 * @param {HtmlEditor} this
17483 * @event savedpreview
17484 * preview the saved version of htmlEditor
17485 * @param {HtmlEditor} this
17492 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17496 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17501 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17506 * @cfg {Number} height (in pixels)
17510 * @cfg {Number} width (in pixels)
17515 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17518 stylesheets: false,
17523 // private properties
17524 validationEvent : false,
17526 initialized : false,
17529 onFocus : Roo.emptyFn,
17531 hideMode:'offsets',
17534 tbContainer : false,
17536 toolbarContainer :function() {
17537 return this.wrap.select('.x-html-editor-tb',true).first();
17541 * Protected method that will not generally be called directly. It
17542 * is called when the editor creates its toolbar. Override this method if you need to
17543 * add custom toolbar buttons.
17544 * @param {HtmlEditor} editor
17546 createToolbar : function(){
17548 Roo.log("create toolbars");
17550 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17551 this.toolbars[0].render(this.toolbarContainer());
17555 // if (!editor.toolbars || !editor.toolbars.length) {
17556 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17559 // for (var i =0 ; i < editor.toolbars.length;i++) {
17560 // editor.toolbars[i] = Roo.factory(
17561 // typeof(editor.toolbars[i]) == 'string' ?
17562 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17563 // Roo.bootstrap.HtmlEditor);
17564 // editor.toolbars[i].init(editor);
17570 onRender : function(ct, position)
17572 // Roo.log("Call onRender: " + this.xtype);
17574 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17576 this.wrap = this.inputEl().wrap({
17577 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17580 this.editorcore.onRender(ct, position);
17582 if (this.resizable) {
17583 this.resizeEl = new Roo.Resizable(this.wrap, {
17587 minHeight : this.height,
17588 height: this.height,
17589 handles : this.resizable,
17592 resize : function(r, w, h) {
17593 _t.onResize(w,h); // -something
17599 this.createToolbar(this);
17602 if(!this.width && this.resizable){
17603 this.setSize(this.wrap.getSize());
17605 if (this.resizeEl) {
17606 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17607 // should trigger onReize..
17613 onResize : function(w, h)
17615 Roo.log('resize: ' +w + ',' + h );
17616 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17620 if(this.inputEl() ){
17621 if(typeof w == 'number'){
17622 var aw = w - this.wrap.getFrameWidth('lr');
17623 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17626 if(typeof h == 'number'){
17627 var tbh = -11; // fixme it needs to tool bar size!
17628 for (var i =0; i < this.toolbars.length;i++) {
17629 // fixme - ask toolbars for heights?
17630 tbh += this.toolbars[i].el.getHeight();
17631 //if (this.toolbars[i].footer) {
17632 // tbh += this.toolbars[i].footer.el.getHeight();
17640 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17641 ah -= 5; // knock a few pixes off for look..
17642 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17646 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17647 this.editorcore.onResize(ew,eh);
17652 * Toggles the editor between standard and source edit mode.
17653 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17655 toggleSourceEdit : function(sourceEditMode)
17657 this.editorcore.toggleSourceEdit(sourceEditMode);
17659 if(this.editorcore.sourceEditMode){
17660 Roo.log('editor - showing textarea');
17663 // Roo.log(this.syncValue());
17665 this.inputEl().removeClass(['hide', 'x-hidden']);
17666 this.inputEl().dom.removeAttribute('tabIndex');
17667 this.inputEl().focus();
17669 Roo.log('editor - hiding textarea');
17671 // Roo.log(this.pushValue());
17674 this.inputEl().addClass(['hide', 'x-hidden']);
17675 this.inputEl().dom.setAttribute('tabIndex', -1);
17676 //this.deferFocus();
17679 if(this.resizable){
17680 this.setSize(this.wrap.getSize());
17683 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17686 // private (for BoxComponent)
17687 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17689 // private (for BoxComponent)
17690 getResizeEl : function(){
17694 // private (for BoxComponent)
17695 getPositionEl : function(){
17700 initEvents : function(){
17701 this.originalValue = this.getValue();
17705 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17708 // markInvalid : Roo.emptyFn,
17710 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17713 // clearInvalid : Roo.emptyFn,
17715 setValue : function(v){
17716 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17717 this.editorcore.pushValue();
17722 deferFocus : function(){
17723 this.focus.defer(10, this);
17727 focus : function(){
17728 this.editorcore.focus();
17734 onDestroy : function(){
17740 for (var i =0; i < this.toolbars.length;i++) {
17741 // fixme - ask toolbars for heights?
17742 this.toolbars[i].onDestroy();
17745 this.wrap.dom.innerHTML = '';
17746 this.wrap.remove();
17751 onFirstFocus : function(){
17752 //Roo.log("onFirstFocus");
17753 this.editorcore.onFirstFocus();
17754 for (var i =0; i < this.toolbars.length;i++) {
17755 this.toolbars[i].onFirstFocus();
17761 syncValue : function()
17763 this.editorcore.syncValue();
17766 pushValue : function()
17768 this.editorcore.pushValue();
17772 // hide stuff that is not compatible
17786 * @event specialkey
17790 * @cfg {String} fieldClass @hide
17793 * @cfg {String} focusClass @hide
17796 * @cfg {String} autoCreate @hide
17799 * @cfg {String} inputType @hide
17802 * @cfg {String} invalidClass @hide
17805 * @cfg {String} invalidText @hide
17808 * @cfg {String} msgFx @hide
17811 * @cfg {String} validateOnBlur @hide
17820 Roo.namespace('Roo.bootstrap.htmleditor');
17822 * @class Roo.bootstrap.HtmlEditorToolbar1
17827 new Roo.bootstrap.HtmlEditor({
17830 new Roo.bootstrap.HtmlEditorToolbar1({
17831 disable : { fonts: 1 , format: 1, ..., ... , ...],
17837 * @cfg {Object} disable List of elements to disable..
17838 * @cfg {Array} btns List of additional buttons.
17842 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17845 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17848 Roo.apply(this, config);
17850 // default disabled, based on 'good practice'..
17851 this.disable = this.disable || {};
17852 Roo.applyIf(this.disable, {
17855 specialElements : true
17857 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17859 this.editor = config.editor;
17860 this.editorcore = config.editor.editorcore;
17862 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17864 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17865 // dont call parent... till later.
17867 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17872 editorcore : false,
17877 "h1","h2","h3","h4","h5","h6",
17879 "abbr", "acronym", "address", "cite", "samp", "var",
17883 onRender : function(ct, position)
17885 // Roo.log("Call onRender: " + this.xtype);
17887 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17889 this.el.dom.style.marginBottom = '0';
17891 var editorcore = this.editorcore;
17892 var editor= this.editor;
17895 var btn = function(id,cmd , toggle, handler){
17897 var event = toggle ? 'toggle' : 'click';
17902 xns: Roo.bootstrap,
17905 enableToggle:toggle !== false,
17907 pressed : toggle ? false : null,
17910 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17911 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17920 xns: Roo.bootstrap,
17921 glyphicon : 'font',
17925 xns: Roo.bootstrap,
17929 Roo.each(this.formats, function(f) {
17930 style.menu.items.push({
17932 xns: Roo.bootstrap,
17933 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17938 editorcore.insertTag(this.tagname);
17945 children.push(style);
17948 btn('bold',false,true);
17949 btn('italic',false,true);
17950 btn('align-left', 'justifyleft',true);
17951 btn('align-center', 'justifycenter',true);
17952 btn('align-right' , 'justifyright',true);
17953 btn('link', false, false, function(btn) {
17954 //Roo.log("create link?");
17955 var url = prompt(this.createLinkText, this.defaultLinkValue);
17956 if(url && url != 'http:/'+'/'){
17957 this.editorcore.relayCmd('createlink', url);
17960 btn('list','insertunorderedlist',true);
17961 btn('pencil', false,true, function(btn){
17964 this.toggleSourceEdit(btn.pressed);
17970 xns: Roo.bootstrap,
17975 xns: Roo.bootstrap,
17980 cog.menu.items.push({
17982 xns: Roo.bootstrap,
17983 html : Clean styles,
17988 editorcore.insertTag(this.tagname);
17997 this.xtype = 'NavSimplebar';
17999 for(var i=0;i< children.length;i++) {
18001 this.buttons.add(this.addxtypeChild(children[i]));
18005 editor.on('editorevent', this.updateToolbar, this);
18007 onBtnClick : function(id)
18009 this.editorcore.relayCmd(id);
18010 this.editorcore.focus();
18014 * Protected method that will not generally be called directly. It triggers
18015 * a toolbar update by reading the markup state of the current selection in the editor.
18017 updateToolbar: function(){
18019 if(!this.editorcore.activated){
18020 this.editor.onFirstFocus(); // is this neeed?
18024 var btns = this.buttons;
18025 var doc = this.editorcore.doc;
18026 btns.get('bold').setActive(doc.queryCommandState('bold'));
18027 btns.get('italic').setActive(doc.queryCommandState('italic'));
18028 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18030 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18031 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18032 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18034 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18035 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18038 var ans = this.editorcore.getAllAncestors();
18039 if (this.formatCombo) {
18042 var store = this.formatCombo.store;
18043 this.formatCombo.setValue("");
18044 for (var i =0; i < ans.length;i++) {
18045 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18047 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18055 // hides menus... - so this cant be on a menu...
18056 Roo.bootstrap.MenuMgr.hideAll();
18058 Roo.bootstrap.MenuMgr.hideAll();
18059 //this.editorsyncValue();
18061 onFirstFocus: function() {
18062 this.buttons.each(function(item){
18066 toggleSourceEdit : function(sourceEditMode){
18069 if(sourceEditMode){
18070 Roo.log("disabling buttons");
18071 this.buttons.each( function(item){
18072 if(item.cmd != 'pencil'){
18078 Roo.log("enabling buttons");
18079 if(this.editorcore.initialized){
18080 this.buttons.each( function(item){
18086 Roo.log("calling toggole on editor");
18087 // tell the editor that it's been pressed..
18088 this.editor.toggleSourceEdit(sourceEditMode);
18098 * @class Roo.bootstrap.Table.AbstractSelectionModel
18099 * @extends Roo.util.Observable
18100 * Abstract base class for grid SelectionModels. It provides the interface that should be
18101 * implemented by descendant classes. This class should not be directly instantiated.
18104 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18105 this.locked = false;
18106 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18110 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18111 /** @ignore Called by the grid automatically. Do not call directly. */
18112 init : function(grid){
18118 * Locks the selections.
18121 this.locked = true;
18125 * Unlocks the selections.
18127 unlock : function(){
18128 this.locked = false;
18132 * Returns true if the selections are locked.
18133 * @return {Boolean}
18135 isLocked : function(){
18136 return this.locked;
18140 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18141 * @class Roo.bootstrap.Table.RowSelectionModel
18142 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18143 * It supports multiple selections and keyboard selection/navigation.
18145 * @param {Object} config
18148 Roo.bootstrap.Table.RowSelectionModel = function(config){
18149 Roo.apply(this, config);
18150 this.selections = new Roo.util.MixedCollection(false, function(o){
18155 this.lastActive = false;
18159 * @event selectionchange
18160 * Fires when the selection changes
18161 * @param {SelectionModel} this
18163 "selectionchange" : true,
18165 * @event afterselectionchange
18166 * Fires after the selection changes (eg. by key press or clicking)
18167 * @param {SelectionModel} this
18169 "afterselectionchange" : true,
18171 * @event beforerowselect
18172 * Fires when a row is selected being selected, return false to cancel.
18173 * @param {SelectionModel} this
18174 * @param {Number} rowIndex The selected index
18175 * @param {Boolean} keepExisting False if other selections will be cleared
18177 "beforerowselect" : true,
18180 * Fires when a row is selected.
18181 * @param {SelectionModel} this
18182 * @param {Number} rowIndex The selected index
18183 * @param {Roo.data.Record} r The record
18185 "rowselect" : true,
18187 * @event rowdeselect
18188 * Fires when a row is deselected.
18189 * @param {SelectionModel} this
18190 * @param {Number} rowIndex The selected index
18192 "rowdeselect" : true
18194 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18195 this.locked = false;
18198 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18200 * @cfg {Boolean} singleSelect
18201 * True to allow selection of only one row at a time (defaults to false)
18203 singleSelect : false,
18206 initEvents : function(){
18208 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18209 this.grid.on("mousedown", this.handleMouseDown, this);
18210 }else{ // allow click to work like normal
18211 this.grid.on("rowclick", this.handleDragableRowClick, this);
18214 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18215 "up" : function(e){
18217 this.selectPrevious(e.shiftKey);
18218 }else if(this.last !== false && this.lastActive !== false){
18219 var last = this.last;
18220 this.selectRange(this.last, this.lastActive-1);
18221 this.grid.getView().focusRow(this.lastActive);
18222 if(last !== false){
18226 this.selectFirstRow();
18228 this.fireEvent("afterselectionchange", this);
18230 "down" : function(e){
18232 this.selectNext(e.shiftKey);
18233 }else if(this.last !== false && this.lastActive !== false){
18234 var last = this.last;
18235 this.selectRange(this.last, this.lastActive+1);
18236 this.grid.getView().focusRow(this.lastActive);
18237 if(last !== false){
18241 this.selectFirstRow();
18243 this.fireEvent("afterselectionchange", this);
18248 var view = this.grid.view;
18249 view.on("refresh", this.onRefresh, this);
18250 view.on("rowupdated", this.onRowUpdated, this);
18251 view.on("rowremoved", this.onRemove, this);
18255 onRefresh : function(){
18256 var ds = this.grid.dataSource, i, v = this.grid.view;
18257 var s = this.selections;
18258 s.each(function(r){
18259 if((i = ds.indexOfId(r.id)) != -1){
18268 onRemove : function(v, index, r){
18269 this.selections.remove(r);
18273 onRowUpdated : function(v, index, r){
18274 if(this.isSelected(r)){
18275 v.onRowSelect(index);
18281 * @param {Array} records The records to select
18282 * @param {Boolean} keepExisting (optional) True to keep existing selections
18284 selectRecords : function(records, keepExisting){
18286 this.clearSelections();
18288 var ds = this.grid.dataSource;
18289 for(var i = 0, len = records.length; i < len; i++){
18290 this.selectRow(ds.indexOf(records[i]), true);
18295 * Gets the number of selected rows.
18298 getCount : function(){
18299 return this.selections.length;
18303 * Selects the first row in the grid.
18305 selectFirstRow : function(){
18310 * Select the last row.
18311 * @param {Boolean} keepExisting (optional) True to keep existing selections
18313 selectLastRow : function(keepExisting){
18314 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18318 * Selects the row immediately following the last selected row.
18319 * @param {Boolean} keepExisting (optional) True to keep existing selections
18321 selectNext : function(keepExisting){
18322 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18323 this.selectRow(this.last+1, keepExisting);
18324 this.grid.getView().focusRow(this.last);
18329 * Selects the row that precedes the last selected row.
18330 * @param {Boolean} keepExisting (optional) True to keep existing selections
18332 selectPrevious : function(keepExisting){
18334 this.selectRow(this.last-1, keepExisting);
18335 this.grid.getView().focusRow(this.last);
18340 * Returns the selected records
18341 * @return {Array} Array of selected records
18343 getSelections : function(){
18344 return [].concat(this.selections.items);
18348 * Returns the first selected record.
18351 getSelected : function(){
18352 return this.selections.itemAt(0);
18357 * Clears all selections.
18359 clearSelections : function(fast){
18360 if(this.locked) return;
18362 var ds = this.grid.dataSource;
18363 var s = this.selections;
18364 s.each(function(r){
18365 this.deselectRow(ds.indexOfId(r.id));
18369 this.selections.clear();
18376 * Selects all rows.
18378 selectAll : function(){
18379 if(this.locked) return;
18380 this.selections.clear();
18381 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18382 this.selectRow(i, true);
18387 * Returns True if there is a selection.
18388 * @return {Boolean}
18390 hasSelection : function(){
18391 return this.selections.length > 0;
18395 * Returns True if the specified row is selected.
18396 * @param {Number/Record} record The record or index of the record to check
18397 * @return {Boolean}
18399 isSelected : function(index){
18400 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18401 return (r && this.selections.key(r.id) ? true : false);
18405 * Returns True if the specified record id is selected.
18406 * @param {String} id The id of record to check
18407 * @return {Boolean}
18409 isIdSelected : function(id){
18410 return (this.selections.key(id) ? true : false);
18414 handleMouseDown : function(e, t){
18415 var view = this.grid.getView(), rowIndex;
18416 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18419 if(e.shiftKey && this.last !== false){
18420 var last = this.last;
18421 this.selectRange(last, rowIndex, e.ctrlKey);
18422 this.last = last; // reset the last
18423 view.focusRow(rowIndex);
18425 var isSelected = this.isSelected(rowIndex);
18426 if(e.button !== 0 && isSelected){
18427 view.focusRow(rowIndex);
18428 }else if(e.ctrlKey && isSelected){
18429 this.deselectRow(rowIndex);
18430 }else if(!isSelected){
18431 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18432 view.focusRow(rowIndex);
18435 this.fireEvent("afterselectionchange", this);
18438 handleDragableRowClick : function(grid, rowIndex, e)
18440 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18441 this.selectRow(rowIndex, false);
18442 grid.view.focusRow(rowIndex);
18443 this.fireEvent("afterselectionchange", this);
18448 * Selects multiple rows.
18449 * @param {Array} rows Array of the indexes of the row to select
18450 * @param {Boolean} keepExisting (optional) True to keep existing selections
18452 selectRows : function(rows, keepExisting){
18454 this.clearSelections();
18456 for(var i = 0, len = rows.length; i < len; i++){
18457 this.selectRow(rows[i], true);
18462 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18463 * @param {Number} startRow The index of the first row in the range
18464 * @param {Number} endRow The index of the last row in the range
18465 * @param {Boolean} keepExisting (optional) True to retain existing selections
18467 selectRange : function(startRow, endRow, keepExisting){
18468 if(this.locked) return;
18470 this.clearSelections();
18472 if(startRow <= endRow){
18473 for(var i = startRow; i <= endRow; i++){
18474 this.selectRow(i, true);
18477 for(var i = startRow; i >= endRow; i--){
18478 this.selectRow(i, true);
18484 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18485 * @param {Number} startRow The index of the first row in the range
18486 * @param {Number} endRow The index of the last row in the range
18488 deselectRange : function(startRow, endRow, preventViewNotify){
18489 if(this.locked) return;
18490 for(var i = startRow; i <= endRow; i++){
18491 this.deselectRow(i, preventViewNotify);
18497 * @param {Number} row The index of the row to select
18498 * @param {Boolean} keepExisting (optional) True to keep existing selections
18500 selectRow : function(index, keepExisting, preventViewNotify){
18501 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18502 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18503 if(!keepExisting || this.singleSelect){
18504 this.clearSelections();
18506 var r = this.grid.dataSource.getAt(index);
18507 this.selections.add(r);
18508 this.last = this.lastActive = index;
18509 if(!preventViewNotify){
18510 this.grid.getView().onRowSelect(index);
18512 this.fireEvent("rowselect", this, index, r);
18513 this.fireEvent("selectionchange", this);
18519 * @param {Number} row The index of the row to deselect
18521 deselectRow : function(index, preventViewNotify){
18522 if(this.locked) return;
18523 if(this.last == index){
18526 if(this.lastActive == index){
18527 this.lastActive = false;
18529 var r = this.grid.dataSource.getAt(index);
18530 this.selections.remove(r);
18531 if(!preventViewNotify){
18532 this.grid.getView().onRowDeselect(index);
18534 this.fireEvent("rowdeselect", this, index);
18535 this.fireEvent("selectionchange", this);
18539 restoreLast : function(){
18541 this.last = this._last;
18546 acceptsNav : function(row, col, cm){
18547 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18551 onEditorKey : function(field, e){
18552 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18557 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18559 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18561 }else if(k == e.ENTER && !e.ctrlKey){
18565 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18567 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18569 }else if(k == e.ESC){
18573 g.startEditing(newCell[0], newCell[1]);
18578 * Ext JS Library 1.1.1
18579 * Copyright(c) 2006-2007, Ext JS, LLC.
18581 * Originally Released Under LGPL - original licence link has changed is not relivant.
18584 * <script type="text/javascript">
18588 * @class Roo.bootstrap.PagingToolbar
18590 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18592 * Create a new PagingToolbar
18593 * @param {Object} config The config object
18595 Roo.bootstrap.PagingToolbar = function(config)
18597 // old args format still supported... - xtype is prefered..
18598 // created from xtype...
18599 var ds = config.dataSource;
18600 this.toolbarItems = [];
18601 if (config.items) {
18602 this.toolbarItems = config.items;
18603 // config.items = [];
18606 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18613 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18617 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18619 * @cfg {Roo.data.Store} dataSource
18620 * The underlying data store providing the paged data
18623 * @cfg {String/HTMLElement/Element} container
18624 * container The id or element that will contain the toolbar
18627 * @cfg {Boolean} displayInfo
18628 * True to display the displayMsg (defaults to false)
18631 * @cfg {Number} pageSize
18632 * The number of records to display per page (defaults to 20)
18636 * @cfg {String} displayMsg
18637 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18639 displayMsg : 'Displaying {0} - {1} of {2}',
18641 * @cfg {String} emptyMsg
18642 * The message to display when no records are found (defaults to "No data to display")
18644 emptyMsg : 'No data to display',
18646 * Customizable piece of the default paging text (defaults to "Page")
18649 beforePageText : "Page",
18651 * Customizable piece of the default paging text (defaults to "of %0")
18654 afterPageText : "of {0}",
18656 * Customizable piece of the default paging text (defaults to "First Page")
18659 firstText : "First Page",
18661 * Customizable piece of the default paging text (defaults to "Previous Page")
18664 prevText : "Previous Page",
18666 * Customizable piece of the default paging text (defaults to "Next Page")
18669 nextText : "Next Page",
18671 * Customizable piece of the default paging text (defaults to "Last Page")
18674 lastText : "Last Page",
18676 * Customizable piece of the default paging text (defaults to "Refresh")
18679 refreshText : "Refresh",
18683 onRender : function(ct, position)
18685 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18686 this.navgroup.parentId = this.id;
18687 this.navgroup.onRender(this.el, null);
18688 // add the buttons to the navgroup
18690 if(this.displayInfo){
18691 Roo.log(this.el.select('ul.navbar-nav',true).first());
18692 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18693 this.displayEl = this.el.select('.x-paging-info', true).first();
18694 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18695 // this.displayEl = navel.el.select('span',true).first();
18701 Roo.each(_this.buttons, function(e){
18702 Roo.factory(e).onRender(_this.el, null);
18706 Roo.each(_this.toolbarItems, function(e) {
18707 _this.navgroup.addItem(e);
18710 this.first = this.navgroup.addItem({
18711 tooltip: this.firstText,
18713 icon : 'fa fa-backward',
18715 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18718 this.prev = this.navgroup.addItem({
18719 tooltip: this.prevText,
18721 icon : 'fa fa-step-backward',
18723 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18725 //this.addSeparator();
18728 var field = this.navgroup.addItem( {
18730 cls : 'x-paging-position',
18732 html : this.beforePageText +
18733 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18734 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18737 this.field = field.el.select('input', true).first();
18738 this.field.on("keydown", this.onPagingKeydown, this);
18739 this.field.on("focus", function(){this.dom.select();});
18742 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18743 //this.field.setHeight(18);
18744 //this.addSeparator();
18745 this.next = this.navgroup.addItem({
18746 tooltip: this.nextText,
18748 html : ' <i class="fa fa-step-forward">',
18750 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18752 this.last = this.navgroup.addItem({
18753 tooltip: this.lastText,
18754 icon : 'fa fa-forward',
18757 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18759 //this.addSeparator();
18760 this.loading = this.navgroup.addItem({
18761 tooltip: this.refreshText,
18762 icon: 'fa fa-refresh',
18764 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18770 updateInfo : function(){
18771 if(this.displayEl){
18772 var count = this.ds.getCount();
18773 var msg = count == 0 ?
18777 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18779 this.displayEl.update(msg);
18784 onLoad : function(ds, r, o){
18785 this.cursor = o.params ? o.params.start : 0;
18786 var d = this.getPageData(),
18790 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18791 this.field.dom.value = ap;
18792 this.first.setDisabled(ap == 1);
18793 this.prev.setDisabled(ap == 1);
18794 this.next.setDisabled(ap == ps);
18795 this.last.setDisabled(ap == ps);
18796 this.loading.enable();
18801 getPageData : function(){
18802 var total = this.ds.getTotalCount();
18805 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18806 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18811 onLoadError : function(){
18812 this.loading.enable();
18816 onPagingKeydown : function(e){
18817 var k = e.getKey();
18818 var d = this.getPageData();
18820 var v = this.field.dom.value, pageNum;
18821 if(!v || isNaN(pageNum = parseInt(v, 10))){
18822 this.field.dom.value = d.activePage;
18825 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18826 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18829 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))
18831 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18832 this.field.dom.value = pageNum;
18833 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18836 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18838 var v = this.field.dom.value, pageNum;
18839 var increment = (e.shiftKey) ? 10 : 1;
18840 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18842 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18843 this.field.dom.value = d.activePage;
18846 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18848 this.field.dom.value = parseInt(v, 10) + increment;
18849 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18850 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18857 beforeLoad : function(){
18859 this.loading.disable();
18864 onClick : function(which){
18871 ds.load({params:{start: 0, limit: this.pageSize}});
18874 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18877 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18880 var total = ds.getTotalCount();
18881 var extra = total % this.pageSize;
18882 var lastStart = extra ? (total - extra) : total-this.pageSize;
18883 ds.load({params:{start: lastStart, limit: this.pageSize}});
18886 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18892 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18893 * @param {Roo.data.Store} store The data store to unbind
18895 unbind : function(ds){
18896 ds.un("beforeload", this.beforeLoad, this);
18897 ds.un("load", this.onLoad, this);
18898 ds.un("loadexception", this.onLoadError, this);
18899 ds.un("remove", this.updateInfo, this);
18900 ds.un("add", this.updateInfo, this);
18901 this.ds = undefined;
18905 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18906 * @param {Roo.data.Store} store The data store to bind
18908 bind : function(ds){
18909 ds.on("beforeload", this.beforeLoad, this);
18910 ds.on("load", this.onLoad, this);
18911 ds.on("loadexception", this.onLoadError, this);
18912 ds.on("remove", this.updateInfo, this);
18913 ds.on("add", this.updateInfo, this);
18924 * @class Roo.bootstrap.MessageBar
18925 * @extends Roo.bootstrap.Component
18926 * Bootstrap MessageBar class
18927 * @cfg {String} html contents of the MessageBar
18928 * @cfg {String} weight (info | success | warning | danger) default info
18929 * @cfg {String} beforeClass insert the bar before the given class
18930 * @cfg {Boolean} closable (true | false) default false
18931 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18934 * Create a new Element
18935 * @param {Object} config The config object
18938 Roo.bootstrap.MessageBar = function(config){
18939 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18942 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18948 beforeClass: 'bootstrap-sticky-wrap',
18950 getAutoCreate : function(){
18954 cls: 'alert alert-dismissable alert-' + this.weight,
18959 html: this.html || ''
18965 cfg.cls += ' alert-messages-fixed';
18979 onRender : function(ct, position)
18981 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18984 var cfg = Roo.apply({}, this.getAutoCreate());
18988 cfg.cls += ' ' + this.cls;
18991 cfg.style = this.style;
18993 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18995 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18998 this.el.select('>button.close').on('click', this.hide, this);
19004 if (!this.rendered) {
19010 this.fireEvent('show', this);
19016 if (!this.rendered) {
19022 this.fireEvent('hide', this);
19025 update : function()
19027 // var e = this.el.dom.firstChild;
19029 // if(this.closable){
19030 // e = e.nextSibling;
19033 // e.data = this.html || '';
19035 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19051 * @class Roo.bootstrap.Graph
19052 * @extends Roo.bootstrap.Component
19053 * Bootstrap Graph class
19057 @cfg {String} graphtype bar | vbar | pie
19058 @cfg {number} g_x coodinator | centre x (pie)
19059 @cfg {number} g_y coodinator | centre y (pie)
19060 @cfg {number} g_r radius (pie)
19061 @cfg {number} g_height height of the chart (respected by all elements in the set)
19062 @cfg {number} g_width width of the chart (respected by all elements in the set)
19063 @cfg {Object} title The title of the chart
19066 -opts (object) options for the chart
19068 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19069 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19071 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.
19072 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19074 o stretch (boolean)
19076 -opts (object) options for the pie
19079 o startAngle (number)
19080 o endAngle (number)
19084 * Create a new Input
19085 * @param {Object} config The config object
19088 Roo.bootstrap.Graph = function(config){
19089 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19095 * The img click event for the img.
19096 * @param {Roo.EventObject} e
19102 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19113 //g_colors: this.colors,
19120 getAutoCreate : function(){
19131 onRender : function(ct,position){
19132 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19133 this.raphael = Raphael(this.el.dom);
19135 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19136 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19137 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19138 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19140 r.text(160, 10, "Single Series Chart").attr(txtattr);
19141 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19142 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19143 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19145 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19146 r.barchart(330, 10, 300, 220, data1);
19147 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19148 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19151 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19152 // r.barchart(30, 30, 560, 250, xdata, {
19153 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19154 // axis : "0 0 1 1",
19155 // axisxlabels : xdata
19156 // //yvalues : cols,
19159 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19161 // this.load(null,xdata,{
19162 // axis : "0 0 1 1",
19163 // axisxlabels : xdata
19168 load : function(graphtype,xdata,opts){
19169 this.raphael.clear();
19171 graphtype = this.graphtype;
19176 var r = this.raphael,
19177 fin = function () {
19178 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19180 fout = function () {
19181 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19183 pfin = function() {
19184 this.sector.stop();
19185 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19188 this.label[0].stop();
19189 this.label[0].attr({ r: 7.5 });
19190 this.label[1].attr({ "font-weight": 800 });
19193 pfout = function() {
19194 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19197 this.label[0].animate({ r: 5 }, 500, "bounce");
19198 this.label[1].attr({ "font-weight": 400 });
19204 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19207 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19210 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19211 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19213 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19220 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19225 setTitle: function(o)
19230 initEvents: function() {
19233 this.el.on('click', this.onClick, this);
19237 onClick : function(e)
19239 Roo.log('img onclick');
19240 this.fireEvent('click', this, e);
19252 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19255 * @class Roo.bootstrap.dash.NumberBox
19256 * @extends Roo.bootstrap.Component
19257 * Bootstrap NumberBox class
19258 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19259 * @cfg {String} headline Box headline
19260 * @cfg {String} content Box content
19261 * @cfg {String} icon Box icon
19262 * @cfg {String} footer Footer text
19263 * @cfg {String} fhref Footer href
19266 * Create a new NumberBox
19267 * @param {Object} config The config object
19271 Roo.bootstrap.dash.NumberBox = function(config){
19272 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19276 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19286 getAutoCreate : function(){
19290 cls : 'small-box bg-' + this.bgcolor,
19298 cls : 'roo-headline',
19299 html : this.headline
19303 cls : 'roo-content',
19304 html : this.content
19318 cls : 'ion ' + this.icon
19327 cls : 'small-box-footer',
19328 href : this.fhref || '#',
19332 cfg.cn.push(footer);
19339 onRender : function(ct,position){
19340 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19347 setHeadline: function (value)
19349 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19352 setFooter: function (value, href)
19354 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19357 this.el.select('a.small-box-footer',true).first().attr('href', href);
19362 setContent: function (value)
19364 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19367 initEvents: function()
19381 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19384 * @class Roo.bootstrap.dash.TabBox
19385 * @extends Roo.bootstrap.Component
19386 * Bootstrap TabBox class
19387 * @cfg {String} title Title of the TabBox
19388 * @cfg {String} icon Icon of the TabBox
19391 * Create a new TabBox
19392 * @param {Object} config The config object
19396 Roo.bootstrap.dash.TabBox = function(config){
19397 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19402 * When a pane is added
19403 * @param {Roo.bootstrap.dash.TabPane} pane
19410 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19415 getChildContainer : function()
19417 return this.el.select('.tab-content', true).first();
19420 getAutoCreate : function(){
19424 cls: 'pull-left header',
19432 cls: 'fa ' + this.icon
19439 cls: 'nav-tabs-custom',
19443 cls: 'nav nav-tabs pull-right',
19450 cls: 'tab-content no-padding',
19458 initEvents : function()
19460 //Roo.log('add add pane handler');
19461 this.on('addpane', this.onAddPane, this);
19464 * Updates the box title
19465 * @param {String} html to set the title to.
19467 setTitle : function(value)
19469 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19471 onAddPane : function(pane)
19473 //Roo.log('addpane');
19475 // tabs are rendere left to right..
19476 var ctr = this.el.select('.nav-tabs', true).first();
19479 var existing = ctr.select('.nav-tab',true);
19480 var qty = existing.getCount();;
19483 var tab = ctr.createChild({
19485 cls : 'nav-tab' + (qty ? '' : ' active'),
19493 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19496 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19498 pane.el.addClass('active');
19503 onTabClick : function(ev,un,ob,pane)
19505 //Roo.log('tab - prev default');
19506 ev.preventDefault();
19509 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19510 pane.tab.addClass('active');
19511 //Roo.log(pane.title);
19512 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19513 // technically we should have a deactivate event.. but maybe add later.
19514 // and it should not de-activate the selected tab...
19516 pane.el.addClass('active');
19517 pane.fireEvent('activate');
19532 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19534 * @class Roo.bootstrap.TabPane
19535 * @extends Roo.bootstrap.Component
19536 * Bootstrap TabPane class
19537 * @cfg {Boolean} active (false | true) Default false
19538 * @cfg {String} title title of panel
19542 * Create a new TabPane
19543 * @param {Object} config The config object
19546 Roo.bootstrap.dash.TabPane = function(config){
19547 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19551 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19556 // the tabBox that this is attached to.
19559 getAutoCreate : function()
19567 cfg.cls += ' active';
19572 initEvents : function()
19574 //Roo.log('trigger add pane handler');
19575 this.parent().fireEvent('addpane', this)
19579 * Updates the tab title
19580 * @param {String} html to set the title to.
19582 setTitle: function(str)
19588 this.tab.select('a'.true).first().dom.innerHTML = str;
19605 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19608 * @class Roo.bootstrap.menu.Menu
19609 * @extends Roo.bootstrap.Component
19610 * Bootstrap Menu class - container for Menu
19611 * @cfg {String} html Text of the menu
19612 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19613 * @cfg {String} icon Font awesome icon
19614 * @cfg {String} pos Menu align to (top | bottom) default bottom
19618 * Create a new Menu
19619 * @param {Object} config The config object
19623 Roo.bootstrap.menu.Menu = function(config){
19624 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19628 * @event beforeshow
19629 * Fires before this menu is displayed
19630 * @param {Roo.bootstrap.menu.Menu} this
19634 * @event beforehide
19635 * Fires before this menu is hidden
19636 * @param {Roo.bootstrap.menu.Menu} this
19641 * Fires after this menu is displayed
19642 * @param {Roo.bootstrap.menu.Menu} this
19647 * Fires after this menu is hidden
19648 * @param {Roo.bootstrap.menu.Menu} this
19653 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19654 * @param {Roo.bootstrap.menu.Menu} this
19655 * @param {Roo.EventObject} e
19662 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19666 weight : 'default',
19671 getChildContainer : function() {
19672 if(this.isSubMenu){
19676 return this.el.select('ul.dropdown-menu', true).first();
19679 getAutoCreate : function()
19684 cls : 'roo-menu-text',
19692 cls : 'fa ' + this.icon
19703 cls : 'dropdown-button btn btn-' + this.weight,
19708 cls : 'dropdown-toggle btn btn-' + this.weight,
19718 cls : 'dropdown-menu'
19724 if(this.pos == 'top'){
19725 cfg.cls += ' dropup';
19728 if(this.isSubMenu){
19731 cls : 'dropdown-menu'
19738 onRender : function(ct, position)
19740 this.isSubMenu = ct.hasClass('dropdown-submenu');
19742 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19745 initEvents : function()
19747 if(this.isSubMenu){
19751 this.hidden = true;
19753 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19754 this.triggerEl.on('click', this.onTriggerPress, this);
19756 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19757 this.buttonEl.on('click', this.onClick, this);
19763 if(this.isSubMenu){
19767 return this.el.select('ul.dropdown-menu', true).first();
19770 onClick : function(e)
19772 this.fireEvent("click", this, e);
19775 onTriggerPress : function(e)
19777 if (this.isVisible()) {
19784 isVisible : function(){
19785 return !this.hidden;
19790 this.fireEvent("beforeshow", this);
19792 this.hidden = false;
19793 this.el.addClass('open');
19795 Roo.get(document).on("mouseup", this.onMouseUp, this);
19797 this.fireEvent("show", this);
19804 this.fireEvent("beforehide", this);
19806 this.hidden = true;
19807 this.el.removeClass('open');
19809 Roo.get(document).un("mouseup", this.onMouseUp);
19811 this.fireEvent("hide", this);
19814 onMouseUp : function()
19828 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19831 * @class Roo.bootstrap.menu.Item
19832 * @extends Roo.bootstrap.Component
19833 * Bootstrap MenuItem class
19834 * @cfg {Boolean} submenu (true | false) default false
19835 * @cfg {String} html text of the item
19836 * @cfg {String} href the link
19837 * @cfg {Boolean} disable (true | false) default false
19838 * @cfg {Boolean} preventDefault (true | false) default true
19839 * @cfg {String} icon Font awesome icon
19840 * @cfg {String} pos Submenu align to (left | right) default right
19844 * Create a new Item
19845 * @param {Object} config The config object
19849 Roo.bootstrap.menu.Item = function(config){
19850 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19854 * Fires when the mouse is hovering over this menu
19855 * @param {Roo.bootstrap.menu.Item} this
19856 * @param {Roo.EventObject} e
19861 * Fires when the mouse exits this menu
19862 * @param {Roo.bootstrap.menu.Item} this
19863 * @param {Roo.EventObject} e
19869 * The raw click event for the entire grid.
19870 * @param {Roo.EventObject} e
19876 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19881 preventDefault: true,
19886 getAutoCreate : function()
19891 cls : 'roo-menu-item-text',
19899 cls : 'fa ' + this.icon
19908 href : this.href || '#',
19915 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19919 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19921 if(this.pos == 'left'){
19922 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19929 initEvents : function()
19931 this.el.on('mouseover', this.onMouseOver, this);
19932 this.el.on('mouseout', this.onMouseOut, this);
19934 this.el.select('a', true).first().on('click', this.onClick, this);
19938 onClick : function(e)
19940 if(this.preventDefault){
19941 e.preventDefault();
19944 this.fireEvent("click", this, e);
19947 onMouseOver : function(e)
19949 if(this.submenu && this.pos == 'left'){
19950 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19953 this.fireEvent("mouseover", this, e);
19956 onMouseOut : function(e)
19958 this.fireEvent("mouseout", this, e);
19970 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19973 * @class Roo.bootstrap.menu.Separator
19974 * @extends Roo.bootstrap.Component
19975 * Bootstrap Separator class
19978 * Create a new Separator
19979 * @param {Object} config The config object
19983 Roo.bootstrap.menu.Separator = function(config){
19984 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19987 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19989 getAutoCreate : function(){