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 indexOfNav : function()
3305 Roo.each(this.navItems, function(v,i){
3316 * adds a Navigation item
3317 * @param {Roo.bootstrap.NavItem} the navitem to add
3319 addItem : function(cfg)
3321 var cn = new Roo.bootstrap.NavItem(cfg);
3323 cn.parentId = this.id;
3324 cn.onRender(this.el, null);
3328 * register a Navigation item
3329 * @param {Roo.bootstrap.NavItem} the navitem to add
3331 register : function(item)
3333 this.navItems.push( item);
3334 item.navId = this.navId;
3339 getNavItem: function(tabId)
3342 Roo.each(this.navItems, function(e) {
3343 if (e.tabId == tabId) {
3353 setActiveNext : function()
3355 var i = this.indexOfNav(this.getActive());
3356 if (i > this.navItems.length) {
3359 this.setActiveItem(this.navItems[i+1]);
3361 setActivePrev : function()
3363 var i = this.indexOfNav(this.getActive());
3367 this.setActiveItem(this.navItems[i-1]);
3369 clearWasActive : function(except) {
3370 Roo.each(this.navItems, function(e) {
3371 if (e.tabId != except.tabId && e.was_active) {
3372 e.was_active = false;
3379 getWasActive : function ()
3382 Roo.each(this.navItems, function(e) {
3397 Roo.apply(Roo.bootstrap.NavGroup, {
3401 * register a Navigation Group
3402 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3404 register : function(navgrp)
3406 this.groups[navgrp.navId] = navgrp;
3410 * fetch a Navigation Group based on the navigation ID
3411 * @param {string} the navgroup to add
3412 * @returns {Roo.bootstrap.NavGroup} the navgroup
3414 get: function(navId) {
3415 if (typeof(this.groups[navId]) == 'undefined') {
3417 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3419 return this.groups[navId] ;
3434 * @class Roo.bootstrap.NavItem
3435 * @extends Roo.bootstrap.Component
3436 * Bootstrap Navbar.NavItem class
3437 * @cfg {String} href link to
3438 * @cfg {String} html content of button
3439 * @cfg {String} badge text inside badge
3440 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3441 * @cfg {String} glyphicon name of glyphicon
3442 * @cfg {String} icon name of font awesome icon
3443 * @cfg {Boolean} active Is item active
3444 * @cfg {Boolean} disabled Is item disabled
3446 * @cfg {Boolean} preventDefault (true | false) default false
3447 * @cfg {String} tabId the tab that this item activates.
3448 * @cfg {String} tagtype (a|span) render as a href or span?
3451 * Create a new Navbar Item
3452 * @param {Object} config The config object
3454 Roo.bootstrap.NavItem = function(config){
3455 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3460 * The raw click event for the entire grid.
3461 * @param {Roo.EventObject} e
3466 * Fires when the active item active state changes
3467 * @param {Roo.bootstrap.NavItem} this
3468 * @param {boolean} state the new state
3476 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3484 preventDefault : false,
3491 getAutoCreate : function(){
3499 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3501 if (this.disabled) {
3502 cfg.cls += ' disabled';
3505 if (this.href || this.html || this.glyphicon || this.icon) {
3509 href : this.href || "#",
3510 html: this.html || ''
3515 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3518 if(this.glyphicon) {
3519 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3524 cfg.cn[0].html += " <span class='caret'></span>";
3528 if (this.badge !== '') {
3530 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3538 initEvents: function() {
3539 // Roo.log('init events?');
3540 // Roo.log(this.el.dom);
3541 if (typeof (this.menu) != 'undefined') {
3542 this.menu.parentType = this.xtype;
3543 this.menu.triggerEl = this.el;
3544 this.addxtype(Roo.apply({}, this.menu));
3548 this.el.select('a',true).on('click', this.onClick, this);
3549 // at this point parent should be available..
3550 this.parent().register(this);
3553 onClick : function(e)
3556 if(this.preventDefault){
3559 if (this.disabled) {
3562 Roo.log("fire event clicked");
3563 if(this.fireEvent('click', this, e) === false){
3567 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3568 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3569 this.parent().setActiveItem(this);
3574 isActive: function () {
3577 setActive : function(state, fire, is_was_active)
3579 if (this.active && !state & this.navId) {
3580 this.was_active = true;
3581 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3583 nv.clearWasActive(this);
3587 this.active = state;
3590 this.el.removeClass('active');
3591 } else if (!this.el.hasClass('active')) {
3592 this.el.addClass('active');
3595 this.fireEvent('changed', this, state);
3598 // show a panel if it's registered and related..
3600 if (!this.navId || !this.tabId || !state || is_was_active) {
3604 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3608 var pan = tg.getPanelByName(this.tabId);
3612 // if we can not flip to new panel - go back to old nav highlight..
3613 if (false == tg.showPanel(pan)) {
3614 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3616 var onav = nv.getWasActive();
3618 onav.setActive(true, false, true);
3627 // this should not be here...
3628 setDisabled : function(state)
3630 this.disabled = state;
3632 this.el.removeClass('disabled');
3633 } else if (!this.el.hasClass('disabled')) {
3634 this.el.addClass('disabled');
3647 * <span> icon </span>
3648 * <span> text </span>
3649 * <span>badge </span>
3653 * @class Roo.bootstrap.NavSidebarItem
3654 * @extends Roo.bootstrap.NavItem
3655 * Bootstrap Navbar.NavSidebarItem class
3657 * Create a new Navbar Button
3658 * @param {Object} config The config object
3660 Roo.bootstrap.NavSidebarItem = function(config){
3661 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3666 * The raw click event for the entire grid.
3667 * @param {Roo.EventObject} e
3672 * Fires when the active item active state changes
3673 * @param {Roo.bootstrap.NavSidebarItem} this
3674 * @param {boolean} state the new state
3682 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3685 getAutoCreate : function(){
3690 href : this.href || '#',
3702 html : this.html || ''
3707 cfg.cls += ' active';
3711 if (this.glyphicon || this.icon) {
3712 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3713 a.cn.push({ tag : 'i', cls : c }) ;
3718 if (this.badge !== '') {
3719 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3723 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3724 a.cls += 'dropdown-toggle treeview' ;
3748 * @class Roo.bootstrap.Row
3749 * @extends Roo.bootstrap.Component
3750 * Bootstrap Row class (contains columns...)
3754 * @param {Object} config The config object
3757 Roo.bootstrap.Row = function(config){
3758 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3761 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3763 getAutoCreate : function(){
3782 * @class Roo.bootstrap.Element
3783 * @extends Roo.bootstrap.Component
3784 * Bootstrap Element class
3785 * @cfg {String} html contents of the element
3786 * @cfg {String} tag tag of the element
3787 * @cfg {String} cls class of the element
3790 * Create a new Element
3791 * @param {Object} config The config object
3794 Roo.bootstrap.Element = function(config){
3795 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3798 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3805 getAutoCreate : function(){
3830 * @class Roo.bootstrap.Pagination
3831 * @extends Roo.bootstrap.Component
3832 * Bootstrap Pagination class
3833 * @cfg {String} size xs | sm | md | lg
3834 * @cfg {Boolean} inverse false | true
3837 * Create a new Pagination
3838 * @param {Object} config The config object
3841 Roo.bootstrap.Pagination = function(config){
3842 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3845 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3851 getAutoCreate : function(){
3857 cfg.cls += ' inverse';
3863 cfg.cls += " " + this.cls;
3881 * @class Roo.bootstrap.PaginationItem
3882 * @extends Roo.bootstrap.Component
3883 * Bootstrap PaginationItem class
3884 * @cfg {String} html text
3885 * @cfg {String} href the link
3886 * @cfg {Boolean} preventDefault (true | false) default true
3887 * @cfg {Boolean} active (true | false) default false
3891 * Create a new PaginationItem
3892 * @param {Object} config The config object
3896 Roo.bootstrap.PaginationItem = function(config){
3897 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3902 * The raw click event for the entire grid.
3903 * @param {Roo.EventObject} e
3909 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3913 preventDefault: true,
3917 getAutoCreate : function(){
3923 href : this.href ? this.href : '#',
3924 html : this.html ? this.html : ''
3934 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3940 initEvents: function() {
3942 this.el.on('click', this.onClick, this);
3945 onClick : function(e)
3947 Roo.log('PaginationItem on click ');
3948 if(this.preventDefault){
3952 this.fireEvent('click', this, e);
3968 * @class Roo.bootstrap.Slider
3969 * @extends Roo.bootstrap.Component
3970 * Bootstrap Slider class
3973 * Create a new Slider
3974 * @param {Object} config The config object
3977 Roo.bootstrap.Slider = function(config){
3978 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3981 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3983 getAutoCreate : function(){
3987 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3991 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4003 * Ext JS Library 1.1.1
4004 * Copyright(c) 2006-2007, Ext JS, LLC.
4006 * Originally Released Under LGPL - original licence link has changed is not relivant.
4009 * <script type="text/javascript">
4014 * @class Roo.grid.ColumnModel
4015 * @extends Roo.util.Observable
4016 * This is the default implementation of a ColumnModel used by the Grid. It defines
4017 * the columns in the grid.
4020 var colModel = new Roo.grid.ColumnModel([
4021 {header: "Ticker", width: 60, sortable: true, locked: true},
4022 {header: "Company Name", width: 150, sortable: true},
4023 {header: "Market Cap.", width: 100, sortable: true},
4024 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4025 {header: "Employees", width: 100, sortable: true, resizable: false}
4030 * The config options listed for this class are options which may appear in each
4031 * individual column definition.
4032 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4034 * @param {Object} config An Array of column config objects. See this class's
4035 * config objects for details.
4037 Roo.grid.ColumnModel = function(config){
4039 * The config passed into the constructor
4041 this.config = config;
4044 // if no id, create one
4045 // if the column does not have a dataIndex mapping,
4046 // map it to the order it is in the config
4047 for(var i = 0, len = config.length; i < len; i++){
4049 if(typeof c.dataIndex == "undefined"){
4052 if(typeof c.renderer == "string"){
4053 c.renderer = Roo.util.Format[c.renderer];
4055 if(typeof c.id == "undefined"){
4058 if(c.editor && c.editor.xtype){
4059 c.editor = Roo.factory(c.editor, Roo.grid);
4061 if(c.editor && c.editor.isFormField){
4062 c.editor = new Roo.grid.GridEditor(c.editor);
4064 this.lookup[c.id] = c;
4068 * The width of columns which have no width specified (defaults to 100)
4071 this.defaultWidth = 100;
4074 * Default sortable of columns which have no sortable specified (defaults to false)
4077 this.defaultSortable = false;
4081 * @event widthchange
4082 * Fires when the width of a column changes.
4083 * @param {ColumnModel} this
4084 * @param {Number} columnIndex The column index
4085 * @param {Number} newWidth The new width
4087 "widthchange": true,
4089 * @event headerchange
4090 * Fires when the text of a header changes.
4091 * @param {ColumnModel} this
4092 * @param {Number} columnIndex The column index
4093 * @param {Number} newText The new header text
4095 "headerchange": true,
4097 * @event hiddenchange
4098 * Fires when a column is hidden or "unhidden".
4099 * @param {ColumnModel} this
4100 * @param {Number} columnIndex The column index
4101 * @param {Boolean} hidden true if hidden, false otherwise
4103 "hiddenchange": true,
4105 * @event columnmoved
4106 * Fires when a column is moved.
4107 * @param {ColumnModel} this
4108 * @param {Number} oldIndex
4109 * @param {Number} newIndex
4111 "columnmoved" : true,
4113 * @event columlockchange
4114 * Fires when a column's locked state is changed
4115 * @param {ColumnModel} this
4116 * @param {Number} colIndex
4117 * @param {Boolean} locked true if locked
4119 "columnlockchange" : true
4121 Roo.grid.ColumnModel.superclass.constructor.call(this);
4123 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4125 * @cfg {String} header The header text to display in the Grid view.
4128 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4129 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4130 * specified, the column's index is used as an index into the Record's data Array.
4133 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4134 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4137 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4138 * Defaults to the value of the {@link #defaultSortable} property.
4139 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4142 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4145 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4148 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4151 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4154 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4155 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4156 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4157 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4160 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4163 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4167 * Returns the id of the column at the specified index.
4168 * @param {Number} index The column index
4169 * @return {String} the id
4171 getColumnId : function(index){
4172 return this.config[index].id;
4176 * Returns the column for a specified id.
4177 * @param {String} id The column id
4178 * @return {Object} the column
4180 getColumnById : function(id){
4181 return this.lookup[id];
4186 * Returns the column for a specified dataIndex.
4187 * @param {String} dataIndex The column dataIndex
4188 * @return {Object|Boolean} the column or false if not found
4190 getColumnByDataIndex: function(dataIndex){
4191 var index = this.findColumnIndex(dataIndex);
4192 return index > -1 ? this.config[index] : false;
4196 * Returns the index for a specified column id.
4197 * @param {String} id The column id
4198 * @return {Number} the index, or -1 if not found
4200 getIndexById : function(id){
4201 for(var i = 0, len = this.config.length; i < len; i++){
4202 if(this.config[i].id == id){
4210 * Returns the index for a specified column dataIndex.
4211 * @param {String} dataIndex The column dataIndex
4212 * @return {Number} the index, or -1 if not found
4215 findColumnIndex : function(dataIndex){
4216 for(var i = 0, len = this.config.length; i < len; i++){
4217 if(this.config[i].dataIndex == dataIndex){
4225 moveColumn : function(oldIndex, newIndex){
4226 var c = this.config[oldIndex];
4227 this.config.splice(oldIndex, 1);
4228 this.config.splice(newIndex, 0, c);
4229 this.dataMap = null;
4230 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4233 isLocked : function(colIndex){
4234 return this.config[colIndex].locked === true;
4237 setLocked : function(colIndex, value, suppressEvent){
4238 if(this.isLocked(colIndex) == value){
4241 this.config[colIndex].locked = value;
4243 this.fireEvent("columnlockchange", this, colIndex, value);
4247 getTotalLockedWidth : function(){
4249 for(var i = 0; i < this.config.length; i++){
4250 if(this.isLocked(i) && !this.isHidden(i)){
4251 this.totalWidth += this.getColumnWidth(i);
4257 getLockedCount : function(){
4258 for(var i = 0, len = this.config.length; i < len; i++){
4259 if(!this.isLocked(i)){
4266 * Returns the number of columns.
4269 getColumnCount : function(visibleOnly){
4270 if(visibleOnly === true){
4272 for(var i = 0, len = this.config.length; i < len; i++){
4273 if(!this.isHidden(i)){
4279 return this.config.length;
4283 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4284 * @param {Function} fn
4285 * @param {Object} scope (optional)
4286 * @return {Array} result
4288 getColumnsBy : function(fn, scope){
4290 for(var i = 0, len = this.config.length; i < len; i++){
4291 var c = this.config[i];
4292 if(fn.call(scope||this, c, i) === true){
4300 * Returns true if the specified column is sortable.
4301 * @param {Number} col The column index
4304 isSortable : function(col){
4305 if(typeof this.config[col].sortable == "undefined"){
4306 return this.defaultSortable;
4308 return this.config[col].sortable;
4312 * Returns the rendering (formatting) function defined for the column.
4313 * @param {Number} col The column index.
4314 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4316 getRenderer : function(col){
4317 if(!this.config[col].renderer){
4318 return Roo.grid.ColumnModel.defaultRenderer;
4320 return this.config[col].renderer;
4324 * Sets the rendering (formatting) function for a column.
4325 * @param {Number} col The column index
4326 * @param {Function} fn The function to use to process the cell's raw data
4327 * to return HTML markup for the grid view. The render function is called with
4328 * the following parameters:<ul>
4329 * <li>Data value.</li>
4330 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4331 * <li>css A CSS style string to apply to the table cell.</li>
4332 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4333 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4334 * <li>Row index</li>
4335 * <li>Column index</li>
4336 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4338 setRenderer : function(col, fn){
4339 this.config[col].renderer = fn;
4343 * Returns the width for the specified column.
4344 * @param {Number} col The column index
4347 getColumnWidth : function(col){
4348 return this.config[col].width * 1 || this.defaultWidth;
4352 * Sets the width for a column.
4353 * @param {Number} col The column index
4354 * @param {Number} width The new width
4356 setColumnWidth : function(col, width, suppressEvent){
4357 this.config[col].width = width;
4358 this.totalWidth = null;
4360 this.fireEvent("widthchange", this, col, width);
4365 * Returns the total width of all columns.
4366 * @param {Boolean} includeHidden True to include hidden column widths
4369 getTotalWidth : function(includeHidden){
4370 if(!this.totalWidth){
4371 this.totalWidth = 0;
4372 for(var i = 0, len = this.config.length; i < len; i++){
4373 if(includeHidden || !this.isHidden(i)){
4374 this.totalWidth += this.getColumnWidth(i);
4378 return this.totalWidth;
4382 * Returns the header for the specified column.
4383 * @param {Number} col The column index
4386 getColumnHeader : function(col){
4387 return this.config[col].header;
4391 * Sets the header for a column.
4392 * @param {Number} col The column index
4393 * @param {String} header The new header
4395 setColumnHeader : function(col, header){
4396 this.config[col].header = header;
4397 this.fireEvent("headerchange", this, col, header);
4401 * Returns the tooltip for the specified column.
4402 * @param {Number} col The column index
4405 getColumnTooltip : function(col){
4406 return this.config[col].tooltip;
4409 * Sets the tooltip for a column.
4410 * @param {Number} col The column index
4411 * @param {String} tooltip The new tooltip
4413 setColumnTooltip : function(col, tooltip){
4414 this.config[col].tooltip = tooltip;
4418 * Returns the dataIndex for the specified column.
4419 * @param {Number} col The column index
4422 getDataIndex : function(col){
4423 return this.config[col].dataIndex;
4427 * Sets the dataIndex for a column.
4428 * @param {Number} col The column index
4429 * @param {Number} dataIndex The new dataIndex
4431 setDataIndex : function(col, dataIndex){
4432 this.config[col].dataIndex = dataIndex;
4438 * Returns true if the cell is editable.
4439 * @param {Number} colIndex The column index
4440 * @param {Number} rowIndex The row index
4443 isCellEditable : function(colIndex, rowIndex){
4444 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4448 * Returns the editor defined for the cell/column.
4449 * return false or null to disable editing.
4450 * @param {Number} colIndex The column index
4451 * @param {Number} rowIndex The row index
4454 getCellEditor : function(colIndex, rowIndex){
4455 return this.config[colIndex].editor;
4459 * Sets if a column is editable.
4460 * @param {Number} col The column index
4461 * @param {Boolean} editable True if the column is editable
4463 setEditable : function(col, editable){
4464 this.config[col].editable = editable;
4469 * Returns true if the column is hidden.
4470 * @param {Number} colIndex The column index
4473 isHidden : function(colIndex){
4474 return this.config[colIndex].hidden;
4479 * Returns true if the column width cannot be changed
4481 isFixed : function(colIndex){
4482 return this.config[colIndex].fixed;
4486 * Returns true if the column can be resized
4489 isResizable : function(colIndex){
4490 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4493 * Sets if a column is hidden.
4494 * @param {Number} colIndex The column index
4495 * @param {Boolean} hidden True if the column is hidden
4497 setHidden : function(colIndex, hidden){
4498 this.config[colIndex].hidden = hidden;
4499 this.totalWidth = null;
4500 this.fireEvent("hiddenchange", this, colIndex, hidden);
4504 * Sets the editor for a column.
4505 * @param {Number} col The column index
4506 * @param {Object} editor The editor object
4508 setEditor : function(col, editor){
4509 this.config[col].editor = editor;
4513 Roo.grid.ColumnModel.defaultRenderer = function(value){
4514 if(typeof value == "string" && value.length < 1){
4520 // Alias for backwards compatibility
4521 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4524 * Ext JS Library 1.1.1
4525 * Copyright(c) 2006-2007, Ext JS, LLC.
4527 * Originally Released Under LGPL - original licence link has changed is not relivant.
4530 * <script type="text/javascript">
4534 * @class Roo.LoadMask
4535 * A simple utility class for generically masking elements while loading data. If the element being masked has
4536 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4537 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4538 * element's UpdateManager load indicator and will be destroyed after the initial load.
4540 * Create a new LoadMask
4541 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4542 * @param {Object} config The config object
4544 Roo.LoadMask = function(el, config){
4545 this.el = Roo.get(el);
4546 Roo.apply(this, config);
4548 this.store.on('beforeload', this.onBeforeLoad, this);
4549 this.store.on('load', this.onLoad, this);
4550 this.store.on('loadexception', this.onLoadException, this);
4551 this.removeMask = false;
4553 var um = this.el.getUpdateManager();
4554 um.showLoadIndicator = false; // disable the default indicator
4555 um.on('beforeupdate', this.onBeforeLoad, this);
4556 um.on('update', this.onLoad, this);
4557 um.on('failure', this.onLoad, this);
4558 this.removeMask = true;
4562 Roo.LoadMask.prototype = {
4564 * @cfg {Boolean} removeMask
4565 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4566 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4570 * The text to display in a centered loading message box (defaults to 'Loading...')
4574 * @cfg {String} msgCls
4575 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4577 msgCls : 'x-mask-loading',
4580 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4586 * Disables the mask to prevent it from being displayed
4588 disable : function(){
4589 this.disabled = true;
4593 * Enables the mask so that it can be displayed
4595 enable : function(){
4596 this.disabled = false;
4599 onLoadException : function()
4603 if (typeof(arguments[3]) != 'undefined') {
4604 Roo.MessageBox.alert("Error loading",arguments[3]);
4608 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4609 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4618 this.el.unmask(this.removeMask);
4623 this.el.unmask(this.removeMask);
4627 onBeforeLoad : function(){
4629 this.el.mask(this.msg, this.msgCls);
4634 destroy : function(){
4636 this.store.un('beforeload', this.onBeforeLoad, this);
4637 this.store.un('load', this.onLoad, this);
4638 this.store.un('loadexception', this.onLoadException, this);
4640 var um = this.el.getUpdateManager();
4641 um.un('beforeupdate', this.onBeforeLoad, this);
4642 um.un('update', this.onLoad, this);
4643 um.un('failure', this.onLoad, this);
4654 * @class Roo.bootstrap.Table
4655 * @extends Roo.bootstrap.Component
4656 * Bootstrap Table class
4657 * @cfg {String} cls table class
4658 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4659 * @cfg {String} bgcolor Specifies the background color for a table
4660 * @cfg {Number} border Specifies whether the table cells should have borders or not
4661 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4662 * @cfg {Number} cellspacing Specifies the space between cells
4663 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4664 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4665 * @cfg {String} sortable Specifies that the table should be sortable
4666 * @cfg {String} summary Specifies a summary of the content of a table
4667 * @cfg {Number} width Specifies the width of a table
4668 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4670 * @cfg {boolean} striped Should the rows be alternative striped
4671 * @cfg {boolean} bordered Add borders to the table
4672 * @cfg {boolean} hover Add hover highlighting
4673 * @cfg {boolean} condensed Format condensed
4674 * @cfg {boolean} responsive Format condensed
4675 * @cfg {Boolean} loadMask (true|false) default false
4676 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4677 * @cfg {Boolean} thead (true|false) generate thead, default true
4678 * @cfg {Boolean} RowSelection (true|false) default false
4679 * @cfg {Boolean} CellSelection (true|false) default false
4681 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4685 * Create a new Table
4686 * @param {Object} config The config object
4689 Roo.bootstrap.Table = function(config){
4690 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4693 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4694 this.sm = this.selModel;
4695 this.sm.xmodule = this.xmodule || false;
4697 if (this.cm && typeof(this.cm.config) == 'undefined') {
4698 this.colModel = new Roo.grid.ColumnModel(this.cm);
4699 this.cm = this.colModel;
4700 this.cm.xmodule = this.xmodule || false;
4703 this.store= Roo.factory(this.store, Roo.data);
4704 this.ds = this.store;
4705 this.ds.xmodule = this.xmodule || false;
4708 if (this.footer && this.store) {
4709 this.footer.dataSource = this.ds;
4710 this.footer = Roo.factory(this.footer);
4717 * Fires when a cell is clicked
4718 * @param {Roo.bootstrap.Table} this
4719 * @param {Roo.Element} el
4720 * @param {Number} rowIndex
4721 * @param {Number} columnIndex
4722 * @param {Roo.EventObject} e
4726 * @event celldblclick
4727 * Fires when a cell is double clicked
4728 * @param {Roo.bootstrap.Table} this
4729 * @param {Roo.Element} el
4730 * @param {Number} rowIndex
4731 * @param {Number} columnIndex
4732 * @param {Roo.EventObject} e
4734 "celldblclick" : true,
4737 * Fires when a row is clicked
4738 * @param {Roo.bootstrap.Table} this
4739 * @param {Roo.Element} el
4740 * @param {Number} rowIndex
4741 * @param {Roo.EventObject} e
4745 * @event rowdblclick
4746 * Fires when a row is double clicked
4747 * @param {Roo.bootstrap.Table} this
4748 * @param {Roo.Element} el
4749 * @param {Number} rowIndex
4750 * @param {Roo.EventObject} e
4752 "rowdblclick" : true,
4755 * Fires when a mouseover occur
4756 * @param {Roo.bootstrap.Table} this
4757 * @param {Roo.Element} el
4758 * @param {Number} rowIndex
4759 * @param {Number} columnIndex
4760 * @param {Roo.EventObject} e
4765 * Fires when a mouseout occur
4766 * @param {Roo.bootstrap.Table} this
4767 * @param {Roo.Element} el
4768 * @param {Number} rowIndex
4769 * @param {Number} columnIndex
4770 * @param {Roo.EventObject} e
4775 * Fires when a row is rendered, so you can change add a style to it.
4776 * @param {Roo.bootstrap.Table} this
4777 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4784 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4808 RowSelection : false,
4809 CellSelection : false,
4812 // Roo.Element - the tbody
4815 getAutoCreate : function(){
4816 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4825 cfg.cls += ' table-striped';
4829 cfg.cls += ' table-hover';
4831 if (this.bordered) {
4832 cfg.cls += ' table-bordered';
4834 if (this.condensed) {
4835 cfg.cls += ' table-condensed';
4837 if (this.responsive) {
4838 cfg.cls += ' table-responsive';
4842 cfg.cls+= ' ' +this.cls;
4845 // this lot should be simplifed...
4848 cfg.align=this.align;
4851 cfg.bgcolor=this.bgcolor;
4854 cfg.border=this.border;
4856 if (this.cellpadding) {
4857 cfg.cellpadding=this.cellpadding;
4859 if (this.cellspacing) {
4860 cfg.cellspacing=this.cellspacing;
4863 cfg.frame=this.frame;
4866 cfg.rules=this.rules;
4868 if (this.sortable) {
4869 cfg.sortable=this.sortable;
4872 cfg.summary=this.summary;
4875 cfg.width=this.width;
4878 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4881 if(this.store || this.cm){
4883 cfg.cn.push(this.renderHeader());
4886 cfg.cn.push(this.renderBody());
4889 cfg.cn.push(this.renderFooter());
4892 cfg.cls+= ' TableGrid';
4895 return { cn : [ cfg ] };
4898 initEvents : function()
4900 if(!this.store || !this.cm){
4904 //Roo.log('initEvents with ds!!!!');
4906 this.mainBody = this.el.select('tbody', true).first();
4911 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4912 e.on('click', _this.sort, _this);
4915 this.el.on("click", this.onClick, this);
4916 this.el.on("dblclick", this.onDblClick, this);
4918 this.parent().el.setStyle('position', 'relative');
4920 this.footer.parentId = this.id;
4921 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4924 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4926 this.store.on('load', this.onLoad, this);
4927 this.store.on('beforeload', this.onBeforeLoad, this);
4928 this.store.on('update', this.onUpdate, this);
4932 onMouseover : function(e, el)
4934 var cell = Roo.get(el);
4940 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4941 cell = cell.findParent('td', false, true);
4944 var row = cell.findParent('tr', false, true);
4945 var cellIndex = cell.dom.cellIndex;
4946 var rowIndex = row.dom.rowIndex - 1; // start from 0
4948 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4952 onMouseout : function(e, el)
4954 var cell = Roo.get(el);
4960 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4961 cell = cell.findParent('td', false, true);
4964 var row = cell.findParent('tr', false, true);
4965 var cellIndex = cell.dom.cellIndex;
4966 var rowIndex = row.dom.rowIndex - 1; // start from 0
4968 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4972 onClick : function(e, el)
4974 var cell = Roo.get(el);
4976 if(!cell || (!this.CellSelection && !this.RowSelection)){
4981 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4982 cell = cell.findParent('td', false, true);
4985 var row = cell.findParent('tr', false, true);
4986 var cellIndex = cell.dom.cellIndex;
4987 var rowIndex = row.dom.rowIndex - 1;
4989 if(this.CellSelection){
4990 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4993 if(this.RowSelection){
4994 this.fireEvent('rowclick', this, row, rowIndex, e);
5000 onDblClick : function(e,el)
5002 var cell = Roo.get(el);
5004 if(!cell || (!this.CellSelection && !this.RowSelection)){
5008 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5009 cell = cell.findParent('td', false, true);
5012 var row = cell.findParent('tr', false, true);
5013 var cellIndex = cell.dom.cellIndex;
5014 var rowIndex = row.dom.rowIndex - 1;
5016 if(this.CellSelection){
5017 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5020 if(this.RowSelection){
5021 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5025 sort : function(e,el)
5027 var col = Roo.get(el)
5029 if(!col.hasClass('sortable')){
5033 var sort = col.attr('sort');
5036 if(col.hasClass('glyphicon-arrow-up')){
5040 this.store.sortInfo = {field : sort, direction : dir};
5043 Roo.log("calling footer first");
5044 this.footer.onClick('first');
5047 this.store.load({ params : { start : 0 } });
5051 renderHeader : function()
5060 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5062 var config = cm.config[i];
5067 html: cm.getColumnHeader(i)
5070 if(typeof(config.hidden) != 'undefined' && config.hidden){
5071 c.style += ' display:none;';
5074 if(typeof(config.dataIndex) != 'undefined'){
5075 c.sort = config.dataIndex;
5078 if(typeof(config.sortable) != 'undefined' && config.sortable){
5082 if(typeof(config.align) != 'undefined' && config.align.length){
5083 c.style += ' text-align:' + config.align + ';';
5086 if(typeof(config.width) != 'undefined'){
5087 c.style += ' width:' + config.width + 'px;';
5096 renderBody : function()
5106 colspan : this.cm.getColumnCount()
5116 renderFooter : function()
5126 colspan : this.cm.getColumnCount()
5140 Roo.log('ds onload');
5145 var ds = this.store;
5147 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5148 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5150 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5151 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5154 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5155 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5159 var tbody = this.mainBody;
5163 if(ds.getCount() > 0){
5164 ds.data.each(function(d,rowIndex){
5165 var row = this.renderRow(cm, ds, rowIndex);
5167 tbody.createChild(row);
5171 if(row.cellObjects.length){
5172 Roo.each(row.cellObjects, function(r){
5173 _this.renderCellObject(r);
5180 Roo.each(this.el.select('tbody td', true).elements, function(e){
5181 e.on('mouseover', _this.onMouseover, _this);
5184 Roo.each(this.el.select('tbody td', true).elements, function(e){
5185 e.on('mouseout', _this.onMouseout, _this);
5188 //if(this.loadMask){
5189 // this.maskEl.hide();
5194 onUpdate : function(ds,record)
5196 this.refreshRow(record);
5198 onRemove : function(ds, record, index, isUpdate){
5199 if(isUpdate !== true){
5200 this.fireEvent("beforerowremoved", this, index, record);
5202 var bt = this.mainBody.dom;
5204 bt.removeChild(bt.rows[index]);
5207 if(isUpdate !== true){
5208 //this.stripeRows(index);
5209 //this.syncRowHeights(index, index);
5211 this.fireEvent("rowremoved", this, index, record);
5216 refreshRow : function(record){
5217 var ds = this.store, index;
5218 if(typeof record == 'number'){
5220 record = ds.getAt(index);
5222 index = ds.indexOf(record);
5224 this.insertRow(ds, index, true);
5225 this.onRemove(ds, record, index+1, true);
5226 //this.syncRowHeights(index, index);
5228 this.fireEvent("rowupdated", this, index, record);
5231 insertRow : function(dm, rowIndex, isUpdate){
5234 this.fireEvent("beforerowsinserted", this, rowIndex);
5236 //var s = this.getScrollState();
5237 var row = this.renderRow(this.cm, this.store, rowIndex);
5238 // insert before rowIndex..
5239 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5244 if(row.cellObjects.length){
5245 Roo.each(row.cellObjects, function(r){
5246 _this.renderCellObject(r);
5251 this.fireEvent("rowsinserted", this, rowIndex);
5252 //this.syncRowHeights(firstRow, lastRow);
5253 //this.stripeRows(firstRow);
5260 getRowDom : function(rowIndex)
5262 // not sure if I need to check this.. but let's do it anyway..
5263 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5264 this.mainBody.dom.rows[rowIndex] : false
5266 // returns the object tree for a tr..
5269 renderRow : function(cm, ds, rowIndex) {
5271 var d = ds.getAt(rowIndex);
5278 var cellObjects = [];
5280 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5281 var config = cm.config[i];
5283 var renderer = cm.getRenderer(i);
5287 if(typeof(renderer) !== 'undefined'){
5288 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5290 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5291 // and are rendered into the cells after the row is rendered - using the id for the element.
5293 if(typeof(value) === 'object'){
5303 rowIndex : rowIndex,
5308 this.fireEvent('rowclass', this, rowcfg);
5312 cls : rowcfg.rowClass,
5314 html: (typeof(value) === 'object') ? '' : value
5321 if(typeof(config.hidden) != 'undefined' && config.hidden){
5322 td.style += ' display:none;';
5325 if(typeof(config.align) != 'undefined' && config.align.length){
5326 td.style += ' text-align:' + config.align + ';';
5329 if(typeof(config.width) != 'undefined'){
5330 td.style += ' width:' + config.width + 'px;';
5337 row.cellObjects = cellObjects;
5345 onBeforeLoad : function()
5347 //Roo.log('ds onBeforeLoad');
5351 //if(this.loadMask){
5352 // this.maskEl.show();
5358 this.el.select('tbody', true).first().dom.innerHTML = '';
5361 getSelectionModel : function(){
5363 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5365 return this.selModel;
5368 * Render the Roo.bootstrap object from renderder
5370 renderCellObject : function(r)
5374 var t = r.cfg.render(r.container);
5377 Roo.each(r.cfg.cn, function(c){
5379 container: t.getChildContainer(),
5382 _this.renderCellObject(child);
5399 * @class Roo.bootstrap.TableCell
5400 * @extends Roo.bootstrap.Component
5401 * Bootstrap TableCell class
5402 * @cfg {String} html cell contain text
5403 * @cfg {String} cls cell class
5404 * @cfg {String} tag cell tag (td|th) default td
5405 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5406 * @cfg {String} align Aligns the content in a cell
5407 * @cfg {String} axis Categorizes cells
5408 * @cfg {String} bgcolor Specifies the background color of a cell
5409 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5410 * @cfg {Number} colspan Specifies the number of columns a cell should span
5411 * @cfg {String} headers Specifies one or more header cells a cell is related to
5412 * @cfg {Number} height Sets the height of a cell
5413 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5414 * @cfg {Number} rowspan Sets the number of rows a cell should span
5415 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5416 * @cfg {String} valign Vertical aligns the content in a cell
5417 * @cfg {Number} width Specifies the width of a cell
5420 * Create a new TableCell
5421 * @param {Object} config The config object
5424 Roo.bootstrap.TableCell = function(config){
5425 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5428 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5448 getAutoCreate : function(){
5449 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5469 cfg.align=this.align
5475 cfg.bgcolor=this.bgcolor
5478 cfg.charoff=this.charoff
5481 cfg.colspan=this.colspan
5484 cfg.headers=this.headers
5487 cfg.height=this.height
5490 cfg.nowrap=this.nowrap
5493 cfg.rowspan=this.rowspan
5496 cfg.scope=this.scope
5499 cfg.valign=this.valign
5502 cfg.width=this.width
5521 * @class Roo.bootstrap.TableRow
5522 * @extends Roo.bootstrap.Component
5523 * Bootstrap TableRow class
5524 * @cfg {String} cls row class
5525 * @cfg {String} align Aligns the content in a table row
5526 * @cfg {String} bgcolor Specifies a background color for a table row
5527 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5528 * @cfg {String} valign Vertical aligns the content in a table row
5531 * Create a new TableRow
5532 * @param {Object} config The config object
5535 Roo.bootstrap.TableRow = function(config){
5536 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5539 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5547 getAutoCreate : function(){
5548 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5558 cfg.align = this.align;
5561 cfg.bgcolor = this.bgcolor;
5564 cfg.charoff = this.charoff;
5567 cfg.valign = this.valign;
5585 * @class Roo.bootstrap.TableBody
5586 * @extends Roo.bootstrap.Component
5587 * Bootstrap TableBody class
5588 * @cfg {String} cls element class
5589 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5590 * @cfg {String} align Aligns the content inside the element
5591 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5592 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5595 * Create a new TableBody
5596 * @param {Object} config The config object
5599 Roo.bootstrap.TableBody = function(config){
5600 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5603 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5611 getAutoCreate : function(){
5612 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5626 cfg.align = this.align;
5629 cfg.charoff = this.charoff;
5632 cfg.valign = this.valign;
5639 // initEvents : function()
5646 // this.store = Roo.factory(this.store, Roo.data);
5647 // this.store.on('load', this.onLoad, this);
5649 // this.store.load();
5653 // onLoad: function ()
5655 // this.fireEvent('load', this);
5665 * Ext JS Library 1.1.1
5666 * Copyright(c) 2006-2007, Ext JS, LLC.
5668 * Originally Released Under LGPL - original licence link has changed is not relivant.
5671 * <script type="text/javascript">
5674 // as we use this in bootstrap.
5675 Roo.namespace('Roo.form');
5677 * @class Roo.form.Action
5678 * Internal Class used to handle form actions
5680 * @param {Roo.form.BasicForm} el The form element or its id
5681 * @param {Object} config Configuration options
5686 // define the action interface
5687 Roo.form.Action = function(form, options){
5689 this.options = options || {};
5692 * Client Validation Failed
5695 Roo.form.Action.CLIENT_INVALID = 'client';
5697 * Server Validation Failed
5700 Roo.form.Action.SERVER_INVALID = 'server';
5702 * Connect to Server Failed
5705 Roo.form.Action.CONNECT_FAILURE = 'connect';
5707 * Reading Data from Server Failed
5710 Roo.form.Action.LOAD_FAILURE = 'load';
5712 Roo.form.Action.prototype = {
5714 failureType : undefined,
5715 response : undefined,
5719 run : function(options){
5724 success : function(response){
5729 handleResponse : function(response){
5733 // default connection failure
5734 failure : function(response){
5736 this.response = response;
5737 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5738 this.form.afterAction(this, false);
5741 processResponse : function(response){
5742 this.response = response;
5743 if(!response.responseText){
5746 this.result = this.handleResponse(response);
5750 // utility functions used internally
5751 getUrl : function(appendParams){
5752 var url = this.options.url || this.form.url || this.form.el.dom.action;
5754 var p = this.getParams();
5756 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5762 getMethod : function(){
5763 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5766 getParams : function(){
5767 var bp = this.form.baseParams;
5768 var p = this.options.params;
5770 if(typeof p == "object"){
5771 p = Roo.urlEncode(Roo.applyIf(p, bp));
5772 }else if(typeof p == 'string' && bp){
5773 p += '&' + Roo.urlEncode(bp);
5776 p = Roo.urlEncode(bp);
5781 createCallback : function(){
5783 success: this.success,
5784 failure: this.failure,
5786 timeout: (this.form.timeout*1000),
5787 upload: this.form.fileUpload ? this.success : undefined
5792 Roo.form.Action.Submit = function(form, options){
5793 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5796 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5799 haveProgress : false,
5800 uploadComplete : false,
5802 // uploadProgress indicator.
5803 uploadProgress : function()
5805 if (!this.form.progressUrl) {
5809 if (!this.haveProgress) {
5810 Roo.MessageBox.progress("Uploading", "Uploading");
5812 if (this.uploadComplete) {
5813 Roo.MessageBox.hide();
5817 this.haveProgress = true;
5819 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5821 var c = new Roo.data.Connection();
5823 url : this.form.progressUrl,
5828 success : function(req){
5829 //console.log(data);
5833 rdata = Roo.decode(req.responseText)
5835 Roo.log("Invalid data from server..");
5839 if (!rdata || !rdata.success) {
5841 Roo.MessageBox.alert(Roo.encode(rdata));
5844 var data = rdata.data;
5846 if (this.uploadComplete) {
5847 Roo.MessageBox.hide();
5852 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5853 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5856 this.uploadProgress.defer(2000,this);
5859 failure: function(data) {
5860 Roo.log('progress url failed ');
5871 // run get Values on the form, so it syncs any secondary forms.
5872 this.form.getValues();
5874 var o = this.options;
5875 var method = this.getMethod();
5876 var isPost = method == 'POST';
5877 if(o.clientValidation === false || this.form.isValid()){
5879 if (this.form.progressUrl) {
5880 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5881 (new Date() * 1) + '' + Math.random());
5886 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5887 form:this.form.el.dom,
5888 url:this.getUrl(!isPost),
5890 params:isPost ? this.getParams() : null,
5891 isUpload: this.form.fileUpload
5894 this.uploadProgress();
5896 }else if (o.clientValidation !== false){ // client validation failed
5897 this.failureType = Roo.form.Action.CLIENT_INVALID;
5898 this.form.afterAction(this, false);
5902 success : function(response)
5904 this.uploadComplete= true;
5905 if (this.haveProgress) {
5906 Roo.MessageBox.hide();
5910 var result = this.processResponse(response);
5911 if(result === true || result.success){
5912 this.form.afterAction(this, true);
5916 this.form.markInvalid(result.errors);
5917 this.failureType = Roo.form.Action.SERVER_INVALID;
5919 this.form.afterAction(this, false);
5921 failure : function(response)
5923 this.uploadComplete= true;
5924 if (this.haveProgress) {
5925 Roo.MessageBox.hide();
5928 this.response = response;
5929 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5930 this.form.afterAction(this, false);
5933 handleResponse : function(response){
5934 if(this.form.errorReader){
5935 var rs = this.form.errorReader.read(response);
5938 for(var i = 0, len = rs.records.length; i < len; i++) {
5939 var r = rs.records[i];
5943 if(errors.length < 1){
5947 success : rs.success,
5953 ret = Roo.decode(response.responseText);
5957 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5967 Roo.form.Action.Load = function(form, options){
5968 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5969 this.reader = this.form.reader;
5972 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5977 Roo.Ajax.request(Roo.apply(
5978 this.createCallback(), {
5979 method:this.getMethod(),
5980 url:this.getUrl(false),
5981 params:this.getParams()
5985 success : function(response){
5987 var result = this.processResponse(response);
5988 if(result === true || !result.success || !result.data){
5989 this.failureType = Roo.form.Action.LOAD_FAILURE;
5990 this.form.afterAction(this, false);
5993 this.form.clearInvalid();
5994 this.form.setValues(result.data);
5995 this.form.afterAction(this, true);
5998 handleResponse : function(response){
5999 if(this.form.reader){
6000 var rs = this.form.reader.read(response);
6001 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6003 success : rs.success,
6007 return Roo.decode(response.responseText);
6011 Roo.form.Action.ACTION_TYPES = {
6012 'load' : Roo.form.Action.Load,
6013 'submit' : Roo.form.Action.Submit
6022 * @class Roo.bootstrap.Form
6023 * @extends Roo.bootstrap.Component
6024 * Bootstrap Form class
6025 * @cfg {String} method GET | POST (default POST)
6026 * @cfg {String} labelAlign top | left (default top)
6027 * @cfg {String} align left | right - for navbars
6032 * @param {Object} config The config object
6036 Roo.bootstrap.Form = function(config){
6037 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6040 * @event clientvalidation
6041 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6042 * @param {Form} this
6043 * @param {Boolean} valid true if the form has passed client-side validation
6045 clientvalidation: true,
6047 * @event beforeaction
6048 * Fires before any action is performed. Return false to cancel the action.
6049 * @param {Form} this
6050 * @param {Action} action The action to be performed
6054 * @event actionfailed
6055 * Fires when an action fails.
6056 * @param {Form} this
6057 * @param {Action} action The action that failed
6059 actionfailed : true,
6061 * @event actioncomplete
6062 * Fires when an action is completed.
6063 * @param {Form} this
6064 * @param {Action} action The action that completed
6066 actioncomplete : true
6071 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6074 * @cfg {String} method
6075 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6080 * The URL to use for form actions if one isn't supplied in the action options.
6083 * @cfg {Boolean} fileUpload
6084 * Set to true if this form is a file upload.
6088 * @cfg {Object} baseParams
6089 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6093 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6097 * @cfg {Sting} align (left|right) for navbar forms
6102 activeAction : null,
6105 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6106 * element by passing it or its id or mask the form itself by passing in true.
6109 waitMsgTarget : false,
6114 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6115 * element by passing it or its id or mask the form itself by passing in true.
6119 getAutoCreate : function(){
6123 method : this.method || 'POST',
6124 id : this.id || Roo.id(),
6127 if (this.parent().xtype.match(/^Nav/)) {
6128 cfg.cls = 'navbar-form navbar-' + this.align;
6132 if (this.labelAlign == 'left' ) {
6133 cfg.cls += ' form-horizontal';
6139 initEvents : function()
6141 this.el.on('submit', this.onSubmit, this);
6142 // this was added as random key presses on the form where triggering form submit.
6143 this.el.on('keypress', function(e) {
6144 if (e.getCharCode() != 13) {
6147 // we might need to allow it for textareas.. and some other items.
6148 // check e.getTarget().
6150 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6154 Roo.log("keypress blocked");
6162 onSubmit : function(e){
6167 * Returns true if client-side validation on the form is successful.
6170 isValid : function(){
6171 var items = this.getItems();
6173 items.each(function(f){
6182 * Returns true if any fields in this form have changed since their original load.
6185 isDirty : function(){
6187 var items = this.getItems();
6188 items.each(function(f){
6198 * Performs a predefined action (submit or load) or custom actions you define on this form.
6199 * @param {String} actionName The name of the action type
6200 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6201 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6202 * accept other config options):
6204 Property Type Description
6205 ---------------- --------------- ----------------------------------------------------------------------------------
6206 url String The url for the action (defaults to the form's url)
6207 method String The form method to use (defaults to the form's method, or POST if not defined)
6208 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6209 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6210 validate the form on the client (defaults to false)
6212 * @return {BasicForm} this
6214 doAction : function(action, options){
6215 if(typeof action == 'string'){
6216 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6218 if(this.fireEvent('beforeaction', this, action) !== false){
6219 this.beforeAction(action);
6220 action.run.defer(100, action);
6226 beforeAction : function(action){
6227 var o = action.options;
6229 // not really supported yet.. ??
6231 //if(this.waitMsgTarget === true){
6232 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6233 //}else if(this.waitMsgTarget){
6234 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6235 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6237 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6243 afterAction : function(action, success){
6244 this.activeAction = null;
6245 var o = action.options;
6247 //if(this.waitMsgTarget === true){
6249 //}else if(this.waitMsgTarget){
6250 // this.waitMsgTarget.unmask();
6252 // Roo.MessageBox.updateProgress(1);
6253 // Roo.MessageBox.hide();
6260 Roo.callback(o.success, o.scope, [this, action]);
6261 this.fireEvent('actioncomplete', this, action);
6265 // failure condition..
6266 // we have a scenario where updates need confirming.
6267 // eg. if a locking scenario exists..
6268 // we look for { errors : { needs_confirm : true }} in the response.
6270 (typeof(action.result) != 'undefined') &&
6271 (typeof(action.result.errors) != 'undefined') &&
6272 (typeof(action.result.errors.needs_confirm) != 'undefined')
6275 Roo.log("not supported yet");
6278 Roo.MessageBox.confirm(
6279 "Change requires confirmation",
6280 action.result.errorMsg,
6285 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6295 Roo.callback(o.failure, o.scope, [this, action]);
6296 // show an error message if no failed handler is set..
6297 if (!this.hasListener('actionfailed')) {
6298 Roo.log("need to add dialog support");
6300 Roo.MessageBox.alert("Error",
6301 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6302 action.result.errorMsg :
6303 "Saving Failed, please check your entries or try again"
6308 this.fireEvent('actionfailed', this, action);
6313 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6314 * @param {String} id The value to search for
6317 findField : function(id){
6318 var items = this.getItems();
6319 var field = items.get(id);
6321 items.each(function(f){
6322 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6329 return field || null;
6332 * Mark fields in this form invalid in bulk.
6333 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6334 * @return {BasicForm} this
6336 markInvalid : function(errors){
6337 if(errors instanceof Array){
6338 for(var i = 0, len = errors.length; i < len; i++){
6339 var fieldError = errors[i];
6340 var f = this.findField(fieldError.id);
6342 f.markInvalid(fieldError.msg);
6348 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6349 field.markInvalid(errors[id]);
6353 //Roo.each(this.childForms || [], function (f) {
6354 // f.markInvalid(errors);
6361 * Set values for fields in this form in bulk.
6362 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6363 * @return {BasicForm} this
6365 setValues : function(values){
6366 if(values instanceof Array){ // array of objects
6367 for(var i = 0, len = values.length; i < len; i++){
6369 var f = this.findField(v.id);
6371 f.setValue(v.value);
6372 if(this.trackResetOnLoad){
6373 f.originalValue = f.getValue();
6377 }else{ // object hash
6380 if(typeof values[id] != 'function' && (field = this.findField(id))){
6382 if (field.setFromData &&
6384 field.displayField &&
6385 // combos' with local stores can
6386 // be queried via setValue()
6387 // to set their value..
6388 (field.store && !field.store.isLocal)
6392 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6393 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6394 field.setFromData(sd);
6397 field.setValue(values[id]);
6401 if(this.trackResetOnLoad){
6402 field.originalValue = field.getValue();
6408 //Roo.each(this.childForms || [], function (f) {
6409 // f.setValues(values);
6416 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6417 * they are returned as an array.
6418 * @param {Boolean} asString
6421 getValues : function(asString){
6422 //if (this.childForms) {
6423 // copy values from the child forms
6424 // Roo.each(this.childForms, function (f) {
6425 // this.setValues(f.getValues());
6431 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6432 if(asString === true){
6435 return Roo.urlDecode(fs);
6439 * Returns the fields in this form as an object with key/value pairs.
6440 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6443 getFieldValues : function(with_hidden)
6445 var items = this.getItems();
6447 items.each(function(f){
6451 var v = f.getValue();
6452 if (f.inputType =='radio') {
6453 if (typeof(ret[f.getName()]) == 'undefined') {
6454 ret[f.getName()] = ''; // empty..
6457 if (!f.el.dom.checked) {
6465 // not sure if this supported any more..
6466 if ((typeof(v) == 'object') && f.getRawValue) {
6467 v = f.getRawValue() ; // dates..
6469 // combo boxes where name != hiddenName...
6470 if (f.name != f.getName()) {
6471 ret[f.name] = f.getRawValue();
6473 ret[f.getName()] = v;
6480 * Clears all invalid messages in this form.
6481 * @return {BasicForm} this
6483 clearInvalid : function(){
6484 var items = this.getItems();
6486 items.each(function(f){
6497 * @return {BasicForm} this
6500 var items = this.getItems();
6501 items.each(function(f){
6505 Roo.each(this.childForms || [], function (f) {
6512 getItems : function()
6514 var r=new Roo.util.MixedCollection(false, function(o){
6515 return o.id || (o.id = Roo.id());
6517 var iter = function(el) {
6524 Roo.each(el.items,function(e) {
6543 * Ext JS Library 1.1.1
6544 * Copyright(c) 2006-2007, Ext JS, LLC.
6546 * Originally Released Under LGPL - original licence link has changed is not relivant.
6549 * <script type="text/javascript">
6552 * @class Roo.form.VTypes
6553 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6556 Roo.form.VTypes = function(){
6557 // closure these in so they are only created once.
6558 var alpha = /^[a-zA-Z_]+$/;
6559 var alphanum = /^[a-zA-Z0-9_]+$/;
6560 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6561 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6563 // All these messages and functions are configurable
6566 * The function used to validate email addresses
6567 * @param {String} value The email address
6569 'email' : function(v){
6570 return email.test(v);
6573 * The error text to display when the email validation function returns false
6576 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6578 * The keystroke filter mask to be applied on email input
6581 'emailMask' : /[a-z0-9_\.\-@]/i,
6584 * The function used to validate URLs
6585 * @param {String} value The URL
6587 'url' : function(v){
6591 * The error text to display when the url validation function returns false
6594 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6597 * The function used to validate alpha values
6598 * @param {String} value The value
6600 'alpha' : function(v){
6601 return alpha.test(v);
6604 * The error text to display when the alpha validation function returns false
6607 'alphaText' : 'This field should only contain letters and _',
6609 * The keystroke filter mask to be applied on alpha input
6612 'alphaMask' : /[a-z_]/i,
6615 * The function used to validate alphanumeric values
6616 * @param {String} value The value
6618 'alphanum' : function(v){
6619 return alphanum.test(v);
6622 * The error text to display when the alphanumeric validation function returns false
6625 'alphanumText' : 'This field should only contain letters, numbers and _',
6627 * The keystroke filter mask to be applied on alphanumeric input
6630 'alphanumMask' : /[a-z0-9_]/i
6640 * @class Roo.bootstrap.Input
6641 * @extends Roo.bootstrap.Component
6642 * Bootstrap Input class
6643 * @cfg {Boolean} disabled is it disabled
6644 * @cfg {String} fieldLabel - the label associated
6645 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6646 * @cfg {String} name name of the input
6647 * @cfg {string} fieldLabel - the label associated
6648 * @cfg {string} inputType - input / file submit ...
6649 * @cfg {string} placeholder - placeholder to put in text.
6650 * @cfg {string} before - input group add on before
6651 * @cfg {string} after - input group add on after
6652 * @cfg {string} size - (lg|sm) or leave empty..
6653 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6654 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6655 * @cfg {Number} md colspan out of 12 for computer-sized screens
6656 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6657 * @cfg {string} value default value of the input
6658 * @cfg {Number} labelWidth set the width of label (0-12)
6659 * @cfg {String} labelAlign (top|left)
6660 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6661 * @cfg {String} align (left|center|right) Default left
6665 * Create a new Input
6666 * @param {Object} config The config object
6669 Roo.bootstrap.Input = function(config){
6670 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6675 * Fires when this field receives input focus.
6676 * @param {Roo.form.Field} this
6681 * Fires when this field loses input focus.
6682 * @param {Roo.form.Field} this
6687 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6688 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6689 * @param {Roo.form.Field} this
6690 * @param {Roo.EventObject} e The event object
6695 * Fires just before the field blurs if the field value has changed.
6696 * @param {Roo.form.Field} this
6697 * @param {Mixed} newValue The new value
6698 * @param {Mixed} oldValue The original value
6703 * Fires after the field has been marked as invalid.
6704 * @param {Roo.form.Field} this
6705 * @param {String} msg The validation message
6710 * Fires after the field has been validated with no errors.
6711 * @param {Roo.form.Field} this
6716 * Fires after the key up
6717 * @param {Roo.form.Field} this
6718 * @param {Roo.EventObject} e The event Object
6724 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6726 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6727 automatic validation (defaults to "keyup").
6729 validationEvent : "keyup",
6731 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6733 validateOnBlur : true,
6735 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6737 validationDelay : 250,
6739 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6741 focusClass : "x-form-focus", // not needed???
6745 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6747 invalidClass : "has-error",
6750 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6752 selectOnFocus : false,
6755 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6759 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6764 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6766 disableKeyFilter : false,
6769 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6773 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6777 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6779 blankText : "This field is required",
6782 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6786 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6788 maxLength : Number.MAX_VALUE,
6790 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6792 minLengthText : "The minimum length for this field is {0}",
6794 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6796 maxLengthText : "The maximum length for this field is {0}",
6800 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6801 * If available, this function will be called only after the basic validators all return true, and will be passed the
6802 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6806 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6807 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6808 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6812 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6835 formatedValue : false,
6837 parentLabelAlign : function()
6840 while (parent.parent()) {
6841 parent = parent.parent();
6842 if (typeof(parent.labelAlign) !='undefined') {
6843 return parent.labelAlign;
6850 getAutoCreate : function(){
6852 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6858 if(this.inputType != 'hidden'){
6859 cfg.cls = 'form-group' //input-group
6865 type : this.inputType,
6867 cls : 'form-control',
6868 placeholder : this.placeholder || ''
6873 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6876 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6877 input.maxLength = this.maxLength;
6880 if (this.disabled) {
6881 input.disabled=true;
6884 if (this.readOnly) {
6885 input.readonly=true;
6889 input.name = this.name;
6892 input.cls += ' input-' + this.size;
6895 ['xs','sm','md','lg'].map(function(size){
6896 if (settings[size]) {
6897 cfg.cls += ' col-' + size + '-' + settings[size];
6901 var inputblock = input;
6903 if (this.before || this.after) {
6906 cls : 'input-group',
6909 if (this.before && typeof(this.before) == 'string') {
6911 inputblock.cn.push({
6913 cls : 'roo-input-before input-group-addon',
6917 if (this.before && typeof(this.before) == 'object') {
6918 this.before = Roo.factory(this.before);
6919 Roo.log(this.before);
6920 inputblock.cn.push({
6922 cls : 'roo-input-before input-group-' +
6923 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6927 inputblock.cn.push(input);
6929 if (this.after && typeof(this.after) == 'string') {
6930 inputblock.cn.push({
6932 cls : 'roo-input-after input-group-addon',
6936 if (this.after && typeof(this.after) == 'object') {
6937 this.after = Roo.factory(this.after);
6938 Roo.log(this.after);
6939 inputblock.cn.push({
6941 cls : 'roo-input-after input-group-' +
6942 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6947 if (align ==='left' && this.fieldLabel.length) {
6948 Roo.log("left and has label");
6954 cls : 'control-label col-sm-' + this.labelWidth,
6955 html : this.fieldLabel
6959 cls : "col-sm-" + (12 - this.labelWidth),
6966 } else if ( this.fieldLabel.length) {
6972 //cls : 'input-group-addon',
6973 html : this.fieldLabel
6983 Roo.log(" no label && no align");
6992 Roo.log('input-parentType: ' + this.parentType);
6994 if (this.parentType === 'Navbar' && this.parent().bar) {
6995 cfg.cls += ' navbar-form';
7003 * return the real input element.
7005 inputEl: function ()
7007 return this.el.select('input.form-control',true).first();
7009 setDisabled : function(v)
7011 var i = this.inputEl().dom;
7013 i.removeAttribute('disabled');
7017 i.setAttribute('disabled','true');
7019 initEvents : function()
7022 this.inputEl().on("keydown" , this.fireKey, this);
7023 this.inputEl().on("focus", this.onFocus, this);
7024 this.inputEl().on("blur", this.onBlur, this);
7026 this.inputEl().relayEvent('keyup', this);
7028 // reference to original value for reset
7029 this.originalValue = this.getValue();
7030 //Roo.form.TextField.superclass.initEvents.call(this);
7031 if(this.validationEvent == 'keyup'){
7032 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7033 this.inputEl().on('keyup', this.filterValidation, this);
7035 else if(this.validationEvent !== false){
7036 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7039 if(this.selectOnFocus){
7040 this.on("focus", this.preFocus, this);
7043 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7044 this.inputEl().on("keypress", this.filterKeys, this);
7047 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7048 this.el.on("click", this.autoSize, this);
7051 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7052 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7055 if (typeof(this.before) == 'object') {
7056 this.before.render(this.el.select('.roo-input-before',true).first());
7058 if (typeof(this.after) == 'object') {
7059 this.after.render(this.el.select('.roo-input-after',true).first());
7064 filterValidation : function(e){
7065 if(!e.isNavKeyPress()){
7066 this.validationTask.delay(this.validationDelay);
7070 * Validates the field value
7071 * @return {Boolean} True if the value is valid, else false
7073 validate : function(){
7074 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7075 if(this.disabled || this.validateValue(this.getRawValue())){
7076 this.clearInvalid();
7084 * Validates a value according to the field's validation rules and marks the field as invalid
7085 * if the validation fails
7086 * @param {Mixed} value The value to validate
7087 * @return {Boolean} True if the value is valid, else false
7089 validateValue : function(value){
7090 if(value.length < 1) { // if it's blank
7091 if(this.allowBlank){
7092 this.clearInvalid();
7095 this.markInvalid(this.blankText);
7099 if(value.length < this.minLength){
7100 this.markInvalid(String.format(this.minLengthText, this.minLength));
7103 if(value.length > this.maxLength){
7104 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7108 var vt = Roo.form.VTypes;
7109 if(!vt[this.vtype](value, this)){
7110 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7114 if(typeof this.validator == "function"){
7115 var msg = this.validator(value);
7117 this.markInvalid(msg);
7121 if(this.regex && !this.regex.test(value)){
7122 this.markInvalid(this.regexText);
7131 fireKey : function(e){
7132 //Roo.log('field ' + e.getKey());
7133 if(e.isNavKeyPress()){
7134 this.fireEvent("specialkey", this, e);
7137 focus : function (selectText){
7139 this.inputEl().focus();
7140 if(selectText === true){
7141 this.inputEl().dom.select();
7147 onFocus : function(){
7148 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7149 // this.el.addClass(this.focusClass);
7152 this.hasFocus = true;
7153 this.startValue = this.getValue();
7154 this.fireEvent("focus", this);
7158 beforeBlur : Roo.emptyFn,
7162 onBlur : function(){
7164 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7165 //this.el.removeClass(this.focusClass);
7167 this.hasFocus = false;
7168 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7171 var v = this.getValue();
7172 if(String(v) !== String(this.startValue)){
7173 this.fireEvent('change', this, v, this.startValue);
7175 this.fireEvent("blur", this);
7179 * Resets the current field value to the originally loaded value and clears any validation messages
7182 this.setValue(this.originalValue);
7183 this.clearInvalid();
7186 * Returns the name of the field
7187 * @return {Mixed} name The name field
7189 getName: function(){
7193 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7194 * @return {Mixed} value The field value
7196 getValue : function(){
7198 var v = this.inputEl().getValue();
7203 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7204 * @return {Mixed} value The field value
7206 getRawValue : function(){
7207 var v = this.inputEl().getValue();
7213 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7214 * @param {Mixed} value The value to set
7216 setRawValue : function(v){
7217 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7220 selectText : function(start, end){
7221 var v = this.getRawValue();
7223 start = start === undefined ? 0 : start;
7224 end = end === undefined ? v.length : end;
7225 var d = this.inputEl().dom;
7226 if(d.setSelectionRange){
7227 d.setSelectionRange(start, end);
7228 }else if(d.createTextRange){
7229 var range = d.createTextRange();
7230 range.moveStart("character", start);
7231 range.moveEnd("character", v.length-end);
7238 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7239 * @param {Mixed} value The value to set
7241 setValue : function(v){
7244 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7250 processValue : function(value){
7251 if(this.stripCharsRe){
7252 var newValue = value.replace(this.stripCharsRe, '');
7253 if(newValue !== value){
7254 this.setRawValue(newValue);
7261 preFocus : function(){
7263 if(this.selectOnFocus){
7264 this.inputEl().dom.select();
7267 filterKeys : function(e){
7269 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7272 var c = e.getCharCode(), cc = String.fromCharCode(c);
7273 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7276 if(!this.maskRe.test(cc)){
7281 * Clear any invalid styles/messages for this field
7283 clearInvalid : function(){
7285 if(!this.el || this.preventMark){ // not rendered
7288 this.el.removeClass(this.invalidClass);
7290 switch(this.msgTarget){
7292 this.el.dom.qtip = '';
7295 this.el.dom.title = '';
7299 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7304 this.errorIcon.dom.qtip = '';
7305 this.errorIcon.hide();
7306 this.un('resize', this.alignErrorIcon, this);
7310 var t = Roo.getDom(this.msgTarget);
7312 t.style.display = 'none';
7316 this.fireEvent('valid', this);
7319 * Mark this field as invalid
7320 * @param {String} msg The validation message
7322 markInvalid : function(msg){
7323 if(!this.el || this.preventMark){ // not rendered
7326 this.el.addClass(this.invalidClass);
7328 msg = msg || this.invalidText;
7329 switch(this.msgTarget){
7331 this.el.dom.qtip = msg;
7332 this.el.dom.qclass = 'x-form-invalid-tip';
7333 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7334 Roo.QuickTips.enable();
7338 this.el.dom.title = msg;
7342 var elp = this.el.findParent('.x-form-element', 5, true);
7343 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7344 this.errorEl.setWidth(elp.getWidth(true)-20);
7346 this.errorEl.update(msg);
7347 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7350 if(!this.errorIcon){
7351 var elp = this.el.findParent('.x-form-element', 5, true);
7352 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7354 this.alignErrorIcon();
7355 this.errorIcon.dom.qtip = msg;
7356 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7357 this.errorIcon.show();
7358 this.on('resize', this.alignErrorIcon, this);
7361 var t = Roo.getDom(this.msgTarget);
7363 t.style.display = this.msgDisplay;
7367 this.fireEvent('invalid', this, msg);
7370 SafariOnKeyDown : function(event)
7372 // this is a workaround for a password hang bug on chrome/ webkit.
7374 var isSelectAll = false;
7376 if(this.inputEl().dom.selectionEnd > 0){
7377 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7379 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7380 event.preventDefault();
7385 if(isSelectAll){ // backspace and delete key
7387 event.preventDefault();
7388 // this is very hacky as keydown always get's upper case.
7390 var cc = String.fromCharCode(event.getCharCode());
7391 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7395 adjustWidth : function(tag, w){
7396 tag = tag.toLowerCase();
7397 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7398 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7402 if(tag == 'textarea'){
7405 }else if(Roo.isOpera){
7409 if(tag == 'textarea'){
7428 * @class Roo.bootstrap.TextArea
7429 * @extends Roo.bootstrap.Input
7430 * Bootstrap TextArea class
7431 * @cfg {Number} cols Specifies the visible width of a text area
7432 * @cfg {Number} rows Specifies the visible number of lines in a text area
7433 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7434 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7435 * @cfg {string} html text
7438 * Create a new TextArea
7439 * @param {Object} config The config object
7442 Roo.bootstrap.TextArea = function(config){
7443 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7447 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7457 getAutoCreate : function(){
7459 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7470 value : this.value || '',
7471 html: this.html || '',
7472 cls : 'form-control',
7473 placeholder : this.placeholder || ''
7477 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7478 input.maxLength = this.maxLength;
7482 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7486 input.cols = this.cols;
7489 if (this.readOnly) {
7490 input.readonly = true;
7494 input.name = this.name;
7498 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7502 ['xs','sm','md','lg'].map(function(size){
7503 if (settings[size]) {
7504 cfg.cls += ' col-' + size + '-' + settings[size];
7508 var inputblock = input;
7510 if (this.before || this.after) {
7513 cls : 'input-group',
7517 inputblock.cn.push({
7519 cls : 'input-group-addon',
7523 inputblock.cn.push(input);
7525 inputblock.cn.push({
7527 cls : 'input-group-addon',
7534 if (align ==='left' && this.fieldLabel.length) {
7535 Roo.log("left and has label");
7541 cls : 'control-label col-sm-' + this.labelWidth,
7542 html : this.fieldLabel
7546 cls : "col-sm-" + (12 - this.labelWidth),
7553 } else if ( this.fieldLabel.length) {
7559 //cls : 'input-group-addon',
7560 html : this.fieldLabel
7570 Roo.log(" no label && no align");
7580 if (this.disabled) {
7581 input.disabled=true;
7588 * return the real textarea element.
7590 inputEl: function ()
7592 return this.el.select('textarea.form-control',true).first();
7600 * trigger field - base class for combo..
7605 * @class Roo.bootstrap.TriggerField
7606 * @extends Roo.bootstrap.Input
7607 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7608 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7609 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7610 * for which you can provide a custom implementation. For example:
7612 var trigger = new Roo.bootstrap.TriggerField();
7613 trigger.onTriggerClick = myTriggerFn;
7614 trigger.applyTo('my-field');
7617 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7618 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7619 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7620 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7622 * Create a new TriggerField.
7623 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7624 * to the base TextField)
7626 Roo.bootstrap.TriggerField = function(config){
7627 this.mimicing = false;
7628 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7631 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7633 * @cfg {String} triggerClass A CSS class to apply to the trigger
7636 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7640 /** @cfg {Boolean} grow @hide */
7641 /** @cfg {Number} growMin @hide */
7642 /** @cfg {Number} growMax @hide */
7648 autoSize: Roo.emptyFn,
7655 actionMode : 'wrap',
7659 getAutoCreate : function(){
7661 var parent = this.parent();
7663 var align = this.labelAlign || this.parentLabelAlign();
7668 cls: 'form-group' //input-group
7675 type : this.inputType,
7676 cls : 'form-control',
7677 autocomplete: 'off',
7678 placeholder : this.placeholder || ''
7682 input.name = this.name;
7685 input.cls += ' input-' + this.size;
7688 if (this.disabled) {
7689 input.disabled=true;
7692 var inputblock = input;
7694 if (this.before || this.after) {
7697 cls : 'input-group',
7701 inputblock.cn.push({
7703 cls : 'input-group-addon',
7707 inputblock.cn.push(input);
7709 inputblock.cn.push({
7711 cls : 'input-group-addon',
7724 cls: 'form-hidden-field'
7732 Roo.log('multiple');
7740 cls: 'form-hidden-field'
7744 cls: 'select2-choices',
7748 cls: 'select2-search-field',
7761 cls: 'select2-container input-group',
7766 cls: 'typeahead typeahead-long dropdown-menu',
7767 style: 'display:none'
7775 cls : 'input-group-addon btn dropdown-toggle',
7783 cls: 'combobox-clear',
7797 combobox.cls += ' select2-container-multi';
7800 if (align ==='left' && this.fieldLabel.length) {
7802 Roo.log("left and has label");
7808 cls : 'control-label col-sm-' + this.labelWidth,
7809 html : this.fieldLabel
7813 cls : "col-sm-" + (12 - this.labelWidth),
7820 } else if ( this.fieldLabel.length) {
7826 //cls : 'input-group-addon',
7827 html : this.fieldLabel
7837 Roo.log(" no label && no align");
7844 ['xs','sm','md','lg'].map(function(size){
7845 if (settings[size]) {
7846 cfg.cls += ' col-' + size + '-' + settings[size];
7857 onResize : function(w, h){
7858 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7859 // if(typeof w == 'number'){
7860 // var x = w - this.trigger.getWidth();
7861 // this.inputEl().setWidth(this.adjustWidth('input', x));
7862 // this.trigger.setStyle('left', x+'px');
7867 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7870 getResizeEl : function(){
7871 return this.inputEl();
7875 getPositionEl : function(){
7876 return this.inputEl();
7880 alignErrorIcon : function(){
7881 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7885 initEvents : function(){
7887 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7888 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7890 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7891 if(this.hideTrigger){
7892 this.trigger.setDisplayed(false);
7894 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7898 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7901 //this.trigger.addClassOnOver('x-form-trigger-over');
7902 //this.trigger.addClassOnClick('x-form-trigger-click');
7905 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7910 initTrigger : function(){
7915 onDestroy : function(){
7917 this.trigger.removeAllListeners();
7918 // this.trigger.remove();
7921 // this.wrap.remove();
7923 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7927 onFocus : function(){
7928 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7931 this.wrap.addClass('x-trigger-wrap-focus');
7932 this.mimicing = true;
7933 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7934 if(this.monitorTab){
7935 this.el.on("keydown", this.checkTab, this);
7942 checkTab : function(e){
7943 if(e.getKey() == e.TAB){
7949 onBlur : function(){
7954 mimicBlur : function(e, t){
7956 if(!this.wrap.contains(t) && this.validateBlur()){
7963 triggerBlur : function(){
7964 this.mimicing = false;
7965 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7966 if(this.monitorTab){
7967 this.el.un("keydown", this.checkTab, this);
7969 //this.wrap.removeClass('x-trigger-wrap-focus');
7970 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7974 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7975 validateBlur : function(e, t){
7980 onDisable : function(){
7981 this.inputEl().dom.disabled = true;
7982 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7984 // this.wrap.addClass('x-item-disabled');
7989 onEnable : function(){
7990 this.inputEl().dom.disabled = false;
7991 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7993 // this.el.removeClass('x-item-disabled');
7998 onShow : function(){
7999 var ae = this.getActionEl();
8002 ae.dom.style.display = '';
8003 ae.dom.style.visibility = 'visible';
8009 onHide : function(){
8010 var ae = this.getActionEl();
8011 ae.dom.style.display = 'none';
8015 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8016 * by an implementing function.
8018 * @param {EventObject} e
8020 onTriggerClick : Roo.emptyFn
8024 * Ext JS Library 1.1.1
8025 * Copyright(c) 2006-2007, Ext JS, LLC.
8027 * Originally Released Under LGPL - original licence link has changed is not relivant.
8030 * <script type="text/javascript">
8035 * @class Roo.data.SortTypes
8037 * Defines the default sorting (casting?) comparison functions used when sorting data.
8039 Roo.data.SortTypes = {
8041 * Default sort that does nothing
8042 * @param {Mixed} s The value being converted
8043 * @return {Mixed} The comparison value
8050 * The regular expression used to strip tags
8054 stripTagsRE : /<\/?[^>]+>/gi,
8057 * Strips all HTML tags to sort on text only
8058 * @param {Mixed} s The value being converted
8059 * @return {String} The comparison value
8061 asText : function(s){
8062 return String(s).replace(this.stripTagsRE, "");
8066 * Strips all HTML tags to sort on text only - Case insensitive
8067 * @param {Mixed} s The value being converted
8068 * @return {String} The comparison value
8070 asUCText : function(s){
8071 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8075 * Case insensitive string
8076 * @param {Mixed} s The value being converted
8077 * @return {String} The comparison value
8079 asUCString : function(s) {
8080 return String(s).toUpperCase();
8085 * @param {Mixed} s The value being converted
8086 * @return {Number} The comparison value
8088 asDate : function(s) {
8092 if(s instanceof Date){
8095 return Date.parse(String(s));
8100 * @param {Mixed} s The value being converted
8101 * @return {Float} The comparison value
8103 asFloat : function(s) {
8104 var val = parseFloat(String(s).replace(/,/g, ""));
8105 if(isNaN(val)) val = 0;
8111 * @param {Mixed} s The value being converted
8112 * @return {Number} The comparison value
8114 asInt : function(s) {
8115 var val = parseInt(String(s).replace(/,/g, ""));
8116 if(isNaN(val)) val = 0;
8121 * Ext JS Library 1.1.1
8122 * Copyright(c) 2006-2007, Ext JS, LLC.
8124 * Originally Released Under LGPL - original licence link has changed is not relivant.
8127 * <script type="text/javascript">
8131 * @class Roo.data.Record
8132 * Instances of this class encapsulate both record <em>definition</em> information, and record
8133 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8134 * to access Records cached in an {@link Roo.data.Store} object.<br>
8136 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8137 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8140 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8142 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8143 * {@link #create}. The parameters are the same.
8144 * @param {Array} data An associative Array of data values keyed by the field name.
8145 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8146 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8147 * not specified an integer id is generated.
8149 Roo.data.Record = function(data, id){
8150 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8155 * Generate a constructor for a specific record layout.
8156 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8157 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8158 * Each field definition object may contain the following properties: <ul>
8159 * <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,
8160 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8161 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8162 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8163 * is being used, then this is a string containing the javascript expression to reference the data relative to
8164 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8165 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8166 * this may be omitted.</p></li>
8167 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8168 * <ul><li>auto (Default, implies no conversion)</li>
8173 * <li>date</li></ul></p></li>
8174 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8175 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8176 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8177 * by the Reader into an object that will be stored in the Record. It is passed the
8178 * following parameters:<ul>
8179 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8181 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8183 * <br>usage:<br><pre><code>
8184 var TopicRecord = Roo.data.Record.create(
8185 {name: 'title', mapping: 'topic_title'},
8186 {name: 'author', mapping: 'username'},
8187 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8188 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8189 {name: 'lastPoster', mapping: 'user2'},
8190 {name: 'excerpt', mapping: 'post_text'}
8193 var myNewRecord = new TopicRecord({
8194 title: 'Do my job please',
8197 lastPost: new Date(),
8198 lastPoster: 'Animal',
8199 excerpt: 'No way dude!'
8201 myStore.add(myNewRecord);
8206 Roo.data.Record.create = function(o){
8208 f.superclass.constructor.apply(this, arguments);
8210 Roo.extend(f, Roo.data.Record);
8211 var p = f.prototype;
8212 p.fields = new Roo.util.MixedCollection(false, function(field){
8215 for(var i = 0, len = o.length; i < len; i++){
8216 p.fields.add(new Roo.data.Field(o[i]));
8218 f.getField = function(name){
8219 return p.fields.get(name);
8224 Roo.data.Record.AUTO_ID = 1000;
8225 Roo.data.Record.EDIT = 'edit';
8226 Roo.data.Record.REJECT = 'reject';
8227 Roo.data.Record.COMMIT = 'commit';
8229 Roo.data.Record.prototype = {
8231 * Readonly flag - true if this record has been modified.
8240 join : function(store){
8245 * Set the named field to the specified value.
8246 * @param {String} name The name of the field to set.
8247 * @param {Object} value The value to set the field to.
8249 set : function(name, value){
8250 if(this.data[name] == value){
8257 if(typeof this.modified[name] == 'undefined'){
8258 this.modified[name] = this.data[name];
8260 this.data[name] = value;
8261 if(!this.editing && this.store){
8262 this.store.afterEdit(this);
8267 * Get the value of the named field.
8268 * @param {String} name The name of the field to get the value of.
8269 * @return {Object} The value of the field.
8271 get : function(name){
8272 return this.data[name];
8276 beginEdit : function(){
8277 this.editing = true;
8282 cancelEdit : function(){
8283 this.editing = false;
8284 delete this.modified;
8288 endEdit : function(){
8289 this.editing = false;
8290 if(this.dirty && this.store){
8291 this.store.afterEdit(this);
8296 * Usually called by the {@link Roo.data.Store} which owns the Record.
8297 * Rejects all changes made to the Record since either creation, or the last commit operation.
8298 * Modified fields are reverted to their original values.
8300 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8301 * of reject operations.
8303 reject : function(){
8304 var m = this.modified;
8306 if(typeof m[n] != "function"){
8307 this.data[n] = m[n];
8311 delete this.modified;
8312 this.editing = false;
8314 this.store.afterReject(this);
8319 * Usually called by the {@link Roo.data.Store} which owns the Record.
8320 * Commits all changes made to the Record since either creation, or the last commit operation.
8322 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8323 * of commit operations.
8325 commit : function(){
8327 delete this.modified;
8328 this.editing = false;
8330 this.store.afterCommit(this);
8335 hasError : function(){
8336 return this.error != null;
8340 clearError : function(){
8345 * Creates a copy of this record.
8346 * @param {String} id (optional) A new record id if you don't want to use this record's id
8349 copy : function(newId) {
8350 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8354 * Ext JS Library 1.1.1
8355 * Copyright(c) 2006-2007, Ext JS, LLC.
8357 * Originally Released Under LGPL - original licence link has changed is not relivant.
8360 * <script type="text/javascript">
8366 * @class Roo.data.Store
8367 * @extends Roo.util.Observable
8368 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8369 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8371 * 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
8372 * has no knowledge of the format of the data returned by the Proxy.<br>
8374 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8375 * instances from the data object. These records are cached and made available through accessor functions.
8377 * Creates a new Store.
8378 * @param {Object} config A config object containing the objects needed for the Store to access data,
8379 * and read the data into Records.
8381 Roo.data.Store = function(config){
8382 this.data = new Roo.util.MixedCollection(false);
8383 this.data.getKey = function(o){
8386 this.baseParams = {};
8393 "multisort" : "_multisort"
8396 if(config && config.data){
8397 this.inlineData = config.data;
8401 Roo.apply(this, config);
8403 if(this.reader){ // reader passed
8404 this.reader = Roo.factory(this.reader, Roo.data);
8405 this.reader.xmodule = this.xmodule || false;
8406 if(!this.recordType){
8407 this.recordType = this.reader.recordType;
8409 if(this.reader.onMetaChange){
8410 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8414 if(this.recordType){
8415 this.fields = this.recordType.prototype.fields;
8421 * @event datachanged
8422 * Fires when the data cache has changed, and a widget which is using this Store
8423 * as a Record cache should refresh its view.
8424 * @param {Store} this
8429 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8430 * @param {Store} this
8431 * @param {Object} meta The JSON metadata
8436 * Fires when Records have been added to the Store
8437 * @param {Store} this
8438 * @param {Roo.data.Record[]} records The array of Records added
8439 * @param {Number} index The index at which the record(s) were added
8444 * Fires when a Record has been removed from the Store
8445 * @param {Store} this
8446 * @param {Roo.data.Record} record The Record that was removed
8447 * @param {Number} index The index at which the record was removed
8452 * Fires when a Record has been updated
8453 * @param {Store} this
8454 * @param {Roo.data.Record} record The Record that was updated
8455 * @param {String} operation The update operation being performed. Value may be one of:
8457 Roo.data.Record.EDIT
8458 Roo.data.Record.REJECT
8459 Roo.data.Record.COMMIT
8465 * Fires when the data cache has been cleared.
8466 * @param {Store} this
8471 * Fires before a request is made for a new data object. If the beforeload handler returns false
8472 * the load action will be canceled.
8473 * @param {Store} this
8474 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8478 * @event beforeloadadd
8479 * Fires after a new set of Records has been loaded.
8480 * @param {Store} this
8481 * @param {Roo.data.Record[]} records The Records that were loaded
8482 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8484 beforeloadadd : true,
8487 * Fires after a new set of Records has been loaded, before they are added to the store.
8488 * @param {Store} this
8489 * @param {Roo.data.Record[]} records The Records that were loaded
8490 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8491 * @params {Object} return from reader
8495 * @event loadexception
8496 * Fires if an exception occurs in the Proxy during loading.
8497 * Called with the signature of the Proxy's "loadexception" event.
8498 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8501 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8502 * @param {Object} load options
8503 * @param {Object} jsonData from your request (normally this contains the Exception)
8505 loadexception : true
8509 this.proxy = Roo.factory(this.proxy, Roo.data);
8510 this.proxy.xmodule = this.xmodule || false;
8511 this.relayEvents(this.proxy, ["loadexception"]);
8513 this.sortToggle = {};
8514 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8516 Roo.data.Store.superclass.constructor.call(this);
8518 if(this.inlineData){
8519 this.loadData(this.inlineData);
8520 delete this.inlineData;
8524 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8526 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8527 * without a remote query - used by combo/forms at present.
8531 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8534 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8537 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8538 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8541 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8542 * on any HTTP request
8545 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8548 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8552 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8553 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8558 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8559 * loaded or when a record is removed. (defaults to false).
8561 pruneModifiedRecords : false,
8567 * Add Records to the Store and fires the add event.
8568 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8570 add : function(records){
8571 records = [].concat(records);
8572 for(var i = 0, len = records.length; i < len; i++){
8573 records[i].join(this);
8575 var index = this.data.length;
8576 this.data.addAll(records);
8577 this.fireEvent("add", this, records, index);
8581 * Remove a Record from the Store and fires the remove event.
8582 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8584 remove : function(record){
8585 var index = this.data.indexOf(record);
8586 this.data.removeAt(index);
8587 if(this.pruneModifiedRecords){
8588 this.modified.remove(record);
8590 this.fireEvent("remove", this, record, index);
8594 * Remove all Records from the Store and fires the clear event.
8596 removeAll : function(){
8598 if(this.pruneModifiedRecords){
8601 this.fireEvent("clear", this);
8605 * Inserts Records to the Store at the given index and fires the add event.
8606 * @param {Number} index The start index at which to insert the passed Records.
8607 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8609 insert : function(index, records){
8610 records = [].concat(records);
8611 for(var i = 0, len = records.length; i < len; i++){
8612 this.data.insert(index, records[i]);
8613 records[i].join(this);
8615 this.fireEvent("add", this, records, index);
8619 * Get the index within the cache of the passed Record.
8620 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8621 * @return {Number} The index of the passed Record. Returns -1 if not found.
8623 indexOf : function(record){
8624 return this.data.indexOf(record);
8628 * Get the index within the cache of the Record with the passed id.
8629 * @param {String} id The id of the Record to find.
8630 * @return {Number} The index of the Record. Returns -1 if not found.
8632 indexOfId : function(id){
8633 return this.data.indexOfKey(id);
8637 * Get the Record with the specified id.
8638 * @param {String} id The id of the Record to find.
8639 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8641 getById : function(id){
8642 return this.data.key(id);
8646 * Get the Record at the specified index.
8647 * @param {Number} index The index of the Record to find.
8648 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8650 getAt : function(index){
8651 return this.data.itemAt(index);
8655 * Returns a range of Records between specified indices.
8656 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8657 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8658 * @return {Roo.data.Record[]} An array of Records
8660 getRange : function(start, end){
8661 return this.data.getRange(start, end);
8665 storeOptions : function(o){
8666 o = Roo.apply({}, o);
8669 this.lastOptions = o;
8673 * Loads the Record cache from the configured Proxy using the configured Reader.
8675 * If using remote paging, then the first load call must specify the <em>start</em>
8676 * and <em>limit</em> properties in the options.params property to establish the initial
8677 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8679 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8680 * and this call will return before the new data has been loaded. Perform any post-processing
8681 * in a callback function, or in a "load" event handler.</strong>
8683 * @param {Object} options An object containing properties which control loading options:<ul>
8684 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8685 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8686 * passed the following arguments:<ul>
8687 * <li>r : Roo.data.Record[]</li>
8688 * <li>options: Options object from the load call</li>
8689 * <li>success: Boolean success indicator</li></ul></li>
8690 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8691 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8694 load : function(options){
8695 options = options || {};
8696 if(this.fireEvent("beforeload", this, options) !== false){
8697 this.storeOptions(options);
8698 var p = Roo.apply(options.params || {}, this.baseParams);
8699 // if meta was not loaded from remote source.. try requesting it.
8700 if (!this.reader.metaFromRemote) {
8703 if(this.sortInfo && this.remoteSort){
8704 var pn = this.paramNames;
8705 p[pn["sort"]] = this.sortInfo.field;
8706 p[pn["dir"]] = this.sortInfo.direction;
8708 if (this.multiSort) {
8709 var pn = this.paramNames;
8710 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8713 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8718 * Reloads the Record cache from the configured Proxy using the configured Reader and
8719 * the options from the last load operation performed.
8720 * @param {Object} options (optional) An object containing properties which may override the options
8721 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8722 * the most recently used options are reused).
8724 reload : function(options){
8725 this.load(Roo.applyIf(options||{}, this.lastOptions));
8729 // Called as a callback by the Reader during a load operation.
8730 loadRecords : function(o, options, success){
8731 if(!o || success === false){
8732 if(success !== false){
8733 this.fireEvent("load", this, [], options, o);
8735 if(options.callback){
8736 options.callback.call(options.scope || this, [], options, false);
8740 // if data returned failure - throw an exception.
8741 if (o.success === false) {
8742 // show a message if no listener is registered.
8743 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8744 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8746 // loadmask wil be hooked into this..
8747 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8750 var r = o.records, t = o.totalRecords || r.length;
8752 this.fireEvent("beforeloadadd", this, r, options, o);
8754 if(!options || options.add !== true){
8755 if(this.pruneModifiedRecords){
8758 for(var i = 0, len = r.length; i < len; i++){
8762 this.data = this.snapshot;
8763 delete this.snapshot;
8766 this.data.addAll(r);
8767 this.totalLength = t;
8769 this.fireEvent("datachanged", this);
8771 this.totalLength = Math.max(t, this.data.length+r.length);
8774 this.fireEvent("load", this, r, options, o);
8775 if(options.callback){
8776 options.callback.call(options.scope || this, r, options, true);
8782 * Loads data from a passed data block. A Reader which understands the format of the data
8783 * must have been configured in the constructor.
8784 * @param {Object} data The data block from which to read the Records. The format of the data expected
8785 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8786 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8788 loadData : function(o, append){
8789 var r = this.reader.readRecords(o);
8790 this.loadRecords(r, {add: append}, true);
8794 * Gets the number of cached records.
8796 * <em>If using paging, this may not be the total size of the dataset. If the data object
8797 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8798 * the data set size</em>
8800 getCount : function(){
8801 return this.data.length || 0;
8805 * Gets the total number of records in the dataset as returned by the server.
8807 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8808 * the dataset size</em>
8810 getTotalCount : function(){
8811 return this.totalLength || 0;
8815 * Returns the sort state of the Store as an object with two properties:
8817 field {String} The name of the field by which the Records are sorted
8818 direction {String} The sort order, "ASC" or "DESC"
8821 getSortState : function(){
8822 return this.sortInfo;
8826 applySort : function(){
8827 if(this.sortInfo && !this.remoteSort){
8828 var s = this.sortInfo, f = s.field;
8829 var st = this.fields.get(f).sortType;
8830 var fn = function(r1, r2){
8831 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8832 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8834 this.data.sort(s.direction, fn);
8835 if(this.snapshot && this.snapshot != this.data){
8836 this.snapshot.sort(s.direction, fn);
8842 * Sets the default sort column and order to be used by the next load operation.
8843 * @param {String} fieldName The name of the field to sort by.
8844 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8846 setDefaultSort : function(field, dir){
8847 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8852 * If remote sorting is used, the sort is performed on the server, and the cache is
8853 * reloaded. If local sorting is used, the cache is sorted internally.
8854 * @param {String} fieldName The name of the field to sort by.
8855 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8857 sort : function(fieldName, dir){
8858 var f = this.fields.get(fieldName);
8860 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8862 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8863 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8868 this.sortToggle[f.name] = dir;
8869 this.sortInfo = {field: f.name, direction: dir};
8870 if(!this.remoteSort){
8872 this.fireEvent("datachanged", this);
8874 this.load(this.lastOptions);
8879 * Calls the specified function for each of the Records in the cache.
8880 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8881 * Returning <em>false</em> aborts and exits the iteration.
8882 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8884 each : function(fn, scope){
8885 this.data.each(fn, scope);
8889 * Gets all records modified since the last commit. Modified records are persisted across load operations
8890 * (e.g., during paging).
8891 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8893 getModifiedRecords : function(){
8894 return this.modified;
8898 createFilterFn : function(property, value, anyMatch){
8899 if(!value.exec){ // not a regex
8900 value = String(value);
8901 if(value.length == 0){
8904 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8907 return value.test(r.data[property]);
8912 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8913 * @param {String} property A field on your records
8914 * @param {Number} start The record index to start at (defaults to 0)
8915 * @param {Number} end The last record index to include (defaults to length - 1)
8916 * @return {Number} The sum
8918 sum : function(property, start, end){
8919 var rs = this.data.items, v = 0;
8921 end = (end || end === 0) ? end : rs.length-1;
8923 for(var i = start; i <= end; i++){
8924 v += (rs[i].data[property] || 0);
8930 * Filter the records by a specified property.
8931 * @param {String} field A field on your records
8932 * @param {String/RegExp} value Either a string that the field
8933 * should start with or a RegExp to test against the field
8934 * @param {Boolean} anyMatch True to match any part not just the beginning
8936 filter : function(property, value, anyMatch){
8937 var fn = this.createFilterFn(property, value, anyMatch);
8938 return fn ? this.filterBy(fn) : this.clearFilter();
8942 * Filter by a function. The specified function will be called with each
8943 * record in this data source. If the function returns true the record is included,
8944 * otherwise it is filtered.
8945 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8946 * @param {Object} scope (optional) The scope of the function (defaults to this)
8948 filterBy : function(fn, scope){
8949 this.snapshot = this.snapshot || this.data;
8950 this.data = this.queryBy(fn, scope||this);
8951 this.fireEvent("datachanged", this);
8955 * Query the records by a specified property.
8956 * @param {String} field A field on your records
8957 * @param {String/RegExp} value Either a string that the field
8958 * should start with or a RegExp to test against the field
8959 * @param {Boolean} anyMatch True to match any part not just the beginning
8960 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8962 query : function(property, value, anyMatch){
8963 var fn = this.createFilterFn(property, value, anyMatch);
8964 return fn ? this.queryBy(fn) : this.data.clone();
8968 * Query by a function. The specified function will be called with each
8969 * record in this data source. If the function returns true the record is included
8971 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8972 * @param {Object} scope (optional) The scope of the function (defaults to this)
8973 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8975 queryBy : function(fn, scope){
8976 var data = this.snapshot || this.data;
8977 return data.filterBy(fn, scope||this);
8981 * Collects unique values for a particular dataIndex from this store.
8982 * @param {String} dataIndex The property to collect
8983 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8984 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8985 * @return {Array} An array of the unique values
8987 collect : function(dataIndex, allowNull, bypassFilter){
8988 var d = (bypassFilter === true && this.snapshot) ?
8989 this.snapshot.items : this.data.items;
8990 var v, sv, r = [], l = {};
8991 for(var i = 0, len = d.length; i < len; i++){
8992 v = d[i].data[dataIndex];
8994 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9003 * Revert to a view of the Record cache with no filtering applied.
9004 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9006 clearFilter : function(suppressEvent){
9007 if(this.snapshot && this.snapshot != this.data){
9008 this.data = this.snapshot;
9009 delete this.snapshot;
9010 if(suppressEvent !== true){
9011 this.fireEvent("datachanged", this);
9017 afterEdit : function(record){
9018 if(this.modified.indexOf(record) == -1){
9019 this.modified.push(record);
9021 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9025 afterReject : function(record){
9026 this.modified.remove(record);
9027 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9031 afterCommit : function(record){
9032 this.modified.remove(record);
9033 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9037 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9038 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9040 commitChanges : function(){
9041 var m = this.modified.slice(0);
9043 for(var i = 0, len = m.length; i < len; i++){
9049 * Cancel outstanding changes on all changed records.
9051 rejectChanges : function(){
9052 var m = this.modified.slice(0);
9054 for(var i = 0, len = m.length; i < len; i++){
9059 onMetaChange : function(meta, rtype, o){
9060 this.recordType = rtype;
9061 this.fields = rtype.prototype.fields;
9062 delete this.snapshot;
9063 this.sortInfo = meta.sortInfo || this.sortInfo;
9065 this.fireEvent('metachange', this, this.reader.meta);
9068 moveIndex : function(data, type)
9070 var index = this.indexOf(data);
9072 var newIndex = index + type;
9076 this.insert(newIndex, data);
9081 * Ext JS Library 1.1.1
9082 * Copyright(c) 2006-2007, Ext JS, LLC.
9084 * Originally Released Under LGPL - original licence link has changed is not relivant.
9087 * <script type="text/javascript">
9091 * @class Roo.data.SimpleStore
9092 * @extends Roo.data.Store
9093 * Small helper class to make creating Stores from Array data easier.
9094 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9095 * @cfg {Array} fields An array of field definition objects, or field name strings.
9096 * @cfg {Array} data The multi-dimensional array of data
9098 * @param {Object} config
9100 Roo.data.SimpleStore = function(config){
9101 Roo.data.SimpleStore.superclass.constructor.call(this, {
9103 reader: new Roo.data.ArrayReader({
9106 Roo.data.Record.create(config.fields)
9108 proxy : new Roo.data.MemoryProxy(config.data)
9112 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9114 * Ext JS Library 1.1.1
9115 * Copyright(c) 2006-2007, Ext JS, LLC.
9117 * Originally Released Under LGPL - original licence link has changed is not relivant.
9120 * <script type="text/javascript">
9125 * @extends Roo.data.Store
9126 * @class Roo.data.JsonStore
9127 * Small helper class to make creating Stores for JSON data easier. <br/>
9129 var store = new Roo.data.JsonStore({
9130 url: 'get-images.php',
9132 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9135 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9136 * JsonReader and HttpProxy (unless inline data is provided).</b>
9137 * @cfg {Array} fields An array of field definition objects, or field name strings.
9139 * @param {Object} config
9141 Roo.data.JsonStore = function(c){
9142 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9143 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9144 reader: new Roo.data.JsonReader(c, c.fields)
9147 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9149 * Ext JS Library 1.1.1
9150 * Copyright(c) 2006-2007, Ext JS, LLC.
9152 * Originally Released Under LGPL - original licence link has changed is not relivant.
9155 * <script type="text/javascript">
9159 Roo.data.Field = function(config){
9160 if(typeof config == "string"){
9161 config = {name: config};
9163 Roo.apply(this, config);
9169 var st = Roo.data.SortTypes;
9170 // named sortTypes are supported, here we look them up
9171 if(typeof this.sortType == "string"){
9172 this.sortType = st[this.sortType];
9175 // set default sortType for strings and dates
9179 this.sortType = st.asUCString;
9182 this.sortType = st.asDate;
9185 this.sortType = st.none;
9190 var stripRe = /[\$,%]/g;
9192 // prebuilt conversion function for this field, instead of
9193 // switching every time we're reading a value
9195 var cv, dateFormat = this.dateFormat;
9200 cv = function(v){ return v; };
9203 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9207 return v !== undefined && v !== null && v !== '' ?
9208 parseInt(String(v).replace(stripRe, ""), 10) : '';
9213 return v !== undefined && v !== null && v !== '' ?
9214 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9219 cv = function(v){ return v === true || v === "true" || v == 1; };
9226 if(v instanceof Date){
9230 if(dateFormat == "timestamp"){
9231 return new Date(v*1000);
9233 return Date.parseDate(v, dateFormat);
9235 var parsed = Date.parse(v);
9236 return parsed ? new Date(parsed) : null;
9245 Roo.data.Field.prototype = {
9253 * Ext JS Library 1.1.1
9254 * Copyright(c) 2006-2007, Ext JS, LLC.
9256 * Originally Released Under LGPL - original licence link has changed is not relivant.
9259 * <script type="text/javascript">
9262 // Base class for reading structured data from a data source. This class is intended to be
9263 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9266 * @class Roo.data.DataReader
9267 * Base class for reading structured data from a data source. This class is intended to be
9268 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9271 Roo.data.DataReader = function(meta, recordType){
9275 this.recordType = recordType instanceof Array ?
9276 Roo.data.Record.create(recordType) : recordType;
9279 Roo.data.DataReader.prototype = {
9281 * Create an empty record
9282 * @param {Object} data (optional) - overlay some values
9283 * @return {Roo.data.Record} record created.
9285 newRow : function(d) {
9287 this.recordType.prototype.fields.each(function(c) {
9289 case 'int' : da[c.name] = 0; break;
9290 case 'date' : da[c.name] = new Date(); break;
9291 case 'float' : da[c.name] = 0.0; break;
9292 case 'boolean' : da[c.name] = false; break;
9293 default : da[c.name] = ""; break;
9297 return new this.recordType(Roo.apply(da, d));
9302 * Ext JS Library 1.1.1
9303 * Copyright(c) 2006-2007, Ext JS, LLC.
9305 * Originally Released Under LGPL - original licence link has changed is not relivant.
9308 * <script type="text/javascript">
9312 * @class Roo.data.DataProxy
9313 * @extends Roo.data.Observable
9314 * This class is an abstract base class for implementations which provide retrieval of
9315 * unformatted data objects.<br>
9317 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9318 * (of the appropriate type which knows how to parse the data object) to provide a block of
9319 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9321 * Custom implementations must implement the load method as described in
9322 * {@link Roo.data.HttpProxy#load}.
9324 Roo.data.DataProxy = function(){
9328 * Fires before a network request is made to retrieve a data object.
9329 * @param {Object} This DataProxy object.
9330 * @param {Object} params The params parameter to the load function.
9335 * Fires before the load method's callback is called.
9336 * @param {Object} This DataProxy object.
9337 * @param {Object} o The data object.
9338 * @param {Object} arg The callback argument object passed to the load function.
9342 * @event loadexception
9343 * Fires if an Exception occurs during data retrieval.
9344 * @param {Object} This DataProxy object.
9345 * @param {Object} o The data object.
9346 * @param {Object} arg The callback argument object passed to the load function.
9347 * @param {Object} e The Exception.
9349 loadexception : true
9351 Roo.data.DataProxy.superclass.constructor.call(this);
9354 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9357 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9361 * Ext JS Library 1.1.1
9362 * Copyright(c) 2006-2007, Ext JS, LLC.
9364 * Originally Released Under LGPL - original licence link has changed is not relivant.
9367 * <script type="text/javascript">
9370 * @class Roo.data.MemoryProxy
9371 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9372 * to the Reader when its load method is called.
9374 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9376 Roo.data.MemoryProxy = function(data){
9380 Roo.data.MemoryProxy.superclass.constructor.call(this);
9384 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9386 * Load data from the requested source (in this case an in-memory
9387 * data object passed to the constructor), read the data object into
9388 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9389 * process that block using the passed callback.
9390 * @param {Object} params This parameter is not used by the MemoryProxy class.
9391 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9392 * object into a block of Roo.data.Records.
9393 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9394 * The function must be passed <ul>
9395 * <li>The Record block object</li>
9396 * <li>The "arg" argument from the load function</li>
9397 * <li>A boolean success indicator</li>
9399 * @param {Object} scope The scope in which to call the callback
9400 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9402 load : function(params, reader, callback, scope, arg){
9403 params = params || {};
9406 result = reader.readRecords(this.data);
9408 this.fireEvent("loadexception", this, arg, null, e);
9409 callback.call(scope, null, arg, false);
9412 callback.call(scope, result, arg, true);
9416 update : function(params, records){
9421 * Ext JS Library 1.1.1
9422 * Copyright(c) 2006-2007, Ext JS, LLC.
9424 * Originally Released Under LGPL - original licence link has changed is not relivant.
9427 * <script type="text/javascript">
9430 * @class Roo.data.HttpProxy
9431 * @extends Roo.data.DataProxy
9432 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9433 * configured to reference a certain URL.<br><br>
9435 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9436 * from which the running page was served.<br><br>
9438 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9440 * Be aware that to enable the browser to parse an XML document, the server must set
9441 * the Content-Type header in the HTTP response to "text/xml".
9443 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9444 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9445 * will be used to make the request.
9447 Roo.data.HttpProxy = function(conn){
9448 Roo.data.HttpProxy.superclass.constructor.call(this);
9449 // is conn a conn config or a real conn?
9451 this.useAjax = !conn || !conn.events;
9455 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9456 // thse are take from connection...
9459 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9462 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9463 * extra parameters to each request made by this object. (defaults to undefined)
9466 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9467 * to each request made by this object. (defaults to undefined)
9470 * @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)
9473 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9476 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9482 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9486 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9487 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9488 * a finer-grained basis than the DataProxy events.
9490 getConnection : function(){
9491 return this.useAjax ? Roo.Ajax : this.conn;
9495 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9496 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9497 * process that block using the passed callback.
9498 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9499 * for the request to the remote server.
9500 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9501 * object into a block of Roo.data.Records.
9502 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9503 * The function must be passed <ul>
9504 * <li>The Record block object</li>
9505 * <li>The "arg" argument from the load function</li>
9506 * <li>A boolean success indicator</li>
9508 * @param {Object} scope The scope in which to call the callback
9509 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9511 load : function(params, reader, callback, scope, arg){
9512 if(this.fireEvent("beforeload", this, params) !== false){
9514 params : params || {},
9516 callback : callback,
9521 callback : this.loadResponse,
9525 Roo.applyIf(o, this.conn);
9526 if(this.activeRequest){
9527 Roo.Ajax.abort(this.activeRequest);
9529 this.activeRequest = Roo.Ajax.request(o);
9531 this.conn.request(o);
9534 callback.call(scope||this, null, arg, false);
9539 loadResponse : function(o, success, response){
9540 delete this.activeRequest;
9542 this.fireEvent("loadexception", this, o, response);
9543 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9548 result = o.reader.read(response);
9550 this.fireEvent("loadexception", this, o, response, e);
9551 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9555 this.fireEvent("load", this, o, o.request.arg);
9556 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9560 update : function(dataSet){
9565 updateResponse : function(dataSet){
9570 * Ext JS Library 1.1.1
9571 * Copyright(c) 2006-2007, Ext JS, LLC.
9573 * Originally Released Under LGPL - original licence link has changed is not relivant.
9576 * <script type="text/javascript">
9580 * @class Roo.data.ScriptTagProxy
9581 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9582 * other than the originating domain of the running page.<br><br>
9584 * <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
9585 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9587 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9588 * source code that is used as the source inside a <script> tag.<br><br>
9590 * In order for the browser to process the returned data, the server must wrap the data object
9591 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9592 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9593 * depending on whether the callback name was passed:
9596 boolean scriptTag = false;
9597 String cb = request.getParameter("callback");
9600 response.setContentType("text/javascript");
9602 response.setContentType("application/x-json");
9604 Writer out = response.getWriter();
9606 out.write(cb + "(");
9608 out.print(dataBlock.toJsonString());
9615 * @param {Object} config A configuration object.
9617 Roo.data.ScriptTagProxy = function(config){
9618 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9619 Roo.apply(this, config);
9620 this.head = document.getElementsByTagName("head")[0];
9623 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9625 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9627 * @cfg {String} url The URL from which to request the data object.
9630 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9634 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9635 * the server the name of the callback function set up by the load call to process the returned data object.
9636 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9637 * javascript output which calls this named function passing the data object as its only parameter.
9639 callbackParam : "callback",
9641 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9642 * name to the request.
9647 * Load data from the configured URL, read the data object into
9648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9649 * process that block using the passed callback.
9650 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9651 * for the request to the remote server.
9652 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9653 * object into a block of Roo.data.Records.
9654 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9655 * The function must be passed <ul>
9656 * <li>The Record block object</li>
9657 * <li>The "arg" argument from the load function</li>
9658 * <li>A boolean success indicator</li>
9660 * @param {Object} scope The scope in which to call the callback
9661 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9663 load : function(params, reader, callback, scope, arg){
9664 if(this.fireEvent("beforeload", this, params) !== false){
9666 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9669 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9671 url += "&_dc=" + (new Date().getTime());
9673 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9676 cb : "stcCallback"+transId,
9677 scriptId : "stcScript"+transId,
9681 callback : callback,
9687 window[trans.cb] = function(o){
9688 conn.handleResponse(o, trans);
9691 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9693 if(this.autoAbort !== false){
9697 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9699 var script = document.createElement("script");
9700 script.setAttribute("src", url);
9701 script.setAttribute("type", "text/javascript");
9702 script.setAttribute("id", trans.scriptId);
9703 this.head.appendChild(script);
9707 callback.call(scope||this, null, arg, false);
9712 isLoading : function(){
9713 return this.trans ? true : false;
9717 * Abort the current server request.
9720 if(this.isLoading()){
9721 this.destroyTrans(this.trans);
9726 destroyTrans : function(trans, isLoaded){
9727 this.head.removeChild(document.getElementById(trans.scriptId));
9728 clearTimeout(trans.timeoutId);
9730 window[trans.cb] = undefined;
9732 delete window[trans.cb];
9735 // if hasn't been loaded, wait for load to remove it to prevent script error
9736 window[trans.cb] = function(){
9737 window[trans.cb] = undefined;
9739 delete window[trans.cb];
9746 handleResponse : function(o, trans){
9748 this.destroyTrans(trans, true);
9751 result = trans.reader.readRecords(o);
9753 this.fireEvent("loadexception", this, o, trans.arg, e);
9754 trans.callback.call(trans.scope||window, null, trans.arg, false);
9757 this.fireEvent("load", this, o, trans.arg);
9758 trans.callback.call(trans.scope||window, result, trans.arg, true);
9762 handleFailure : function(trans){
9764 this.destroyTrans(trans, false);
9765 this.fireEvent("loadexception", this, null, trans.arg);
9766 trans.callback.call(trans.scope||window, null, trans.arg, false);
9770 * Ext JS Library 1.1.1
9771 * Copyright(c) 2006-2007, Ext JS, LLC.
9773 * Originally Released Under LGPL - original licence link has changed is not relivant.
9776 * <script type="text/javascript">
9780 * @class Roo.data.JsonReader
9781 * @extends Roo.data.DataReader
9782 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9783 * based on mappings in a provided Roo.data.Record constructor.
9785 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9786 * in the reply previously.
9791 var RecordDef = Roo.data.Record.create([
9792 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9793 {name: 'occupation'} // This field will use "occupation" as the mapping.
9795 var myReader = new Roo.data.JsonReader({
9796 totalProperty: "results", // The property which contains the total dataset size (optional)
9797 root: "rows", // The property which contains an Array of row objects
9798 id: "id" // The property within each row object that provides an ID for the record (optional)
9802 * This would consume a JSON file like this:
9804 { 'results': 2, 'rows': [
9805 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9806 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9809 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9810 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9811 * paged from the remote server.
9812 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9813 * @cfg {String} root name of the property which contains the Array of row objects.
9814 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9816 * Create a new JsonReader
9817 * @param {Object} meta Metadata configuration options
9818 * @param {Object} recordType Either an Array of field definition objects,
9819 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9821 Roo.data.JsonReader = function(meta, recordType){
9824 // set some defaults:
9826 totalProperty: 'total',
9827 successProperty : 'success',
9832 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9834 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9837 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9838 * Used by Store query builder to append _requestMeta to params.
9841 metaFromRemote : false,
9843 * This method is only used by a DataProxy which has retrieved data from a remote server.
9844 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9845 * @return {Object} data A data block which is used by an Roo.data.Store object as
9846 * a cache of Roo.data.Records.
9848 read : function(response){
9849 var json = response.responseText;
9851 var o = /* eval:var:o */ eval("("+json+")");
9853 throw {message: "JsonReader.read: Json object not found"};
9859 this.metaFromRemote = true;
9860 this.meta = o.metaData;
9861 this.recordType = Roo.data.Record.create(o.metaData.fields);
9862 this.onMetaChange(this.meta, this.recordType, o);
9864 return this.readRecords(o);
9867 // private function a store will implement
9868 onMetaChange : function(meta, recordType, o){
9875 simpleAccess: function(obj, subsc) {
9882 getJsonAccessor: function(){
9884 return function(expr) {
9886 return(re.test(expr))
9887 ? new Function("obj", "return obj." + expr)
9897 * Create a data block containing Roo.data.Records from an XML document.
9898 * @param {Object} o An object which contains an Array of row objects in the property specified
9899 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9900 * which contains the total size of the dataset.
9901 * @return {Object} data A data block which is used by an Roo.data.Store object as
9902 * a cache of Roo.data.Records.
9904 readRecords : function(o){
9906 * After any data loads, the raw JSON data is available for further custom processing.
9910 var s = this.meta, Record = this.recordType,
9911 f = Record.prototype.fields, fi = f.items, fl = f.length;
9913 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9915 if(s.totalProperty) {
9916 this.getTotal = this.getJsonAccessor(s.totalProperty);
9918 if(s.successProperty) {
9919 this.getSuccess = this.getJsonAccessor(s.successProperty);
9921 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9923 var g = this.getJsonAccessor(s.id);
9924 this.getId = function(rec) {
9926 return (r === undefined || r === "") ? null : r;
9929 this.getId = function(){return null;};
9932 for(var jj = 0; jj < fl; jj++){
9934 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9935 this.ef[jj] = this.getJsonAccessor(map);
9939 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9940 if(s.totalProperty){
9941 var vt = parseInt(this.getTotal(o), 10);
9946 if(s.successProperty){
9947 var vs = this.getSuccess(o);
9948 if(vs === false || vs === 'false'){
9953 for(var i = 0; i < c; i++){
9956 var id = this.getId(n);
9957 for(var j = 0; j < fl; j++){
9959 var v = this.ef[j](n);
9961 Roo.log('missing convert for ' + f.name);
9965 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9967 var record = new Record(values, id);
9969 records[i] = record;
9975 totalRecords : totalRecords
9980 * Ext JS Library 1.1.1
9981 * Copyright(c) 2006-2007, Ext JS, LLC.
9983 * Originally Released Under LGPL - original licence link has changed is not relivant.
9986 * <script type="text/javascript">
9990 * @class Roo.data.ArrayReader
9991 * @extends Roo.data.DataReader
9992 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9993 * Each element of that Array represents a row of data fields. The
9994 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9995 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9999 var RecordDef = Roo.data.Record.create([
10000 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10001 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10003 var myReader = new Roo.data.ArrayReader({
10004 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10008 * This would consume an Array like this:
10010 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10012 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10014 * Create a new JsonReader
10015 * @param {Object} meta Metadata configuration options.
10016 * @param {Object} recordType Either an Array of field definition objects
10017 * as specified to {@link Roo.data.Record#create},
10018 * or an {@link Roo.data.Record} object
10019 * created using {@link Roo.data.Record#create}.
10021 Roo.data.ArrayReader = function(meta, recordType){
10022 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10025 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10027 * Create a data block containing Roo.data.Records from an XML document.
10028 * @param {Object} o An Array of row objects which represents the dataset.
10029 * @return {Object} data A data block which is used by an Roo.data.Store object as
10030 * a cache of Roo.data.Records.
10032 readRecords : function(o){
10033 var sid = this.meta ? this.meta.id : null;
10034 var recordType = this.recordType, fields = recordType.prototype.fields;
10037 for(var i = 0; i < root.length; i++){
10040 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10041 for(var j = 0, jlen = fields.length; j < jlen; j++){
10042 var f = fields.items[j];
10043 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10044 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10046 values[f.name] = v;
10048 var record = new recordType(values, id);
10050 records[records.length] = record;
10054 totalRecords : records.length
10063 * @class Roo.bootstrap.ComboBox
10064 * @extends Roo.bootstrap.TriggerField
10065 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10066 * @cfg {Boolean} append (true|false) default false
10067 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10068 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10069 * @cfg {Boolean} editNotList allow text type,but not show pull down, default false
10070 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10072 * Create a new ComboBox.
10073 * @param {Object} config Configuration options
10075 Roo.bootstrap.ComboBox = function(config){
10076 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10080 * Fires when the dropdown list is expanded
10081 * @param {Roo.bootstrap.ComboBox} combo This combo box
10086 * Fires when the dropdown list is collapsed
10087 * @param {Roo.bootstrap.ComboBox} combo This combo box
10091 * @event beforeselect
10092 * Fires before a list item is selected. Return false to cancel the selection.
10093 * @param {Roo.bootstrap.ComboBox} combo This combo box
10094 * @param {Roo.data.Record} record The data record returned from the underlying store
10095 * @param {Number} index The index of the selected item in the dropdown list
10097 'beforeselect' : true,
10100 * Fires when a list item is selected
10101 * @param {Roo.bootstrap.ComboBox} combo This combo box
10102 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10103 * @param {Number} index The index of the selected item in the dropdown list
10107 * @event beforequery
10108 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10109 * The event object passed has these properties:
10110 * @param {Roo.bootstrap.ComboBox} combo This combo box
10111 * @param {String} query The query
10112 * @param {Boolean} forceAll true to force "all" query
10113 * @param {Boolean} cancel true to cancel the query
10114 * @param {Object} e The query event object
10116 'beforequery': true,
10119 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10120 * @param {Roo.bootstrap.ComboBox} combo This combo box
10125 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10126 * @param {Roo.bootstrap.ComboBox} combo This combo box
10127 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10132 * Fires when the remove value from the combobox array
10133 * @param {Roo.bootstrap.ComboBox} combo This combo box
10140 this.tickItems = [];
10142 this.selectedIndex = -1;
10143 if(this.mode == 'local'){
10144 if(config.queryDelay === undefined){
10145 this.queryDelay = 10;
10147 if(config.minChars === undefined){
10153 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10156 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10157 * rendering into an Roo.Editor, defaults to false)
10160 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10161 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10164 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10167 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10168 * the dropdown list (defaults to undefined, with no header element)
10172 * @cfg {String/Roo.Template} tpl The template to use to render the output
10176 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10178 listWidth: undefined,
10180 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10181 * mode = 'remote' or 'text' if mode = 'local')
10183 displayField: undefined,
10185 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10186 * mode = 'remote' or 'value' if mode = 'local').
10187 * Note: use of a valueField requires the user make a selection
10188 * in order for a value to be mapped.
10190 valueField: undefined,
10194 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10195 * field's data value (defaults to the underlying DOM element's name)
10197 hiddenName: undefined,
10199 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10203 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10205 selectedClass: 'active',
10208 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10212 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10213 * anchor positions (defaults to 'tl-bl')
10215 listAlign: 'tl-bl?',
10217 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10221 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10222 * query specified by the allQuery config option (defaults to 'query')
10224 triggerAction: 'query',
10226 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10227 * (defaults to 4, does not apply if editable = false)
10231 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10232 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10236 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10237 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10241 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10242 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10246 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10247 * when editable = true (defaults to false)
10249 selectOnFocus:false,
10251 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10253 queryParam: 'query',
10255 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10256 * when mode = 'remote' (defaults to 'Loading...')
10258 loadingText: 'Loading...',
10260 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10264 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10268 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10269 * traditional select (defaults to true)
10273 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10277 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10281 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10282 * listWidth has a higher value)
10286 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10287 * allow the user to set arbitrary text into the field (defaults to false)
10289 forceSelection:false,
10291 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10292 * if typeAhead = true (defaults to 250)
10294 typeAheadDelay : 250,
10296 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10297 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10299 valueNotFoundText : undefined,
10301 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10303 blockFocus : false,
10306 * @cfg {Boolean} disableClear Disable showing of clear button.
10308 disableClear : false,
10310 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10312 alwaysQuery : false,
10315 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10329 btnPosition : 'right',
10330 editNotList : false,
10331 // element that contains real text value.. (when hidden is used..)
10333 getAutoCreate : function()
10340 if(!this.tickable){
10341 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10346 * ComboBox with tickable selections
10349 var align = this.labelAlign || this.parentLabelAlign();
10352 cls : 'form-group roo-combobox-tickable' //input-group
10358 cls : 'tickable-buttons',
10363 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10370 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10377 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10384 Roo.each(buttons.cn, function(c){
10386 c.cls += ' btn-' + _this.size;
10389 if (_this.disabled) {
10400 cls: 'form-hidden-field'
10404 cls: 'select2-choices',
10408 cls: 'select2-search-field',
10420 cls: 'select2-container input-group select2-container-multi',
10425 cls: 'typeahead typeahead-long dropdown-menu',
10426 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10431 if (align ==='left' && this.fieldLabel.length) {
10433 Roo.log("left and has label");
10439 cls : 'control-label col-sm-' + this.labelWidth,
10440 html : this.fieldLabel
10444 cls : "col-sm-" + (12 - this.labelWidth),
10451 } else if ( this.fieldLabel.length) {
10457 //cls : 'input-group-addon',
10458 html : this.fieldLabel
10468 Roo.log(" no label && no align");
10475 ['xs','sm','md','lg'].map(function(size){
10476 if (settings[size]) {
10477 cfg.cls += ' col-' + size + '-' + settings[size];
10486 initEvents: function()
10490 throw "can not find store for combo";
10492 this.store = Roo.factory(this.store, Roo.data);
10495 this.initTickableEvnets();
10499 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10502 if(this.hiddenName){
10504 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10506 this.hiddenField.dom.value =
10507 this.hiddenValue !== undefined ? this.hiddenValue :
10508 this.value !== undefined ? this.value : '';
10510 // prevent input submission
10511 this.el.dom.removeAttribute('name');
10512 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10517 // this.el.dom.setAttribute('autocomplete', 'off');
10520 var cls = 'x-combo-list';
10521 this.list = this.el.select('ul.dropdown-menu',true).first();
10523 //this.list = new Roo.Layer({
10524 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10530 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10531 _this.list.setWidth(lw);
10534 this.list.on('mouseover', this.onViewOver, this);
10535 this.list.on('mousemove', this.onViewMove, this);
10537 this.list.on('scroll', this.onViewScroll, this);
10540 this.list.swallowEvent('mousewheel');
10541 this.assetHeight = 0;
10544 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10545 this.assetHeight += this.header.getHeight();
10548 this.innerList = this.list.createChild({cls:cls+'-inner'});
10549 this.innerList.on('mouseover', this.onViewOver, this);
10550 this.innerList.on('mousemove', this.onViewMove, this);
10551 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10553 if(this.allowBlank && !this.pageSize && !this.disableClear){
10554 this.footer = this.list.createChild({cls:cls+'-ft'});
10555 this.pageTb = new Roo.Toolbar(this.footer);
10559 this.footer = this.list.createChild({cls:cls+'-ft'});
10560 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10561 {pageSize: this.pageSize});
10565 if (this.pageTb && this.allowBlank && !this.disableClear) {
10567 this.pageTb.add(new Roo.Toolbar.Fill(), {
10568 cls: 'x-btn-icon x-btn-clear',
10570 handler: function()
10573 _this.clearValue();
10574 _this.onSelect(false, -1);
10579 this.assetHeight += this.footer.getHeight();
10584 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10587 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10588 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10590 //this.view.wrapEl.setDisplayed(false);
10591 this.view.on('click', this.onViewClick, this);
10595 this.store.on('beforeload', this.onBeforeLoad, this);
10596 this.store.on('load', this.onLoad, this);
10597 this.store.on('loadexception', this.onLoadException, this);
10599 if(this.resizable){
10600 this.resizer = new Roo.Resizable(this.list, {
10601 pinned:true, handles:'se'
10603 this.resizer.on('resize', function(r, w, h){
10604 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10605 this.listWidth = w;
10606 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10607 this.restrictHeight();
10609 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10612 if(!this.editable){
10613 this.editable = true;
10614 this.setEditable(false);
10619 if (typeof(this.events.add.listeners) != 'undefined') {
10621 this.addicon = this.wrap.createChild(
10622 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10624 this.addicon.on('click', function(e) {
10625 this.fireEvent('add', this);
10628 if (typeof(this.events.edit.listeners) != 'undefined') {
10630 this.editicon = this.wrap.createChild(
10631 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10632 if (this.addicon) {
10633 this.editicon.setStyle('margin-left', '40px');
10635 this.editicon.on('click', function(e) {
10637 // we fire even if inothing is selected..
10638 this.fireEvent('edit', this, this.lastData );
10644 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10645 "up" : function(e){
10646 this.inKeyMode = true;
10650 "down" : function(e){
10651 if(!this.isExpanded()){
10652 this.onTriggerClick();
10654 this.inKeyMode = true;
10659 "enter" : function(e){
10660 // this.onViewClick();
10664 if(this.fireEvent("specialkey", this, e)){
10665 this.onViewClick(false);
10671 "esc" : function(e){
10675 "tab" : function(e){
10678 if(this.fireEvent("specialkey", this, e)){
10679 this.onViewClick(false);
10687 doRelay : function(foo, bar, hname){
10688 if(hname == 'down' || this.scope.isExpanded()){
10689 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10698 this.queryDelay = Math.max(this.queryDelay || 10,
10699 this.mode == 'local' ? 10 : 250);
10702 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10704 if(this.typeAhead){
10705 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10707 if(this.editable !== false){
10708 this.inputEl().on("keyup", this.onKeyUp, this);
10710 if(this.forceSelection){
10711 this.inputEl().on('blur', this.doForce, this);
10715 this.choices = this.el.select('ul.select2-choices', true).first();
10716 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10720 initTickableEvnets: function()
10722 if(this.hiddenName){
10724 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10726 this.hiddenField.dom.value =
10727 this.hiddenValue !== undefined ? this.hiddenValue :
10728 this.value !== undefined ? this.value : '';
10730 // prevent input submission
10731 this.el.dom.removeAttribute('name');
10732 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10737 this.list = this.el.select('ul.dropdown-menu',true).first();
10739 this.choices = this.el.select('ul.select2-choices', true).first();
10740 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10741 if(this.editNotList){
10742 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10745 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10746 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10748 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10749 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10751 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10752 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10754 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10755 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10756 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10759 this.cancelBtn.hide();
10764 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10765 _this.list.setWidth(lw);
10768 this.list.on('mouseover', this.onViewOver, this);
10769 this.list.on('mousemove', this.onViewMove, this);
10771 this.list.on('scroll', this.onViewScroll, this);
10774 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>';
10777 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10778 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10781 //this.view.wrapEl.setDisplayed(false);
10782 this.view.on('click', this.onViewClick, this);
10786 this.store.on('beforeload', this.onBeforeLoad, this);
10787 this.store.on('load', this.onLoad, this);
10788 this.store.on('loadexception', this.onLoadException, this);
10790 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10791 // "up" : function(e){
10792 // this.inKeyMode = true;
10793 // this.selectPrev();
10796 // "down" : function(e){
10797 // if(!this.isExpanded()){
10798 // this.onTriggerClick();
10800 // this.inKeyMode = true;
10801 // this.selectNext();
10805 // "enter" : function(e){
10806 //// this.onViewClick();
10808 // this.collapse();
10810 // if(this.fireEvent("specialkey", this, e)){
10811 // this.onViewClick(false);
10817 // "esc" : function(e){
10818 // this.collapse();
10821 // "tab" : function(e){
10822 // this.collapse();
10824 // if(this.fireEvent("specialkey", this, e)){
10825 // this.onViewClick(false);
10833 // doRelay : function(foo, bar, hname){
10834 // if(hname == 'down' || this.scope.isExpanded()){
10835 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10840 // forceKeyDown: true
10844 this.queryDelay = Math.max(this.queryDelay || 10,
10845 this.mode == 'local' ? 10 : 250);
10848 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10850 if(this.typeAhead){
10851 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10855 onDestroy : function(){
10857 this.view.setStore(null);
10858 this.view.el.removeAllListeners();
10859 this.view.el.remove();
10860 this.view.purgeListeners();
10863 this.list.dom.innerHTML = '';
10867 this.store.un('beforeload', this.onBeforeLoad, this);
10868 this.store.un('load', this.onLoad, this);
10869 this.store.un('loadexception', this.onLoadException, this);
10871 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10875 fireKey : function(e){
10876 if(e.isNavKeyPress() && !this.list.isVisible()){
10877 this.fireEvent("specialkey", this, e);
10882 onResize: function(w, h){
10883 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10885 // if(typeof w != 'number'){
10886 // // we do not handle it!?!?
10889 // var tw = this.trigger.getWidth();
10890 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10891 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10893 // this.inputEl().setWidth( this.adjustWidth('input', x));
10895 // //this.trigger.setStyle('left', x+'px');
10897 // if(this.list && this.listWidth === undefined){
10898 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10899 // this.list.setWidth(lw);
10900 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10908 * Allow or prevent the user from directly editing the field text. If false is passed,
10909 * the user will only be able to select from the items defined in the dropdown list. This method
10910 * is the runtime equivalent of setting the 'editable' config option at config time.
10911 * @param {Boolean} value True to allow the user to directly edit the field text
10913 setEditable : function(value){
10914 if(value == this.editable){
10917 this.editable = value;
10919 this.inputEl().dom.setAttribute('readOnly', true);
10920 this.inputEl().on('mousedown', this.onTriggerClick, this);
10921 this.inputEl().addClass('x-combo-noedit');
10923 this.inputEl().dom.setAttribute('readOnly', false);
10924 this.inputEl().un('mousedown', this.onTriggerClick, this);
10925 this.inputEl().removeClass('x-combo-noedit');
10931 onBeforeLoad : function(combo,opts){
10932 if(!this.hasFocus){
10936 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10938 this.restrictHeight();
10939 this.selectedIndex = -1;
10943 onLoad : function(){
10945 this.hasQuery = false;
10947 if(!this.hasFocus){
10951 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10952 this.loading.hide();
10955 if(this.store.getCount() > 0){
10957 this.restrictHeight();
10958 if(this.lastQuery == this.allQuery){
10959 if(this.editable && !this.tickable){
10960 this.inputEl().dom.select();
10962 if(!this.selectByValue(this.value, true) && this.autoFocus){
10963 this.select(0, true);
10966 if(this.autoFocus){
10969 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10970 this.taTask.delay(this.typeAheadDelay);
10974 this.onEmptyResults();
10980 onLoadException : function()
10982 this.hasQuery = false;
10984 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10985 this.loading.hide();
10989 Roo.log(this.store.reader.jsonData);
10990 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10992 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10998 onTypeAhead : function(){
10999 if(this.store.getCount() > 0){
11000 var r = this.store.getAt(0);
11001 var newValue = r.data[this.displayField];
11002 var len = newValue.length;
11003 var selStart = this.getRawValue().length;
11005 if(selStart != len){
11006 this.setRawValue(newValue);
11007 this.selectText(selStart, newValue.length);
11013 onSelect : function(record, index){
11015 if(this.fireEvent('beforeselect', this, record, index) !== false){
11017 this.setFromData(index > -1 ? record.data : false);
11020 this.fireEvent('select', this, record, index);
11025 * Returns the currently selected field value or empty string if no value is set.
11026 * @return {String} value The selected value
11028 getValue : function(){
11031 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11034 if(this.valueField){
11035 return typeof this.value != 'undefined' ? this.value : '';
11037 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11042 * Clears any text/value currently set in the field
11044 clearValue : function(){
11045 if(this.hiddenField){
11046 this.hiddenField.dom.value = '';
11049 this.setRawValue('');
11050 this.lastSelectionText = '';
11055 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11056 * will be displayed in the field. If the value does not match the data value of an existing item,
11057 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11058 * Otherwise the field will be blank (although the value will still be set).
11059 * @param {String} value The value to match
11061 setValue : function(v){
11068 if(this.valueField){
11069 var r = this.findRecord(this.valueField, v);
11071 text = r.data[this.displayField];
11072 }else if(this.valueNotFoundText !== undefined){
11073 text = this.valueNotFoundText;
11076 this.lastSelectionText = text;
11077 if(this.hiddenField){
11078 this.hiddenField.dom.value = v;
11080 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11084 * @property {Object} the last set data for the element
11089 * Sets the value of the field based on a object which is related to the record format for the store.
11090 * @param {Object} value the value to set as. or false on reset?
11092 setFromData : function(o){
11099 var dv = ''; // display value
11100 var vv = ''; // value value..
11102 if (this.displayField) {
11103 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11105 // this is an error condition!!!
11106 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11109 if(this.valueField){
11110 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11113 if(this.hiddenField){
11114 this.hiddenField.dom.value = vv;
11116 this.lastSelectionText = dv;
11117 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11121 // no hidden field.. - we store the value in 'value', but still display
11122 // display field!!!!
11123 this.lastSelectionText = dv;
11124 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11130 reset : function(){
11131 // overridden so that last data is reset..
11132 this.setValue(this.originalValue);
11133 this.clearInvalid();
11134 this.lastData = false;
11136 this.view.clearSelections();
11140 findRecord : function(prop, value){
11142 if(this.store.getCount() > 0){
11143 this.store.each(function(r){
11144 if(r.data[prop] == value){
11154 getName: function()
11156 // returns hidden if it's set..
11157 if (!this.rendered) {return ''};
11158 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11162 onViewMove : function(e, t){
11163 this.inKeyMode = false;
11167 onViewOver : function(e, t){
11168 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11171 var item = this.view.findItemFromChild(t);
11174 var index = this.view.indexOf(item);
11175 this.select(index, false);
11180 onViewClick : function(view, doFocus, el, e)
11182 var index = this.view.getSelectedIndexes()[0];
11184 var r = this.store.getAt(index);
11188 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11195 Roo.each(this.tickItems, function(v,k){
11197 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11198 _this.tickItems.splice(k, 1);
11208 this.tickItems.push(r.data);
11213 this.onSelect(r, index);
11215 if(doFocus !== false && !this.blockFocus){
11216 this.inputEl().focus();
11221 restrictHeight : function(){
11222 //this.innerList.dom.style.height = '';
11223 //var inner = this.innerList.dom;
11224 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11225 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11226 //this.list.beginUpdate();
11227 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11228 this.list.alignTo(this.inputEl(), this.listAlign);
11229 //this.list.endUpdate();
11233 onEmptyResults : function(){
11238 * Returns true if the dropdown list is expanded, else false.
11240 isExpanded : function(){
11241 return this.list.isVisible();
11245 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11246 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11247 * @param {String} value The data value of the item to select
11248 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11249 * selected item if it is not currently in view (defaults to true)
11250 * @return {Boolean} True if the value matched an item in the list, else false
11252 selectByValue : function(v, scrollIntoView){
11253 if(v !== undefined && v !== null){
11254 var r = this.findRecord(this.valueField || this.displayField, v);
11256 this.select(this.store.indexOf(r), scrollIntoView);
11264 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11265 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11266 * @param {Number} index The zero-based index of the list item to select
11267 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11268 * selected item if it is not currently in view (defaults to true)
11270 select : function(index, scrollIntoView){
11271 this.selectedIndex = index;
11272 this.view.select(index);
11273 if(scrollIntoView !== false){
11274 var el = this.view.getNode(index);
11276 //this.innerList.scrollChildIntoView(el, false);
11283 selectNext : function(){
11284 var ct = this.store.getCount();
11286 if(this.selectedIndex == -1){
11288 }else if(this.selectedIndex < ct-1){
11289 this.select(this.selectedIndex+1);
11295 selectPrev : function(){
11296 var ct = this.store.getCount();
11298 if(this.selectedIndex == -1){
11300 }else if(this.selectedIndex != 0){
11301 this.select(this.selectedIndex-1);
11307 onKeyUp : function(e){
11308 if(this.editable !== false && !e.isSpecialKey()){
11309 this.lastKey = e.getKey();
11310 this.dqTask.delay(this.queryDelay);
11315 validateBlur : function(){
11316 return !this.list || !this.list.isVisible();
11320 initQuery : function(){
11321 this.doQuery(this.getRawValue());
11325 doForce : function(){
11326 if(this.inputEl().dom.value.length > 0){
11327 this.inputEl().dom.value =
11328 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11334 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11335 * query allowing the query action to be canceled if needed.
11336 * @param {String} query The SQL query to execute
11337 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11338 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11339 * saved in the current store (defaults to false)
11341 doQuery : function(q, forceAll){
11343 if(q === undefined || q === null){
11348 forceAll: forceAll,
11352 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11357 forceAll = qe.forceAll;
11358 if(forceAll === true || (q.length >= this.minChars)){
11360 this.hasQuery = true;
11362 if(this.lastQuery != q || this.alwaysQuery){
11363 this.lastQuery = q;
11364 if(this.mode == 'local'){
11365 this.selectedIndex = -1;
11367 this.store.clearFilter();
11369 this.store.filter(this.displayField, q);
11373 this.store.baseParams[this.queryParam] = q;
11375 var options = {params : this.getParams(q)};
11378 options.add = true;
11379 options.params.start = this.page * this.pageSize;
11382 this.store.load(options);
11384 * this code will make the page width larger, at the beginning, the list not align correctly,
11385 * we should expand the list on onLoad
11386 * so command out it
11391 this.selectedIndex = -1;
11396 this.loadNext = false;
11400 getParams : function(q){
11402 //p[this.queryParam] = q;
11406 p.limit = this.pageSize;
11412 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11414 collapse : function(){
11415 if(!this.isExpanded()){
11419 this.hasFocus = false;
11425 this.cancelBtn.hide();
11426 this.trigger.show();
11429 Roo.get(document).un('mousedown', this.collapseIf, this);
11430 Roo.get(document).un('mousewheel', this.collapseIf, this);
11431 if (!this.editable) {
11432 Roo.get(document).un('keydown', this.listKeyPress, this);
11434 this.fireEvent('collapse', this);
11438 collapseIf : function(e){
11439 var in_combo = e.within(this.el);
11440 var in_list = e.within(this.list);
11442 if (in_combo || in_list) {
11443 //e.stopPropagation();
11448 this.onTickableFooterButtonClick(e, false, false);
11456 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11458 expand : function(){
11460 if(this.isExpanded() || !this.hasFocus){
11464 this.list.alignTo(this.inputEl(), this.listAlign);
11469 this.tickItems = Roo.apply([], this.item);
11472 this.cancelBtn.show();
11473 this.trigger.hide();
11477 Roo.get(document).on('mousedown', this.collapseIf, this);
11478 Roo.get(document).on('mousewheel', this.collapseIf, this);
11479 if (!this.editable) {
11480 Roo.get(document).on('keydown', this.listKeyPress, this);
11483 this.fireEvent('expand', this);
11487 // Implements the default empty TriggerField.onTriggerClick function
11488 onTriggerClick : function(e)
11490 Roo.log('trigger click');
11492 if(this.disabled || this.editNotList){
11497 this.loadNext = false;
11499 if(this.isExpanded()){
11501 if (!this.blockFocus) {
11502 this.inputEl().focus();
11506 this.hasFocus = true;
11507 if(this.triggerAction == 'all') {
11508 this.doQuery(this.allQuery, true);
11510 this.doQuery(this.getRawValue());
11512 if (!this.blockFocus) {
11513 this.inputEl().focus();
11518 onTickableTriggerClick : function(e)
11525 this.loadNext = false;
11526 this.hasFocus = true;
11528 if(this.triggerAction == 'all') {
11529 this.doQuery(this.allQuery, true);
11531 this.doQuery(this.getRawValue());
11535 onSearchFieldClick : function(e)
11537 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11542 this.loadNext = false;
11543 this.hasFocus = true;
11545 if(this.triggerAction == 'all') {
11546 this.doQuery(this.allQuery, true);
11548 this.doQuery(this.getRawValue());
11552 listKeyPress : function(e)
11554 //Roo.log('listkeypress');
11555 // scroll to first matching element based on key pres..
11556 if (e.isSpecialKey()) {
11559 var k = String.fromCharCode(e.getKey()).toUpperCase();
11562 var csel = this.view.getSelectedNodes();
11563 var cselitem = false;
11565 var ix = this.view.indexOf(csel[0]);
11566 cselitem = this.store.getAt(ix);
11567 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11573 this.store.each(function(v) {
11575 // start at existing selection.
11576 if (cselitem.id == v.id) {
11582 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11583 match = this.store.indexOf(v);
11589 if (match === false) {
11590 return true; // no more action?
11593 this.view.select(match);
11594 var sn = Roo.get(this.view.getSelectedNodes()[0])
11595 //sn.scrollIntoView(sn.dom.parentNode, false);
11598 onViewScroll : function(e, t){
11600 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11604 this.hasQuery = true;
11606 this.loading = this.list.select('.loading', true).first();
11608 if(this.loading === null){
11609 this.list.createChild({
11611 cls: 'loading select2-more-results select2-active',
11612 html: 'Loading more results...'
11615 this.loading = this.list.select('.loading', true).first();
11617 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11619 this.loading.hide();
11622 this.loading.show();
11627 this.loadNext = true;
11629 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11634 addItem : function(o)
11636 var dv = ''; // display value
11638 if (this.displayField) {
11639 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11641 // this is an error condition!!!
11642 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11649 var choice = this.choices.createChild({
11651 cls: 'select2-search-choice',
11660 cls: 'select2-search-choice-close',
11665 }, this.searchField);
11667 var close = choice.select('a.select2-search-choice-close', true).first()
11669 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11677 this.inputEl().dom.value = '';
11681 onRemoveItem : function(e, _self, o)
11683 e.preventDefault();
11684 var index = this.item.indexOf(o.data) * 1;
11687 Roo.log('not this item?!');
11691 this.item.splice(index, 1);
11696 this.fireEvent('remove', this, e);
11700 syncValue : function()
11702 if(!this.item.length){
11709 Roo.each(this.item, function(i){
11710 if(_this.valueField){
11711 value.push(i[_this.valueField]);
11718 this.value = value.join(',');
11720 if(this.hiddenField){
11721 this.hiddenField.dom.value = this.value;
11725 clearItem : function()
11727 if(!this.multiple){
11733 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11740 inputEl: function ()
11743 return this.searchField;
11745 return this.el.select('input.form-control',true).first();
11749 onTickableFooterButtonClick : function(e, btn, el)
11751 e.preventDefault();
11753 if(btn && btn.name == 'cancel'){
11754 this.tickItems = Roo.apply([], this.item);
11763 Roo.each(this.tickItems, function(o){
11774 * @cfg {Boolean} grow
11778 * @cfg {Number} growMin
11782 * @cfg {Number} growMax
11792 * Ext JS Library 1.1.1
11793 * Copyright(c) 2006-2007, Ext JS, LLC.
11795 * Originally Released Under LGPL - original licence link has changed is not relivant.
11798 * <script type="text/javascript">
11803 * @extends Roo.util.Observable
11804 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11805 * This class also supports single and multi selection modes. <br>
11806 * Create a data model bound view:
11808 var store = new Roo.data.Store(...);
11810 var view = new Roo.View({
11812 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11814 singleSelect: true,
11815 selectedClass: "ydataview-selected",
11819 // listen for node click?
11820 view.on("click", function(vw, index, node, e){
11821 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11825 dataModel.load("foobar.xml");
11827 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11829 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11830 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11832 * Note: old style constructor is still suported (container, template, config)
11835 * Create a new View
11836 * @param {Object} config The config object
11839 Roo.View = function(config, depreciated_tpl, depreciated_config){
11841 this.parent = false;
11843 if (typeof(depreciated_tpl) == 'undefined') {
11844 // new way.. - universal constructor.
11845 Roo.apply(this, config);
11846 this.el = Roo.get(this.el);
11849 this.el = Roo.get(config);
11850 this.tpl = depreciated_tpl;
11851 Roo.apply(this, depreciated_config);
11853 this.wrapEl = this.el.wrap().wrap();
11854 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11857 if(typeof(this.tpl) == "string"){
11858 this.tpl = new Roo.Template(this.tpl);
11860 // support xtype ctors..
11861 this.tpl = new Roo.factory(this.tpl, Roo);
11865 this.tpl.compile();
11870 * @event beforeclick
11871 * Fires before a click is processed. Returns false to cancel the default action.
11872 * @param {Roo.View} this
11873 * @param {Number} index The index of the target node
11874 * @param {HTMLElement} node The target node
11875 * @param {Roo.EventObject} e The raw event object
11877 "beforeclick" : true,
11880 * Fires when a template node is clicked.
11881 * @param {Roo.View} this
11882 * @param {Number} index The index of the target node
11883 * @param {HTMLElement} node The target node
11884 * @param {Roo.EventObject} e The raw event object
11889 * Fires when a template node is double clicked.
11890 * @param {Roo.View} this
11891 * @param {Number} index The index of the target node
11892 * @param {HTMLElement} node The target node
11893 * @param {Roo.EventObject} e The raw event object
11897 * @event contextmenu
11898 * Fires when a template node is right clicked.
11899 * @param {Roo.View} this
11900 * @param {Number} index The index of the target node
11901 * @param {HTMLElement} node The target node
11902 * @param {Roo.EventObject} e The raw event object
11904 "contextmenu" : true,
11906 * @event selectionchange
11907 * Fires when the selected nodes change.
11908 * @param {Roo.View} this
11909 * @param {Array} selections Array of the selected nodes
11911 "selectionchange" : true,
11914 * @event beforeselect
11915 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11916 * @param {Roo.View} this
11917 * @param {HTMLElement} node The node to be selected
11918 * @param {Array} selections Array of currently selected nodes
11920 "beforeselect" : true,
11922 * @event preparedata
11923 * Fires on every row to render, to allow you to change the data.
11924 * @param {Roo.View} this
11925 * @param {Object} data to be rendered (change this)
11927 "preparedata" : true
11935 "click": this.onClick,
11936 "dblclick": this.onDblClick,
11937 "contextmenu": this.onContextMenu,
11941 this.selections = [];
11943 this.cmp = new Roo.CompositeElementLite([]);
11945 this.store = Roo.factory(this.store, Roo.data);
11946 this.setStore(this.store, true);
11949 if ( this.footer && this.footer.xtype) {
11951 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11953 this.footer.dataSource = this.store
11954 this.footer.container = fctr;
11955 this.footer = Roo.factory(this.footer, Roo);
11956 fctr.insertFirst(this.el);
11958 // this is a bit insane - as the paging toolbar seems to detach the el..
11959 // dom.parentNode.parentNode.parentNode
11960 // they get detached?
11964 Roo.View.superclass.constructor.call(this);
11969 Roo.extend(Roo.View, Roo.util.Observable, {
11972 * @cfg {Roo.data.Store} store Data store to load data from.
11977 * @cfg {String|Roo.Element} el The container element.
11982 * @cfg {String|Roo.Template} tpl The template used by this View
11986 * @cfg {String} dataName the named area of the template to use as the data area
11987 * Works with domtemplates roo-name="name"
11991 * @cfg {String} selectedClass The css class to add to selected nodes
11993 selectedClass : "x-view-selected",
11995 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12000 * @cfg {String} text to display on mask (default Loading)
12004 * @cfg {Boolean} multiSelect Allow multiple selection
12006 multiSelect : false,
12008 * @cfg {Boolean} singleSelect Allow single selection
12010 singleSelect: false,
12013 * @cfg {Boolean} toggleSelect - selecting
12015 toggleSelect : false,
12018 * @cfg {Boolean} tickable - selecting
12023 * Returns the element this view is bound to.
12024 * @return {Roo.Element}
12026 getEl : function(){
12027 return this.wrapEl;
12033 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12035 refresh : function(){
12036 Roo.log('refresh');
12039 // if we are using something like 'domtemplate', then
12040 // the what gets used is:
12041 // t.applySubtemplate(NAME, data, wrapping data..)
12042 // the outer template then get' applied with
12043 // the store 'extra data'
12044 // and the body get's added to the
12045 // roo-name="data" node?
12046 // <span class='roo-tpl-{name}'></span> ?????
12050 this.clearSelections();
12051 this.el.update("");
12053 var records = this.store.getRange();
12054 if(records.length < 1) {
12056 // is this valid?? = should it render a template??
12058 this.el.update(this.emptyText);
12062 if (this.dataName) {
12063 this.el.update(t.apply(this.store.meta)); //????
12064 el = this.el.child('.roo-tpl-' + this.dataName);
12067 for(var i = 0, len = records.length; i < len; i++){
12068 var data = this.prepareData(records[i].data, i, records[i]);
12069 this.fireEvent("preparedata", this, data, i, records[i]);
12071 var d = Roo.apply({}, data);
12074 Roo.apply(d, {'roo-id' : Roo.id()});
12078 Roo.each(this.parent.item, function(item){
12079 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12082 Roo.apply(d, {'roo-data-checked' : 'checked'});
12086 html[html.length] = Roo.util.Format.trim(
12088 t.applySubtemplate(this.dataName, d, this.store.meta) :
12095 el.update(html.join(""));
12096 this.nodes = el.dom.childNodes;
12097 this.updateIndexes(0);
12102 * Function to override to reformat the data that is sent to
12103 * the template for each node.
12104 * DEPRICATED - use the preparedata event handler.
12105 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12106 * a JSON object for an UpdateManager bound view).
12108 prepareData : function(data, index, record)
12110 this.fireEvent("preparedata", this, data, index, record);
12114 onUpdate : function(ds, record){
12115 Roo.log('on update');
12116 this.clearSelections();
12117 var index = this.store.indexOf(record);
12118 var n = this.nodes[index];
12119 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12120 n.parentNode.removeChild(n);
12121 this.updateIndexes(index, index);
12127 onAdd : function(ds, records, index)
12129 Roo.log(['on Add', ds, records, index] );
12130 this.clearSelections();
12131 if(this.nodes.length == 0){
12135 var n = this.nodes[index];
12136 for(var i = 0, len = records.length; i < len; i++){
12137 var d = this.prepareData(records[i].data, i, records[i]);
12139 this.tpl.insertBefore(n, d);
12142 this.tpl.append(this.el, d);
12145 this.updateIndexes(index);
12148 onRemove : function(ds, record, index){
12149 Roo.log('onRemove');
12150 this.clearSelections();
12151 var el = this.dataName ?
12152 this.el.child('.roo-tpl-' + this.dataName) :
12155 el.dom.removeChild(this.nodes[index]);
12156 this.updateIndexes(index);
12160 * Refresh an individual node.
12161 * @param {Number} index
12163 refreshNode : function(index){
12164 this.onUpdate(this.store, this.store.getAt(index));
12167 updateIndexes : function(startIndex, endIndex){
12168 var ns = this.nodes;
12169 startIndex = startIndex || 0;
12170 endIndex = endIndex || ns.length - 1;
12171 for(var i = startIndex; i <= endIndex; i++){
12172 ns[i].nodeIndex = i;
12177 * Changes the data store this view uses and refresh the view.
12178 * @param {Store} store
12180 setStore : function(store, initial){
12181 if(!initial && this.store){
12182 this.store.un("datachanged", this.refresh);
12183 this.store.un("add", this.onAdd);
12184 this.store.un("remove", this.onRemove);
12185 this.store.un("update", this.onUpdate);
12186 this.store.un("clear", this.refresh);
12187 this.store.un("beforeload", this.onBeforeLoad);
12188 this.store.un("load", this.onLoad);
12189 this.store.un("loadexception", this.onLoad);
12193 store.on("datachanged", this.refresh, this);
12194 store.on("add", this.onAdd, this);
12195 store.on("remove", this.onRemove, this);
12196 store.on("update", this.onUpdate, this);
12197 store.on("clear", this.refresh, this);
12198 store.on("beforeload", this.onBeforeLoad, this);
12199 store.on("load", this.onLoad, this);
12200 store.on("loadexception", this.onLoad, this);
12208 * onbeforeLoad - masks the loading area.
12211 onBeforeLoad : function(store,opts)
12213 Roo.log('onBeforeLoad');
12215 this.el.update("");
12217 this.el.mask(this.mask ? this.mask : "Loading" );
12219 onLoad : function ()
12226 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12227 * @param {HTMLElement} node
12228 * @return {HTMLElement} The template node
12230 findItemFromChild : function(node){
12231 var el = this.dataName ?
12232 this.el.child('.roo-tpl-' + this.dataName,true) :
12235 if(!node || node.parentNode == el){
12238 var p = node.parentNode;
12239 while(p && p != el){
12240 if(p.parentNode == el){
12249 onClick : function(e){
12250 var item = this.findItemFromChild(e.getTarget());
12252 var index = this.indexOf(item);
12253 if(this.onItemClick(item, index, e) !== false){
12254 this.fireEvent("click", this, index, item, e);
12257 this.clearSelections();
12262 onContextMenu : function(e){
12263 var item = this.findItemFromChild(e.getTarget());
12265 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12270 onDblClick : function(e){
12271 var item = this.findItemFromChild(e.getTarget());
12273 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12277 onItemClick : function(item, index, e)
12279 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12282 if (this.toggleSelect) {
12283 var m = this.isSelected(item) ? 'unselect' : 'select';
12286 _t[m](item, true, false);
12289 if(this.multiSelect || this.singleSelect){
12290 if(this.multiSelect && e.shiftKey && this.lastSelection){
12291 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12293 this.select(item, this.multiSelect && e.ctrlKey);
12294 this.lastSelection = item;
12297 if(!this.tickable){
12298 e.preventDefault();
12306 * Get the number of selected nodes.
12309 getSelectionCount : function(){
12310 return this.selections.length;
12314 * Get the currently selected nodes.
12315 * @return {Array} An array of HTMLElements
12317 getSelectedNodes : function(){
12318 return this.selections;
12322 * Get the indexes of the selected nodes.
12325 getSelectedIndexes : function(){
12326 var indexes = [], s = this.selections;
12327 for(var i = 0, len = s.length; i < len; i++){
12328 indexes.push(s[i].nodeIndex);
12334 * Clear all selections
12335 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12337 clearSelections : function(suppressEvent){
12338 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12339 this.cmp.elements = this.selections;
12340 this.cmp.removeClass(this.selectedClass);
12341 this.selections = [];
12342 if(!suppressEvent){
12343 this.fireEvent("selectionchange", this, this.selections);
12349 * Returns true if the passed node is selected
12350 * @param {HTMLElement/Number} node The node or node index
12351 * @return {Boolean}
12353 isSelected : function(node){
12354 var s = this.selections;
12358 node = this.getNode(node);
12359 return s.indexOf(node) !== -1;
12364 * @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
12365 * @param {Boolean} keepExisting (optional) true to keep existing selections
12366 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12368 select : function(nodeInfo, keepExisting, suppressEvent){
12369 if(nodeInfo instanceof Array){
12371 this.clearSelections(true);
12373 for(var i = 0, len = nodeInfo.length; i < len; i++){
12374 this.select(nodeInfo[i], true, true);
12378 var node = this.getNode(nodeInfo);
12379 if(!node || this.isSelected(node)){
12380 return; // already selected.
12383 this.clearSelections(true);
12385 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12386 Roo.fly(node).addClass(this.selectedClass);
12387 this.selections.push(node);
12388 if(!suppressEvent){
12389 this.fireEvent("selectionchange", this, this.selections);
12397 * @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
12398 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12399 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12401 unselect : function(nodeInfo, keepExisting, suppressEvent)
12403 if(nodeInfo instanceof Array){
12404 Roo.each(this.selections, function(s) {
12405 this.unselect(s, nodeInfo);
12409 var node = this.getNode(nodeInfo);
12410 if(!node || !this.isSelected(node)){
12411 Roo.log("not selected");
12412 return; // not selected.
12416 Roo.each(this.selections, function(s) {
12418 Roo.fly(node).removeClass(this.selectedClass);
12425 this.selections= ns;
12426 this.fireEvent("selectionchange", this, this.selections);
12430 * Gets a template node.
12431 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12432 * @return {HTMLElement} The node or null if it wasn't found
12434 getNode : function(nodeInfo){
12435 if(typeof nodeInfo == "string"){
12436 return document.getElementById(nodeInfo);
12437 }else if(typeof nodeInfo == "number"){
12438 return this.nodes[nodeInfo];
12444 * Gets a range template nodes.
12445 * @param {Number} startIndex
12446 * @param {Number} endIndex
12447 * @return {Array} An array of nodes
12449 getNodes : function(start, end){
12450 var ns = this.nodes;
12451 start = start || 0;
12452 end = typeof end == "undefined" ? ns.length - 1 : end;
12455 for(var i = start; i <= end; i++){
12459 for(var i = start; i >= end; i--){
12467 * Finds the index of the passed node
12468 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12469 * @return {Number} The index of the node or -1
12471 indexOf : function(node){
12472 node = this.getNode(node);
12473 if(typeof node.nodeIndex == "number"){
12474 return node.nodeIndex;
12476 var ns = this.nodes;
12477 for(var i = 0, len = ns.length; i < len; i++){
12488 * based on jquery fullcalendar
12492 Roo.bootstrap = Roo.bootstrap || {};
12494 * @class Roo.bootstrap.Calendar
12495 * @extends Roo.bootstrap.Component
12496 * Bootstrap Calendar class
12497 * @cfg {Boolean} loadMask (true|false) default false
12498 * @cfg {Object} header generate the user specific header of the calendar, default false
12501 * Create a new Container
12502 * @param {Object} config The config object
12507 Roo.bootstrap.Calendar = function(config){
12508 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12512 * Fires when a date is selected
12513 * @param {DatePicker} this
12514 * @param {Date} date The selected date
12518 * @event monthchange
12519 * Fires when the displayed month changes
12520 * @param {DatePicker} this
12521 * @param {Date} date The selected month
12523 'monthchange': true,
12525 * @event evententer
12526 * Fires when mouse over an event
12527 * @param {Calendar} this
12528 * @param {event} Event
12530 'evententer': true,
12532 * @event eventleave
12533 * Fires when the mouse leaves an
12534 * @param {Calendar} this
12537 'eventleave': true,
12539 * @event eventclick
12540 * Fires when the mouse click an
12541 * @param {Calendar} this
12550 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12553 * @cfg {Number} startDay
12554 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12562 getAutoCreate : function(){
12565 var fc_button = function(name, corner, style, content ) {
12566 return Roo.apply({},{
12568 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12570 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12573 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12584 style : 'width:100%',
12591 cls : 'fc-header-left',
12593 fc_button('prev', 'left', 'arrow', '‹' ),
12594 fc_button('next', 'right', 'arrow', '›' ),
12595 { tag: 'span', cls: 'fc-header-space' },
12596 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12604 cls : 'fc-header-center',
12608 cls: 'fc-header-title',
12611 html : 'month / year'
12619 cls : 'fc-header-right',
12621 /* fc_button('month', 'left', '', 'month' ),
12622 fc_button('week', '', '', 'week' ),
12623 fc_button('day', 'right', '', 'day' )
12635 header = this.header;
12638 var cal_heads = function() {
12640 // fixme - handle this.
12642 for (var i =0; i < Date.dayNames.length; i++) {
12643 var d = Date.dayNames[i];
12646 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12647 html : d.substring(0,3)
12651 ret[0].cls += ' fc-first';
12652 ret[6].cls += ' fc-last';
12655 var cal_cell = function(n) {
12658 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12663 cls: 'fc-day-number',
12667 cls: 'fc-day-content',
12671 style: 'position: relative;' // height: 17px;
12683 var cal_rows = function() {
12686 for (var r = 0; r < 6; r++) {
12693 for (var i =0; i < Date.dayNames.length; i++) {
12694 var d = Date.dayNames[i];
12695 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12698 row.cn[0].cls+=' fc-first';
12699 row.cn[0].cn[0].style = 'min-height:90px';
12700 row.cn[6].cls+=' fc-last';
12704 ret[0].cls += ' fc-first';
12705 ret[4].cls += ' fc-prev-last';
12706 ret[5].cls += ' fc-last';
12713 cls: 'fc-border-separate',
12714 style : 'width:100%',
12722 cls : 'fc-first fc-last',
12740 cls : 'fc-content',
12741 style : "position: relative;",
12744 cls : 'fc-view fc-view-month fc-grid',
12745 style : 'position: relative',
12746 unselectable : 'on',
12749 cls : 'fc-event-container',
12750 style : 'position:absolute;z-index:8;top:0;left:0;'
12768 initEvents : function()
12771 throw "can not find store for calendar";
12777 style: "text-align:center",
12781 style: "background-color:white;width:50%;margin:250 auto",
12785 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12796 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12798 var size = this.el.select('.fc-content', true).first().getSize();
12799 this.maskEl.setSize(size.width, size.height);
12800 this.maskEl.enableDisplayMode("block");
12801 if(!this.loadMask){
12802 this.maskEl.hide();
12805 this.store = Roo.factory(this.store, Roo.data);
12806 this.store.on('load', this.onLoad, this);
12807 this.store.on('beforeload', this.onBeforeLoad, this);
12811 this.cells = this.el.select('.fc-day',true);
12812 //Roo.log(this.cells);
12813 this.textNodes = this.el.query('.fc-day-number');
12814 this.cells.addClassOnOver('fc-state-hover');
12816 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12817 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12818 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12819 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12821 this.on('monthchange', this.onMonthChange, this);
12823 this.update(new Date().clearTime());
12826 resize : function() {
12827 var sz = this.el.getSize();
12829 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12830 this.el.select('.fc-day-content div',true).setHeight(34);
12835 showPrevMonth : function(e){
12836 this.update(this.activeDate.add("mo", -1));
12838 showToday : function(e){
12839 this.update(new Date().clearTime());
12842 showNextMonth : function(e){
12843 this.update(this.activeDate.add("mo", 1));
12847 showPrevYear : function(){
12848 this.update(this.activeDate.add("y", -1));
12852 showNextYear : function(){
12853 this.update(this.activeDate.add("y", 1));
12858 update : function(date)
12860 var vd = this.activeDate;
12861 this.activeDate = date;
12862 // if(vd && this.el){
12863 // var t = date.getTime();
12864 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12865 // Roo.log('using add remove');
12867 // this.fireEvent('monthchange', this, date);
12869 // this.cells.removeClass("fc-state-highlight");
12870 // this.cells.each(function(c){
12871 // if(c.dateValue == t){
12872 // c.addClass("fc-state-highlight");
12873 // setTimeout(function(){
12874 // try{c.dom.firstChild.focus();}catch(e){}
12884 var days = date.getDaysInMonth();
12886 var firstOfMonth = date.getFirstDateOfMonth();
12887 var startingPos = firstOfMonth.getDay()-this.startDay;
12889 if(startingPos < this.startDay){
12893 var pm = date.add(Date.MONTH, -1);
12894 var prevStart = pm.getDaysInMonth()-startingPos;
12896 this.cells = this.el.select('.fc-day',true);
12897 this.textNodes = this.el.query('.fc-day-number');
12898 this.cells.addClassOnOver('fc-state-hover');
12900 var cells = this.cells.elements;
12901 var textEls = this.textNodes;
12903 Roo.each(cells, function(cell){
12904 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12907 days += startingPos;
12909 // convert everything to numbers so it's fast
12910 var day = 86400000;
12911 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12914 //Roo.log(prevStart);
12916 var today = new Date().clearTime().getTime();
12917 var sel = date.clearTime().getTime();
12918 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12919 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12920 var ddMatch = this.disabledDatesRE;
12921 var ddText = this.disabledDatesText;
12922 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12923 var ddaysText = this.disabledDaysText;
12924 var format = this.format;
12926 var setCellClass = function(cal, cell){
12930 //Roo.log('set Cell Class');
12932 var t = d.getTime();
12936 cell.dateValue = t;
12938 cell.className += " fc-today";
12939 cell.className += " fc-state-highlight";
12940 cell.title = cal.todayText;
12943 // disable highlight in other month..
12944 //cell.className += " fc-state-highlight";
12949 cell.className = " fc-state-disabled";
12950 cell.title = cal.minText;
12954 cell.className = " fc-state-disabled";
12955 cell.title = cal.maxText;
12959 if(ddays.indexOf(d.getDay()) != -1){
12960 cell.title = ddaysText;
12961 cell.className = " fc-state-disabled";
12964 if(ddMatch && format){
12965 var fvalue = d.dateFormat(format);
12966 if(ddMatch.test(fvalue)){
12967 cell.title = ddText.replace("%0", fvalue);
12968 cell.className = " fc-state-disabled";
12972 if (!cell.initialClassName) {
12973 cell.initialClassName = cell.dom.className;
12976 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12981 for(; i < startingPos; i++) {
12982 textEls[i].innerHTML = (++prevStart);
12983 d.setDate(d.getDate()+1);
12985 cells[i].className = "fc-past fc-other-month";
12986 setCellClass(this, cells[i]);
12991 for(; i < days; i++){
12992 intDay = i - startingPos + 1;
12993 textEls[i].innerHTML = (intDay);
12994 d.setDate(d.getDate()+1);
12996 cells[i].className = ''; // "x-date-active";
12997 setCellClass(this, cells[i]);
13001 for(; i < 42; i++) {
13002 textEls[i].innerHTML = (++extraDays);
13003 d.setDate(d.getDate()+1);
13005 cells[i].className = "fc-future fc-other-month";
13006 setCellClass(this, cells[i]);
13009 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13011 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13013 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13014 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13016 if(totalRows != 6){
13017 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13018 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13021 this.fireEvent('monthchange', this, date);
13025 if(!this.internalRender){
13026 var main = this.el.dom.firstChild;
13027 var w = main.offsetWidth;
13028 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13029 Roo.fly(main).setWidth(w);
13030 this.internalRender = true;
13031 // opera does not respect the auto grow header center column
13032 // then, after it gets a width opera refuses to recalculate
13033 // without a second pass
13034 if(Roo.isOpera && !this.secondPass){
13035 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13036 this.secondPass = true;
13037 this.update.defer(10, this, [date]);
13044 findCell : function(dt) {
13045 dt = dt.clearTime().getTime();
13047 this.cells.each(function(c){
13048 //Roo.log("check " +c.dateValue + '?=' + dt);
13049 if(c.dateValue == dt){
13059 findCells : function(ev) {
13060 var s = ev.start.clone().clearTime().getTime();
13062 var e= ev.end.clone().clearTime().getTime();
13065 this.cells.each(function(c){
13066 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13068 if(c.dateValue > e){
13071 if(c.dateValue < s){
13080 // findBestRow: function(cells)
13084 // for (var i =0 ; i < cells.length;i++) {
13085 // ret = Math.max(cells[i].rows || 0,ret);
13092 addItem : function(ev)
13094 // look for vertical location slot in
13095 var cells = this.findCells(ev);
13097 // ev.row = this.findBestRow(cells);
13099 // work out the location.
13103 for(var i =0; i < cells.length; i++) {
13105 cells[i].row = cells[0].row;
13108 cells[i].row = cells[i].row + 1;
13118 if (crow.start.getY() == cells[i].getY()) {
13120 crow.end = cells[i];
13137 cells[0].events.push(ev);
13139 this.calevents.push(ev);
13142 clearEvents: function() {
13144 if(!this.calevents){
13148 Roo.each(this.cells.elements, function(c){
13154 Roo.each(this.calevents, function(e) {
13155 Roo.each(e.els, function(el) {
13156 el.un('mouseenter' ,this.onEventEnter, this);
13157 el.un('mouseleave' ,this.onEventLeave, this);
13162 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13168 renderEvents: function()
13172 this.cells.each(function(c) {
13181 if(c.row != c.events.length){
13182 r = 4 - (4 - (c.row - c.events.length));
13185 c.events = ev.slice(0, r);
13186 c.more = ev.slice(r);
13188 if(c.more.length && c.more.length == 1){
13189 c.events.push(c.more.pop());
13192 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13196 this.cells.each(function(c) {
13198 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13201 for (var e = 0; e < c.events.length; e++){
13202 var ev = c.events[e];
13203 var rows = ev.rows;
13205 for(var i = 0; i < rows.length; i++) {
13207 // how many rows should it span..
13210 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13211 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13213 unselectable : "on",
13216 cls: 'fc-event-inner',
13220 // cls: 'fc-event-time',
13221 // html : cells.length > 1 ? '' : ev.time
13225 cls: 'fc-event-title',
13226 html : String.format('{0}', ev.title)
13233 cls: 'ui-resizable-handle ui-resizable-e',
13234 html : '  '
13241 cfg.cls += ' fc-event-start';
13243 if ((i+1) == rows.length) {
13244 cfg.cls += ' fc-event-end';
13247 var ctr = _this.el.select('.fc-event-container',true).first();
13248 var cg = ctr.createChild(cfg);
13250 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13251 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13253 var r = (c.more.length) ? 1 : 0;
13254 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13255 cg.setWidth(ebox.right - sbox.x -2);
13257 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13258 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13259 cg.on('click', _this.onEventClick, _this, ev);
13270 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13271 style : 'position: absolute',
13272 unselectable : "on",
13275 cls: 'fc-event-inner',
13279 cls: 'fc-event-title',
13287 cls: 'ui-resizable-handle ui-resizable-e',
13288 html : '  '
13294 var ctr = _this.el.select('.fc-event-container',true).first();
13295 var cg = ctr.createChild(cfg);
13297 var sbox = c.select('.fc-day-content',true).first().getBox();
13298 var ebox = c.select('.fc-day-content',true).first().getBox();
13300 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13301 cg.setWidth(ebox.right - sbox.x -2);
13303 cg.on('click', _this.onMoreEventClick, _this, c.more);
13313 onEventEnter: function (e, el,event,d) {
13314 this.fireEvent('evententer', this, el, event);
13317 onEventLeave: function (e, el,event,d) {
13318 this.fireEvent('eventleave', this, el, event);
13321 onEventClick: function (e, el,event,d) {
13322 this.fireEvent('eventclick', this, el, event);
13325 onMonthChange: function () {
13329 onMoreEventClick: function(e, el, more)
13333 this.calpopover.placement = 'right';
13334 this.calpopover.setTitle('More');
13336 this.calpopover.setContent('');
13338 var ctr = this.calpopover.el.select('.popover-content', true).first();
13340 Roo.each(more, function(m){
13342 cls : 'fc-event-hori fc-event-draggable',
13345 var cg = ctr.createChild(cfg);
13347 cg.on('click', _this.onEventClick, _this, m);
13350 this.calpopover.show(el);
13355 onLoad: function ()
13357 this.calevents = [];
13360 if(this.store.getCount() > 0){
13361 this.store.data.each(function(d){
13364 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13365 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13366 time : d.data.start_time,
13367 title : d.data.title,
13368 description : d.data.description,
13369 venue : d.data.venue
13374 this.renderEvents();
13376 if(this.calevents.length && this.loadMask){
13377 this.maskEl.hide();
13381 onBeforeLoad: function()
13383 this.clearEvents();
13385 this.maskEl.show();
13399 * @class Roo.bootstrap.Popover
13400 * @extends Roo.bootstrap.Component
13401 * Bootstrap Popover class
13402 * @cfg {String} html contents of the popover (or false to use children..)
13403 * @cfg {String} title of popover (or false to hide)
13404 * @cfg {String} placement how it is placed
13405 * @cfg {String} trigger click || hover (or false to trigger manually)
13406 * @cfg {String} over what (parent or false to trigger manually.)
13409 * Create a new Popover
13410 * @param {Object} config The config object
13413 Roo.bootstrap.Popover = function(config){
13414 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13417 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13419 title: 'Fill in a title',
13422 placement : 'right',
13423 trigger : 'hover', // hover
13427 can_build_overlaid : false,
13429 getChildContainer : function()
13431 return this.el.select('.popover-content',true).first();
13434 getAutoCreate : function(){
13435 Roo.log('make popover?');
13437 cls : 'popover roo-dynamic',
13438 style: 'display:block',
13444 cls : 'popover-inner',
13448 cls: 'popover-title',
13452 cls : 'popover-content',
13463 setTitle: function(str)
13465 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13467 setContent: function(str)
13469 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13471 // as it get's added to the bottom of the page.
13472 onRender : function(ct, position)
13474 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13476 var cfg = Roo.apply({}, this.getAutoCreate());
13480 cfg.cls += ' ' + this.cls;
13483 cfg.style = this.style;
13485 Roo.log("adding to ")
13486 this.el = Roo.get(document.body).createChild(cfg, position);
13492 initEvents : function()
13494 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13495 this.el.enableDisplayMode('block');
13497 if (this.over === false) {
13500 if (this.triggers === false) {
13503 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13504 var triggers = this.trigger ? this.trigger.split(' ') : [];
13505 Roo.each(triggers, function(trigger) {
13507 if (trigger == 'click') {
13508 on_el.on('click', this.toggle, this);
13509 } else if (trigger != 'manual') {
13510 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13511 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13513 on_el.on(eventIn ,this.enter, this);
13514 on_el.on(eventOut, this.leave, this);
13525 toggle : function () {
13526 this.hoverState == 'in' ? this.leave() : this.enter();
13529 enter : function () {
13532 clearTimeout(this.timeout);
13534 this.hoverState = 'in'
13536 if (!this.delay || !this.delay.show) {
13541 this.timeout = setTimeout(function () {
13542 if (_t.hoverState == 'in') {
13545 }, this.delay.show)
13547 leave : function() {
13548 clearTimeout(this.timeout);
13550 this.hoverState = 'out'
13552 if (!this.delay || !this.delay.hide) {
13557 this.timeout = setTimeout(function () {
13558 if (_t.hoverState == 'out') {
13561 }, this.delay.hide)
13564 show : function (on_el)
13567 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13570 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13571 if (this.html !== false) {
13572 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13574 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13575 if (!this.title.length) {
13576 this.el.select('.popover-title',true).hide();
13579 var placement = typeof this.placement == 'function' ?
13580 this.placement.call(this, this.el, on_el) :
13583 var autoToken = /\s?auto?\s?/i;
13584 var autoPlace = autoToken.test(placement);
13586 placement = placement.replace(autoToken, '') || 'top';
13590 //this.el.setXY([0,0]);
13592 this.el.dom.style.display='block';
13593 this.el.addClass(placement);
13595 //this.el.appendTo(on_el);
13597 var p = this.getPosition();
13598 var box = this.el.getBox();
13603 var align = Roo.bootstrap.Popover.alignment[placement]
13604 this.el.alignTo(on_el, align[0],align[1]);
13605 //var arrow = this.el.select('.arrow',true).first();
13606 //arrow.set(align[2],
13608 this.el.addClass('in');
13609 this.hoverState = null;
13611 if (this.el.hasClass('fade')) {
13618 this.el.setXY([0,0]);
13619 this.el.removeClass('in');
13626 Roo.bootstrap.Popover.alignment = {
13627 'left' : ['r-l', [-10,0], 'right'],
13628 'right' : ['l-r', [10,0], 'left'],
13629 'bottom' : ['t-b', [0,10], 'top'],
13630 'top' : [ 'b-t', [0,-10], 'bottom']
13641 * @class Roo.bootstrap.Progress
13642 * @extends Roo.bootstrap.Component
13643 * Bootstrap Progress class
13644 * @cfg {Boolean} striped striped of the progress bar
13645 * @cfg {Boolean} active animated of the progress bar
13649 * Create a new Progress
13650 * @param {Object} config The config object
13653 Roo.bootstrap.Progress = function(config){
13654 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13657 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13662 getAutoCreate : function(){
13670 cfg.cls += ' progress-striped';
13674 cfg.cls += ' active';
13693 * @class Roo.bootstrap.ProgressBar
13694 * @extends Roo.bootstrap.Component
13695 * Bootstrap ProgressBar class
13696 * @cfg {Number} aria_valuenow aria-value now
13697 * @cfg {Number} aria_valuemin aria-value min
13698 * @cfg {Number} aria_valuemax aria-value max
13699 * @cfg {String} label label for the progress bar
13700 * @cfg {String} panel (success | info | warning | danger )
13701 * @cfg {String} role role of the progress bar
13702 * @cfg {String} sr_only text
13706 * Create a new ProgressBar
13707 * @param {Object} config The config object
13710 Roo.bootstrap.ProgressBar = function(config){
13711 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13714 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13718 aria_valuemax : 100,
13724 getAutoCreate : function()
13729 cls: 'progress-bar',
13730 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13742 cfg.role = this.role;
13745 if(this.aria_valuenow){
13746 cfg['aria-valuenow'] = this.aria_valuenow;
13749 if(this.aria_valuemin){
13750 cfg['aria-valuemin'] = this.aria_valuemin;
13753 if(this.aria_valuemax){
13754 cfg['aria-valuemax'] = this.aria_valuemax;
13757 if(this.label && !this.sr_only){
13758 cfg.html = this.label;
13762 cfg.cls += ' progress-bar-' + this.panel;
13768 update : function(aria_valuenow)
13770 this.aria_valuenow = aria_valuenow;
13772 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13787 * @class Roo.bootstrap.TabGroup
13788 * @extends Roo.bootstrap.Column
13789 * Bootstrap Column class
13790 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13791 * @cfg {Boolean} carousel true to make the group behave like a carousel
13794 * Create a new TabGroup
13795 * @param {Object} config The config object
13798 Roo.bootstrap.TabGroup = function(config){
13799 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13801 this.navId = Roo.id();
13804 Roo.bootstrap.TabGroup.register(this);
13808 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13812 getAutoCreate : function()
13814 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13816 cfg.cls += ' tab-content';
13818 if (this.carousel) {
13819 cfg.cls += ' carousel slide';
13821 cls : 'carousel-inner'
13828 getChildContainer : function()
13830 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13834 * register a Navigation item
13835 * @param {Roo.bootstrap.NavItem} the navitem to add
13837 register : function(item)
13839 this.tabs.push( item);
13840 item.navId = this.navId; // not really needed..
13844 getActivePanel : function()
13847 Roo.each(this.tabs, function(t) {
13857 getPanelByName : function(n)
13860 Roo.each(this.tabs, function(t) {
13861 if (t.tabId == n) {
13869 indexOfPanel : function(p)
13872 Roo.each(this.tabs, function(t,i) {
13873 if (t.tabId == p.tabId) {
13882 * show a specific panel
13883 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13884 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13886 showPanel : function (pan)
13891 if (typeof(pan) == 'number') {
13892 pan = this.tabs[pan];
13894 if (typeof(pan) == 'string') {
13895 pan = this.getPanelByName(pan);
13897 if (pan.tabId == this.getActivePanel().tabId) {
13900 var cur = this.getActivePanel();
13902 if (false === cur.fireEvent('beforedeactivate')) {
13908 if (this.carousel) {
13909 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13910 var lr = dir == 'next' ? 'left' : 'right';
13911 pan.el.addClass(dir); // or prev
13912 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13913 cur.el.addClass(lr); // or right
13914 pan.el.addClass(lr);
13915 cur.el.on('transitionend', function() {
13916 Roo.log("trans end?");
13918 pan.el.removeClass([lr,dir]);
13919 pan.setActive(true);
13921 cur.el.removeClass([lr]);
13922 cur.setActive(false);
13925 }, this, { single: true } );
13929 cur.setActive(false);
13930 pan.setActive(true);
13934 showPanelNext : function()
13936 var i = this.indexOfPanel(this.getActivePanel());
13937 if (i > this.tabs.length) {
13940 this.showPanel(this.tabs[i+1]);
13942 showPanelPrev : function()
13944 var i = this.indexOfPanel(this.getActivePanel());
13948 this.showPanel(this.tabs[i-1]);
13959 Roo.apply(Roo.bootstrap.TabGroup, {
13963 * register a Navigation Group
13964 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13966 register : function(navgrp)
13968 this.groups[navgrp.navId] = navgrp;
13972 * fetch a Navigation Group based on the navigation ID
13973 * if one does not exist , it will get created.
13974 * @param {string} the navgroup to add
13975 * @returns {Roo.bootstrap.NavGroup} the navgroup
13977 get: function(navId) {
13978 if (typeof(this.groups[navId]) == 'undefined') {
13979 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13981 return this.groups[navId] ;
13996 * @class Roo.bootstrap.TabPanel
13997 * @extends Roo.bootstrap.Component
13998 * Bootstrap TabPanel class
13999 * @cfg {Boolean} active panel active
14000 * @cfg {String} html panel content
14001 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14002 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14006 * Create a new TabPanel
14007 * @param {Object} config The config object
14010 Roo.bootstrap.TabPanel = function(config){
14011 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14015 * Fires when the active status changes
14016 * @param {Roo.bootstrap.TabPanel} this
14017 * @param {Boolean} state the new state
14022 * @event beforedeactivate
14023 * Fires before a tab is de-activated - can be used to do validation on a form.
14024 * @param {Roo.bootstrap.TabPanel} this
14025 * @return {Boolean} false if there is an error
14028 'beforedeactivate': true
14031 this.tabId = this.tabId || Roo.id();
14035 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14042 getAutoCreate : function(){
14045 // item is needed for carousel - not sure if it has any effect otherwise
14046 cls: 'tab-pane item',
14047 html: this.html || ''
14051 cfg.cls += ' active';
14055 cfg.tabId = this.tabId;
14062 initEvents: function()
14064 Roo.log('-------- init events on tab panel ---------');
14066 var p = this.parent();
14067 this.navId = this.navId || p.navId;
14069 if (typeof(this.navId) != 'undefined') {
14070 // not really needed.. but just in case.. parent should be a NavGroup.
14071 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14072 Roo.log(['register', tg, this]);
14078 onRender : function(ct, position)
14080 // Roo.log("Call onRender: " + this.xtype);
14082 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14090 setActive: function(state)
14092 Roo.log("panel - set active " + this.tabId + "=" + state);
14094 this.active = state;
14096 this.el.removeClass('active');
14098 } else if (!this.el.hasClass('active')) {
14099 this.el.addClass('active');
14101 this.fireEvent('changed', this, state);
14118 * @class Roo.bootstrap.DateField
14119 * @extends Roo.bootstrap.Input
14120 * Bootstrap DateField class
14121 * @cfg {Number} weekStart default 0
14122 * @cfg {Number} weekStart default 0
14123 * @cfg {Number} viewMode default empty, (months|years)
14124 * @cfg {Number} minViewMode default empty, (months|years)
14125 * @cfg {Number} startDate default -Infinity
14126 * @cfg {Number} endDate default Infinity
14127 * @cfg {Boolean} todayHighlight default false
14128 * @cfg {Boolean} todayBtn default false
14129 * @cfg {Boolean} calendarWeeks default false
14130 * @cfg {Object} daysOfWeekDisabled default empty
14132 * @cfg {Boolean} keyboardNavigation default true
14133 * @cfg {String} language default en
14136 * Create a new DateField
14137 * @param {Object} config The config object
14140 Roo.bootstrap.DateField = function(config){
14141 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14145 * Fires when this field show.
14146 * @param {Roo.bootstrap.DateField} this
14147 * @param {Mixed} date The date value
14152 * Fires when this field hide.
14153 * @param {Roo.bootstrap.DateField} this
14154 * @param {Mixed} date The date value
14159 * Fires when select a date.
14160 * @param {Roo.bootstrap.DateField} this
14161 * @param {Mixed} date The date value
14167 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14170 * @cfg {String} format
14171 * The default date format string which can be overriden for localization support. The format must be
14172 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14176 * @cfg {String} altFormats
14177 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14178 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14180 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14188 todayHighlight : false,
14194 keyboardNavigation: true,
14196 calendarWeeks: false,
14198 startDate: -Infinity,
14202 daysOfWeekDisabled: [],
14206 UTCDate: function()
14208 return new Date(Date.UTC.apply(Date, arguments));
14211 UTCToday: function()
14213 var today = new Date();
14214 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14217 getDate: function() {
14218 var d = this.getUTCDate();
14219 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14222 getUTCDate: function() {
14226 setDate: function(d) {
14227 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14230 setUTCDate: function(d) {
14232 this.setValue(this.formatDate(this.date));
14235 onRender: function(ct, position)
14238 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14240 this.language = this.language || 'en';
14241 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14242 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14244 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14245 this.format = this.format || 'm/d/y';
14246 this.isInline = false;
14247 this.isInput = true;
14248 this.component = this.el.select('.add-on', true).first() || false;
14249 this.component = (this.component && this.component.length === 0) ? false : this.component;
14250 this.hasInput = this.component && this.inputEL().length;
14252 if (typeof(this.minViewMode === 'string')) {
14253 switch (this.minViewMode) {
14255 this.minViewMode = 1;
14258 this.minViewMode = 2;
14261 this.minViewMode = 0;
14266 if (typeof(this.viewMode === 'string')) {
14267 switch (this.viewMode) {
14280 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14282 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14284 this.picker().on('mousedown', this.onMousedown, this);
14285 this.picker().on('click', this.onClick, this);
14287 this.picker().addClass('datepicker-dropdown');
14289 this.startViewMode = this.viewMode;
14292 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14293 if(!this.calendarWeeks){
14298 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14299 v.attr('colspan', function(i, val){
14300 return parseInt(val) + 1;
14305 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14307 this.setStartDate(this.startDate);
14308 this.setEndDate(this.endDate);
14310 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14317 if(this.isInline) {
14322 picker : function()
14324 return this.el.select('.datepicker', true).first();
14327 fillDow: function()
14329 var dowCnt = this.weekStart;
14338 if(this.calendarWeeks){
14346 while (dowCnt < this.weekStart + 7) {
14350 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14354 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14357 fillMonths: function()
14360 var months = this.picker().select('>.datepicker-months td', true).first();
14362 months.dom.innerHTML = '';
14368 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14371 months.createChild(month);
14379 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14381 if (this.date < this.startDate) {
14382 this.viewDate = new Date(this.startDate);
14383 } else if (this.date > this.endDate) {
14384 this.viewDate = new Date(this.endDate);
14386 this.viewDate = new Date(this.date);
14394 var d = new Date(this.viewDate),
14395 year = d.getUTCFullYear(),
14396 month = d.getUTCMonth(),
14397 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14398 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14399 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14400 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14401 currentDate = this.date && this.date.valueOf(),
14402 today = this.UTCToday();
14404 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14406 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14408 // this.picker.select('>tfoot th.today').
14409 // .text(dates[this.language].today)
14410 // .toggle(this.todayBtn !== false);
14412 this.updateNavArrows();
14415 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14417 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14419 prevMonth.setUTCDate(day);
14421 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14423 var nextMonth = new Date(prevMonth);
14425 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14427 nextMonth = nextMonth.valueOf();
14429 var fillMonths = false;
14431 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14433 while(prevMonth.valueOf() < nextMonth) {
14436 if (prevMonth.getUTCDay() === this.weekStart) {
14438 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14446 if(this.calendarWeeks){
14447 // ISO 8601: First week contains first thursday.
14448 // ISO also states week starts on Monday, but we can be more abstract here.
14450 // Start of current week: based on weekstart/current date
14451 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14452 // Thursday of this week
14453 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14454 // First Thursday of year, year from thursday
14455 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14456 // Calendar week: ms between thursdays, div ms per day, div 7 days
14457 calWeek = (th - yth) / 864e5 / 7 + 1;
14459 fillMonths.cn.push({
14467 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14469 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14472 if (this.todayHighlight &&
14473 prevMonth.getUTCFullYear() == today.getFullYear() &&
14474 prevMonth.getUTCMonth() == today.getMonth() &&
14475 prevMonth.getUTCDate() == today.getDate()) {
14476 clsName += ' today';
14479 if (currentDate && prevMonth.valueOf() === currentDate) {
14480 clsName += ' active';
14483 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14484 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14485 clsName += ' disabled';
14488 fillMonths.cn.push({
14490 cls: 'day ' + clsName,
14491 html: prevMonth.getDate()
14494 prevMonth.setDate(prevMonth.getDate()+1);
14497 var currentYear = this.date && this.date.getUTCFullYear();
14498 var currentMonth = this.date && this.date.getUTCMonth();
14500 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14502 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14503 v.removeClass('active');
14505 if(currentYear === year && k === currentMonth){
14506 v.addClass('active');
14509 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14510 v.addClass('disabled');
14516 year = parseInt(year/10, 10) * 10;
14518 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14520 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14523 for (var i = -1; i < 11; i++) {
14524 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14526 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14534 showMode: function(dir)
14537 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14539 Roo.each(this.picker().select('>div',true).elements, function(v){
14540 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14543 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14548 if(this.isInline) return;
14550 this.picker().removeClass(['bottom', 'top']);
14552 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14554 * place to the top of element!
14558 this.picker().addClass('top');
14559 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14564 this.picker().addClass('bottom');
14566 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14569 parseDate : function(value)
14571 if(!value || value instanceof Date){
14574 var v = Date.parseDate(value, this.format);
14575 if (!v && this.useIso) {
14576 v = Date.parseDate(value, 'Y-m-d');
14578 if(!v && this.altFormats){
14579 if(!this.altFormatsArray){
14580 this.altFormatsArray = this.altFormats.split("|");
14582 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14583 v = Date.parseDate(value, this.altFormatsArray[i]);
14589 formatDate : function(date, fmt)
14591 return (!date || !(date instanceof Date)) ?
14592 date : date.dateFormat(fmt || this.format);
14595 onFocus : function()
14597 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14601 onBlur : function()
14603 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14605 var d = this.inputEl().getValue();
14616 this.picker().show();
14620 this.fireEvent('show', this, this.date);
14625 if(this.isInline) return;
14626 this.picker().hide();
14627 this.viewMode = this.startViewMode;
14630 this.fireEvent('hide', this, this.date);
14634 onMousedown: function(e)
14636 e.stopPropagation();
14637 e.preventDefault();
14642 Roo.bootstrap.DateField.superclass.keyup.call(this);
14646 setValue: function(v)
14648 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14650 var d = new Date(v);
14652 if(isNaN(d.getTime())){
14656 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14660 this.fireEvent('select', this, this.date);
14664 getValue: function()
14666 return this.formatDate(this.date);
14669 fireKey: function(e)
14671 if (!this.picker().isVisible()){
14672 if (e.keyCode == 27) // allow escape to hide and re-show picker
14677 var dateChanged = false,
14679 newDate, newViewDate;
14684 e.preventDefault();
14688 if (!this.keyboardNavigation) break;
14689 dir = e.keyCode == 37 ? -1 : 1;
14692 newDate = this.moveYear(this.date, dir);
14693 newViewDate = this.moveYear(this.viewDate, dir);
14694 } else if (e.shiftKey){
14695 newDate = this.moveMonth(this.date, dir);
14696 newViewDate = this.moveMonth(this.viewDate, dir);
14698 newDate = new Date(this.date);
14699 newDate.setUTCDate(this.date.getUTCDate() + dir);
14700 newViewDate = new Date(this.viewDate);
14701 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14703 if (this.dateWithinRange(newDate)){
14704 this.date = newDate;
14705 this.viewDate = newViewDate;
14706 this.setValue(this.formatDate(this.date));
14708 e.preventDefault();
14709 dateChanged = true;
14714 if (!this.keyboardNavigation) break;
14715 dir = e.keyCode == 38 ? -1 : 1;
14717 newDate = this.moveYear(this.date, dir);
14718 newViewDate = this.moveYear(this.viewDate, dir);
14719 } else if (e.shiftKey){
14720 newDate = this.moveMonth(this.date, dir);
14721 newViewDate = this.moveMonth(this.viewDate, dir);
14723 newDate = new Date(this.date);
14724 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14725 newViewDate = new Date(this.viewDate);
14726 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14728 if (this.dateWithinRange(newDate)){
14729 this.date = newDate;
14730 this.viewDate = newViewDate;
14731 this.setValue(this.formatDate(this.date));
14733 e.preventDefault();
14734 dateChanged = true;
14738 this.setValue(this.formatDate(this.date));
14740 e.preventDefault();
14743 this.setValue(this.formatDate(this.date));
14757 onClick: function(e)
14759 e.stopPropagation();
14760 e.preventDefault();
14762 var target = e.getTarget();
14764 if(target.nodeName.toLowerCase() === 'i'){
14765 target = Roo.get(target).dom.parentNode;
14768 var nodeName = target.nodeName;
14769 var className = target.className;
14770 var html = target.innerHTML;
14772 switch(nodeName.toLowerCase()) {
14774 switch(className) {
14780 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14781 switch(this.viewMode){
14783 this.viewDate = this.moveMonth(this.viewDate, dir);
14787 this.viewDate = this.moveYear(this.viewDate, dir);
14793 var date = new Date();
14794 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14796 this.setValue(this.formatDate(this.date));
14803 if (className.indexOf('disabled') === -1) {
14804 this.viewDate.setUTCDate(1);
14805 if (className.indexOf('month') !== -1) {
14806 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14808 var year = parseInt(html, 10) || 0;
14809 this.viewDate.setUTCFullYear(year);
14818 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14819 var day = parseInt(html, 10) || 1;
14820 var year = this.viewDate.getUTCFullYear(),
14821 month = this.viewDate.getUTCMonth();
14823 if (className.indexOf('old') !== -1) {
14830 } else if (className.indexOf('new') !== -1) {
14838 this.date = this.UTCDate(year, month, day,0,0,0,0);
14839 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14841 this.setValue(this.formatDate(this.date));
14848 setStartDate: function(startDate)
14850 this.startDate = startDate || -Infinity;
14851 if (this.startDate !== -Infinity) {
14852 this.startDate = this.parseDate(this.startDate);
14855 this.updateNavArrows();
14858 setEndDate: function(endDate)
14860 this.endDate = endDate || Infinity;
14861 if (this.endDate !== Infinity) {
14862 this.endDate = this.parseDate(this.endDate);
14865 this.updateNavArrows();
14868 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14870 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14871 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14872 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14874 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14875 return parseInt(d, 10);
14878 this.updateNavArrows();
14881 updateNavArrows: function()
14883 var d = new Date(this.viewDate),
14884 year = d.getUTCFullYear(),
14885 month = d.getUTCMonth();
14887 Roo.each(this.picker().select('.prev', true).elements, function(v){
14889 switch (this.viewMode) {
14892 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14898 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14905 Roo.each(this.picker().select('.next', true).elements, function(v){
14907 switch (this.viewMode) {
14910 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14916 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14924 moveMonth: function(date, dir)
14926 if (!dir) return date;
14927 var new_date = new Date(date.valueOf()),
14928 day = new_date.getUTCDate(),
14929 month = new_date.getUTCMonth(),
14930 mag = Math.abs(dir),
14932 dir = dir > 0 ? 1 : -1;
14935 // If going back one month, make sure month is not current month
14936 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14938 return new_date.getUTCMonth() == month;
14940 // If going forward one month, make sure month is as expected
14941 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14943 return new_date.getUTCMonth() != new_month;
14945 new_month = month + dir;
14946 new_date.setUTCMonth(new_month);
14947 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14948 if (new_month < 0 || new_month > 11)
14949 new_month = (new_month + 12) % 12;
14951 // For magnitudes >1, move one month at a time...
14952 for (var i=0; i<mag; i++)
14953 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14954 new_date = this.moveMonth(new_date, dir);
14955 // ...then reset the day, keeping it in the new month
14956 new_month = new_date.getUTCMonth();
14957 new_date.setUTCDate(day);
14959 return new_month != new_date.getUTCMonth();
14962 // Common date-resetting loop -- if date is beyond end of month, make it
14965 new_date.setUTCDate(--day);
14966 new_date.setUTCMonth(new_month);
14971 moveYear: function(date, dir)
14973 return this.moveMonth(date, dir*12);
14976 dateWithinRange: function(date)
14978 return date >= this.startDate && date <= this.endDate;
14984 this.picker().remove();
14989 Roo.apply(Roo.bootstrap.DateField, {
15000 html: '<i class="fa fa-arrow-left"/>'
15010 html: '<i class="fa fa-arrow-right"/>'
15052 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15053 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15054 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15055 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15056 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15069 navFnc: 'FullYear',
15074 navFnc: 'FullYear',
15079 Roo.apply(Roo.bootstrap.DateField, {
15083 cls: 'datepicker dropdown-menu',
15087 cls: 'datepicker-days',
15091 cls: 'table-condensed',
15093 Roo.bootstrap.DateField.head,
15097 Roo.bootstrap.DateField.footer
15104 cls: 'datepicker-months',
15108 cls: 'table-condensed',
15110 Roo.bootstrap.DateField.head,
15111 Roo.bootstrap.DateField.content,
15112 Roo.bootstrap.DateField.footer
15119 cls: 'datepicker-years',
15123 cls: 'table-condensed',
15125 Roo.bootstrap.DateField.head,
15126 Roo.bootstrap.DateField.content,
15127 Roo.bootstrap.DateField.footer
15146 * @class Roo.bootstrap.TimeField
15147 * @extends Roo.bootstrap.Input
15148 * Bootstrap DateField class
15152 * Create a new TimeField
15153 * @param {Object} config The config object
15156 Roo.bootstrap.TimeField = function(config){
15157 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15161 * Fires when this field show.
15162 * @param {Roo.bootstrap.DateField} this
15163 * @param {Mixed} date The date value
15168 * Fires when this field hide.
15169 * @param {Roo.bootstrap.DateField} this
15170 * @param {Mixed} date The date value
15175 * Fires when select a date.
15176 * @param {Roo.bootstrap.DateField} this
15177 * @param {Mixed} date The date value
15183 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15186 * @cfg {String} format
15187 * The default time format string which can be overriden for localization support. The format must be
15188 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15192 onRender: function(ct, position)
15195 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15197 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15199 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15201 this.pop = this.picker().select('>.datepicker-time',true).first();
15202 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15204 this.picker().on('mousedown', this.onMousedown, this);
15205 this.picker().on('click', this.onClick, this);
15207 this.picker().addClass('datepicker-dropdown');
15212 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15213 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15214 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15215 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15216 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15217 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15221 fireKey: function(e){
15222 if (!this.picker().isVisible()){
15223 if (e.keyCode == 27) // allow escape to hide and re-show picker
15228 e.preventDefault();
15236 this.onTogglePeriod();
15239 this.onIncrementMinutes();
15242 this.onDecrementMinutes();
15251 onClick: function(e) {
15252 e.stopPropagation();
15253 e.preventDefault();
15256 picker : function()
15258 return this.el.select('.datepicker', true).first();
15261 fillTime: function()
15263 var time = this.pop.select('tbody', true).first();
15265 time.dom.innerHTML = '';
15280 cls: 'hours-up glyphicon glyphicon-chevron-up'
15300 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15321 cls: 'timepicker-hour',
15336 cls: 'timepicker-minute',
15351 cls: 'btn btn-primary period',
15373 cls: 'hours-down glyphicon glyphicon-chevron-down'
15393 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15411 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15418 var hours = this.time.getHours();
15419 var minutes = this.time.getMinutes();
15432 hours = hours - 12;
15436 hours = '0' + hours;
15440 minutes = '0' + minutes;
15443 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15444 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15445 this.pop.select('button', true).first().dom.innerHTML = period;
15451 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15453 var cls = ['bottom'];
15455 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15462 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15467 this.picker().addClass(cls.join('-'));
15471 Roo.each(cls, function(c){
15473 _this.picker().setTop(_this.inputEl().getHeight());
15477 _this.picker().setTop(0 - _this.picker().getHeight());
15482 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15486 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15493 onFocus : function()
15495 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15499 onBlur : function()
15501 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15507 this.picker().show();
15512 this.fireEvent('show', this, this.date);
15517 this.picker().hide();
15520 this.fireEvent('hide', this, this.date);
15523 setTime : function()
15526 this.setValue(this.time.format(this.format));
15528 this.fireEvent('select', this, this.date);
15533 onMousedown: function(e){
15534 e.stopPropagation();
15535 e.preventDefault();
15538 onIncrementHours: function()
15540 Roo.log('onIncrementHours');
15541 this.time = this.time.add(Date.HOUR, 1);
15546 onDecrementHours: function()
15548 Roo.log('onDecrementHours');
15549 this.time = this.time.add(Date.HOUR, -1);
15553 onIncrementMinutes: function()
15555 Roo.log('onIncrementMinutes');
15556 this.time = this.time.add(Date.MINUTE, 1);
15560 onDecrementMinutes: function()
15562 Roo.log('onDecrementMinutes');
15563 this.time = this.time.add(Date.MINUTE, -1);
15567 onTogglePeriod: function()
15569 Roo.log('onTogglePeriod');
15570 this.time = this.time.add(Date.HOUR, 12);
15577 Roo.apply(Roo.bootstrap.TimeField, {
15607 cls: 'btn btn-info ok',
15619 Roo.apply(Roo.bootstrap.TimeField, {
15623 cls: 'datepicker dropdown-menu',
15627 cls: 'datepicker-time',
15631 cls: 'table-condensed',
15633 Roo.bootstrap.TimeField.content,
15634 Roo.bootstrap.TimeField.footer
15653 * @class Roo.bootstrap.CheckBox
15654 * @extends Roo.bootstrap.Input
15655 * Bootstrap CheckBox class
15657 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15658 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15659 * @cfg {String} boxLabel The text that appears beside the checkbox
15660 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15661 * @cfg {Boolean} checked initnal the element
15665 * Create a new CheckBox
15666 * @param {Object} config The config object
15669 Roo.bootstrap.CheckBox = function(config){
15670 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15675 * Fires when the element is checked or unchecked.
15676 * @param {Roo.bootstrap.CheckBox} this This input
15677 * @param {Boolean} checked The new checked value
15683 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15685 inputType: 'checkbox',
15692 getAutoCreate : function()
15694 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15700 cfg.cls = 'form-group checkbox' //input-group
15708 type : this.inputType,
15709 value : (!this.checked) ? this.valueOff : this.inputValue,
15710 cls : 'roo-checkbox', //'form-box',
15711 placeholder : this.placeholder || ''
15715 if (this.weight) { // Validity check?
15716 cfg.cls += " checkbox-" + this.weight;
15719 if (this.disabled) {
15720 input.disabled=true;
15724 input.checked = this.checked;
15728 input.name = this.name;
15732 input.cls += ' input-' + this.size;
15736 ['xs','sm','md','lg'].map(function(size){
15737 if (settings[size]) {
15738 cfg.cls += ' col-' + size + '-' + settings[size];
15744 var inputblock = input;
15749 if (this.before || this.after) {
15752 cls : 'input-group',
15756 inputblock.cn.push({
15758 cls : 'input-group-addon',
15762 inputblock.cn.push(input);
15764 inputblock.cn.push({
15766 cls : 'input-group-addon',
15773 if (align ==='left' && this.fieldLabel.length) {
15774 Roo.log("left and has label");
15780 cls : 'control-label col-md-' + this.labelWidth,
15781 html : this.fieldLabel
15785 cls : "col-md-" + (12 - this.labelWidth),
15792 } else if ( this.fieldLabel.length) {
15797 tag: this.boxLabel ? 'span' : 'label',
15799 cls: 'control-label box-input-label',
15800 //cls : 'input-group-addon',
15801 html : this.fieldLabel
15811 Roo.log(" no label && no align");
15812 cfg.cn = [ inputblock ] ;
15821 html: this.boxLabel
15833 * return the real input element.
15835 inputEl: function ()
15837 return this.el.select('input.roo-checkbox',true).first();
15842 return this.el.select('label.control-label',true).first();
15845 initEvents : function()
15847 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15849 this.inputEl().on('click', this.onClick, this);
15853 onClick : function()
15855 this.setChecked(!this.checked);
15858 setChecked : function(state,suppressEvent)
15860 this.checked = state;
15862 this.inputEl().dom.checked = state;
15864 if(suppressEvent !== true){
15865 this.fireEvent('check', this, state);
15868 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15872 setValue : function(v,suppressEvent)
15874 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15888 * @class Roo.bootstrap.Radio
15889 * @extends Roo.bootstrap.CheckBox
15890 * Bootstrap Radio class
15893 * Create a new Radio
15894 * @param {Object} config The config object
15897 Roo.bootstrap.Radio = function(config){
15898 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15902 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15904 inputType: 'radio',
15908 getAutoCreate : function()
15910 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15916 cfg.cls = 'form-group radio' //input-group
15921 type : this.inputType,
15922 value : (!this.checked) ? this.valueOff : this.inputValue,
15924 placeholder : this.placeholder || ''
15927 if (this.weight) { // Validity check?
15928 cfg.cls += " radio-" + this.weight;
15930 if (this.disabled) {
15931 input.disabled=true;
15935 input.checked = this.checked;
15939 input.name = this.name;
15943 input.cls += ' input-' + this.size;
15947 ['xs','sm','md','lg'].map(function(size){
15948 if (settings[size]) {
15949 cfg.cls += ' col-' + size + '-' + settings[size];
15953 var inputblock = input;
15955 if (this.before || this.after) {
15958 cls : 'input-group',
15962 inputblock.cn.push({
15964 cls : 'input-group-addon',
15968 inputblock.cn.push(input);
15970 inputblock.cn.push({
15972 cls : 'input-group-addon',
15979 if (align ==='left' && this.fieldLabel.length) {
15980 Roo.log("left and has label");
15986 cls : 'control-label col-md-' + this.labelWidth,
15987 html : this.fieldLabel
15991 cls : "col-md-" + (12 - this.labelWidth),
15998 } else if ( this.fieldLabel.length) {
16005 cls: 'control-label box-input-label',
16006 //cls : 'input-group-addon',
16007 html : this.fieldLabel
16017 Roo.log(" no label && no align");
16032 html: this.boxLabel
16039 inputEl: function ()
16041 return this.el.select('input.roo-radio',true).first();
16043 onClick : function()
16045 this.setChecked(true);
16048 setChecked : function(state,suppressEvent)
16051 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16052 v.dom.checked = false;
16056 this.checked = state;
16057 this.inputEl().dom.checked = state;
16059 if(suppressEvent !== true){
16060 this.fireEvent('check', this, state);
16063 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16067 getGroupValue : function()
16070 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16071 if(v.dom.checked == true){
16072 value = v.dom.value;
16080 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16081 * @return {Mixed} value The field value
16083 getValue : function(){
16084 return this.getGroupValue();
16090 //<script type="text/javascript">
16093 * Based Ext JS Library 1.1.1
16094 * Copyright(c) 2006-2007, Ext JS, LLC.
16100 * @class Roo.HtmlEditorCore
16101 * @extends Roo.Component
16102 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16104 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16107 Roo.HtmlEditorCore = function(config){
16110 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16113 * @event initialize
16114 * Fires when the editor is fully initialized (including the iframe)
16115 * @param {Roo.HtmlEditorCore} this
16120 * Fires when the editor is first receives the focus. Any insertion must wait
16121 * until after this event.
16122 * @param {Roo.HtmlEditorCore} this
16126 * @event beforesync
16127 * Fires before the textarea is updated with content from the editor iframe. Return false
16128 * to cancel the sync.
16129 * @param {Roo.HtmlEditorCore} this
16130 * @param {String} html
16134 * @event beforepush
16135 * Fires before the iframe editor is updated with content from the textarea. Return false
16136 * to cancel the push.
16137 * @param {Roo.HtmlEditorCore} this
16138 * @param {String} html
16143 * Fires when the textarea is updated with content from the editor iframe.
16144 * @param {Roo.HtmlEditorCore} this
16145 * @param {String} html
16150 * Fires when the iframe editor is updated with content from the textarea.
16151 * @param {Roo.HtmlEditorCore} this
16152 * @param {String} html
16157 * @event editorevent
16158 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16159 * @param {Roo.HtmlEditorCore} this
16167 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16171 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16177 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16182 * @cfg {Number} height (in pixels)
16186 * @cfg {Number} width (in pixels)
16191 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16194 stylesheets: false,
16199 // private properties
16200 validationEvent : false,
16202 initialized : false,
16204 sourceEditMode : false,
16205 onFocus : Roo.emptyFn,
16207 hideMode:'offsets',
16215 * Protected method that will not generally be called directly. It
16216 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16217 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16219 getDocMarkup : function(){
16222 Roo.log(this.stylesheets);
16224 // inherit styels from page...??
16225 if (this.stylesheets === false) {
16227 Roo.get(document.head).select('style').each(function(node) {
16228 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16231 Roo.get(document.head).select('link').each(function(node) {
16232 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16235 } else if (!this.stylesheets.length) {
16237 st = '<style type="text/css">' +
16238 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16241 Roo.each(this.stylesheets, function(s) {
16242 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16247 st += '<style type="text/css">' +
16248 'IMG { cursor: pointer } ' +
16252 return '<html><head>' + st +
16253 //<style type="text/css">' +
16254 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16256 ' </head><body class="roo-htmleditor-body"></body></html>';
16260 onRender : function(ct, position)
16263 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16264 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16267 this.el.dom.style.border = '0 none';
16268 this.el.dom.setAttribute('tabIndex', -1);
16269 this.el.addClass('x-hidden hide');
16273 if(Roo.isIE){ // fix IE 1px bogus margin
16274 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16278 this.frameId = Roo.id();
16282 var iframe = this.owner.wrap.createChild({
16284 cls: 'form-control', // bootstrap..
16286 name: this.frameId,
16287 frameBorder : 'no',
16288 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16293 this.iframe = iframe.dom;
16295 this.assignDocWin();
16297 this.doc.designMode = 'on';
16300 this.doc.write(this.getDocMarkup());
16304 var task = { // must defer to wait for browser to be ready
16306 //console.log("run task?" + this.doc.readyState);
16307 this.assignDocWin();
16308 if(this.doc.body || this.doc.readyState == 'complete'){
16310 this.doc.designMode="on";
16314 Roo.TaskMgr.stop(task);
16315 this.initEditor.defer(10, this);
16322 Roo.TaskMgr.start(task);
16329 onResize : function(w, h)
16331 Roo.log('resize: ' +w + ',' + h );
16332 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16336 if(typeof w == 'number'){
16338 this.iframe.style.width = w + 'px';
16340 if(typeof h == 'number'){
16342 this.iframe.style.height = h + 'px';
16344 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16351 * Toggles the editor between standard and source edit mode.
16352 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16354 toggleSourceEdit : function(sourceEditMode){
16356 this.sourceEditMode = sourceEditMode === true;
16358 if(this.sourceEditMode){
16360 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16363 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16364 //this.iframe.className = '';
16367 //this.setSize(this.owner.wrap.getSize());
16368 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16375 * Protected method that will not generally be called directly. If you need/want
16376 * custom HTML cleanup, this is the method you should override.
16377 * @param {String} html The HTML to be cleaned
16378 * return {String} The cleaned HTML
16380 cleanHtml : function(html){
16381 html = String(html);
16382 if(html.length > 5){
16383 if(Roo.isSafari){ // strip safari nonsense
16384 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16387 if(html == ' '){
16394 * HTML Editor -> Textarea
16395 * Protected method that will not generally be called directly. Syncs the contents
16396 * of the editor iframe with the textarea.
16398 syncValue : function(){
16399 if(this.initialized){
16400 var bd = (this.doc.body || this.doc.documentElement);
16401 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16402 var html = bd.innerHTML;
16404 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16405 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16407 html = '<div style="'+m[0]+'">' + html + '</div>';
16410 html = this.cleanHtml(html);
16411 // fix up the special chars.. normaly like back quotes in word...
16412 // however we do not want to do this with chinese..
16413 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16414 var cc = b.charCodeAt();
16416 (cc >= 0x4E00 && cc < 0xA000 ) ||
16417 (cc >= 0x3400 && cc < 0x4E00 ) ||
16418 (cc >= 0xf900 && cc < 0xfb00 )
16424 if(this.owner.fireEvent('beforesync', this, html) !== false){
16425 this.el.dom.value = html;
16426 this.owner.fireEvent('sync', this, html);
16432 * Protected method that will not generally be called directly. Pushes the value of the textarea
16433 * into the iframe editor.
16435 pushValue : function(){
16436 if(this.initialized){
16437 var v = this.el.dom.value.trim();
16439 // if(v.length < 1){
16443 if(this.owner.fireEvent('beforepush', this, v) !== false){
16444 var d = (this.doc.body || this.doc.documentElement);
16446 this.cleanUpPaste();
16447 this.el.dom.value = d.innerHTML;
16448 this.owner.fireEvent('push', this, v);
16454 deferFocus : function(){
16455 this.focus.defer(10, this);
16459 focus : function(){
16460 if(this.win && !this.sourceEditMode){
16467 assignDocWin: function()
16469 var iframe = this.iframe;
16472 this.doc = iframe.contentWindow.document;
16473 this.win = iframe.contentWindow;
16475 if (!Roo.get(this.frameId)) {
16478 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16479 this.win = Roo.get(this.frameId).dom.contentWindow;
16484 initEditor : function(){
16485 //console.log("INIT EDITOR");
16486 this.assignDocWin();
16490 this.doc.designMode="on";
16492 this.doc.write(this.getDocMarkup());
16495 var dbody = (this.doc.body || this.doc.documentElement);
16496 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16497 // this copies styles from the containing element into thsi one..
16498 // not sure why we need all of this..
16499 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16501 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16502 //ss['background-attachment'] = 'fixed'; // w3c
16503 dbody.bgProperties = 'fixed'; // ie
16504 //Roo.DomHelper.applyStyles(dbody, ss);
16505 Roo.EventManager.on(this.doc, {
16506 //'mousedown': this.onEditorEvent,
16507 'mouseup': this.onEditorEvent,
16508 'dblclick': this.onEditorEvent,
16509 'click': this.onEditorEvent,
16510 'keyup': this.onEditorEvent,
16515 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16517 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16518 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16520 this.initialized = true;
16522 this.owner.fireEvent('initialize', this);
16527 onDestroy : function(){
16533 //for (var i =0; i < this.toolbars.length;i++) {
16534 // // fixme - ask toolbars for heights?
16535 // this.toolbars[i].onDestroy();
16538 //this.wrap.dom.innerHTML = '';
16539 //this.wrap.remove();
16544 onFirstFocus : function(){
16546 this.assignDocWin();
16549 this.activated = true;
16552 if(Roo.isGecko){ // prevent silly gecko errors
16554 var s = this.win.getSelection();
16555 if(!s.focusNode || s.focusNode.nodeType != 3){
16556 var r = s.getRangeAt(0);
16557 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16562 this.execCmd('useCSS', true);
16563 this.execCmd('styleWithCSS', false);
16566 this.owner.fireEvent('activate', this);
16570 adjustFont: function(btn){
16571 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16572 //if(Roo.isSafari){ // safari
16575 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16576 if(Roo.isSafari){ // safari
16577 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16578 v = (v < 10) ? 10 : v;
16579 v = (v > 48) ? 48 : v;
16580 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16585 v = Math.max(1, v+adjust);
16587 this.execCmd('FontSize', v );
16590 onEditorEvent : function(e){
16591 this.owner.fireEvent('editorevent', this, e);
16592 // this.updateToolbar();
16593 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16596 insertTag : function(tg)
16598 // could be a bit smarter... -> wrap the current selected tRoo..
16599 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16601 range = this.createRange(this.getSelection());
16602 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16603 wrappingNode.appendChild(range.extractContents());
16604 range.insertNode(wrappingNode);
16611 this.execCmd("formatblock", tg);
16615 insertText : function(txt)
16619 var range = this.createRange();
16620 range.deleteContents();
16621 //alert(Sender.getAttribute('label'));
16623 range.insertNode(this.doc.createTextNode(txt));
16629 * Executes a Midas editor command on the editor document and performs necessary focus and
16630 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16631 * @param {String} cmd The Midas command
16632 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16634 relayCmd : function(cmd, value){
16636 this.execCmd(cmd, value);
16637 this.owner.fireEvent('editorevent', this);
16638 //this.updateToolbar();
16639 this.owner.deferFocus();
16643 * Executes a Midas editor command directly on the editor document.
16644 * For visual commands, you should use {@link #relayCmd} instead.
16645 * <b>This should only be called after the editor is initialized.</b>
16646 * @param {String} cmd The Midas command
16647 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16649 execCmd : function(cmd, value){
16650 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16657 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16659 * @param {String} text | dom node..
16661 insertAtCursor : function(text)
16666 if(!this.activated){
16672 var r = this.doc.selection.createRange();
16683 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16687 // from jquery ui (MIT licenced)
16689 var win = this.win;
16691 if (win.getSelection && win.getSelection().getRangeAt) {
16692 range = win.getSelection().getRangeAt(0);
16693 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16694 range.insertNode(node);
16695 } else if (win.document.selection && win.document.selection.createRange) {
16696 // no firefox support
16697 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16698 win.document.selection.createRange().pasteHTML(txt);
16700 // no firefox support
16701 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16702 this.execCmd('InsertHTML', txt);
16711 mozKeyPress : function(e){
16713 var c = e.getCharCode(), cmd;
16716 c = String.fromCharCode(c).toLowerCase();
16730 this.cleanUpPaste.defer(100, this);
16738 e.preventDefault();
16746 fixKeys : function(){ // load time branching for fastest keydown performance
16748 return function(e){
16749 var k = e.getKey(), r;
16752 r = this.doc.selection.createRange();
16755 r.pasteHTML('    ');
16762 r = this.doc.selection.createRange();
16764 var target = r.parentElement();
16765 if(!target || target.tagName.toLowerCase() != 'li'){
16767 r.pasteHTML('<br />');
16773 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16774 this.cleanUpPaste.defer(100, this);
16780 }else if(Roo.isOpera){
16781 return function(e){
16782 var k = e.getKey();
16786 this.execCmd('InsertHTML','    ');
16789 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16790 this.cleanUpPaste.defer(100, this);
16795 }else if(Roo.isSafari){
16796 return function(e){
16797 var k = e.getKey();
16801 this.execCmd('InsertText','\t');
16805 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16806 this.cleanUpPaste.defer(100, this);
16814 getAllAncestors: function()
16816 var p = this.getSelectedNode();
16819 a.push(p); // push blank onto stack..
16820 p = this.getParentElement();
16824 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16828 a.push(this.doc.body);
16832 lastSelNode : false,
16835 getSelection : function()
16837 this.assignDocWin();
16838 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16841 getSelectedNode: function()
16843 // this may only work on Gecko!!!
16845 // should we cache this!!!!
16850 var range = this.createRange(this.getSelection()).cloneRange();
16853 var parent = range.parentElement();
16855 var testRange = range.duplicate();
16856 testRange.moveToElementText(parent);
16857 if (testRange.inRange(range)) {
16860 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16863 parent = parent.parentElement;
16868 // is ancestor a text element.
16869 var ac = range.commonAncestorContainer;
16870 if (ac.nodeType == 3) {
16871 ac = ac.parentNode;
16874 var ar = ac.childNodes;
16877 var other_nodes = [];
16878 var has_other_nodes = false;
16879 for (var i=0;i<ar.length;i++) {
16880 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16883 // fullly contained node.
16885 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16890 // probably selected..
16891 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16892 other_nodes.push(ar[i]);
16896 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16901 has_other_nodes = true;
16903 if (!nodes.length && other_nodes.length) {
16904 nodes= other_nodes;
16906 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16912 createRange: function(sel)
16914 // this has strange effects when using with
16915 // top toolbar - not sure if it's a great idea.
16916 //this.editor.contentWindow.focus();
16917 if (typeof sel != "undefined") {
16919 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16921 return this.doc.createRange();
16924 return this.doc.createRange();
16927 getParentElement: function()
16930 this.assignDocWin();
16931 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16933 var range = this.createRange(sel);
16936 var p = range.commonAncestorContainer;
16937 while (p.nodeType == 3) { // text node
16948 * Range intersection.. the hard stuff...
16952 * [ -- selected range --- ]
16956 * if end is before start or hits it. fail.
16957 * if start is after end or hits it fail.
16959 * if either hits (but other is outside. - then it's not
16965 // @see http://www.thismuchiknow.co.uk/?p=64.
16966 rangeIntersectsNode : function(range, node)
16968 var nodeRange = node.ownerDocument.createRange();
16970 nodeRange.selectNode(node);
16972 nodeRange.selectNodeContents(node);
16975 var rangeStartRange = range.cloneRange();
16976 rangeStartRange.collapse(true);
16978 var rangeEndRange = range.cloneRange();
16979 rangeEndRange.collapse(false);
16981 var nodeStartRange = nodeRange.cloneRange();
16982 nodeStartRange.collapse(true);
16984 var nodeEndRange = nodeRange.cloneRange();
16985 nodeEndRange.collapse(false);
16987 return rangeStartRange.compareBoundaryPoints(
16988 Range.START_TO_START, nodeEndRange) == -1 &&
16989 rangeEndRange.compareBoundaryPoints(
16990 Range.START_TO_START, nodeStartRange) == 1;
16994 rangeCompareNode : function(range, node)
16996 var nodeRange = node.ownerDocument.createRange();
16998 nodeRange.selectNode(node);
17000 nodeRange.selectNodeContents(node);
17004 range.collapse(true);
17006 nodeRange.collapse(true);
17008 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17009 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17011 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17013 var nodeIsBefore = ss == 1;
17014 var nodeIsAfter = ee == -1;
17016 if (nodeIsBefore && nodeIsAfter)
17018 if (!nodeIsBefore && nodeIsAfter)
17019 return 1; //right trailed.
17021 if (nodeIsBefore && !nodeIsAfter)
17022 return 2; // left trailed.
17027 // private? - in a new class?
17028 cleanUpPaste : function()
17030 // cleans up the whole document..
17031 Roo.log('cleanuppaste');
17033 this.cleanUpChildren(this.doc.body);
17034 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17035 if (clean != this.doc.body.innerHTML) {
17036 this.doc.body.innerHTML = clean;
17041 cleanWordChars : function(input) {// change the chars to hex code
17042 var he = Roo.HtmlEditorCore;
17044 var output = input;
17045 Roo.each(he.swapCodes, function(sw) {
17046 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17048 output = output.replace(swapper, sw[1]);
17055 cleanUpChildren : function (n)
17057 if (!n.childNodes.length) {
17060 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17061 this.cleanUpChild(n.childNodes[i]);
17068 cleanUpChild : function (node)
17071 //console.log(node);
17072 if (node.nodeName == "#text") {
17073 // clean up silly Windows -- stuff?
17076 if (node.nodeName == "#comment") {
17077 node.parentNode.removeChild(node);
17078 // clean up silly Windows -- stuff?
17082 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17084 node.parentNode.removeChild(node);
17089 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17091 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17092 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17094 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17095 // remove_keep_children = true;
17098 if (remove_keep_children) {
17099 this.cleanUpChildren(node);
17100 // inserts everything just before this node...
17101 while (node.childNodes.length) {
17102 var cn = node.childNodes[0];
17103 node.removeChild(cn);
17104 node.parentNode.insertBefore(cn, node);
17106 node.parentNode.removeChild(node);
17110 if (!node.attributes || !node.attributes.length) {
17111 this.cleanUpChildren(node);
17115 function cleanAttr(n,v)
17118 if (v.match(/^\./) || v.match(/^\//)) {
17121 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17124 if (v.match(/^#/)) {
17127 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17128 node.removeAttribute(n);
17132 function cleanStyle(n,v)
17134 if (v.match(/expression/)) { //XSS?? should we even bother..
17135 node.removeAttribute(n);
17138 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17139 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17142 var parts = v.split(/;/);
17145 Roo.each(parts, function(p) {
17146 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17150 var l = p.split(':').shift().replace(/\s+/g,'');
17151 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17153 if ( cblack.indexOf(l) > -1) {
17154 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17155 //node.removeAttribute(n);
17159 // only allow 'c whitelisted system attributes'
17160 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17161 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17162 //node.removeAttribute(n);
17172 if (clean.length) {
17173 node.setAttribute(n, clean.join(';'));
17175 node.removeAttribute(n);
17181 for (var i = node.attributes.length-1; i > -1 ; i--) {
17182 var a = node.attributes[i];
17185 if (a.name.toLowerCase().substr(0,2)=='on') {
17186 node.removeAttribute(a.name);
17189 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17190 node.removeAttribute(a.name);
17193 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17194 cleanAttr(a.name,a.value); // fixme..
17197 if (a.name == 'style') {
17198 cleanStyle(a.name,a.value);
17201 /// clean up MS crap..
17202 // tecnically this should be a list of valid class'es..
17205 if (a.name == 'class') {
17206 if (a.value.match(/^Mso/)) {
17207 node.className = '';
17210 if (a.value.match(/body/)) {
17211 node.className = '';
17222 this.cleanUpChildren(node);
17227 * Clean up MS wordisms...
17229 cleanWord : function(node)
17232 var cleanWordChildren = function()
17234 if (!node.childNodes.length) {
17237 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17238 _t.cleanWord(node.childNodes[i]);
17244 this.cleanWord(this.doc.body);
17247 if (node.nodeName == "#text") {
17248 // clean up silly Windows -- stuff?
17251 if (node.nodeName == "#comment") {
17252 node.parentNode.removeChild(node);
17253 // clean up silly Windows -- stuff?
17257 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17258 node.parentNode.removeChild(node);
17262 // remove - but keep children..
17263 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17264 while (node.childNodes.length) {
17265 var cn = node.childNodes[0];
17266 node.removeChild(cn);
17267 node.parentNode.insertBefore(cn, node);
17269 node.parentNode.removeChild(node);
17270 cleanWordChildren();
17274 if (node.className.length) {
17276 var cn = node.className.split(/\W+/);
17278 Roo.each(cn, function(cls) {
17279 if (cls.match(/Mso[a-zA-Z]+/)) {
17284 node.className = cna.length ? cna.join(' ') : '';
17286 node.removeAttribute("class");
17290 if (node.hasAttribute("lang")) {
17291 node.removeAttribute("lang");
17294 if (node.hasAttribute("style")) {
17296 var styles = node.getAttribute("style").split(";");
17298 Roo.each(styles, function(s) {
17299 if (!s.match(/:/)) {
17302 var kv = s.split(":");
17303 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17306 // what ever is left... we allow.
17309 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17310 if (!nstyle.length) {
17311 node.removeAttribute('style');
17315 cleanWordChildren();
17319 domToHTML : function(currentElement, depth, nopadtext) {
17321 depth = depth || 0;
17322 nopadtext = nopadtext || false;
17324 if (!currentElement) {
17325 return this.domToHTML(this.doc.body);
17328 //Roo.log(currentElement);
17330 var allText = false;
17331 var nodeName = currentElement.nodeName;
17332 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17334 if (nodeName == '#text') {
17335 return currentElement.nodeValue;
17340 if (nodeName != 'BODY') {
17343 // Prints the node tagName, such as <A>, <IMG>, etc
17346 for(i = 0; i < currentElement.attributes.length;i++) {
17348 var aname = currentElement.attributes.item(i).name;
17349 if (!currentElement.attributes.item(i).value.length) {
17352 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17355 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17364 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17367 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17372 // Traverse the tree
17374 var currentElementChild = currentElement.childNodes.item(i);
17375 var allText = true;
17376 var innerHTML = '';
17378 while (currentElementChild) {
17379 // Formatting code (indent the tree so it looks nice on the screen)
17380 var nopad = nopadtext;
17381 if (lastnode == 'SPAN') {
17385 if (currentElementChild.nodeName == '#text') {
17386 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17387 if (!nopad && toadd.length > 80) {
17388 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17390 innerHTML += toadd;
17393 currentElementChild = currentElement.childNodes.item(i);
17399 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17401 // Recursively traverse the tree structure of the child node
17402 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17403 lastnode = currentElementChild.nodeName;
17405 currentElementChild=currentElement.childNodes.item(i);
17411 // The remaining code is mostly for formatting the tree
17412 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17417 ret+= "</"+tagName+">";
17423 // hide stuff that is not compatible
17437 * @event specialkey
17441 * @cfg {String} fieldClass @hide
17444 * @cfg {String} focusClass @hide
17447 * @cfg {String} autoCreate @hide
17450 * @cfg {String} inputType @hide
17453 * @cfg {String} invalidClass @hide
17456 * @cfg {String} invalidText @hide
17459 * @cfg {String} msgFx @hide
17462 * @cfg {String} validateOnBlur @hide
17466 Roo.HtmlEditorCore.white = [
17467 'area', 'br', 'img', 'input', 'hr', 'wbr',
17469 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17470 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17471 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17472 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17473 'table', 'ul', 'xmp',
17475 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17478 'dir', 'menu', 'ol', 'ul', 'dl',
17484 Roo.HtmlEditorCore.black = [
17485 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17487 'base', 'basefont', 'bgsound', 'blink', 'body',
17488 'frame', 'frameset', 'head', 'html', 'ilayer',
17489 'iframe', 'layer', 'link', 'meta', 'object',
17490 'script', 'style' ,'title', 'xml' // clean later..
17492 Roo.HtmlEditorCore.clean = [
17493 'script', 'style', 'title', 'xml'
17495 Roo.HtmlEditorCore.remove = [
17500 Roo.HtmlEditorCore.ablack = [
17504 Roo.HtmlEditorCore.aclean = [
17505 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17509 Roo.HtmlEditorCore.pwhite= [
17510 'http', 'https', 'mailto'
17513 // white listed style attributes.
17514 Roo.HtmlEditorCore.cwhite= [
17515 // 'text-align', /// default is to allow most things..
17521 // black listed style attributes.
17522 Roo.HtmlEditorCore.cblack= [
17523 // 'font-size' -- this can be set by the project
17527 Roo.HtmlEditorCore.swapCodes =[
17546 * @class Roo.bootstrap.HtmlEditor
17547 * @extends Roo.bootstrap.TextArea
17548 * Bootstrap HtmlEditor class
17551 * Create a new HtmlEditor
17552 * @param {Object} config The config object
17555 Roo.bootstrap.HtmlEditor = function(config){
17556 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17557 if (!this.toolbars) {
17558 this.toolbars = [];
17560 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17563 * @event initialize
17564 * Fires when the editor is fully initialized (including the iframe)
17565 * @param {HtmlEditor} this
17570 * Fires when the editor is first receives the focus. Any insertion must wait
17571 * until after this event.
17572 * @param {HtmlEditor} this
17576 * @event beforesync
17577 * Fires before the textarea is updated with content from the editor iframe. Return false
17578 * to cancel the sync.
17579 * @param {HtmlEditor} this
17580 * @param {String} html
17584 * @event beforepush
17585 * Fires before the iframe editor is updated with content from the textarea. Return false
17586 * to cancel the push.
17587 * @param {HtmlEditor} this
17588 * @param {String} html
17593 * Fires when the textarea is updated with content from the editor iframe.
17594 * @param {HtmlEditor} this
17595 * @param {String} html
17600 * Fires when the iframe editor is updated with content from the textarea.
17601 * @param {HtmlEditor} this
17602 * @param {String} html
17606 * @event editmodechange
17607 * Fires when the editor switches edit modes
17608 * @param {HtmlEditor} this
17609 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17611 editmodechange: true,
17613 * @event editorevent
17614 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17615 * @param {HtmlEditor} this
17619 * @event firstfocus
17620 * Fires when on first focus - needed by toolbars..
17621 * @param {HtmlEditor} this
17626 * Auto save the htmlEditor value as a file into Events
17627 * @param {HtmlEditor} this
17631 * @event savedpreview
17632 * preview the saved version of htmlEditor
17633 * @param {HtmlEditor} this
17640 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17644 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17649 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17654 * @cfg {Number} height (in pixels)
17658 * @cfg {Number} width (in pixels)
17663 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17666 stylesheets: false,
17671 // private properties
17672 validationEvent : false,
17674 initialized : false,
17677 onFocus : Roo.emptyFn,
17679 hideMode:'offsets',
17682 tbContainer : false,
17684 toolbarContainer :function() {
17685 return this.wrap.select('.x-html-editor-tb',true).first();
17689 * Protected method that will not generally be called directly. It
17690 * is called when the editor creates its toolbar. Override this method if you need to
17691 * add custom toolbar buttons.
17692 * @param {HtmlEditor} editor
17694 createToolbar : function(){
17696 Roo.log("create toolbars");
17698 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17699 this.toolbars[0].render(this.toolbarContainer());
17703 // if (!editor.toolbars || !editor.toolbars.length) {
17704 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17707 // for (var i =0 ; i < editor.toolbars.length;i++) {
17708 // editor.toolbars[i] = Roo.factory(
17709 // typeof(editor.toolbars[i]) == 'string' ?
17710 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17711 // Roo.bootstrap.HtmlEditor);
17712 // editor.toolbars[i].init(editor);
17718 onRender : function(ct, position)
17720 // Roo.log("Call onRender: " + this.xtype);
17722 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17724 this.wrap = this.inputEl().wrap({
17725 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17728 this.editorcore.onRender(ct, position);
17730 if (this.resizable) {
17731 this.resizeEl = new Roo.Resizable(this.wrap, {
17735 minHeight : this.height,
17736 height: this.height,
17737 handles : this.resizable,
17740 resize : function(r, w, h) {
17741 _t.onResize(w,h); // -something
17747 this.createToolbar(this);
17750 if(!this.width && this.resizable){
17751 this.setSize(this.wrap.getSize());
17753 if (this.resizeEl) {
17754 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17755 // should trigger onReize..
17761 onResize : function(w, h)
17763 Roo.log('resize: ' +w + ',' + h );
17764 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17768 if(this.inputEl() ){
17769 if(typeof w == 'number'){
17770 var aw = w - this.wrap.getFrameWidth('lr');
17771 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17774 if(typeof h == 'number'){
17775 var tbh = -11; // fixme it needs to tool bar size!
17776 for (var i =0; i < this.toolbars.length;i++) {
17777 // fixme - ask toolbars for heights?
17778 tbh += this.toolbars[i].el.getHeight();
17779 //if (this.toolbars[i].footer) {
17780 // tbh += this.toolbars[i].footer.el.getHeight();
17788 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17789 ah -= 5; // knock a few pixes off for look..
17790 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17794 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17795 this.editorcore.onResize(ew,eh);
17800 * Toggles the editor between standard and source edit mode.
17801 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17803 toggleSourceEdit : function(sourceEditMode)
17805 this.editorcore.toggleSourceEdit(sourceEditMode);
17807 if(this.editorcore.sourceEditMode){
17808 Roo.log('editor - showing textarea');
17811 // Roo.log(this.syncValue());
17813 this.inputEl().removeClass(['hide', 'x-hidden']);
17814 this.inputEl().dom.removeAttribute('tabIndex');
17815 this.inputEl().focus();
17817 Roo.log('editor - hiding textarea');
17819 // Roo.log(this.pushValue());
17822 this.inputEl().addClass(['hide', 'x-hidden']);
17823 this.inputEl().dom.setAttribute('tabIndex', -1);
17824 //this.deferFocus();
17827 if(this.resizable){
17828 this.setSize(this.wrap.getSize());
17831 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17834 // private (for BoxComponent)
17835 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17837 // private (for BoxComponent)
17838 getResizeEl : function(){
17842 // private (for BoxComponent)
17843 getPositionEl : function(){
17848 initEvents : function(){
17849 this.originalValue = this.getValue();
17853 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17856 // markInvalid : Roo.emptyFn,
17858 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17861 // clearInvalid : Roo.emptyFn,
17863 setValue : function(v){
17864 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17865 this.editorcore.pushValue();
17870 deferFocus : function(){
17871 this.focus.defer(10, this);
17875 focus : function(){
17876 this.editorcore.focus();
17882 onDestroy : function(){
17888 for (var i =0; i < this.toolbars.length;i++) {
17889 // fixme - ask toolbars for heights?
17890 this.toolbars[i].onDestroy();
17893 this.wrap.dom.innerHTML = '';
17894 this.wrap.remove();
17899 onFirstFocus : function(){
17900 //Roo.log("onFirstFocus");
17901 this.editorcore.onFirstFocus();
17902 for (var i =0; i < this.toolbars.length;i++) {
17903 this.toolbars[i].onFirstFocus();
17909 syncValue : function()
17911 this.editorcore.syncValue();
17914 pushValue : function()
17916 this.editorcore.pushValue();
17920 // hide stuff that is not compatible
17934 * @event specialkey
17938 * @cfg {String} fieldClass @hide
17941 * @cfg {String} focusClass @hide
17944 * @cfg {String} autoCreate @hide
17947 * @cfg {String} inputType @hide
17950 * @cfg {String} invalidClass @hide
17953 * @cfg {String} invalidText @hide
17956 * @cfg {String} msgFx @hide
17959 * @cfg {String} validateOnBlur @hide
17968 Roo.namespace('Roo.bootstrap.htmleditor');
17970 * @class Roo.bootstrap.HtmlEditorToolbar1
17975 new Roo.bootstrap.HtmlEditor({
17978 new Roo.bootstrap.HtmlEditorToolbar1({
17979 disable : { fonts: 1 , format: 1, ..., ... , ...],
17985 * @cfg {Object} disable List of elements to disable..
17986 * @cfg {Array} btns List of additional buttons.
17990 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17993 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17996 Roo.apply(this, config);
17998 // default disabled, based on 'good practice'..
17999 this.disable = this.disable || {};
18000 Roo.applyIf(this.disable, {
18003 specialElements : true
18005 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18007 this.editor = config.editor;
18008 this.editorcore = config.editor.editorcore;
18010 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18012 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18013 // dont call parent... till later.
18015 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18020 editorcore : false,
18025 "h1","h2","h3","h4","h5","h6",
18027 "abbr", "acronym", "address", "cite", "samp", "var",
18031 onRender : function(ct, position)
18033 // Roo.log("Call onRender: " + this.xtype);
18035 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18037 this.el.dom.style.marginBottom = '0';
18039 var editorcore = this.editorcore;
18040 var editor= this.editor;
18043 var btn = function(id,cmd , toggle, handler){
18045 var event = toggle ? 'toggle' : 'click';
18050 xns: Roo.bootstrap,
18053 enableToggle:toggle !== false,
18055 pressed : toggle ? false : null,
18058 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18059 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18068 xns: Roo.bootstrap,
18069 glyphicon : 'font',
18073 xns: Roo.bootstrap,
18077 Roo.each(this.formats, function(f) {
18078 style.menu.items.push({
18080 xns: Roo.bootstrap,
18081 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18086 editorcore.insertTag(this.tagname);
18093 children.push(style);
18096 btn('bold',false,true);
18097 btn('italic',false,true);
18098 btn('align-left', 'justifyleft',true);
18099 btn('align-center', 'justifycenter',true);
18100 btn('align-right' , 'justifyright',true);
18101 btn('link', false, false, function(btn) {
18102 //Roo.log("create link?");
18103 var url = prompt(this.createLinkText, this.defaultLinkValue);
18104 if(url && url != 'http:/'+'/'){
18105 this.editorcore.relayCmd('createlink', url);
18108 btn('list','insertunorderedlist',true);
18109 btn('pencil', false,true, function(btn){
18112 this.toggleSourceEdit(btn.pressed);
18118 xns: Roo.bootstrap,
18123 xns: Roo.bootstrap,
18128 cog.menu.items.push({
18130 xns: Roo.bootstrap,
18131 html : Clean styles,
18136 editorcore.insertTag(this.tagname);
18145 this.xtype = 'NavSimplebar';
18147 for(var i=0;i< children.length;i++) {
18149 this.buttons.add(this.addxtypeChild(children[i]));
18153 editor.on('editorevent', this.updateToolbar, this);
18155 onBtnClick : function(id)
18157 this.editorcore.relayCmd(id);
18158 this.editorcore.focus();
18162 * Protected method that will not generally be called directly. It triggers
18163 * a toolbar update by reading the markup state of the current selection in the editor.
18165 updateToolbar: function(){
18167 if(!this.editorcore.activated){
18168 this.editor.onFirstFocus(); // is this neeed?
18172 var btns = this.buttons;
18173 var doc = this.editorcore.doc;
18174 btns.get('bold').setActive(doc.queryCommandState('bold'));
18175 btns.get('italic').setActive(doc.queryCommandState('italic'));
18176 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18178 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18179 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18180 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18182 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18183 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18186 var ans = this.editorcore.getAllAncestors();
18187 if (this.formatCombo) {
18190 var store = this.formatCombo.store;
18191 this.formatCombo.setValue("");
18192 for (var i =0; i < ans.length;i++) {
18193 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18195 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18203 // hides menus... - so this cant be on a menu...
18204 Roo.bootstrap.MenuMgr.hideAll();
18206 Roo.bootstrap.MenuMgr.hideAll();
18207 //this.editorsyncValue();
18209 onFirstFocus: function() {
18210 this.buttons.each(function(item){
18214 toggleSourceEdit : function(sourceEditMode){
18217 if(sourceEditMode){
18218 Roo.log("disabling buttons");
18219 this.buttons.each( function(item){
18220 if(item.cmd != 'pencil'){
18226 Roo.log("enabling buttons");
18227 if(this.editorcore.initialized){
18228 this.buttons.each( function(item){
18234 Roo.log("calling toggole on editor");
18235 // tell the editor that it's been pressed..
18236 this.editor.toggleSourceEdit(sourceEditMode);
18246 * @class Roo.bootstrap.Table.AbstractSelectionModel
18247 * @extends Roo.util.Observable
18248 * Abstract base class for grid SelectionModels. It provides the interface that should be
18249 * implemented by descendant classes. This class should not be directly instantiated.
18252 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18253 this.locked = false;
18254 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18258 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18259 /** @ignore Called by the grid automatically. Do not call directly. */
18260 init : function(grid){
18266 * Locks the selections.
18269 this.locked = true;
18273 * Unlocks the selections.
18275 unlock : function(){
18276 this.locked = false;
18280 * Returns true if the selections are locked.
18281 * @return {Boolean}
18283 isLocked : function(){
18284 return this.locked;
18288 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18289 * @class Roo.bootstrap.Table.RowSelectionModel
18290 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18291 * It supports multiple selections and keyboard selection/navigation.
18293 * @param {Object} config
18296 Roo.bootstrap.Table.RowSelectionModel = function(config){
18297 Roo.apply(this, config);
18298 this.selections = new Roo.util.MixedCollection(false, function(o){
18303 this.lastActive = false;
18307 * @event selectionchange
18308 * Fires when the selection changes
18309 * @param {SelectionModel} this
18311 "selectionchange" : true,
18313 * @event afterselectionchange
18314 * Fires after the selection changes (eg. by key press or clicking)
18315 * @param {SelectionModel} this
18317 "afterselectionchange" : true,
18319 * @event beforerowselect
18320 * Fires when a row is selected being selected, return false to cancel.
18321 * @param {SelectionModel} this
18322 * @param {Number} rowIndex The selected index
18323 * @param {Boolean} keepExisting False if other selections will be cleared
18325 "beforerowselect" : true,
18328 * Fires when a row is selected.
18329 * @param {SelectionModel} this
18330 * @param {Number} rowIndex The selected index
18331 * @param {Roo.data.Record} r The record
18333 "rowselect" : true,
18335 * @event rowdeselect
18336 * Fires when a row is deselected.
18337 * @param {SelectionModel} this
18338 * @param {Number} rowIndex The selected index
18340 "rowdeselect" : true
18342 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18343 this.locked = false;
18346 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18348 * @cfg {Boolean} singleSelect
18349 * True to allow selection of only one row at a time (defaults to false)
18351 singleSelect : false,
18354 initEvents : function(){
18356 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18357 this.grid.on("mousedown", this.handleMouseDown, this);
18358 }else{ // allow click to work like normal
18359 this.grid.on("rowclick", this.handleDragableRowClick, this);
18362 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18363 "up" : function(e){
18365 this.selectPrevious(e.shiftKey);
18366 }else if(this.last !== false && this.lastActive !== false){
18367 var last = this.last;
18368 this.selectRange(this.last, this.lastActive-1);
18369 this.grid.getView().focusRow(this.lastActive);
18370 if(last !== false){
18374 this.selectFirstRow();
18376 this.fireEvent("afterselectionchange", this);
18378 "down" : function(e){
18380 this.selectNext(e.shiftKey);
18381 }else if(this.last !== false && this.lastActive !== false){
18382 var last = this.last;
18383 this.selectRange(this.last, this.lastActive+1);
18384 this.grid.getView().focusRow(this.lastActive);
18385 if(last !== false){
18389 this.selectFirstRow();
18391 this.fireEvent("afterselectionchange", this);
18396 var view = this.grid.view;
18397 view.on("refresh", this.onRefresh, this);
18398 view.on("rowupdated", this.onRowUpdated, this);
18399 view.on("rowremoved", this.onRemove, this);
18403 onRefresh : function(){
18404 var ds = this.grid.dataSource, i, v = this.grid.view;
18405 var s = this.selections;
18406 s.each(function(r){
18407 if((i = ds.indexOfId(r.id)) != -1){
18416 onRemove : function(v, index, r){
18417 this.selections.remove(r);
18421 onRowUpdated : function(v, index, r){
18422 if(this.isSelected(r)){
18423 v.onRowSelect(index);
18429 * @param {Array} records The records to select
18430 * @param {Boolean} keepExisting (optional) True to keep existing selections
18432 selectRecords : function(records, keepExisting){
18434 this.clearSelections();
18436 var ds = this.grid.dataSource;
18437 for(var i = 0, len = records.length; i < len; i++){
18438 this.selectRow(ds.indexOf(records[i]), true);
18443 * Gets the number of selected rows.
18446 getCount : function(){
18447 return this.selections.length;
18451 * Selects the first row in the grid.
18453 selectFirstRow : function(){
18458 * Select the last row.
18459 * @param {Boolean} keepExisting (optional) True to keep existing selections
18461 selectLastRow : function(keepExisting){
18462 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18466 * Selects the row immediately following the last selected row.
18467 * @param {Boolean} keepExisting (optional) True to keep existing selections
18469 selectNext : function(keepExisting){
18470 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18471 this.selectRow(this.last+1, keepExisting);
18472 this.grid.getView().focusRow(this.last);
18477 * Selects the row that precedes the last selected row.
18478 * @param {Boolean} keepExisting (optional) True to keep existing selections
18480 selectPrevious : function(keepExisting){
18482 this.selectRow(this.last-1, keepExisting);
18483 this.grid.getView().focusRow(this.last);
18488 * Returns the selected records
18489 * @return {Array} Array of selected records
18491 getSelections : function(){
18492 return [].concat(this.selections.items);
18496 * Returns the first selected record.
18499 getSelected : function(){
18500 return this.selections.itemAt(0);
18505 * Clears all selections.
18507 clearSelections : function(fast){
18508 if(this.locked) return;
18510 var ds = this.grid.dataSource;
18511 var s = this.selections;
18512 s.each(function(r){
18513 this.deselectRow(ds.indexOfId(r.id));
18517 this.selections.clear();
18524 * Selects all rows.
18526 selectAll : function(){
18527 if(this.locked) return;
18528 this.selections.clear();
18529 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18530 this.selectRow(i, true);
18535 * Returns True if there is a selection.
18536 * @return {Boolean}
18538 hasSelection : function(){
18539 return this.selections.length > 0;
18543 * Returns True if the specified row is selected.
18544 * @param {Number/Record} record The record or index of the record to check
18545 * @return {Boolean}
18547 isSelected : function(index){
18548 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18549 return (r && this.selections.key(r.id) ? true : false);
18553 * Returns True if the specified record id is selected.
18554 * @param {String} id The id of record to check
18555 * @return {Boolean}
18557 isIdSelected : function(id){
18558 return (this.selections.key(id) ? true : false);
18562 handleMouseDown : function(e, t){
18563 var view = this.grid.getView(), rowIndex;
18564 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18567 if(e.shiftKey && this.last !== false){
18568 var last = this.last;
18569 this.selectRange(last, rowIndex, e.ctrlKey);
18570 this.last = last; // reset the last
18571 view.focusRow(rowIndex);
18573 var isSelected = this.isSelected(rowIndex);
18574 if(e.button !== 0 && isSelected){
18575 view.focusRow(rowIndex);
18576 }else if(e.ctrlKey && isSelected){
18577 this.deselectRow(rowIndex);
18578 }else if(!isSelected){
18579 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18580 view.focusRow(rowIndex);
18583 this.fireEvent("afterselectionchange", this);
18586 handleDragableRowClick : function(grid, rowIndex, e)
18588 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18589 this.selectRow(rowIndex, false);
18590 grid.view.focusRow(rowIndex);
18591 this.fireEvent("afterselectionchange", this);
18596 * Selects multiple rows.
18597 * @param {Array} rows Array of the indexes of the row to select
18598 * @param {Boolean} keepExisting (optional) True to keep existing selections
18600 selectRows : function(rows, keepExisting){
18602 this.clearSelections();
18604 for(var i = 0, len = rows.length; i < len; i++){
18605 this.selectRow(rows[i], true);
18610 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18611 * @param {Number} startRow The index of the first row in the range
18612 * @param {Number} endRow The index of the last row in the range
18613 * @param {Boolean} keepExisting (optional) True to retain existing selections
18615 selectRange : function(startRow, endRow, keepExisting){
18616 if(this.locked) return;
18618 this.clearSelections();
18620 if(startRow <= endRow){
18621 for(var i = startRow; i <= endRow; i++){
18622 this.selectRow(i, true);
18625 for(var i = startRow; i >= endRow; i--){
18626 this.selectRow(i, true);
18632 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18633 * @param {Number} startRow The index of the first row in the range
18634 * @param {Number} endRow The index of the last row in the range
18636 deselectRange : function(startRow, endRow, preventViewNotify){
18637 if(this.locked) return;
18638 for(var i = startRow; i <= endRow; i++){
18639 this.deselectRow(i, preventViewNotify);
18645 * @param {Number} row The index of the row to select
18646 * @param {Boolean} keepExisting (optional) True to keep existing selections
18648 selectRow : function(index, keepExisting, preventViewNotify){
18649 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18650 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18651 if(!keepExisting || this.singleSelect){
18652 this.clearSelections();
18654 var r = this.grid.dataSource.getAt(index);
18655 this.selections.add(r);
18656 this.last = this.lastActive = index;
18657 if(!preventViewNotify){
18658 this.grid.getView().onRowSelect(index);
18660 this.fireEvent("rowselect", this, index, r);
18661 this.fireEvent("selectionchange", this);
18667 * @param {Number} row The index of the row to deselect
18669 deselectRow : function(index, preventViewNotify){
18670 if(this.locked) return;
18671 if(this.last == index){
18674 if(this.lastActive == index){
18675 this.lastActive = false;
18677 var r = this.grid.dataSource.getAt(index);
18678 this.selections.remove(r);
18679 if(!preventViewNotify){
18680 this.grid.getView().onRowDeselect(index);
18682 this.fireEvent("rowdeselect", this, index);
18683 this.fireEvent("selectionchange", this);
18687 restoreLast : function(){
18689 this.last = this._last;
18694 acceptsNav : function(row, col, cm){
18695 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18699 onEditorKey : function(field, e){
18700 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18705 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18707 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18709 }else if(k == e.ENTER && !e.ctrlKey){
18713 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18715 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18717 }else if(k == e.ESC){
18721 g.startEditing(newCell[0], newCell[1]);
18726 * Ext JS Library 1.1.1
18727 * Copyright(c) 2006-2007, Ext JS, LLC.
18729 * Originally Released Under LGPL - original licence link has changed is not relivant.
18732 * <script type="text/javascript">
18736 * @class Roo.bootstrap.PagingToolbar
18738 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18740 * Create a new PagingToolbar
18741 * @param {Object} config The config object
18743 Roo.bootstrap.PagingToolbar = function(config)
18745 // old args format still supported... - xtype is prefered..
18746 // created from xtype...
18747 var ds = config.dataSource;
18748 this.toolbarItems = [];
18749 if (config.items) {
18750 this.toolbarItems = config.items;
18751 // config.items = [];
18754 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18761 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18765 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18767 * @cfg {Roo.data.Store} dataSource
18768 * The underlying data store providing the paged data
18771 * @cfg {String/HTMLElement/Element} container
18772 * container The id or element that will contain the toolbar
18775 * @cfg {Boolean} displayInfo
18776 * True to display the displayMsg (defaults to false)
18779 * @cfg {Number} pageSize
18780 * The number of records to display per page (defaults to 20)
18784 * @cfg {String} displayMsg
18785 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18787 displayMsg : 'Displaying {0} - {1} of {2}',
18789 * @cfg {String} emptyMsg
18790 * The message to display when no records are found (defaults to "No data to display")
18792 emptyMsg : 'No data to display',
18794 * Customizable piece of the default paging text (defaults to "Page")
18797 beforePageText : "Page",
18799 * Customizable piece of the default paging text (defaults to "of %0")
18802 afterPageText : "of {0}",
18804 * Customizable piece of the default paging text (defaults to "First Page")
18807 firstText : "First Page",
18809 * Customizable piece of the default paging text (defaults to "Previous Page")
18812 prevText : "Previous Page",
18814 * Customizable piece of the default paging text (defaults to "Next Page")
18817 nextText : "Next Page",
18819 * Customizable piece of the default paging text (defaults to "Last Page")
18822 lastText : "Last Page",
18824 * Customizable piece of the default paging text (defaults to "Refresh")
18827 refreshText : "Refresh",
18831 onRender : function(ct, position)
18833 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18834 this.navgroup.parentId = this.id;
18835 this.navgroup.onRender(this.el, null);
18836 // add the buttons to the navgroup
18838 if(this.displayInfo){
18839 Roo.log(this.el.select('ul.navbar-nav',true).first());
18840 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18841 this.displayEl = this.el.select('.x-paging-info', true).first();
18842 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18843 // this.displayEl = navel.el.select('span',true).first();
18849 Roo.each(_this.buttons, function(e){
18850 Roo.factory(e).onRender(_this.el, null);
18854 Roo.each(_this.toolbarItems, function(e) {
18855 _this.navgroup.addItem(e);
18858 this.first = this.navgroup.addItem({
18859 tooltip: this.firstText,
18861 icon : 'fa fa-backward',
18863 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18866 this.prev = this.navgroup.addItem({
18867 tooltip: this.prevText,
18869 icon : 'fa fa-step-backward',
18871 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18873 //this.addSeparator();
18876 var field = this.navgroup.addItem( {
18878 cls : 'x-paging-position',
18880 html : this.beforePageText +
18881 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18882 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18885 this.field = field.el.select('input', true).first();
18886 this.field.on("keydown", this.onPagingKeydown, this);
18887 this.field.on("focus", function(){this.dom.select();});
18890 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18891 //this.field.setHeight(18);
18892 //this.addSeparator();
18893 this.next = this.navgroup.addItem({
18894 tooltip: this.nextText,
18896 html : ' <i class="fa fa-step-forward">',
18898 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18900 this.last = this.navgroup.addItem({
18901 tooltip: this.lastText,
18902 icon : 'fa fa-forward',
18905 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18907 //this.addSeparator();
18908 this.loading = this.navgroup.addItem({
18909 tooltip: this.refreshText,
18910 icon: 'fa fa-refresh',
18912 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18918 updateInfo : function(){
18919 if(this.displayEl){
18920 var count = this.ds.getCount();
18921 var msg = count == 0 ?
18925 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18927 this.displayEl.update(msg);
18932 onLoad : function(ds, r, o){
18933 this.cursor = o.params ? o.params.start : 0;
18934 var d = this.getPageData(),
18938 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18939 this.field.dom.value = ap;
18940 this.first.setDisabled(ap == 1);
18941 this.prev.setDisabled(ap == 1);
18942 this.next.setDisabled(ap == ps);
18943 this.last.setDisabled(ap == ps);
18944 this.loading.enable();
18949 getPageData : function(){
18950 var total = this.ds.getTotalCount();
18953 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18954 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18959 onLoadError : function(){
18960 this.loading.enable();
18964 onPagingKeydown : function(e){
18965 var k = e.getKey();
18966 var d = this.getPageData();
18968 var v = this.field.dom.value, pageNum;
18969 if(!v || isNaN(pageNum = parseInt(v, 10))){
18970 this.field.dom.value = d.activePage;
18973 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18974 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18977 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))
18979 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18980 this.field.dom.value = pageNum;
18981 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18984 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18986 var v = this.field.dom.value, pageNum;
18987 var increment = (e.shiftKey) ? 10 : 1;
18988 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18990 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18991 this.field.dom.value = d.activePage;
18994 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18996 this.field.dom.value = parseInt(v, 10) + increment;
18997 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18998 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19005 beforeLoad : function(){
19007 this.loading.disable();
19012 onClick : function(which){
19019 ds.load({params:{start: 0, limit: this.pageSize}});
19022 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19025 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19028 var total = ds.getTotalCount();
19029 var extra = total % this.pageSize;
19030 var lastStart = extra ? (total - extra) : total-this.pageSize;
19031 ds.load({params:{start: lastStart, limit: this.pageSize}});
19034 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19040 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19041 * @param {Roo.data.Store} store The data store to unbind
19043 unbind : function(ds){
19044 ds.un("beforeload", this.beforeLoad, this);
19045 ds.un("load", this.onLoad, this);
19046 ds.un("loadexception", this.onLoadError, this);
19047 ds.un("remove", this.updateInfo, this);
19048 ds.un("add", this.updateInfo, this);
19049 this.ds = undefined;
19053 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19054 * @param {Roo.data.Store} store The data store to bind
19056 bind : function(ds){
19057 ds.on("beforeload", this.beforeLoad, this);
19058 ds.on("load", this.onLoad, this);
19059 ds.on("loadexception", this.onLoadError, this);
19060 ds.on("remove", this.updateInfo, this);
19061 ds.on("add", this.updateInfo, this);
19072 * @class Roo.bootstrap.MessageBar
19073 * @extends Roo.bootstrap.Component
19074 * Bootstrap MessageBar class
19075 * @cfg {String} html contents of the MessageBar
19076 * @cfg {String} weight (info | success | warning | danger) default info
19077 * @cfg {String} beforeClass insert the bar before the given class
19078 * @cfg {Boolean} closable (true | false) default false
19079 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19082 * Create a new Element
19083 * @param {Object} config The config object
19086 Roo.bootstrap.MessageBar = function(config){
19087 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19090 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19096 beforeClass: 'bootstrap-sticky-wrap',
19098 getAutoCreate : function(){
19102 cls: 'alert alert-dismissable alert-' + this.weight,
19107 html: this.html || ''
19113 cfg.cls += ' alert-messages-fixed';
19127 onRender : function(ct, position)
19129 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19132 var cfg = Roo.apply({}, this.getAutoCreate());
19136 cfg.cls += ' ' + this.cls;
19139 cfg.style = this.style;
19141 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19143 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19146 this.el.select('>button.close').on('click', this.hide, this);
19152 if (!this.rendered) {
19158 this.fireEvent('show', this);
19164 if (!this.rendered) {
19170 this.fireEvent('hide', this);
19173 update : function()
19175 // var e = this.el.dom.firstChild;
19177 // if(this.closable){
19178 // e = e.nextSibling;
19181 // e.data = this.html || '';
19183 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19199 * @class Roo.bootstrap.Graph
19200 * @extends Roo.bootstrap.Component
19201 * Bootstrap Graph class
19205 @cfg {String} graphtype bar | vbar | pie
19206 @cfg {number} g_x coodinator | centre x (pie)
19207 @cfg {number} g_y coodinator | centre y (pie)
19208 @cfg {number} g_r radius (pie)
19209 @cfg {number} g_height height of the chart (respected by all elements in the set)
19210 @cfg {number} g_width width of the chart (respected by all elements in the set)
19211 @cfg {Object} title The title of the chart
19214 -opts (object) options for the chart
19216 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19217 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19219 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.
19220 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19222 o stretch (boolean)
19224 -opts (object) options for the pie
19227 o startAngle (number)
19228 o endAngle (number)
19232 * Create a new Input
19233 * @param {Object} config The config object
19236 Roo.bootstrap.Graph = function(config){
19237 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19243 * The img click event for the img.
19244 * @param {Roo.EventObject} e
19250 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19261 //g_colors: this.colors,
19268 getAutoCreate : function(){
19279 onRender : function(ct,position){
19280 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19281 this.raphael = Raphael(this.el.dom);
19283 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19284 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19285 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19286 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19288 r.text(160, 10, "Single Series Chart").attr(txtattr);
19289 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19290 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19291 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19293 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19294 r.barchart(330, 10, 300, 220, data1);
19295 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19296 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19299 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19300 // r.barchart(30, 30, 560, 250, xdata, {
19301 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19302 // axis : "0 0 1 1",
19303 // axisxlabels : xdata
19304 // //yvalues : cols,
19307 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19309 // this.load(null,xdata,{
19310 // axis : "0 0 1 1",
19311 // axisxlabels : xdata
19316 load : function(graphtype,xdata,opts){
19317 this.raphael.clear();
19319 graphtype = this.graphtype;
19324 var r = this.raphael,
19325 fin = function () {
19326 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19328 fout = function () {
19329 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19331 pfin = function() {
19332 this.sector.stop();
19333 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19336 this.label[0].stop();
19337 this.label[0].attr({ r: 7.5 });
19338 this.label[1].attr({ "font-weight": 800 });
19341 pfout = function() {
19342 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19345 this.label[0].animate({ r: 5 }, 500, "bounce");
19346 this.label[1].attr({ "font-weight": 400 });
19352 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19355 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19358 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19359 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19361 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19368 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19373 setTitle: function(o)
19378 initEvents: function() {
19381 this.el.on('click', this.onClick, this);
19385 onClick : function(e)
19387 Roo.log('img onclick');
19388 this.fireEvent('click', this, e);
19400 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19403 * @class Roo.bootstrap.dash.NumberBox
19404 * @extends Roo.bootstrap.Component
19405 * Bootstrap NumberBox class
19406 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19407 * @cfg {String} headline Box headline
19408 * @cfg {String} content Box content
19409 * @cfg {String} icon Box icon
19410 * @cfg {String} footer Footer text
19411 * @cfg {String} fhref Footer href
19414 * Create a new NumberBox
19415 * @param {Object} config The config object
19419 Roo.bootstrap.dash.NumberBox = function(config){
19420 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19424 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19434 getAutoCreate : function(){
19438 cls : 'small-box bg-' + this.bgcolor,
19446 cls : 'roo-headline',
19447 html : this.headline
19451 cls : 'roo-content',
19452 html : this.content
19466 cls : 'ion ' + this.icon
19475 cls : 'small-box-footer',
19476 href : this.fhref || '#',
19480 cfg.cn.push(footer);
19487 onRender : function(ct,position){
19488 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19495 setHeadline: function (value)
19497 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19500 setFooter: function (value, href)
19502 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19505 this.el.select('a.small-box-footer',true).first().attr('href', href);
19510 setContent: function (value)
19512 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19515 initEvents: function()
19529 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19532 * @class Roo.bootstrap.dash.TabBox
19533 * @extends Roo.bootstrap.Component
19534 * Bootstrap TabBox class
19535 * @cfg {String} title Title of the TabBox
19536 * @cfg {String} icon Icon of the TabBox
19539 * Create a new TabBox
19540 * @param {Object} config The config object
19544 Roo.bootstrap.dash.TabBox = function(config){
19545 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19550 * When a pane is added
19551 * @param {Roo.bootstrap.dash.TabPane} pane
19558 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19563 getChildContainer : function()
19565 return this.el.select('.tab-content', true).first();
19568 getAutoCreate : function(){
19572 cls: 'pull-left header',
19580 cls: 'fa ' + this.icon
19587 cls: 'nav-tabs-custom',
19591 cls: 'nav nav-tabs pull-right',
19598 cls: 'tab-content no-padding',
19606 initEvents : function()
19608 //Roo.log('add add pane handler');
19609 this.on('addpane', this.onAddPane, this);
19612 * Updates the box title
19613 * @param {String} html to set the title to.
19615 setTitle : function(value)
19617 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19619 onAddPane : function(pane)
19621 //Roo.log('addpane');
19623 // tabs are rendere left to right..
19624 var ctr = this.el.select('.nav-tabs', true).first();
19627 var existing = ctr.select('.nav-tab',true);
19628 var qty = existing.getCount();;
19631 var tab = ctr.createChild({
19633 cls : 'nav-tab' + (qty ? '' : ' active'),
19641 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19644 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19646 pane.el.addClass('active');
19651 onTabClick : function(ev,un,ob,pane)
19653 //Roo.log('tab - prev default');
19654 ev.preventDefault();
19657 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19658 pane.tab.addClass('active');
19659 //Roo.log(pane.title);
19660 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19661 // technically we should have a deactivate event.. but maybe add later.
19662 // and it should not de-activate the selected tab...
19664 pane.el.addClass('active');
19665 pane.fireEvent('activate');
19680 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19682 * @class Roo.bootstrap.TabPane
19683 * @extends Roo.bootstrap.Component
19684 * Bootstrap TabPane class
19685 * @cfg {Boolean} active (false | true) Default false
19686 * @cfg {String} title title of panel
19690 * Create a new TabPane
19691 * @param {Object} config The config object
19694 Roo.bootstrap.dash.TabPane = function(config){
19695 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19699 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19704 // the tabBox that this is attached to.
19707 getAutoCreate : function()
19715 cfg.cls += ' active';
19720 initEvents : function()
19722 //Roo.log('trigger add pane handler');
19723 this.parent().fireEvent('addpane', this)
19727 * Updates the tab title
19728 * @param {String} html to set the title to.
19730 setTitle: function(str)
19736 this.tab.select('a'.true).first().dom.innerHTML = str;
19753 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19756 * @class Roo.bootstrap.menu.Menu
19757 * @extends Roo.bootstrap.Component
19758 * Bootstrap Menu class - container for Menu
19759 * @cfg {String} html Text of the menu
19760 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19761 * @cfg {String} icon Font awesome icon
19762 * @cfg {String} pos Menu align to (top | bottom) default bottom
19766 * Create a new Menu
19767 * @param {Object} config The config object
19771 Roo.bootstrap.menu.Menu = function(config){
19772 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19776 * @event beforeshow
19777 * Fires before this menu is displayed
19778 * @param {Roo.bootstrap.menu.Menu} this
19782 * @event beforehide
19783 * Fires before this menu is hidden
19784 * @param {Roo.bootstrap.menu.Menu} this
19789 * Fires after this menu is displayed
19790 * @param {Roo.bootstrap.menu.Menu} this
19795 * Fires after this menu is hidden
19796 * @param {Roo.bootstrap.menu.Menu} this
19801 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19802 * @param {Roo.bootstrap.menu.Menu} this
19803 * @param {Roo.EventObject} e
19810 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19814 weight : 'default',
19819 getChildContainer : function() {
19820 if(this.isSubMenu){
19824 return this.el.select('ul.dropdown-menu', true).first();
19827 getAutoCreate : function()
19832 cls : 'roo-menu-text',
19840 cls : 'fa ' + this.icon
19851 cls : 'dropdown-button btn btn-' + this.weight,
19856 cls : 'dropdown-toggle btn btn-' + this.weight,
19866 cls : 'dropdown-menu'
19872 if(this.pos == 'top'){
19873 cfg.cls += ' dropup';
19876 if(this.isSubMenu){
19879 cls : 'dropdown-menu'
19886 onRender : function(ct, position)
19888 this.isSubMenu = ct.hasClass('dropdown-submenu');
19890 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19893 initEvents : function()
19895 if(this.isSubMenu){
19899 this.hidden = true;
19901 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19902 this.triggerEl.on('click', this.onTriggerPress, this);
19904 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19905 this.buttonEl.on('click', this.onClick, this);
19911 if(this.isSubMenu){
19915 return this.el.select('ul.dropdown-menu', true).first();
19918 onClick : function(e)
19920 this.fireEvent("click", this, e);
19923 onTriggerPress : function(e)
19925 if (this.isVisible()) {
19932 isVisible : function(){
19933 return !this.hidden;
19938 this.fireEvent("beforeshow", this);
19940 this.hidden = false;
19941 this.el.addClass('open');
19943 Roo.get(document).on("mouseup", this.onMouseUp, this);
19945 this.fireEvent("show", this);
19952 this.fireEvent("beforehide", this);
19954 this.hidden = true;
19955 this.el.removeClass('open');
19957 Roo.get(document).un("mouseup", this.onMouseUp);
19959 this.fireEvent("hide", this);
19962 onMouseUp : function()
19976 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19979 * @class Roo.bootstrap.menu.Item
19980 * @extends Roo.bootstrap.Component
19981 * Bootstrap MenuItem class
19982 * @cfg {Boolean} submenu (true | false) default false
19983 * @cfg {String} html text of the item
19984 * @cfg {String} href the link
19985 * @cfg {Boolean} disable (true | false) default false
19986 * @cfg {Boolean} preventDefault (true | false) default true
19987 * @cfg {String} icon Font awesome icon
19988 * @cfg {String} pos Submenu align to (left | right) default right
19992 * Create a new Item
19993 * @param {Object} config The config object
19997 Roo.bootstrap.menu.Item = function(config){
19998 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20002 * Fires when the mouse is hovering over this menu
20003 * @param {Roo.bootstrap.menu.Item} this
20004 * @param {Roo.EventObject} e
20009 * Fires when the mouse exits this menu
20010 * @param {Roo.bootstrap.menu.Item} this
20011 * @param {Roo.EventObject} e
20017 * The raw click event for the entire grid.
20018 * @param {Roo.EventObject} e
20024 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20029 preventDefault: true,
20034 getAutoCreate : function()
20039 cls : 'roo-menu-item-text',
20047 cls : 'fa ' + this.icon
20056 href : this.href || '#',
20063 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20067 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20069 if(this.pos == 'left'){
20070 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20077 initEvents : function()
20079 this.el.on('mouseover', this.onMouseOver, this);
20080 this.el.on('mouseout', this.onMouseOut, this);
20082 this.el.select('a', true).first().on('click', this.onClick, this);
20086 onClick : function(e)
20088 if(this.preventDefault){
20089 e.preventDefault();
20092 this.fireEvent("click", this, e);
20095 onMouseOver : function(e)
20097 if(this.submenu && this.pos == 'left'){
20098 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20101 this.fireEvent("mouseover", this, e);
20104 onMouseOut : function(e)
20106 this.fireEvent("mouseout", this, e);
20118 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20121 * @class Roo.bootstrap.menu.Separator
20122 * @extends Roo.bootstrap.Component
20123 * Bootstrap Separator class
20126 * Create a new Separator
20127 * @param {Object} config The config object
20131 Roo.bootstrap.menu.Separator = function(config){
20132 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20135 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20137 getAutoCreate : function(){