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..
13701 * @cfg {Boolean} carousel true to make the group behave like a carousel
13704 * Create a new TabGroup
13705 * @param {Object} config The config object
13708 Roo.bootstrap.TabGroup = function(config){
13709 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13711 this.navId = Roo.id();
13714 Roo.bootstrap.TabGroup.register(this);
13718 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13722 getAutoCreate : function()
13724 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13726 cfg.cls += ' tab-content';
13728 if (this.carousel) {
13729 cfg.cls += ' carousel slide';
13736 * register a Navigation item
13737 * @param {Roo.bootstrap.NavItem} the navitem to add
13739 register : function(item)
13741 this.tabs.push( item);
13742 item.navId = this.navId; // not really needed..
13746 getActivePanel : function()
13749 Roo.each(this.tabs, function(t) {
13759 getPanelByName : function(n)
13762 Roo.each(this.tabs, function(t) {
13763 if (t.tabId == n) {
13771 indexOfPanel : function(p)
13774 Roo.each(this.tabs, function(t,i) {
13775 if (t.tabId == p.tabId) {
13783 showPanel : function (pan)
13785 if (typeof(pan) == 'pnumber') {
13786 pan = this.tabs[pan];
13788 if (typeof(pan) == 'string') {
13789 pan = this.getPanelByName(pan);
13791 if (pan.tabId == this.getActivePanel().tabId) {
13794 this.getActivePanel().setActive(false);
13795 pan.setActive(true);
13798 showNextPanel : function()
13800 var i = this.indexOfPanel(this.getActivePanel());
13801 if (i > this.tabs.length) {
13804 this.showPanel(this.tabs[i+1]);
13806 showPrevPanel : function()
13808 var i = this.indexOfPanel(this.getActivePanel());
13812 this.showPanel(this.tabs[i-1]);
13823 Roo.apply(Roo.bootstrap.TabGroup, {
13827 * register a Navigation Group
13828 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13830 register : function(navgrp)
13832 this.groups[navgrp.navId] = navgrp;
13836 * fetch a Navigation Group based on the navigation ID
13837 * if one does not exist , it will get created.
13838 * @param {string} the navgroup to add
13839 * @returns {Roo.bootstrap.NavGroup} the navgroup
13841 get: function(navId) {
13842 if (typeof(this.groups[navId]) == 'undefined') {
13843 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13845 return this.groups[navId] ;
13860 * @class Roo.bootstrap.TabPanel
13861 * @extends Roo.bootstrap.Component
13862 * Bootstrap TabPanel class
13863 * @cfg {Boolean} active panel active
13864 * @cfg {String} html panel content
13865 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
13866 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13870 * Create a new TabPanel
13871 * @param {Object} config The config object
13874 Roo.bootstrap.TabPanel = function(config){
13875 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13879 * Fires when the active status changes
13880 * @param {Roo.bootstrap.TabPanel} this
13881 * @param {Boolean} state the new state
13886 this.tabId = this.tabId || Roo.id();
13890 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13897 getAutoCreate : function(){
13901 html: this.html || ''
13905 cfg.cls += ' active';
13909 cfg.tabId = this.tabId;
13915 initEvents: function()
13917 Roo.log('-------- init events on tab panel ---------');
13919 var p = this.parent();
13920 this.navId = this.navId || p.navId;
13922 if (typeof(this.navId) != 'undefined') {
13923 // not really needed.. but just in case.. parent should be a NavGroup.
13924 var tg = Roo.bootstrap.TabGroup.get(this.navId);
13925 Roo.log(['register', tg, this]);
13931 onRender : function(ct, position)
13933 // Roo.log("Call onRender: " + this.xtype);
13935 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13937 // registration with navgroups..
13938 if (this.navId && this.tabId) {
13939 var grp = Roo.bootstrap.NavGroup.get(this.navId);
13942 var item = grp.getNavItem(this.tabId);
13944 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13946 item.on('changed', function(item, state) {
13947 this.setActive(state);
13956 setActive: function(state)
13958 Roo.log("panel - set active " + this.tabId + "=" + state);
13960 this.active = state;
13962 this.el.removeClass('active');
13964 } else if (!this.el.hasClass('active')) {
13965 this.el.addClass('active');
13967 this.fireEvent('changed', this, state);
13984 * @class Roo.bootstrap.DateField
13985 * @extends Roo.bootstrap.Input
13986 * Bootstrap DateField class
13987 * @cfg {Number} weekStart default 0
13988 * @cfg {Number} weekStart default 0
13989 * @cfg {Number} viewMode default empty, (months|years)
13990 * @cfg {Number} minViewMode default empty, (months|years)
13991 * @cfg {Number} startDate default -Infinity
13992 * @cfg {Number} endDate default Infinity
13993 * @cfg {Boolean} todayHighlight default false
13994 * @cfg {Boolean} todayBtn default false
13995 * @cfg {Boolean} calendarWeeks default false
13996 * @cfg {Object} daysOfWeekDisabled default empty
13998 * @cfg {Boolean} keyboardNavigation default true
13999 * @cfg {String} language default en
14002 * Create a new DateField
14003 * @param {Object} config The config object
14006 Roo.bootstrap.DateField = function(config){
14007 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14011 * Fires when this field show.
14012 * @param {Roo.bootstrap.DateField} this
14013 * @param {Mixed} date The date value
14018 * Fires when this field hide.
14019 * @param {Roo.bootstrap.DateField} this
14020 * @param {Mixed} date The date value
14025 * Fires when select a date.
14026 * @param {Roo.bootstrap.DateField} this
14027 * @param {Mixed} date The date value
14033 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14036 * @cfg {String} format
14037 * The default date format string which can be overriden for localization support. The format must be
14038 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14042 * @cfg {String} altFormats
14043 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14044 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14046 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14054 todayHighlight : false,
14060 keyboardNavigation: true,
14062 calendarWeeks: false,
14064 startDate: -Infinity,
14068 daysOfWeekDisabled: [],
14072 UTCDate: function()
14074 return new Date(Date.UTC.apply(Date, arguments));
14077 UTCToday: function()
14079 var today = new Date();
14080 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14083 getDate: function() {
14084 var d = this.getUTCDate();
14085 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14088 getUTCDate: function() {
14092 setDate: function(d) {
14093 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14096 setUTCDate: function(d) {
14098 this.setValue(this.formatDate(this.date));
14101 onRender: function(ct, position)
14104 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14106 this.language = this.language || 'en';
14107 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14108 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14110 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14111 this.format = this.format || 'm/d/y';
14112 this.isInline = false;
14113 this.isInput = true;
14114 this.component = this.el.select('.add-on', true).first() || false;
14115 this.component = (this.component && this.component.length === 0) ? false : this.component;
14116 this.hasInput = this.component && this.inputEL().length;
14118 if (typeof(this.minViewMode === 'string')) {
14119 switch (this.minViewMode) {
14121 this.minViewMode = 1;
14124 this.minViewMode = 2;
14127 this.minViewMode = 0;
14132 if (typeof(this.viewMode === 'string')) {
14133 switch (this.viewMode) {
14146 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14148 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14150 this.picker().on('mousedown', this.onMousedown, this);
14151 this.picker().on('click', this.onClick, this);
14153 this.picker().addClass('datepicker-dropdown');
14155 this.startViewMode = this.viewMode;
14158 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14159 if(!this.calendarWeeks){
14164 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14165 v.attr('colspan', function(i, val){
14166 return parseInt(val) + 1;
14171 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14173 this.setStartDate(this.startDate);
14174 this.setEndDate(this.endDate);
14176 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14183 if(this.isInline) {
14188 picker : function()
14190 return this.el.select('.datepicker', true).first();
14193 fillDow: function()
14195 var dowCnt = this.weekStart;
14204 if(this.calendarWeeks){
14212 while (dowCnt < this.weekStart + 7) {
14216 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14220 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14223 fillMonths: function()
14226 var months = this.picker().select('>.datepicker-months td', true).first();
14228 months.dom.innerHTML = '';
14234 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14237 months.createChild(month);
14245 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14247 if (this.date < this.startDate) {
14248 this.viewDate = new Date(this.startDate);
14249 } else if (this.date > this.endDate) {
14250 this.viewDate = new Date(this.endDate);
14252 this.viewDate = new Date(this.date);
14260 var d = new Date(this.viewDate),
14261 year = d.getUTCFullYear(),
14262 month = d.getUTCMonth(),
14263 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14264 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14265 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14266 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14267 currentDate = this.date && this.date.valueOf(),
14268 today = this.UTCToday();
14270 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14272 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14274 // this.picker.select('>tfoot th.today').
14275 // .text(dates[this.language].today)
14276 // .toggle(this.todayBtn !== false);
14278 this.updateNavArrows();
14281 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14283 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14285 prevMonth.setUTCDate(day);
14287 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14289 var nextMonth = new Date(prevMonth);
14291 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14293 nextMonth = nextMonth.valueOf();
14295 var fillMonths = false;
14297 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14299 while(prevMonth.valueOf() < nextMonth) {
14302 if (prevMonth.getUTCDay() === this.weekStart) {
14304 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14312 if(this.calendarWeeks){
14313 // ISO 8601: First week contains first thursday.
14314 // ISO also states week starts on Monday, but we can be more abstract here.
14316 // Start of current week: based on weekstart/current date
14317 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14318 // Thursday of this week
14319 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14320 // First Thursday of year, year from thursday
14321 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14322 // Calendar week: ms between thursdays, div ms per day, div 7 days
14323 calWeek = (th - yth) / 864e5 / 7 + 1;
14325 fillMonths.cn.push({
14333 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14335 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14338 if (this.todayHighlight &&
14339 prevMonth.getUTCFullYear() == today.getFullYear() &&
14340 prevMonth.getUTCMonth() == today.getMonth() &&
14341 prevMonth.getUTCDate() == today.getDate()) {
14342 clsName += ' today';
14345 if (currentDate && prevMonth.valueOf() === currentDate) {
14346 clsName += ' active';
14349 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14350 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14351 clsName += ' disabled';
14354 fillMonths.cn.push({
14356 cls: 'day ' + clsName,
14357 html: prevMonth.getDate()
14360 prevMonth.setDate(prevMonth.getDate()+1);
14363 var currentYear = this.date && this.date.getUTCFullYear();
14364 var currentMonth = this.date && this.date.getUTCMonth();
14366 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14368 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14369 v.removeClass('active');
14371 if(currentYear === year && k === currentMonth){
14372 v.addClass('active');
14375 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14376 v.addClass('disabled');
14382 year = parseInt(year/10, 10) * 10;
14384 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14386 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14389 for (var i = -1; i < 11; i++) {
14390 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14392 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14400 showMode: function(dir)
14403 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14405 Roo.each(this.picker().select('>div',true).elements, function(v){
14406 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14409 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14414 if(this.isInline) return;
14416 this.picker().removeClass(['bottom', 'top']);
14418 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14420 * place to the top of element!
14424 this.picker().addClass('top');
14425 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14430 this.picker().addClass('bottom');
14432 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14435 parseDate : function(value)
14437 if(!value || value instanceof Date){
14440 var v = Date.parseDate(value, this.format);
14441 if (!v && this.useIso) {
14442 v = Date.parseDate(value, 'Y-m-d');
14444 if(!v && this.altFormats){
14445 if(!this.altFormatsArray){
14446 this.altFormatsArray = this.altFormats.split("|");
14448 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14449 v = Date.parseDate(value, this.altFormatsArray[i]);
14455 formatDate : function(date, fmt)
14457 return (!date || !(date instanceof Date)) ?
14458 date : date.dateFormat(fmt || this.format);
14461 onFocus : function()
14463 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14467 onBlur : function()
14469 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14471 var d = this.inputEl().getValue();
14482 this.picker().show();
14486 this.fireEvent('show', this, this.date);
14491 if(this.isInline) return;
14492 this.picker().hide();
14493 this.viewMode = this.startViewMode;
14496 this.fireEvent('hide', this, this.date);
14500 onMousedown: function(e)
14502 e.stopPropagation();
14503 e.preventDefault();
14508 Roo.bootstrap.DateField.superclass.keyup.call(this);
14512 setValue: function(v)
14514 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14516 var d = new Date(v);
14518 if(isNaN(d.getTime())){
14522 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14526 this.fireEvent('select', this, this.date);
14530 getValue: function()
14532 return this.formatDate(this.date);
14535 fireKey: function(e)
14537 if (!this.picker().isVisible()){
14538 if (e.keyCode == 27) // allow escape to hide and re-show picker
14543 var dateChanged = false,
14545 newDate, newViewDate;
14550 e.preventDefault();
14554 if (!this.keyboardNavigation) break;
14555 dir = e.keyCode == 37 ? -1 : 1;
14558 newDate = this.moveYear(this.date, dir);
14559 newViewDate = this.moveYear(this.viewDate, dir);
14560 } else if (e.shiftKey){
14561 newDate = this.moveMonth(this.date, dir);
14562 newViewDate = this.moveMonth(this.viewDate, dir);
14564 newDate = new Date(this.date);
14565 newDate.setUTCDate(this.date.getUTCDate() + dir);
14566 newViewDate = new Date(this.viewDate);
14567 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14569 if (this.dateWithinRange(newDate)){
14570 this.date = newDate;
14571 this.viewDate = newViewDate;
14572 this.setValue(this.formatDate(this.date));
14574 e.preventDefault();
14575 dateChanged = true;
14580 if (!this.keyboardNavigation) break;
14581 dir = e.keyCode == 38 ? -1 : 1;
14583 newDate = this.moveYear(this.date, dir);
14584 newViewDate = this.moveYear(this.viewDate, dir);
14585 } else if (e.shiftKey){
14586 newDate = this.moveMonth(this.date, dir);
14587 newViewDate = this.moveMonth(this.viewDate, dir);
14589 newDate = new Date(this.date);
14590 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14591 newViewDate = new Date(this.viewDate);
14592 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14594 if (this.dateWithinRange(newDate)){
14595 this.date = newDate;
14596 this.viewDate = newViewDate;
14597 this.setValue(this.formatDate(this.date));
14599 e.preventDefault();
14600 dateChanged = true;
14604 this.setValue(this.formatDate(this.date));
14606 e.preventDefault();
14609 this.setValue(this.formatDate(this.date));
14623 onClick: function(e)
14625 e.stopPropagation();
14626 e.preventDefault();
14628 var target = e.getTarget();
14630 if(target.nodeName.toLowerCase() === 'i'){
14631 target = Roo.get(target).dom.parentNode;
14634 var nodeName = target.nodeName;
14635 var className = target.className;
14636 var html = target.innerHTML;
14638 switch(nodeName.toLowerCase()) {
14640 switch(className) {
14646 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14647 switch(this.viewMode){
14649 this.viewDate = this.moveMonth(this.viewDate, dir);
14653 this.viewDate = this.moveYear(this.viewDate, dir);
14659 var date = new Date();
14660 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14662 this.setValue(this.formatDate(this.date));
14669 if (className.indexOf('disabled') === -1) {
14670 this.viewDate.setUTCDate(1);
14671 if (className.indexOf('month') !== -1) {
14672 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14674 var year = parseInt(html, 10) || 0;
14675 this.viewDate.setUTCFullYear(year);
14684 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14685 var day = parseInt(html, 10) || 1;
14686 var year = this.viewDate.getUTCFullYear(),
14687 month = this.viewDate.getUTCMonth();
14689 if (className.indexOf('old') !== -1) {
14696 } else if (className.indexOf('new') !== -1) {
14704 this.date = this.UTCDate(year, month, day,0,0,0,0);
14705 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14707 this.setValue(this.formatDate(this.date));
14714 setStartDate: function(startDate)
14716 this.startDate = startDate || -Infinity;
14717 if (this.startDate !== -Infinity) {
14718 this.startDate = this.parseDate(this.startDate);
14721 this.updateNavArrows();
14724 setEndDate: function(endDate)
14726 this.endDate = endDate || Infinity;
14727 if (this.endDate !== Infinity) {
14728 this.endDate = this.parseDate(this.endDate);
14731 this.updateNavArrows();
14734 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14736 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14737 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14738 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14740 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14741 return parseInt(d, 10);
14744 this.updateNavArrows();
14747 updateNavArrows: function()
14749 var d = new Date(this.viewDate),
14750 year = d.getUTCFullYear(),
14751 month = d.getUTCMonth();
14753 Roo.each(this.picker().select('.prev', true).elements, function(v){
14755 switch (this.viewMode) {
14758 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14764 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14771 Roo.each(this.picker().select('.next', true).elements, function(v){
14773 switch (this.viewMode) {
14776 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14782 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14790 moveMonth: function(date, dir)
14792 if (!dir) return date;
14793 var new_date = new Date(date.valueOf()),
14794 day = new_date.getUTCDate(),
14795 month = new_date.getUTCMonth(),
14796 mag = Math.abs(dir),
14798 dir = dir > 0 ? 1 : -1;
14801 // If going back one month, make sure month is not current month
14802 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14804 return new_date.getUTCMonth() == month;
14806 // If going forward one month, make sure month is as expected
14807 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14809 return new_date.getUTCMonth() != new_month;
14811 new_month = month + dir;
14812 new_date.setUTCMonth(new_month);
14813 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14814 if (new_month < 0 || new_month > 11)
14815 new_month = (new_month + 12) % 12;
14817 // For magnitudes >1, move one month at a time...
14818 for (var i=0; i<mag; i++)
14819 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14820 new_date = this.moveMonth(new_date, dir);
14821 // ...then reset the day, keeping it in the new month
14822 new_month = new_date.getUTCMonth();
14823 new_date.setUTCDate(day);
14825 return new_month != new_date.getUTCMonth();
14828 // Common date-resetting loop -- if date is beyond end of month, make it
14831 new_date.setUTCDate(--day);
14832 new_date.setUTCMonth(new_month);
14837 moveYear: function(date, dir)
14839 return this.moveMonth(date, dir*12);
14842 dateWithinRange: function(date)
14844 return date >= this.startDate && date <= this.endDate;
14850 this.picker().remove();
14855 Roo.apply(Roo.bootstrap.DateField, {
14866 html: '<i class="fa fa-arrow-left"/>'
14876 html: '<i class="fa fa-arrow-right"/>'
14918 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14919 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14920 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14921 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14922 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14935 navFnc: 'FullYear',
14940 navFnc: 'FullYear',
14945 Roo.apply(Roo.bootstrap.DateField, {
14949 cls: 'datepicker dropdown-menu',
14953 cls: 'datepicker-days',
14957 cls: 'table-condensed',
14959 Roo.bootstrap.DateField.head,
14963 Roo.bootstrap.DateField.footer
14970 cls: 'datepicker-months',
14974 cls: 'table-condensed',
14976 Roo.bootstrap.DateField.head,
14977 Roo.bootstrap.DateField.content,
14978 Roo.bootstrap.DateField.footer
14985 cls: 'datepicker-years',
14989 cls: 'table-condensed',
14991 Roo.bootstrap.DateField.head,
14992 Roo.bootstrap.DateField.content,
14993 Roo.bootstrap.DateField.footer
15012 * @class Roo.bootstrap.TimeField
15013 * @extends Roo.bootstrap.Input
15014 * Bootstrap DateField class
15018 * Create a new TimeField
15019 * @param {Object} config The config object
15022 Roo.bootstrap.TimeField = function(config){
15023 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15027 * Fires when this field show.
15028 * @param {Roo.bootstrap.DateField} this
15029 * @param {Mixed} date The date value
15034 * Fires when this field hide.
15035 * @param {Roo.bootstrap.DateField} this
15036 * @param {Mixed} date The date value
15041 * Fires when select a date.
15042 * @param {Roo.bootstrap.DateField} this
15043 * @param {Mixed} date The date value
15049 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15052 * @cfg {String} format
15053 * The default time format string which can be overriden for localization support. The format must be
15054 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15058 onRender: function(ct, position)
15061 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15063 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15065 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15067 this.pop = this.picker().select('>.datepicker-time',true).first();
15068 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15070 this.picker().on('mousedown', this.onMousedown, this);
15071 this.picker().on('click', this.onClick, this);
15073 this.picker().addClass('datepicker-dropdown');
15078 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15079 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15080 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15081 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15082 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15083 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15087 fireKey: function(e){
15088 if (!this.picker().isVisible()){
15089 if (e.keyCode == 27) // allow escape to hide and re-show picker
15094 e.preventDefault();
15102 this.onTogglePeriod();
15105 this.onIncrementMinutes();
15108 this.onDecrementMinutes();
15117 onClick: function(e) {
15118 e.stopPropagation();
15119 e.preventDefault();
15122 picker : function()
15124 return this.el.select('.datepicker', true).first();
15127 fillTime: function()
15129 var time = this.pop.select('tbody', true).first();
15131 time.dom.innerHTML = '';
15146 cls: 'hours-up glyphicon glyphicon-chevron-up'
15166 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15187 cls: 'timepicker-hour',
15202 cls: 'timepicker-minute',
15217 cls: 'btn btn-primary period',
15239 cls: 'hours-down glyphicon glyphicon-chevron-down'
15259 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15277 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15284 var hours = this.time.getHours();
15285 var minutes = this.time.getMinutes();
15298 hours = hours - 12;
15302 hours = '0' + hours;
15306 minutes = '0' + minutes;
15309 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15310 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15311 this.pop.select('button', true).first().dom.innerHTML = period;
15317 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15319 var cls = ['bottom'];
15321 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15328 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15333 this.picker().addClass(cls.join('-'));
15337 Roo.each(cls, function(c){
15339 _this.picker().setTop(_this.inputEl().getHeight());
15343 _this.picker().setTop(0 - _this.picker().getHeight());
15348 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15352 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15359 onFocus : function()
15361 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15365 onBlur : function()
15367 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15373 this.picker().show();
15378 this.fireEvent('show', this, this.date);
15383 this.picker().hide();
15386 this.fireEvent('hide', this, this.date);
15389 setTime : function()
15392 this.setValue(this.time.format(this.format));
15394 this.fireEvent('select', this, this.date);
15399 onMousedown: function(e){
15400 e.stopPropagation();
15401 e.preventDefault();
15404 onIncrementHours: function()
15406 Roo.log('onIncrementHours');
15407 this.time = this.time.add(Date.HOUR, 1);
15412 onDecrementHours: function()
15414 Roo.log('onDecrementHours');
15415 this.time = this.time.add(Date.HOUR, -1);
15419 onIncrementMinutes: function()
15421 Roo.log('onIncrementMinutes');
15422 this.time = this.time.add(Date.MINUTE, 1);
15426 onDecrementMinutes: function()
15428 Roo.log('onDecrementMinutes');
15429 this.time = this.time.add(Date.MINUTE, -1);
15433 onTogglePeriod: function()
15435 Roo.log('onTogglePeriod');
15436 this.time = this.time.add(Date.HOUR, 12);
15443 Roo.apply(Roo.bootstrap.TimeField, {
15473 cls: 'btn btn-info ok',
15485 Roo.apply(Roo.bootstrap.TimeField, {
15489 cls: 'datepicker dropdown-menu',
15493 cls: 'datepicker-time',
15497 cls: 'table-condensed',
15499 Roo.bootstrap.TimeField.content,
15500 Roo.bootstrap.TimeField.footer
15519 * @class Roo.bootstrap.CheckBox
15520 * @extends Roo.bootstrap.Input
15521 * Bootstrap CheckBox class
15523 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15524 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15525 * @cfg {String} boxLabel The text that appears beside the checkbox
15526 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15527 * @cfg {Boolean} checked initnal the element
15531 * Create a new CheckBox
15532 * @param {Object} config The config object
15535 Roo.bootstrap.CheckBox = function(config){
15536 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15541 * Fires when the element is checked or unchecked.
15542 * @param {Roo.bootstrap.CheckBox} this This input
15543 * @param {Boolean} checked The new checked value
15549 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15551 inputType: 'checkbox',
15558 getAutoCreate : function()
15560 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15566 cfg.cls = 'form-group checkbox' //input-group
15574 type : this.inputType,
15575 value : (!this.checked) ? this.valueOff : this.inputValue,
15576 cls : 'roo-checkbox', //'form-box',
15577 placeholder : this.placeholder || ''
15581 if (this.weight) { // Validity check?
15582 cfg.cls += " checkbox-" + this.weight;
15585 if (this.disabled) {
15586 input.disabled=true;
15590 input.checked = this.checked;
15594 input.name = this.name;
15598 input.cls += ' input-' + this.size;
15602 ['xs','sm','md','lg'].map(function(size){
15603 if (settings[size]) {
15604 cfg.cls += ' col-' + size + '-' + settings[size];
15610 var inputblock = input;
15615 if (this.before || this.after) {
15618 cls : 'input-group',
15622 inputblock.cn.push({
15624 cls : 'input-group-addon',
15628 inputblock.cn.push(input);
15630 inputblock.cn.push({
15632 cls : 'input-group-addon',
15639 if (align ==='left' && this.fieldLabel.length) {
15640 Roo.log("left and has label");
15646 cls : 'control-label col-md-' + this.labelWidth,
15647 html : this.fieldLabel
15651 cls : "col-md-" + (12 - this.labelWidth),
15658 } else if ( this.fieldLabel.length) {
15663 tag: this.boxLabel ? 'span' : 'label',
15665 cls: 'control-label box-input-label',
15666 //cls : 'input-group-addon',
15667 html : this.fieldLabel
15677 Roo.log(" no label && no align");
15678 cfg.cn = [ inputblock ] ;
15687 html: this.boxLabel
15699 * return the real input element.
15701 inputEl: function ()
15703 return this.el.select('input.roo-checkbox',true).first();
15708 return this.el.select('label.control-label',true).first();
15711 initEvents : function()
15713 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15715 this.inputEl().on('click', this.onClick, this);
15719 onClick : function()
15721 this.setChecked(!this.checked);
15724 setChecked : function(state,suppressEvent)
15726 this.checked = state;
15728 this.inputEl().dom.checked = state;
15730 if(suppressEvent !== true){
15731 this.fireEvent('check', this, state);
15734 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15738 setValue : function(v,suppressEvent)
15740 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15754 * @class Roo.bootstrap.Radio
15755 * @extends Roo.bootstrap.CheckBox
15756 * Bootstrap Radio class
15759 * Create a new Radio
15760 * @param {Object} config The config object
15763 Roo.bootstrap.Radio = function(config){
15764 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15768 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15770 inputType: 'radio',
15774 getAutoCreate : function()
15776 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15782 cfg.cls = 'form-group radio' //input-group
15787 type : this.inputType,
15788 value : (!this.checked) ? this.valueOff : this.inputValue,
15790 placeholder : this.placeholder || ''
15793 if (this.weight) { // Validity check?
15794 cfg.cls += " radio-" + this.weight;
15796 if (this.disabled) {
15797 input.disabled=true;
15801 input.checked = this.checked;
15805 input.name = this.name;
15809 input.cls += ' input-' + this.size;
15813 ['xs','sm','md','lg'].map(function(size){
15814 if (settings[size]) {
15815 cfg.cls += ' col-' + size + '-' + settings[size];
15819 var inputblock = input;
15821 if (this.before || this.after) {
15824 cls : 'input-group',
15828 inputblock.cn.push({
15830 cls : 'input-group-addon',
15834 inputblock.cn.push(input);
15836 inputblock.cn.push({
15838 cls : 'input-group-addon',
15845 if (align ==='left' && this.fieldLabel.length) {
15846 Roo.log("left and has label");
15852 cls : 'control-label col-md-' + this.labelWidth,
15853 html : this.fieldLabel
15857 cls : "col-md-" + (12 - this.labelWidth),
15864 } else if ( this.fieldLabel.length) {
15871 cls: 'control-label box-input-label',
15872 //cls : 'input-group-addon',
15873 html : this.fieldLabel
15883 Roo.log(" no label && no align");
15898 html: this.boxLabel
15905 inputEl: function ()
15907 return this.el.select('input.roo-radio',true).first();
15909 onClick : function()
15911 this.setChecked(true);
15914 setChecked : function(state,suppressEvent)
15917 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15918 v.dom.checked = false;
15922 this.checked = state;
15923 this.inputEl().dom.checked = state;
15925 if(suppressEvent !== true){
15926 this.fireEvent('check', this, state);
15929 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15933 getGroupValue : function()
15936 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15937 if(v.dom.checked == true){
15938 value = v.dom.value;
15946 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15947 * @return {Mixed} value The field value
15949 getValue : function(){
15950 return this.getGroupValue();
15956 //<script type="text/javascript">
15959 * Based Ext JS Library 1.1.1
15960 * Copyright(c) 2006-2007, Ext JS, LLC.
15966 * @class Roo.HtmlEditorCore
15967 * @extends Roo.Component
15968 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15970 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15973 Roo.HtmlEditorCore = function(config){
15976 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15979 * @event initialize
15980 * Fires when the editor is fully initialized (including the iframe)
15981 * @param {Roo.HtmlEditorCore} this
15986 * Fires when the editor is first receives the focus. Any insertion must wait
15987 * until after this event.
15988 * @param {Roo.HtmlEditorCore} this
15992 * @event beforesync
15993 * Fires before the textarea is updated with content from the editor iframe. Return false
15994 * to cancel the sync.
15995 * @param {Roo.HtmlEditorCore} this
15996 * @param {String} html
16000 * @event beforepush
16001 * Fires before the iframe editor is updated with content from the textarea. Return false
16002 * to cancel the push.
16003 * @param {Roo.HtmlEditorCore} this
16004 * @param {String} html
16009 * Fires when the textarea is updated with content from the editor iframe.
16010 * @param {Roo.HtmlEditorCore} this
16011 * @param {String} html
16016 * Fires when the iframe editor is updated with content from the textarea.
16017 * @param {Roo.HtmlEditorCore} this
16018 * @param {String} html
16023 * @event editorevent
16024 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16025 * @param {Roo.HtmlEditorCore} this
16033 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16037 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16043 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16048 * @cfg {Number} height (in pixels)
16052 * @cfg {Number} width (in pixels)
16057 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16060 stylesheets: false,
16065 // private properties
16066 validationEvent : false,
16068 initialized : false,
16070 sourceEditMode : false,
16071 onFocus : Roo.emptyFn,
16073 hideMode:'offsets',
16081 * Protected method that will not generally be called directly. It
16082 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16083 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16085 getDocMarkup : function(){
16088 Roo.log(this.stylesheets);
16090 // inherit styels from page...??
16091 if (this.stylesheets === false) {
16093 Roo.get(document.head).select('style').each(function(node) {
16094 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16097 Roo.get(document.head).select('link').each(function(node) {
16098 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16101 } else if (!this.stylesheets.length) {
16103 st = '<style type="text/css">' +
16104 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16107 Roo.each(this.stylesheets, function(s) {
16108 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16113 st += '<style type="text/css">' +
16114 'IMG { cursor: pointer } ' +
16118 return '<html><head>' + st +
16119 //<style type="text/css">' +
16120 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16122 ' </head><body class="roo-htmleditor-body"></body></html>';
16126 onRender : function(ct, position)
16129 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16130 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16133 this.el.dom.style.border = '0 none';
16134 this.el.dom.setAttribute('tabIndex', -1);
16135 this.el.addClass('x-hidden hide');
16139 if(Roo.isIE){ // fix IE 1px bogus margin
16140 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16144 this.frameId = Roo.id();
16148 var iframe = this.owner.wrap.createChild({
16150 cls: 'form-control', // bootstrap..
16152 name: this.frameId,
16153 frameBorder : 'no',
16154 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16159 this.iframe = iframe.dom;
16161 this.assignDocWin();
16163 this.doc.designMode = 'on';
16166 this.doc.write(this.getDocMarkup());
16170 var task = { // must defer to wait for browser to be ready
16172 //console.log("run task?" + this.doc.readyState);
16173 this.assignDocWin();
16174 if(this.doc.body || this.doc.readyState == 'complete'){
16176 this.doc.designMode="on";
16180 Roo.TaskMgr.stop(task);
16181 this.initEditor.defer(10, this);
16188 Roo.TaskMgr.start(task);
16195 onResize : function(w, h)
16197 Roo.log('resize: ' +w + ',' + h );
16198 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16202 if(typeof w == 'number'){
16204 this.iframe.style.width = w + 'px';
16206 if(typeof h == 'number'){
16208 this.iframe.style.height = h + 'px';
16210 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16217 * Toggles the editor between standard and source edit mode.
16218 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16220 toggleSourceEdit : function(sourceEditMode){
16222 this.sourceEditMode = sourceEditMode === true;
16224 if(this.sourceEditMode){
16226 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16229 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16230 //this.iframe.className = '';
16233 //this.setSize(this.owner.wrap.getSize());
16234 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16241 * Protected method that will not generally be called directly. If you need/want
16242 * custom HTML cleanup, this is the method you should override.
16243 * @param {String} html The HTML to be cleaned
16244 * return {String} The cleaned HTML
16246 cleanHtml : function(html){
16247 html = String(html);
16248 if(html.length > 5){
16249 if(Roo.isSafari){ // strip safari nonsense
16250 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16253 if(html == ' '){
16260 * HTML Editor -> Textarea
16261 * Protected method that will not generally be called directly. Syncs the contents
16262 * of the editor iframe with the textarea.
16264 syncValue : function(){
16265 if(this.initialized){
16266 var bd = (this.doc.body || this.doc.documentElement);
16267 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16268 var html = bd.innerHTML;
16270 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16271 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16273 html = '<div style="'+m[0]+'">' + html + '</div>';
16276 html = this.cleanHtml(html);
16277 // fix up the special chars.. normaly like back quotes in word...
16278 // however we do not want to do this with chinese..
16279 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16280 var cc = b.charCodeAt();
16282 (cc >= 0x4E00 && cc < 0xA000 ) ||
16283 (cc >= 0x3400 && cc < 0x4E00 ) ||
16284 (cc >= 0xf900 && cc < 0xfb00 )
16290 if(this.owner.fireEvent('beforesync', this, html) !== false){
16291 this.el.dom.value = html;
16292 this.owner.fireEvent('sync', this, html);
16298 * Protected method that will not generally be called directly. Pushes the value of the textarea
16299 * into the iframe editor.
16301 pushValue : function(){
16302 if(this.initialized){
16303 var v = this.el.dom.value.trim();
16305 // if(v.length < 1){
16309 if(this.owner.fireEvent('beforepush', this, v) !== false){
16310 var d = (this.doc.body || this.doc.documentElement);
16312 this.cleanUpPaste();
16313 this.el.dom.value = d.innerHTML;
16314 this.owner.fireEvent('push', this, v);
16320 deferFocus : function(){
16321 this.focus.defer(10, this);
16325 focus : function(){
16326 if(this.win && !this.sourceEditMode){
16333 assignDocWin: function()
16335 var iframe = this.iframe;
16338 this.doc = iframe.contentWindow.document;
16339 this.win = iframe.contentWindow;
16341 if (!Roo.get(this.frameId)) {
16344 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16345 this.win = Roo.get(this.frameId).dom.contentWindow;
16350 initEditor : function(){
16351 //console.log("INIT EDITOR");
16352 this.assignDocWin();
16356 this.doc.designMode="on";
16358 this.doc.write(this.getDocMarkup());
16361 var dbody = (this.doc.body || this.doc.documentElement);
16362 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16363 // this copies styles from the containing element into thsi one..
16364 // not sure why we need all of this..
16365 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16367 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16368 //ss['background-attachment'] = 'fixed'; // w3c
16369 dbody.bgProperties = 'fixed'; // ie
16370 //Roo.DomHelper.applyStyles(dbody, ss);
16371 Roo.EventManager.on(this.doc, {
16372 //'mousedown': this.onEditorEvent,
16373 'mouseup': this.onEditorEvent,
16374 'dblclick': this.onEditorEvent,
16375 'click': this.onEditorEvent,
16376 'keyup': this.onEditorEvent,
16381 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16383 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16384 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16386 this.initialized = true;
16388 this.owner.fireEvent('initialize', this);
16393 onDestroy : function(){
16399 //for (var i =0; i < this.toolbars.length;i++) {
16400 // // fixme - ask toolbars for heights?
16401 // this.toolbars[i].onDestroy();
16404 //this.wrap.dom.innerHTML = '';
16405 //this.wrap.remove();
16410 onFirstFocus : function(){
16412 this.assignDocWin();
16415 this.activated = true;
16418 if(Roo.isGecko){ // prevent silly gecko errors
16420 var s = this.win.getSelection();
16421 if(!s.focusNode || s.focusNode.nodeType != 3){
16422 var r = s.getRangeAt(0);
16423 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16428 this.execCmd('useCSS', true);
16429 this.execCmd('styleWithCSS', false);
16432 this.owner.fireEvent('activate', this);
16436 adjustFont: function(btn){
16437 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16438 //if(Roo.isSafari){ // safari
16441 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16442 if(Roo.isSafari){ // safari
16443 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16444 v = (v < 10) ? 10 : v;
16445 v = (v > 48) ? 48 : v;
16446 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16451 v = Math.max(1, v+adjust);
16453 this.execCmd('FontSize', v );
16456 onEditorEvent : function(e){
16457 this.owner.fireEvent('editorevent', this, e);
16458 // this.updateToolbar();
16459 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16462 insertTag : function(tg)
16464 // could be a bit smarter... -> wrap the current selected tRoo..
16465 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16467 range = this.createRange(this.getSelection());
16468 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16469 wrappingNode.appendChild(range.extractContents());
16470 range.insertNode(wrappingNode);
16477 this.execCmd("formatblock", tg);
16481 insertText : function(txt)
16485 var range = this.createRange();
16486 range.deleteContents();
16487 //alert(Sender.getAttribute('label'));
16489 range.insertNode(this.doc.createTextNode(txt));
16495 * Executes a Midas editor command on the editor document and performs necessary focus and
16496 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16497 * @param {String} cmd The Midas command
16498 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16500 relayCmd : function(cmd, value){
16502 this.execCmd(cmd, value);
16503 this.owner.fireEvent('editorevent', this);
16504 //this.updateToolbar();
16505 this.owner.deferFocus();
16509 * Executes a Midas editor command directly on the editor document.
16510 * For visual commands, you should use {@link #relayCmd} instead.
16511 * <b>This should only be called after the editor is initialized.</b>
16512 * @param {String} cmd The Midas command
16513 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16515 execCmd : function(cmd, value){
16516 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16523 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16525 * @param {String} text | dom node..
16527 insertAtCursor : function(text)
16532 if(!this.activated){
16538 var r = this.doc.selection.createRange();
16549 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16553 // from jquery ui (MIT licenced)
16555 var win = this.win;
16557 if (win.getSelection && win.getSelection().getRangeAt) {
16558 range = win.getSelection().getRangeAt(0);
16559 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16560 range.insertNode(node);
16561 } else if (win.document.selection && win.document.selection.createRange) {
16562 // no firefox support
16563 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16564 win.document.selection.createRange().pasteHTML(txt);
16566 // no firefox support
16567 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16568 this.execCmd('InsertHTML', txt);
16577 mozKeyPress : function(e){
16579 var c = e.getCharCode(), cmd;
16582 c = String.fromCharCode(c).toLowerCase();
16596 this.cleanUpPaste.defer(100, this);
16604 e.preventDefault();
16612 fixKeys : function(){ // load time branching for fastest keydown performance
16614 return function(e){
16615 var k = e.getKey(), r;
16618 r = this.doc.selection.createRange();
16621 r.pasteHTML('    ');
16628 r = this.doc.selection.createRange();
16630 var target = r.parentElement();
16631 if(!target || target.tagName.toLowerCase() != 'li'){
16633 r.pasteHTML('<br />');
16639 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16640 this.cleanUpPaste.defer(100, this);
16646 }else if(Roo.isOpera){
16647 return function(e){
16648 var k = e.getKey();
16652 this.execCmd('InsertHTML','    ');
16655 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16656 this.cleanUpPaste.defer(100, this);
16661 }else if(Roo.isSafari){
16662 return function(e){
16663 var k = e.getKey();
16667 this.execCmd('InsertText','\t');
16671 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16672 this.cleanUpPaste.defer(100, this);
16680 getAllAncestors: function()
16682 var p = this.getSelectedNode();
16685 a.push(p); // push blank onto stack..
16686 p = this.getParentElement();
16690 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16694 a.push(this.doc.body);
16698 lastSelNode : false,
16701 getSelection : function()
16703 this.assignDocWin();
16704 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16707 getSelectedNode: function()
16709 // this may only work on Gecko!!!
16711 // should we cache this!!!!
16716 var range = this.createRange(this.getSelection()).cloneRange();
16719 var parent = range.parentElement();
16721 var testRange = range.duplicate();
16722 testRange.moveToElementText(parent);
16723 if (testRange.inRange(range)) {
16726 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16729 parent = parent.parentElement;
16734 // is ancestor a text element.
16735 var ac = range.commonAncestorContainer;
16736 if (ac.nodeType == 3) {
16737 ac = ac.parentNode;
16740 var ar = ac.childNodes;
16743 var other_nodes = [];
16744 var has_other_nodes = false;
16745 for (var i=0;i<ar.length;i++) {
16746 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16749 // fullly contained node.
16751 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16756 // probably selected..
16757 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16758 other_nodes.push(ar[i]);
16762 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16767 has_other_nodes = true;
16769 if (!nodes.length && other_nodes.length) {
16770 nodes= other_nodes;
16772 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16778 createRange: function(sel)
16780 // this has strange effects when using with
16781 // top toolbar - not sure if it's a great idea.
16782 //this.editor.contentWindow.focus();
16783 if (typeof sel != "undefined") {
16785 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16787 return this.doc.createRange();
16790 return this.doc.createRange();
16793 getParentElement: function()
16796 this.assignDocWin();
16797 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16799 var range = this.createRange(sel);
16802 var p = range.commonAncestorContainer;
16803 while (p.nodeType == 3) { // text node
16814 * Range intersection.. the hard stuff...
16818 * [ -- selected range --- ]
16822 * if end is before start or hits it. fail.
16823 * if start is after end or hits it fail.
16825 * if either hits (but other is outside. - then it's not
16831 // @see http://www.thismuchiknow.co.uk/?p=64.
16832 rangeIntersectsNode : function(range, node)
16834 var nodeRange = node.ownerDocument.createRange();
16836 nodeRange.selectNode(node);
16838 nodeRange.selectNodeContents(node);
16841 var rangeStartRange = range.cloneRange();
16842 rangeStartRange.collapse(true);
16844 var rangeEndRange = range.cloneRange();
16845 rangeEndRange.collapse(false);
16847 var nodeStartRange = nodeRange.cloneRange();
16848 nodeStartRange.collapse(true);
16850 var nodeEndRange = nodeRange.cloneRange();
16851 nodeEndRange.collapse(false);
16853 return rangeStartRange.compareBoundaryPoints(
16854 Range.START_TO_START, nodeEndRange) == -1 &&
16855 rangeEndRange.compareBoundaryPoints(
16856 Range.START_TO_START, nodeStartRange) == 1;
16860 rangeCompareNode : function(range, node)
16862 var nodeRange = node.ownerDocument.createRange();
16864 nodeRange.selectNode(node);
16866 nodeRange.selectNodeContents(node);
16870 range.collapse(true);
16872 nodeRange.collapse(true);
16874 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16875 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16877 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16879 var nodeIsBefore = ss == 1;
16880 var nodeIsAfter = ee == -1;
16882 if (nodeIsBefore && nodeIsAfter)
16884 if (!nodeIsBefore && nodeIsAfter)
16885 return 1; //right trailed.
16887 if (nodeIsBefore && !nodeIsAfter)
16888 return 2; // left trailed.
16893 // private? - in a new class?
16894 cleanUpPaste : function()
16896 // cleans up the whole document..
16897 Roo.log('cleanuppaste');
16899 this.cleanUpChildren(this.doc.body);
16900 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16901 if (clean != this.doc.body.innerHTML) {
16902 this.doc.body.innerHTML = clean;
16907 cleanWordChars : function(input) {// change the chars to hex code
16908 var he = Roo.HtmlEditorCore;
16910 var output = input;
16911 Roo.each(he.swapCodes, function(sw) {
16912 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16914 output = output.replace(swapper, sw[1]);
16921 cleanUpChildren : function (n)
16923 if (!n.childNodes.length) {
16926 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16927 this.cleanUpChild(n.childNodes[i]);
16934 cleanUpChild : function (node)
16937 //console.log(node);
16938 if (node.nodeName == "#text") {
16939 // clean up silly Windows -- stuff?
16942 if (node.nodeName == "#comment") {
16943 node.parentNode.removeChild(node);
16944 // clean up silly Windows -- stuff?
16948 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16950 node.parentNode.removeChild(node);
16955 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16957 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16958 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16960 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16961 // remove_keep_children = true;
16964 if (remove_keep_children) {
16965 this.cleanUpChildren(node);
16966 // inserts everything just before this node...
16967 while (node.childNodes.length) {
16968 var cn = node.childNodes[0];
16969 node.removeChild(cn);
16970 node.parentNode.insertBefore(cn, node);
16972 node.parentNode.removeChild(node);
16976 if (!node.attributes || !node.attributes.length) {
16977 this.cleanUpChildren(node);
16981 function cleanAttr(n,v)
16984 if (v.match(/^\./) || v.match(/^\//)) {
16987 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16990 if (v.match(/^#/)) {
16993 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16994 node.removeAttribute(n);
16998 function cleanStyle(n,v)
17000 if (v.match(/expression/)) { //XSS?? should we even bother..
17001 node.removeAttribute(n);
17004 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17005 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17008 var parts = v.split(/;/);
17011 Roo.each(parts, function(p) {
17012 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17016 var l = p.split(':').shift().replace(/\s+/g,'');
17017 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17019 if ( cblack.indexOf(l) > -1) {
17020 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17021 //node.removeAttribute(n);
17025 // only allow 'c whitelisted system attributes'
17026 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17027 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17028 //node.removeAttribute(n);
17038 if (clean.length) {
17039 node.setAttribute(n, clean.join(';'));
17041 node.removeAttribute(n);
17047 for (var i = node.attributes.length-1; i > -1 ; i--) {
17048 var a = node.attributes[i];
17051 if (a.name.toLowerCase().substr(0,2)=='on') {
17052 node.removeAttribute(a.name);
17055 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17056 node.removeAttribute(a.name);
17059 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17060 cleanAttr(a.name,a.value); // fixme..
17063 if (a.name == 'style') {
17064 cleanStyle(a.name,a.value);
17067 /// clean up MS crap..
17068 // tecnically this should be a list of valid class'es..
17071 if (a.name == 'class') {
17072 if (a.value.match(/^Mso/)) {
17073 node.className = '';
17076 if (a.value.match(/body/)) {
17077 node.className = '';
17088 this.cleanUpChildren(node);
17093 * Clean up MS wordisms...
17095 cleanWord : function(node)
17098 var cleanWordChildren = function()
17100 if (!node.childNodes.length) {
17103 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17104 _t.cleanWord(node.childNodes[i]);
17110 this.cleanWord(this.doc.body);
17113 if (node.nodeName == "#text") {
17114 // clean up silly Windows -- stuff?
17117 if (node.nodeName == "#comment") {
17118 node.parentNode.removeChild(node);
17119 // clean up silly Windows -- stuff?
17123 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17124 node.parentNode.removeChild(node);
17128 // remove - but keep children..
17129 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17130 while (node.childNodes.length) {
17131 var cn = node.childNodes[0];
17132 node.removeChild(cn);
17133 node.parentNode.insertBefore(cn, node);
17135 node.parentNode.removeChild(node);
17136 cleanWordChildren();
17140 if (node.className.length) {
17142 var cn = node.className.split(/\W+/);
17144 Roo.each(cn, function(cls) {
17145 if (cls.match(/Mso[a-zA-Z]+/)) {
17150 node.className = cna.length ? cna.join(' ') : '';
17152 node.removeAttribute("class");
17156 if (node.hasAttribute("lang")) {
17157 node.removeAttribute("lang");
17160 if (node.hasAttribute("style")) {
17162 var styles = node.getAttribute("style").split(";");
17164 Roo.each(styles, function(s) {
17165 if (!s.match(/:/)) {
17168 var kv = s.split(":");
17169 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17172 // what ever is left... we allow.
17175 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17176 if (!nstyle.length) {
17177 node.removeAttribute('style');
17181 cleanWordChildren();
17185 domToHTML : function(currentElement, depth, nopadtext) {
17187 depth = depth || 0;
17188 nopadtext = nopadtext || false;
17190 if (!currentElement) {
17191 return this.domToHTML(this.doc.body);
17194 //Roo.log(currentElement);
17196 var allText = false;
17197 var nodeName = currentElement.nodeName;
17198 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17200 if (nodeName == '#text') {
17201 return currentElement.nodeValue;
17206 if (nodeName != 'BODY') {
17209 // Prints the node tagName, such as <A>, <IMG>, etc
17212 for(i = 0; i < currentElement.attributes.length;i++) {
17214 var aname = currentElement.attributes.item(i).name;
17215 if (!currentElement.attributes.item(i).value.length) {
17218 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17221 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17230 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17233 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17238 // Traverse the tree
17240 var currentElementChild = currentElement.childNodes.item(i);
17241 var allText = true;
17242 var innerHTML = '';
17244 while (currentElementChild) {
17245 // Formatting code (indent the tree so it looks nice on the screen)
17246 var nopad = nopadtext;
17247 if (lastnode == 'SPAN') {
17251 if (currentElementChild.nodeName == '#text') {
17252 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17253 if (!nopad && toadd.length > 80) {
17254 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17256 innerHTML += toadd;
17259 currentElementChild = currentElement.childNodes.item(i);
17265 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17267 // Recursively traverse the tree structure of the child node
17268 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17269 lastnode = currentElementChild.nodeName;
17271 currentElementChild=currentElement.childNodes.item(i);
17277 // The remaining code is mostly for formatting the tree
17278 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17283 ret+= "</"+tagName+">";
17289 // hide stuff that is not compatible
17303 * @event specialkey
17307 * @cfg {String} fieldClass @hide
17310 * @cfg {String} focusClass @hide
17313 * @cfg {String} autoCreate @hide
17316 * @cfg {String} inputType @hide
17319 * @cfg {String} invalidClass @hide
17322 * @cfg {String} invalidText @hide
17325 * @cfg {String} msgFx @hide
17328 * @cfg {String} validateOnBlur @hide
17332 Roo.HtmlEditorCore.white = [
17333 'area', 'br', 'img', 'input', 'hr', 'wbr',
17335 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17336 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17337 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17338 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17339 'table', 'ul', 'xmp',
17341 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17344 'dir', 'menu', 'ol', 'ul', 'dl',
17350 Roo.HtmlEditorCore.black = [
17351 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17353 'base', 'basefont', 'bgsound', 'blink', 'body',
17354 'frame', 'frameset', 'head', 'html', 'ilayer',
17355 'iframe', 'layer', 'link', 'meta', 'object',
17356 'script', 'style' ,'title', 'xml' // clean later..
17358 Roo.HtmlEditorCore.clean = [
17359 'script', 'style', 'title', 'xml'
17361 Roo.HtmlEditorCore.remove = [
17366 Roo.HtmlEditorCore.ablack = [
17370 Roo.HtmlEditorCore.aclean = [
17371 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17375 Roo.HtmlEditorCore.pwhite= [
17376 'http', 'https', 'mailto'
17379 // white listed style attributes.
17380 Roo.HtmlEditorCore.cwhite= [
17381 // 'text-align', /// default is to allow most things..
17387 // black listed style attributes.
17388 Roo.HtmlEditorCore.cblack= [
17389 // 'font-size' -- this can be set by the project
17393 Roo.HtmlEditorCore.swapCodes =[
17412 * @class Roo.bootstrap.HtmlEditor
17413 * @extends Roo.bootstrap.TextArea
17414 * Bootstrap HtmlEditor class
17417 * Create a new HtmlEditor
17418 * @param {Object} config The config object
17421 Roo.bootstrap.HtmlEditor = function(config){
17422 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17423 if (!this.toolbars) {
17424 this.toolbars = [];
17426 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17429 * @event initialize
17430 * Fires when the editor is fully initialized (including the iframe)
17431 * @param {HtmlEditor} this
17436 * Fires when the editor is first receives the focus. Any insertion must wait
17437 * until after this event.
17438 * @param {HtmlEditor} this
17442 * @event beforesync
17443 * Fires before the textarea is updated with content from the editor iframe. Return false
17444 * to cancel the sync.
17445 * @param {HtmlEditor} this
17446 * @param {String} html
17450 * @event beforepush
17451 * Fires before the iframe editor is updated with content from the textarea. Return false
17452 * to cancel the push.
17453 * @param {HtmlEditor} this
17454 * @param {String} html
17459 * Fires when the textarea is updated with content from the editor iframe.
17460 * @param {HtmlEditor} this
17461 * @param {String} html
17466 * Fires when the iframe editor is updated with content from the textarea.
17467 * @param {HtmlEditor} this
17468 * @param {String} html
17472 * @event editmodechange
17473 * Fires when the editor switches edit modes
17474 * @param {HtmlEditor} this
17475 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17477 editmodechange: true,
17479 * @event editorevent
17480 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17481 * @param {HtmlEditor} this
17485 * @event firstfocus
17486 * Fires when on first focus - needed by toolbars..
17487 * @param {HtmlEditor} this
17492 * Auto save the htmlEditor value as a file into Events
17493 * @param {HtmlEditor} this
17497 * @event savedpreview
17498 * preview the saved version of htmlEditor
17499 * @param {HtmlEditor} this
17506 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17510 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17515 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17520 * @cfg {Number} height (in pixels)
17524 * @cfg {Number} width (in pixels)
17529 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17532 stylesheets: false,
17537 // private properties
17538 validationEvent : false,
17540 initialized : false,
17543 onFocus : Roo.emptyFn,
17545 hideMode:'offsets',
17548 tbContainer : false,
17550 toolbarContainer :function() {
17551 return this.wrap.select('.x-html-editor-tb',true).first();
17555 * Protected method that will not generally be called directly. It
17556 * is called when the editor creates its toolbar. Override this method if you need to
17557 * add custom toolbar buttons.
17558 * @param {HtmlEditor} editor
17560 createToolbar : function(){
17562 Roo.log("create toolbars");
17564 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17565 this.toolbars[0].render(this.toolbarContainer());
17569 // if (!editor.toolbars || !editor.toolbars.length) {
17570 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17573 // for (var i =0 ; i < editor.toolbars.length;i++) {
17574 // editor.toolbars[i] = Roo.factory(
17575 // typeof(editor.toolbars[i]) == 'string' ?
17576 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17577 // Roo.bootstrap.HtmlEditor);
17578 // editor.toolbars[i].init(editor);
17584 onRender : function(ct, position)
17586 // Roo.log("Call onRender: " + this.xtype);
17588 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17590 this.wrap = this.inputEl().wrap({
17591 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17594 this.editorcore.onRender(ct, position);
17596 if (this.resizable) {
17597 this.resizeEl = new Roo.Resizable(this.wrap, {
17601 minHeight : this.height,
17602 height: this.height,
17603 handles : this.resizable,
17606 resize : function(r, w, h) {
17607 _t.onResize(w,h); // -something
17613 this.createToolbar(this);
17616 if(!this.width && this.resizable){
17617 this.setSize(this.wrap.getSize());
17619 if (this.resizeEl) {
17620 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17621 // should trigger onReize..
17627 onResize : function(w, h)
17629 Roo.log('resize: ' +w + ',' + h );
17630 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17634 if(this.inputEl() ){
17635 if(typeof w == 'number'){
17636 var aw = w - this.wrap.getFrameWidth('lr');
17637 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17640 if(typeof h == 'number'){
17641 var tbh = -11; // fixme it needs to tool bar size!
17642 for (var i =0; i < this.toolbars.length;i++) {
17643 // fixme - ask toolbars for heights?
17644 tbh += this.toolbars[i].el.getHeight();
17645 //if (this.toolbars[i].footer) {
17646 // tbh += this.toolbars[i].footer.el.getHeight();
17654 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17655 ah -= 5; // knock a few pixes off for look..
17656 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17660 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17661 this.editorcore.onResize(ew,eh);
17666 * Toggles the editor between standard and source edit mode.
17667 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17669 toggleSourceEdit : function(sourceEditMode)
17671 this.editorcore.toggleSourceEdit(sourceEditMode);
17673 if(this.editorcore.sourceEditMode){
17674 Roo.log('editor - showing textarea');
17677 // Roo.log(this.syncValue());
17679 this.inputEl().removeClass(['hide', 'x-hidden']);
17680 this.inputEl().dom.removeAttribute('tabIndex');
17681 this.inputEl().focus();
17683 Roo.log('editor - hiding textarea');
17685 // Roo.log(this.pushValue());
17688 this.inputEl().addClass(['hide', 'x-hidden']);
17689 this.inputEl().dom.setAttribute('tabIndex', -1);
17690 //this.deferFocus();
17693 if(this.resizable){
17694 this.setSize(this.wrap.getSize());
17697 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17700 // private (for BoxComponent)
17701 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17703 // private (for BoxComponent)
17704 getResizeEl : function(){
17708 // private (for BoxComponent)
17709 getPositionEl : function(){
17714 initEvents : function(){
17715 this.originalValue = this.getValue();
17719 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17722 // markInvalid : Roo.emptyFn,
17724 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17727 // clearInvalid : Roo.emptyFn,
17729 setValue : function(v){
17730 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17731 this.editorcore.pushValue();
17736 deferFocus : function(){
17737 this.focus.defer(10, this);
17741 focus : function(){
17742 this.editorcore.focus();
17748 onDestroy : function(){
17754 for (var i =0; i < this.toolbars.length;i++) {
17755 // fixme - ask toolbars for heights?
17756 this.toolbars[i].onDestroy();
17759 this.wrap.dom.innerHTML = '';
17760 this.wrap.remove();
17765 onFirstFocus : function(){
17766 //Roo.log("onFirstFocus");
17767 this.editorcore.onFirstFocus();
17768 for (var i =0; i < this.toolbars.length;i++) {
17769 this.toolbars[i].onFirstFocus();
17775 syncValue : function()
17777 this.editorcore.syncValue();
17780 pushValue : function()
17782 this.editorcore.pushValue();
17786 // hide stuff that is not compatible
17800 * @event specialkey
17804 * @cfg {String} fieldClass @hide
17807 * @cfg {String} focusClass @hide
17810 * @cfg {String} autoCreate @hide
17813 * @cfg {String} inputType @hide
17816 * @cfg {String} invalidClass @hide
17819 * @cfg {String} invalidText @hide
17822 * @cfg {String} msgFx @hide
17825 * @cfg {String} validateOnBlur @hide
17834 Roo.namespace('Roo.bootstrap.htmleditor');
17836 * @class Roo.bootstrap.HtmlEditorToolbar1
17841 new Roo.bootstrap.HtmlEditor({
17844 new Roo.bootstrap.HtmlEditorToolbar1({
17845 disable : { fonts: 1 , format: 1, ..., ... , ...],
17851 * @cfg {Object} disable List of elements to disable..
17852 * @cfg {Array} btns List of additional buttons.
17856 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17859 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17862 Roo.apply(this, config);
17864 // default disabled, based on 'good practice'..
17865 this.disable = this.disable || {};
17866 Roo.applyIf(this.disable, {
17869 specialElements : true
17871 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17873 this.editor = config.editor;
17874 this.editorcore = config.editor.editorcore;
17876 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17878 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17879 // dont call parent... till later.
17881 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17886 editorcore : false,
17891 "h1","h2","h3","h4","h5","h6",
17893 "abbr", "acronym", "address", "cite", "samp", "var",
17897 onRender : function(ct, position)
17899 // Roo.log("Call onRender: " + this.xtype);
17901 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17903 this.el.dom.style.marginBottom = '0';
17905 var editorcore = this.editorcore;
17906 var editor= this.editor;
17909 var btn = function(id,cmd , toggle, handler){
17911 var event = toggle ? 'toggle' : 'click';
17916 xns: Roo.bootstrap,
17919 enableToggle:toggle !== false,
17921 pressed : toggle ? false : null,
17924 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17925 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17934 xns: Roo.bootstrap,
17935 glyphicon : 'font',
17939 xns: Roo.bootstrap,
17943 Roo.each(this.formats, function(f) {
17944 style.menu.items.push({
17946 xns: Roo.bootstrap,
17947 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17952 editorcore.insertTag(this.tagname);
17959 children.push(style);
17962 btn('bold',false,true);
17963 btn('italic',false,true);
17964 btn('align-left', 'justifyleft',true);
17965 btn('align-center', 'justifycenter',true);
17966 btn('align-right' , 'justifyright',true);
17967 btn('link', false, false, function(btn) {
17968 //Roo.log("create link?");
17969 var url = prompt(this.createLinkText, this.defaultLinkValue);
17970 if(url && url != 'http:/'+'/'){
17971 this.editorcore.relayCmd('createlink', url);
17974 btn('list','insertunorderedlist',true);
17975 btn('pencil', false,true, function(btn){
17978 this.toggleSourceEdit(btn.pressed);
17984 xns: Roo.bootstrap,
17989 xns: Roo.bootstrap,
17994 cog.menu.items.push({
17996 xns: Roo.bootstrap,
17997 html : Clean styles,
18002 editorcore.insertTag(this.tagname);
18011 this.xtype = 'NavSimplebar';
18013 for(var i=0;i< children.length;i++) {
18015 this.buttons.add(this.addxtypeChild(children[i]));
18019 editor.on('editorevent', this.updateToolbar, this);
18021 onBtnClick : function(id)
18023 this.editorcore.relayCmd(id);
18024 this.editorcore.focus();
18028 * Protected method that will not generally be called directly. It triggers
18029 * a toolbar update by reading the markup state of the current selection in the editor.
18031 updateToolbar: function(){
18033 if(!this.editorcore.activated){
18034 this.editor.onFirstFocus(); // is this neeed?
18038 var btns = this.buttons;
18039 var doc = this.editorcore.doc;
18040 btns.get('bold').setActive(doc.queryCommandState('bold'));
18041 btns.get('italic').setActive(doc.queryCommandState('italic'));
18042 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18044 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18045 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18046 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18048 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18049 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18052 var ans = this.editorcore.getAllAncestors();
18053 if (this.formatCombo) {
18056 var store = this.formatCombo.store;
18057 this.formatCombo.setValue("");
18058 for (var i =0; i < ans.length;i++) {
18059 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18061 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18069 // hides menus... - so this cant be on a menu...
18070 Roo.bootstrap.MenuMgr.hideAll();
18072 Roo.bootstrap.MenuMgr.hideAll();
18073 //this.editorsyncValue();
18075 onFirstFocus: function() {
18076 this.buttons.each(function(item){
18080 toggleSourceEdit : function(sourceEditMode){
18083 if(sourceEditMode){
18084 Roo.log("disabling buttons");
18085 this.buttons.each( function(item){
18086 if(item.cmd != 'pencil'){
18092 Roo.log("enabling buttons");
18093 if(this.editorcore.initialized){
18094 this.buttons.each( function(item){
18100 Roo.log("calling toggole on editor");
18101 // tell the editor that it's been pressed..
18102 this.editor.toggleSourceEdit(sourceEditMode);
18112 * @class Roo.bootstrap.Table.AbstractSelectionModel
18113 * @extends Roo.util.Observable
18114 * Abstract base class for grid SelectionModels. It provides the interface that should be
18115 * implemented by descendant classes. This class should not be directly instantiated.
18118 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18119 this.locked = false;
18120 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18124 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18125 /** @ignore Called by the grid automatically. Do not call directly. */
18126 init : function(grid){
18132 * Locks the selections.
18135 this.locked = true;
18139 * Unlocks the selections.
18141 unlock : function(){
18142 this.locked = false;
18146 * Returns true if the selections are locked.
18147 * @return {Boolean}
18149 isLocked : function(){
18150 return this.locked;
18154 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18155 * @class Roo.bootstrap.Table.RowSelectionModel
18156 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18157 * It supports multiple selections and keyboard selection/navigation.
18159 * @param {Object} config
18162 Roo.bootstrap.Table.RowSelectionModel = function(config){
18163 Roo.apply(this, config);
18164 this.selections = new Roo.util.MixedCollection(false, function(o){
18169 this.lastActive = false;
18173 * @event selectionchange
18174 * Fires when the selection changes
18175 * @param {SelectionModel} this
18177 "selectionchange" : true,
18179 * @event afterselectionchange
18180 * Fires after the selection changes (eg. by key press or clicking)
18181 * @param {SelectionModel} this
18183 "afterselectionchange" : true,
18185 * @event beforerowselect
18186 * Fires when a row is selected being selected, return false to cancel.
18187 * @param {SelectionModel} this
18188 * @param {Number} rowIndex The selected index
18189 * @param {Boolean} keepExisting False if other selections will be cleared
18191 "beforerowselect" : true,
18194 * Fires when a row is selected.
18195 * @param {SelectionModel} this
18196 * @param {Number} rowIndex The selected index
18197 * @param {Roo.data.Record} r The record
18199 "rowselect" : true,
18201 * @event rowdeselect
18202 * Fires when a row is deselected.
18203 * @param {SelectionModel} this
18204 * @param {Number} rowIndex The selected index
18206 "rowdeselect" : true
18208 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18209 this.locked = false;
18212 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18214 * @cfg {Boolean} singleSelect
18215 * True to allow selection of only one row at a time (defaults to false)
18217 singleSelect : false,
18220 initEvents : function(){
18222 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18223 this.grid.on("mousedown", this.handleMouseDown, this);
18224 }else{ // allow click to work like normal
18225 this.grid.on("rowclick", this.handleDragableRowClick, this);
18228 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18229 "up" : function(e){
18231 this.selectPrevious(e.shiftKey);
18232 }else if(this.last !== false && this.lastActive !== false){
18233 var last = this.last;
18234 this.selectRange(this.last, this.lastActive-1);
18235 this.grid.getView().focusRow(this.lastActive);
18236 if(last !== false){
18240 this.selectFirstRow();
18242 this.fireEvent("afterselectionchange", this);
18244 "down" : function(e){
18246 this.selectNext(e.shiftKey);
18247 }else if(this.last !== false && this.lastActive !== false){
18248 var last = this.last;
18249 this.selectRange(this.last, this.lastActive+1);
18250 this.grid.getView().focusRow(this.lastActive);
18251 if(last !== false){
18255 this.selectFirstRow();
18257 this.fireEvent("afterselectionchange", this);
18262 var view = this.grid.view;
18263 view.on("refresh", this.onRefresh, this);
18264 view.on("rowupdated", this.onRowUpdated, this);
18265 view.on("rowremoved", this.onRemove, this);
18269 onRefresh : function(){
18270 var ds = this.grid.dataSource, i, v = this.grid.view;
18271 var s = this.selections;
18272 s.each(function(r){
18273 if((i = ds.indexOfId(r.id)) != -1){
18282 onRemove : function(v, index, r){
18283 this.selections.remove(r);
18287 onRowUpdated : function(v, index, r){
18288 if(this.isSelected(r)){
18289 v.onRowSelect(index);
18295 * @param {Array} records The records to select
18296 * @param {Boolean} keepExisting (optional) True to keep existing selections
18298 selectRecords : function(records, keepExisting){
18300 this.clearSelections();
18302 var ds = this.grid.dataSource;
18303 for(var i = 0, len = records.length; i < len; i++){
18304 this.selectRow(ds.indexOf(records[i]), true);
18309 * Gets the number of selected rows.
18312 getCount : function(){
18313 return this.selections.length;
18317 * Selects the first row in the grid.
18319 selectFirstRow : function(){
18324 * Select the last row.
18325 * @param {Boolean} keepExisting (optional) True to keep existing selections
18327 selectLastRow : function(keepExisting){
18328 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18332 * Selects the row immediately following the last selected row.
18333 * @param {Boolean} keepExisting (optional) True to keep existing selections
18335 selectNext : function(keepExisting){
18336 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18337 this.selectRow(this.last+1, keepExisting);
18338 this.grid.getView().focusRow(this.last);
18343 * Selects the row that precedes the last selected row.
18344 * @param {Boolean} keepExisting (optional) True to keep existing selections
18346 selectPrevious : function(keepExisting){
18348 this.selectRow(this.last-1, keepExisting);
18349 this.grid.getView().focusRow(this.last);
18354 * Returns the selected records
18355 * @return {Array} Array of selected records
18357 getSelections : function(){
18358 return [].concat(this.selections.items);
18362 * Returns the first selected record.
18365 getSelected : function(){
18366 return this.selections.itemAt(0);
18371 * Clears all selections.
18373 clearSelections : function(fast){
18374 if(this.locked) return;
18376 var ds = this.grid.dataSource;
18377 var s = this.selections;
18378 s.each(function(r){
18379 this.deselectRow(ds.indexOfId(r.id));
18383 this.selections.clear();
18390 * Selects all rows.
18392 selectAll : function(){
18393 if(this.locked) return;
18394 this.selections.clear();
18395 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18396 this.selectRow(i, true);
18401 * Returns True if there is a selection.
18402 * @return {Boolean}
18404 hasSelection : function(){
18405 return this.selections.length > 0;
18409 * Returns True if the specified row is selected.
18410 * @param {Number/Record} record The record or index of the record to check
18411 * @return {Boolean}
18413 isSelected : function(index){
18414 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18415 return (r && this.selections.key(r.id) ? true : false);
18419 * Returns True if the specified record id is selected.
18420 * @param {String} id The id of record to check
18421 * @return {Boolean}
18423 isIdSelected : function(id){
18424 return (this.selections.key(id) ? true : false);
18428 handleMouseDown : function(e, t){
18429 var view = this.grid.getView(), rowIndex;
18430 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18433 if(e.shiftKey && this.last !== false){
18434 var last = this.last;
18435 this.selectRange(last, rowIndex, e.ctrlKey);
18436 this.last = last; // reset the last
18437 view.focusRow(rowIndex);
18439 var isSelected = this.isSelected(rowIndex);
18440 if(e.button !== 0 && isSelected){
18441 view.focusRow(rowIndex);
18442 }else if(e.ctrlKey && isSelected){
18443 this.deselectRow(rowIndex);
18444 }else if(!isSelected){
18445 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18446 view.focusRow(rowIndex);
18449 this.fireEvent("afterselectionchange", this);
18452 handleDragableRowClick : function(grid, rowIndex, e)
18454 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18455 this.selectRow(rowIndex, false);
18456 grid.view.focusRow(rowIndex);
18457 this.fireEvent("afterselectionchange", this);
18462 * Selects multiple rows.
18463 * @param {Array} rows Array of the indexes of the row to select
18464 * @param {Boolean} keepExisting (optional) True to keep existing selections
18466 selectRows : function(rows, keepExisting){
18468 this.clearSelections();
18470 for(var i = 0, len = rows.length; i < len; i++){
18471 this.selectRow(rows[i], true);
18476 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18477 * @param {Number} startRow The index of the first row in the range
18478 * @param {Number} endRow The index of the last row in the range
18479 * @param {Boolean} keepExisting (optional) True to retain existing selections
18481 selectRange : function(startRow, endRow, keepExisting){
18482 if(this.locked) return;
18484 this.clearSelections();
18486 if(startRow <= endRow){
18487 for(var i = startRow; i <= endRow; i++){
18488 this.selectRow(i, true);
18491 for(var i = startRow; i >= endRow; i--){
18492 this.selectRow(i, true);
18498 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18499 * @param {Number} startRow The index of the first row in the range
18500 * @param {Number} endRow The index of the last row in the range
18502 deselectRange : function(startRow, endRow, preventViewNotify){
18503 if(this.locked) return;
18504 for(var i = startRow; i <= endRow; i++){
18505 this.deselectRow(i, preventViewNotify);
18511 * @param {Number} row The index of the row to select
18512 * @param {Boolean} keepExisting (optional) True to keep existing selections
18514 selectRow : function(index, keepExisting, preventViewNotify){
18515 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18516 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18517 if(!keepExisting || this.singleSelect){
18518 this.clearSelections();
18520 var r = this.grid.dataSource.getAt(index);
18521 this.selections.add(r);
18522 this.last = this.lastActive = index;
18523 if(!preventViewNotify){
18524 this.grid.getView().onRowSelect(index);
18526 this.fireEvent("rowselect", this, index, r);
18527 this.fireEvent("selectionchange", this);
18533 * @param {Number} row The index of the row to deselect
18535 deselectRow : function(index, preventViewNotify){
18536 if(this.locked) return;
18537 if(this.last == index){
18540 if(this.lastActive == index){
18541 this.lastActive = false;
18543 var r = this.grid.dataSource.getAt(index);
18544 this.selections.remove(r);
18545 if(!preventViewNotify){
18546 this.grid.getView().onRowDeselect(index);
18548 this.fireEvent("rowdeselect", this, index);
18549 this.fireEvent("selectionchange", this);
18553 restoreLast : function(){
18555 this.last = this._last;
18560 acceptsNav : function(row, col, cm){
18561 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18565 onEditorKey : function(field, e){
18566 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18571 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18573 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18575 }else if(k == e.ENTER && !e.ctrlKey){
18579 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18581 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18583 }else if(k == e.ESC){
18587 g.startEditing(newCell[0], newCell[1]);
18592 * Ext JS Library 1.1.1
18593 * Copyright(c) 2006-2007, Ext JS, LLC.
18595 * Originally Released Under LGPL - original licence link has changed is not relivant.
18598 * <script type="text/javascript">
18602 * @class Roo.bootstrap.PagingToolbar
18604 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18606 * Create a new PagingToolbar
18607 * @param {Object} config The config object
18609 Roo.bootstrap.PagingToolbar = function(config)
18611 // old args format still supported... - xtype is prefered..
18612 // created from xtype...
18613 var ds = config.dataSource;
18614 this.toolbarItems = [];
18615 if (config.items) {
18616 this.toolbarItems = config.items;
18617 // config.items = [];
18620 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18627 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18631 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18633 * @cfg {Roo.data.Store} dataSource
18634 * The underlying data store providing the paged data
18637 * @cfg {String/HTMLElement/Element} container
18638 * container The id or element that will contain the toolbar
18641 * @cfg {Boolean} displayInfo
18642 * True to display the displayMsg (defaults to false)
18645 * @cfg {Number} pageSize
18646 * The number of records to display per page (defaults to 20)
18650 * @cfg {String} displayMsg
18651 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18653 displayMsg : 'Displaying {0} - {1} of {2}',
18655 * @cfg {String} emptyMsg
18656 * The message to display when no records are found (defaults to "No data to display")
18658 emptyMsg : 'No data to display',
18660 * Customizable piece of the default paging text (defaults to "Page")
18663 beforePageText : "Page",
18665 * Customizable piece of the default paging text (defaults to "of %0")
18668 afterPageText : "of {0}",
18670 * Customizable piece of the default paging text (defaults to "First Page")
18673 firstText : "First Page",
18675 * Customizable piece of the default paging text (defaults to "Previous Page")
18678 prevText : "Previous Page",
18680 * Customizable piece of the default paging text (defaults to "Next Page")
18683 nextText : "Next Page",
18685 * Customizable piece of the default paging text (defaults to "Last Page")
18688 lastText : "Last Page",
18690 * Customizable piece of the default paging text (defaults to "Refresh")
18693 refreshText : "Refresh",
18697 onRender : function(ct, position)
18699 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18700 this.navgroup.parentId = this.id;
18701 this.navgroup.onRender(this.el, null);
18702 // add the buttons to the navgroup
18704 if(this.displayInfo){
18705 Roo.log(this.el.select('ul.navbar-nav',true).first());
18706 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18707 this.displayEl = this.el.select('.x-paging-info', true).first();
18708 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18709 // this.displayEl = navel.el.select('span',true).first();
18715 Roo.each(_this.buttons, function(e){
18716 Roo.factory(e).onRender(_this.el, null);
18720 Roo.each(_this.toolbarItems, function(e) {
18721 _this.navgroup.addItem(e);
18724 this.first = this.navgroup.addItem({
18725 tooltip: this.firstText,
18727 icon : 'fa fa-backward',
18729 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18732 this.prev = this.navgroup.addItem({
18733 tooltip: this.prevText,
18735 icon : 'fa fa-step-backward',
18737 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18739 //this.addSeparator();
18742 var field = this.navgroup.addItem( {
18744 cls : 'x-paging-position',
18746 html : this.beforePageText +
18747 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18748 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18751 this.field = field.el.select('input', true).first();
18752 this.field.on("keydown", this.onPagingKeydown, this);
18753 this.field.on("focus", function(){this.dom.select();});
18756 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18757 //this.field.setHeight(18);
18758 //this.addSeparator();
18759 this.next = this.navgroup.addItem({
18760 tooltip: this.nextText,
18762 html : ' <i class="fa fa-step-forward">',
18764 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18766 this.last = this.navgroup.addItem({
18767 tooltip: this.lastText,
18768 icon : 'fa fa-forward',
18771 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18773 //this.addSeparator();
18774 this.loading = this.navgroup.addItem({
18775 tooltip: this.refreshText,
18776 icon: 'fa fa-refresh',
18778 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18784 updateInfo : function(){
18785 if(this.displayEl){
18786 var count = this.ds.getCount();
18787 var msg = count == 0 ?
18791 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18793 this.displayEl.update(msg);
18798 onLoad : function(ds, r, o){
18799 this.cursor = o.params ? o.params.start : 0;
18800 var d = this.getPageData(),
18804 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18805 this.field.dom.value = ap;
18806 this.first.setDisabled(ap == 1);
18807 this.prev.setDisabled(ap == 1);
18808 this.next.setDisabled(ap == ps);
18809 this.last.setDisabled(ap == ps);
18810 this.loading.enable();
18815 getPageData : function(){
18816 var total = this.ds.getTotalCount();
18819 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18820 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18825 onLoadError : function(){
18826 this.loading.enable();
18830 onPagingKeydown : function(e){
18831 var k = e.getKey();
18832 var d = this.getPageData();
18834 var v = this.field.dom.value, pageNum;
18835 if(!v || isNaN(pageNum = parseInt(v, 10))){
18836 this.field.dom.value = d.activePage;
18839 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18840 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18843 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))
18845 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18846 this.field.dom.value = pageNum;
18847 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18850 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18852 var v = this.field.dom.value, pageNum;
18853 var increment = (e.shiftKey) ? 10 : 1;
18854 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18856 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18857 this.field.dom.value = d.activePage;
18860 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18862 this.field.dom.value = parseInt(v, 10) + increment;
18863 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18864 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18871 beforeLoad : function(){
18873 this.loading.disable();
18878 onClick : function(which){
18885 ds.load({params:{start: 0, limit: this.pageSize}});
18888 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18891 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18894 var total = ds.getTotalCount();
18895 var extra = total % this.pageSize;
18896 var lastStart = extra ? (total - extra) : total-this.pageSize;
18897 ds.load({params:{start: lastStart, limit: this.pageSize}});
18900 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18906 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18907 * @param {Roo.data.Store} store The data store to unbind
18909 unbind : function(ds){
18910 ds.un("beforeload", this.beforeLoad, this);
18911 ds.un("load", this.onLoad, this);
18912 ds.un("loadexception", this.onLoadError, this);
18913 ds.un("remove", this.updateInfo, this);
18914 ds.un("add", this.updateInfo, this);
18915 this.ds = undefined;
18919 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18920 * @param {Roo.data.Store} store The data store to bind
18922 bind : function(ds){
18923 ds.on("beforeload", this.beforeLoad, this);
18924 ds.on("load", this.onLoad, this);
18925 ds.on("loadexception", this.onLoadError, this);
18926 ds.on("remove", this.updateInfo, this);
18927 ds.on("add", this.updateInfo, this);
18938 * @class Roo.bootstrap.MessageBar
18939 * @extends Roo.bootstrap.Component
18940 * Bootstrap MessageBar class
18941 * @cfg {String} html contents of the MessageBar
18942 * @cfg {String} weight (info | success | warning | danger) default info
18943 * @cfg {String} beforeClass insert the bar before the given class
18944 * @cfg {Boolean} closable (true | false) default false
18945 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18948 * Create a new Element
18949 * @param {Object} config The config object
18952 Roo.bootstrap.MessageBar = function(config){
18953 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18956 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18962 beforeClass: 'bootstrap-sticky-wrap',
18964 getAutoCreate : function(){
18968 cls: 'alert alert-dismissable alert-' + this.weight,
18973 html: this.html || ''
18979 cfg.cls += ' alert-messages-fixed';
18993 onRender : function(ct, position)
18995 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18998 var cfg = Roo.apply({}, this.getAutoCreate());
19002 cfg.cls += ' ' + this.cls;
19005 cfg.style = this.style;
19007 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19009 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19012 this.el.select('>button.close').on('click', this.hide, this);
19018 if (!this.rendered) {
19024 this.fireEvent('show', this);
19030 if (!this.rendered) {
19036 this.fireEvent('hide', this);
19039 update : function()
19041 // var e = this.el.dom.firstChild;
19043 // if(this.closable){
19044 // e = e.nextSibling;
19047 // e.data = this.html || '';
19049 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19065 * @class Roo.bootstrap.Graph
19066 * @extends Roo.bootstrap.Component
19067 * Bootstrap Graph class
19071 @cfg {String} graphtype bar | vbar | pie
19072 @cfg {number} g_x coodinator | centre x (pie)
19073 @cfg {number} g_y coodinator | centre y (pie)
19074 @cfg {number} g_r radius (pie)
19075 @cfg {number} g_height height of the chart (respected by all elements in the set)
19076 @cfg {number} g_width width of the chart (respected by all elements in the set)
19077 @cfg {Object} title The title of the chart
19080 -opts (object) options for the chart
19082 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19083 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19085 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.
19086 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19088 o stretch (boolean)
19090 -opts (object) options for the pie
19093 o startAngle (number)
19094 o endAngle (number)
19098 * Create a new Input
19099 * @param {Object} config The config object
19102 Roo.bootstrap.Graph = function(config){
19103 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19109 * The img click event for the img.
19110 * @param {Roo.EventObject} e
19116 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19127 //g_colors: this.colors,
19134 getAutoCreate : function(){
19145 onRender : function(ct,position){
19146 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19147 this.raphael = Raphael(this.el.dom);
19149 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19150 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19151 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19152 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19154 r.text(160, 10, "Single Series Chart").attr(txtattr);
19155 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19156 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19157 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19159 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19160 r.barchart(330, 10, 300, 220, data1);
19161 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19162 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19165 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19166 // r.barchart(30, 30, 560, 250, xdata, {
19167 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19168 // axis : "0 0 1 1",
19169 // axisxlabels : xdata
19170 // //yvalues : cols,
19173 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19175 // this.load(null,xdata,{
19176 // axis : "0 0 1 1",
19177 // axisxlabels : xdata
19182 load : function(graphtype,xdata,opts){
19183 this.raphael.clear();
19185 graphtype = this.graphtype;
19190 var r = this.raphael,
19191 fin = function () {
19192 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19194 fout = function () {
19195 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19197 pfin = function() {
19198 this.sector.stop();
19199 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19202 this.label[0].stop();
19203 this.label[0].attr({ r: 7.5 });
19204 this.label[1].attr({ "font-weight": 800 });
19207 pfout = function() {
19208 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19211 this.label[0].animate({ r: 5 }, 500, "bounce");
19212 this.label[1].attr({ "font-weight": 400 });
19218 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19221 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19224 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19225 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19227 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19234 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19239 setTitle: function(o)
19244 initEvents: function() {
19247 this.el.on('click', this.onClick, this);
19251 onClick : function(e)
19253 Roo.log('img onclick');
19254 this.fireEvent('click', this, e);
19266 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19269 * @class Roo.bootstrap.dash.NumberBox
19270 * @extends Roo.bootstrap.Component
19271 * Bootstrap NumberBox class
19272 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19273 * @cfg {String} headline Box headline
19274 * @cfg {String} content Box content
19275 * @cfg {String} icon Box icon
19276 * @cfg {String} footer Footer text
19277 * @cfg {String} fhref Footer href
19280 * Create a new NumberBox
19281 * @param {Object} config The config object
19285 Roo.bootstrap.dash.NumberBox = function(config){
19286 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19290 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19300 getAutoCreate : function(){
19304 cls : 'small-box bg-' + this.bgcolor,
19312 cls : 'roo-headline',
19313 html : this.headline
19317 cls : 'roo-content',
19318 html : this.content
19332 cls : 'ion ' + this.icon
19341 cls : 'small-box-footer',
19342 href : this.fhref || '#',
19346 cfg.cn.push(footer);
19353 onRender : function(ct,position){
19354 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19361 setHeadline: function (value)
19363 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19366 setFooter: function (value, href)
19368 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19371 this.el.select('a.small-box-footer',true).first().attr('href', href);
19376 setContent: function (value)
19378 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19381 initEvents: function()
19395 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19398 * @class Roo.bootstrap.dash.TabBox
19399 * @extends Roo.bootstrap.Component
19400 * Bootstrap TabBox class
19401 * @cfg {String} title Title of the TabBox
19402 * @cfg {String} icon Icon of the TabBox
19405 * Create a new TabBox
19406 * @param {Object} config The config object
19410 Roo.bootstrap.dash.TabBox = function(config){
19411 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19416 * When a pane is added
19417 * @param {Roo.bootstrap.dash.TabPane} pane
19424 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19429 getChildContainer : function()
19431 return this.el.select('.tab-content', true).first();
19434 getAutoCreate : function(){
19438 cls: 'pull-left header',
19446 cls: 'fa ' + this.icon
19453 cls: 'nav-tabs-custom',
19457 cls: 'nav nav-tabs pull-right',
19464 cls: 'tab-content no-padding',
19472 initEvents : function()
19474 //Roo.log('add add pane handler');
19475 this.on('addpane', this.onAddPane, this);
19478 * Updates the box title
19479 * @param {String} html to set the title to.
19481 setTitle : function(value)
19483 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19485 onAddPane : function(pane)
19487 //Roo.log('addpane');
19489 // tabs are rendere left to right..
19490 var ctr = this.el.select('.nav-tabs', true).first();
19493 var existing = ctr.select('.nav-tab',true);
19494 var qty = existing.getCount();;
19497 var tab = ctr.createChild({
19499 cls : 'nav-tab' + (qty ? '' : ' active'),
19507 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19510 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19512 pane.el.addClass('active');
19517 onTabClick : function(ev,un,ob,pane)
19519 //Roo.log('tab - prev default');
19520 ev.preventDefault();
19523 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19524 pane.tab.addClass('active');
19525 //Roo.log(pane.title);
19526 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19527 // technically we should have a deactivate event.. but maybe add later.
19528 // and it should not de-activate the selected tab...
19530 pane.el.addClass('active');
19531 pane.fireEvent('activate');
19546 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19548 * @class Roo.bootstrap.TabPane
19549 * @extends Roo.bootstrap.Component
19550 * Bootstrap TabPane class
19551 * @cfg {Boolean} active (false | true) Default false
19552 * @cfg {String} title title of panel
19556 * Create a new TabPane
19557 * @param {Object} config The config object
19560 Roo.bootstrap.dash.TabPane = function(config){
19561 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19565 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19570 // the tabBox that this is attached to.
19573 getAutoCreate : function()
19581 cfg.cls += ' active';
19586 initEvents : function()
19588 //Roo.log('trigger add pane handler');
19589 this.parent().fireEvent('addpane', this)
19593 * Updates the tab title
19594 * @param {String} html to set the title to.
19596 setTitle: function(str)
19602 this.tab.select('a'.true).first().dom.innerHTML = str;
19619 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19622 * @class Roo.bootstrap.menu.Menu
19623 * @extends Roo.bootstrap.Component
19624 * Bootstrap Menu class - container for Menu
19625 * @cfg {String} html Text of the menu
19626 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19627 * @cfg {String} icon Font awesome icon
19628 * @cfg {String} pos Menu align to (top | bottom) default bottom
19632 * Create a new Menu
19633 * @param {Object} config The config object
19637 Roo.bootstrap.menu.Menu = function(config){
19638 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19642 * @event beforeshow
19643 * Fires before this menu is displayed
19644 * @param {Roo.bootstrap.menu.Menu} this
19648 * @event beforehide
19649 * Fires before this menu is hidden
19650 * @param {Roo.bootstrap.menu.Menu} this
19655 * Fires after this menu is displayed
19656 * @param {Roo.bootstrap.menu.Menu} this
19661 * Fires after this menu is hidden
19662 * @param {Roo.bootstrap.menu.Menu} this
19667 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19668 * @param {Roo.bootstrap.menu.Menu} this
19669 * @param {Roo.EventObject} e
19676 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19680 weight : 'default',
19685 getChildContainer : function() {
19686 if(this.isSubMenu){
19690 return this.el.select('ul.dropdown-menu', true).first();
19693 getAutoCreate : function()
19698 cls : 'roo-menu-text',
19706 cls : 'fa ' + this.icon
19717 cls : 'dropdown-button btn btn-' + this.weight,
19722 cls : 'dropdown-toggle btn btn-' + this.weight,
19732 cls : 'dropdown-menu'
19738 if(this.pos == 'top'){
19739 cfg.cls += ' dropup';
19742 if(this.isSubMenu){
19745 cls : 'dropdown-menu'
19752 onRender : function(ct, position)
19754 this.isSubMenu = ct.hasClass('dropdown-submenu');
19756 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19759 initEvents : function()
19761 if(this.isSubMenu){
19765 this.hidden = true;
19767 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19768 this.triggerEl.on('click', this.onTriggerPress, this);
19770 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19771 this.buttonEl.on('click', this.onClick, this);
19777 if(this.isSubMenu){
19781 return this.el.select('ul.dropdown-menu', true).first();
19784 onClick : function(e)
19786 this.fireEvent("click", this, e);
19789 onTriggerPress : function(e)
19791 if (this.isVisible()) {
19798 isVisible : function(){
19799 return !this.hidden;
19804 this.fireEvent("beforeshow", this);
19806 this.hidden = false;
19807 this.el.addClass('open');
19809 Roo.get(document).on("mouseup", this.onMouseUp, this);
19811 this.fireEvent("show", this);
19818 this.fireEvent("beforehide", this);
19820 this.hidden = true;
19821 this.el.removeClass('open');
19823 Roo.get(document).un("mouseup", this.onMouseUp);
19825 this.fireEvent("hide", this);
19828 onMouseUp : function()
19842 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19845 * @class Roo.bootstrap.menu.Item
19846 * @extends Roo.bootstrap.Component
19847 * Bootstrap MenuItem class
19848 * @cfg {Boolean} submenu (true | false) default false
19849 * @cfg {String} html text of the item
19850 * @cfg {String} href the link
19851 * @cfg {Boolean} disable (true | false) default false
19852 * @cfg {Boolean} preventDefault (true | false) default true
19853 * @cfg {String} icon Font awesome icon
19854 * @cfg {String} pos Submenu align to (left | right) default right
19858 * Create a new Item
19859 * @param {Object} config The config object
19863 Roo.bootstrap.menu.Item = function(config){
19864 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19868 * Fires when the mouse is hovering over this menu
19869 * @param {Roo.bootstrap.menu.Item} this
19870 * @param {Roo.EventObject} e
19875 * Fires when the mouse exits this menu
19876 * @param {Roo.bootstrap.menu.Item} this
19877 * @param {Roo.EventObject} e
19883 * The raw click event for the entire grid.
19884 * @param {Roo.EventObject} e
19890 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19895 preventDefault: true,
19900 getAutoCreate : function()
19905 cls : 'roo-menu-item-text',
19913 cls : 'fa ' + this.icon
19922 href : this.href || '#',
19929 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19933 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19935 if(this.pos == 'left'){
19936 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19943 initEvents : function()
19945 this.el.on('mouseover', this.onMouseOver, this);
19946 this.el.on('mouseout', this.onMouseOut, this);
19948 this.el.select('a', true).first().on('click', this.onClick, this);
19952 onClick : function(e)
19954 if(this.preventDefault){
19955 e.preventDefault();
19958 this.fireEvent("click", this, e);
19961 onMouseOver : function(e)
19963 if(this.submenu && this.pos == 'left'){
19964 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19967 this.fireEvent("mouseover", this, e);
19970 onMouseOut : function(e)
19972 this.fireEvent("mouseout", this, e);
19984 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19987 * @class Roo.bootstrap.menu.Separator
19988 * @extends Roo.bootstrap.Component
19989 * Bootstrap Separator class
19992 * Create a new Separator
19993 * @param {Object} config The config object
19997 Roo.bootstrap.menu.Separator = function(config){
19998 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20001 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20003 getAutoCreate : function(){