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 {String} btnPosition set the position of the trigger button (left | right) default right
10071 * Create a new ComboBox.
10072 * @param {Object} config Configuration options
10074 Roo.bootstrap.ComboBox = function(config){
10075 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10079 * Fires when the dropdown list is expanded
10080 * @param {Roo.bootstrap.ComboBox} combo This combo box
10085 * Fires when the dropdown list is collapsed
10086 * @param {Roo.bootstrap.ComboBox} combo This combo box
10090 * @event beforeselect
10091 * Fires before a list item is selected. Return false to cancel the selection.
10092 * @param {Roo.bootstrap.ComboBox} combo This combo box
10093 * @param {Roo.data.Record} record The data record returned from the underlying store
10094 * @param {Number} index The index of the selected item in the dropdown list
10096 'beforeselect' : true,
10099 * Fires when a list item is selected
10100 * @param {Roo.bootstrap.ComboBox} combo This combo box
10101 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10102 * @param {Number} index The index of the selected item in the dropdown list
10106 * @event beforequery
10107 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10108 * The event object passed has these properties:
10109 * @param {Roo.bootstrap.ComboBox} combo This combo box
10110 * @param {String} query The query
10111 * @param {Boolean} forceAll true to force "all" query
10112 * @param {Boolean} cancel true to cancel the query
10113 * @param {Object} e The query event object
10115 'beforequery': true,
10118 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10119 * @param {Roo.bootstrap.ComboBox} combo This combo box
10124 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10125 * @param {Roo.bootstrap.ComboBox} combo This combo box
10126 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10131 * Fires when the remove value from the combobox array
10132 * @param {Roo.bootstrap.ComboBox} combo This combo box
10139 this.tickItems = [];
10141 this.selectedIndex = -1;
10142 if(this.mode == 'local'){
10143 if(config.queryDelay === undefined){
10144 this.queryDelay = 10;
10146 if(config.minChars === undefined){
10152 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10155 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10156 * rendering into an Roo.Editor, defaults to false)
10159 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10160 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10163 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10166 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10167 * the dropdown list (defaults to undefined, with no header element)
10171 * @cfg {String/Roo.Template} tpl The template to use to render the output
10175 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10177 listWidth: undefined,
10179 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10180 * mode = 'remote' or 'text' if mode = 'local')
10182 displayField: undefined,
10184 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10185 * mode = 'remote' or 'value' if mode = 'local').
10186 * Note: use of a valueField requires the user make a selection
10187 * in order for a value to be mapped.
10189 valueField: undefined,
10193 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10194 * field's data value (defaults to the underlying DOM element's name)
10196 hiddenName: undefined,
10198 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10202 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10204 selectedClass: 'active',
10207 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10211 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10212 * anchor positions (defaults to 'tl-bl')
10214 listAlign: 'tl-bl?',
10216 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10220 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10221 * query specified by the allQuery config option (defaults to 'query')
10223 triggerAction: 'query',
10225 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10226 * (defaults to 4, does not apply if editable = false)
10230 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10231 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10235 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10236 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10240 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10241 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10245 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10246 * when editable = true (defaults to false)
10248 selectOnFocus:false,
10250 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10252 queryParam: 'query',
10254 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10255 * when mode = 'remote' (defaults to 'Loading...')
10257 loadingText: 'Loading...',
10259 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10263 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10267 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10268 * traditional select (defaults to true)
10272 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10276 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10280 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10281 * listWidth has a higher value)
10285 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10286 * allow the user to set arbitrary text into the field (defaults to false)
10288 forceSelection:false,
10290 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10291 * if typeAhead = true (defaults to 250)
10293 typeAheadDelay : 250,
10295 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10296 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10298 valueNotFoundText : undefined,
10300 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10302 blockFocus : false,
10305 * @cfg {Boolean} disableClear Disable showing of clear button.
10307 disableClear : false,
10309 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10311 alwaysQuery : false,
10314 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10328 btnPosition : 'right',
10330 // element that contains real text value.. (when hidden is used..)
10332 getAutoCreate : function()
10339 if(!this.tickable){
10340 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10345 * ComboBox with tickable selections
10348 var align = this.labelAlign || this.parentLabelAlign();
10351 cls : 'form-group roo-combobox-tickable' //input-group
10357 cls : 'tickable-buttons',
10362 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10369 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10376 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10383 Roo.each(buttons.cn, function(c){
10385 c.cls += ' btn-' + _this.size;
10388 if (_this.disabled) {
10399 cls: 'form-hidden-field'
10403 cls: 'select2-choices',
10407 cls: 'select2-search-field',
10419 cls: 'select2-container input-group select2-container-multi',
10424 cls: 'typeahead typeahead-long dropdown-menu',
10425 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10430 if (align ==='left' && this.fieldLabel.length) {
10432 Roo.log("left and has label");
10438 cls : 'control-label col-sm-' + this.labelWidth,
10439 html : this.fieldLabel
10443 cls : "col-sm-" + (12 - this.labelWidth),
10450 } else if ( this.fieldLabel.length) {
10456 //cls : 'input-group-addon',
10457 html : this.fieldLabel
10467 Roo.log(" no label && no align");
10474 ['xs','sm','md','lg'].map(function(size){
10475 if (settings[size]) {
10476 cfg.cls += ' col-' + size + '-' + settings[size];
10485 initEvents: function()
10489 throw "can not find store for combo";
10491 this.store = Roo.factory(this.store, Roo.data);
10494 this.initTickableEvnets();
10498 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10501 if(this.hiddenName){
10503 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10505 this.hiddenField.dom.value =
10506 this.hiddenValue !== undefined ? this.hiddenValue :
10507 this.value !== undefined ? this.value : '';
10509 // prevent input submission
10510 this.el.dom.removeAttribute('name');
10511 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10516 // this.el.dom.setAttribute('autocomplete', 'off');
10519 var cls = 'x-combo-list';
10520 this.list = this.el.select('ul.dropdown-menu',true).first();
10522 //this.list = new Roo.Layer({
10523 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10529 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10530 _this.list.setWidth(lw);
10533 this.list.on('mouseover', this.onViewOver, this);
10534 this.list.on('mousemove', this.onViewMove, this);
10536 this.list.on('scroll', this.onViewScroll, this);
10539 this.list.swallowEvent('mousewheel');
10540 this.assetHeight = 0;
10543 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10544 this.assetHeight += this.header.getHeight();
10547 this.innerList = this.list.createChild({cls:cls+'-inner'});
10548 this.innerList.on('mouseover', this.onViewOver, this);
10549 this.innerList.on('mousemove', this.onViewMove, this);
10550 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10552 if(this.allowBlank && !this.pageSize && !this.disableClear){
10553 this.footer = this.list.createChild({cls:cls+'-ft'});
10554 this.pageTb = new Roo.Toolbar(this.footer);
10558 this.footer = this.list.createChild({cls:cls+'-ft'});
10559 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10560 {pageSize: this.pageSize});
10564 if (this.pageTb && this.allowBlank && !this.disableClear) {
10566 this.pageTb.add(new Roo.Toolbar.Fill(), {
10567 cls: 'x-btn-icon x-btn-clear',
10569 handler: function()
10572 _this.clearValue();
10573 _this.onSelect(false, -1);
10578 this.assetHeight += this.footer.getHeight();
10583 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10586 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10587 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10589 //this.view.wrapEl.setDisplayed(false);
10590 this.view.on('click', this.onViewClick, this);
10594 this.store.on('beforeload', this.onBeforeLoad, this);
10595 this.store.on('load', this.onLoad, this);
10596 this.store.on('loadexception', this.onLoadException, this);
10598 if(this.resizable){
10599 this.resizer = new Roo.Resizable(this.list, {
10600 pinned:true, handles:'se'
10602 this.resizer.on('resize', function(r, w, h){
10603 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10604 this.listWidth = w;
10605 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10606 this.restrictHeight();
10608 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10611 if(!this.editable){
10612 this.editable = true;
10613 this.setEditable(false);
10618 if (typeof(this.events.add.listeners) != 'undefined') {
10620 this.addicon = this.wrap.createChild(
10621 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10623 this.addicon.on('click', function(e) {
10624 this.fireEvent('add', this);
10627 if (typeof(this.events.edit.listeners) != 'undefined') {
10629 this.editicon = this.wrap.createChild(
10630 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10631 if (this.addicon) {
10632 this.editicon.setStyle('margin-left', '40px');
10634 this.editicon.on('click', function(e) {
10636 // we fire even if inothing is selected..
10637 this.fireEvent('edit', this, this.lastData );
10643 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10644 "up" : function(e){
10645 this.inKeyMode = true;
10649 "down" : function(e){
10650 if(!this.isExpanded()){
10651 this.onTriggerClick();
10653 this.inKeyMode = true;
10658 "enter" : function(e){
10659 // this.onViewClick();
10663 if(this.fireEvent("specialkey", this, e)){
10664 this.onViewClick(false);
10670 "esc" : function(e){
10674 "tab" : function(e){
10677 if(this.fireEvent("specialkey", this, e)){
10678 this.onViewClick(false);
10686 doRelay : function(foo, bar, hname){
10687 if(hname == 'down' || this.scope.isExpanded()){
10688 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10697 this.queryDelay = Math.max(this.queryDelay || 10,
10698 this.mode == 'local' ? 10 : 250);
10701 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10703 if(this.typeAhead){
10704 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10706 if(this.editable !== false){
10707 this.inputEl().on("keyup", this.onKeyUp, this);
10709 if(this.forceSelection){
10710 this.inputEl().on('blur', this.doForce, this);
10714 this.choices = this.el.select('ul.select2-choices', true).first();
10715 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10719 initTickableEvnets: function()
10721 if(this.hiddenName){
10723 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10725 this.hiddenField.dom.value =
10726 this.hiddenValue !== undefined ? this.hiddenValue :
10727 this.value !== undefined ? this.value : '';
10729 // prevent input submission
10730 this.el.dom.removeAttribute('name');
10731 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10736 this.list = this.el.select('ul.dropdown-menu',true).first();
10738 this.choices = this.el.select('ul.select2-choices', true).first();
10739 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10741 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10743 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10744 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10746 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10747 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10749 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10750 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10752 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10753 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10754 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10757 this.cancelBtn.hide();
10762 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10763 _this.list.setWidth(lw);
10766 this.list.on('mouseover', this.onViewOver, this);
10767 this.list.on('mousemove', this.onViewMove, this);
10769 this.list.on('scroll', this.onViewScroll, this);
10772 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>';
10775 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10776 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10779 //this.view.wrapEl.setDisplayed(false);
10780 this.view.on('click', this.onViewClick, this);
10784 this.store.on('beforeload', this.onBeforeLoad, this);
10785 this.store.on('load', this.onLoad, this);
10786 this.store.on('loadexception', this.onLoadException, this);
10788 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10789 // "up" : function(e){
10790 // this.inKeyMode = true;
10791 // this.selectPrev();
10794 // "down" : function(e){
10795 // if(!this.isExpanded()){
10796 // this.onTriggerClick();
10798 // this.inKeyMode = true;
10799 // this.selectNext();
10803 // "enter" : function(e){
10804 //// this.onViewClick();
10806 // this.collapse();
10808 // if(this.fireEvent("specialkey", this, e)){
10809 // this.onViewClick(false);
10815 // "esc" : function(e){
10816 // this.collapse();
10819 // "tab" : function(e){
10820 // this.collapse();
10822 // if(this.fireEvent("specialkey", this, e)){
10823 // this.onViewClick(false);
10831 // doRelay : function(foo, bar, hname){
10832 // if(hname == 'down' || this.scope.isExpanded()){
10833 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10838 // forceKeyDown: true
10842 this.queryDelay = Math.max(this.queryDelay || 10,
10843 this.mode == 'local' ? 10 : 250);
10846 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10848 if(this.typeAhead){
10849 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10853 onDestroy : function(){
10855 this.view.setStore(null);
10856 this.view.el.removeAllListeners();
10857 this.view.el.remove();
10858 this.view.purgeListeners();
10861 this.list.dom.innerHTML = '';
10865 this.store.un('beforeload', this.onBeforeLoad, this);
10866 this.store.un('load', this.onLoad, this);
10867 this.store.un('loadexception', this.onLoadException, this);
10869 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10873 fireKey : function(e){
10874 if(e.isNavKeyPress() && !this.list.isVisible()){
10875 this.fireEvent("specialkey", this, e);
10880 onResize: function(w, h){
10881 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10883 // if(typeof w != 'number'){
10884 // // we do not handle it!?!?
10887 // var tw = this.trigger.getWidth();
10888 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10889 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10891 // this.inputEl().setWidth( this.adjustWidth('input', x));
10893 // //this.trigger.setStyle('left', x+'px');
10895 // if(this.list && this.listWidth === undefined){
10896 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10897 // this.list.setWidth(lw);
10898 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10906 * Allow or prevent the user from directly editing the field text. If false is passed,
10907 * the user will only be able to select from the items defined in the dropdown list. This method
10908 * is the runtime equivalent of setting the 'editable' config option at config time.
10909 * @param {Boolean} value True to allow the user to directly edit the field text
10911 setEditable : function(value){
10912 if(value == this.editable){
10915 this.editable = value;
10917 this.inputEl().dom.setAttribute('readOnly', true);
10918 this.inputEl().on('mousedown', this.onTriggerClick, this);
10919 this.inputEl().addClass('x-combo-noedit');
10921 this.inputEl().dom.setAttribute('readOnly', false);
10922 this.inputEl().un('mousedown', this.onTriggerClick, this);
10923 this.inputEl().removeClass('x-combo-noedit');
10929 onBeforeLoad : function(combo,opts){
10930 if(!this.hasFocus){
10934 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10936 this.restrictHeight();
10937 this.selectedIndex = -1;
10941 onLoad : function(){
10943 this.hasQuery = false;
10945 if(!this.hasFocus){
10949 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10950 this.loading.hide();
10953 if(this.store.getCount() > 0){
10955 this.restrictHeight();
10956 if(this.lastQuery == this.allQuery){
10957 if(this.editable && !this.tickable){
10958 this.inputEl().dom.select();
10960 if(!this.selectByValue(this.value, true) && this.autoFocus){
10961 this.select(0, true);
10964 if(this.autoFocus){
10967 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10968 this.taTask.delay(this.typeAheadDelay);
10972 this.onEmptyResults();
10978 onLoadException : function()
10980 this.hasQuery = false;
10982 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10983 this.loading.hide();
10987 Roo.log(this.store.reader.jsonData);
10988 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10990 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10996 onTypeAhead : function(){
10997 if(this.store.getCount() > 0){
10998 var r = this.store.getAt(0);
10999 var newValue = r.data[this.displayField];
11000 var len = newValue.length;
11001 var selStart = this.getRawValue().length;
11003 if(selStart != len){
11004 this.setRawValue(newValue);
11005 this.selectText(selStart, newValue.length);
11011 onSelect : function(record, index){
11013 if(this.fireEvent('beforeselect', this, record, index) !== false){
11015 this.setFromData(index > -1 ? record.data : false);
11018 this.fireEvent('select', this, record, index);
11023 * Returns the currently selected field value or empty string if no value is set.
11024 * @return {String} value The selected value
11026 getValue : function(){
11029 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11032 if(this.valueField){
11033 return typeof this.value != 'undefined' ? this.value : '';
11035 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11040 * Clears any text/value currently set in the field
11042 clearValue : function(){
11043 if(this.hiddenField){
11044 this.hiddenField.dom.value = '';
11047 this.setRawValue('');
11048 this.lastSelectionText = '';
11053 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11054 * will be displayed in the field. If the value does not match the data value of an existing item,
11055 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11056 * Otherwise the field will be blank (although the value will still be set).
11057 * @param {String} value The value to match
11059 setValue : function(v){
11066 if(this.valueField){
11067 var r = this.findRecord(this.valueField, v);
11069 text = r.data[this.displayField];
11070 }else if(this.valueNotFoundText !== undefined){
11071 text = this.valueNotFoundText;
11074 this.lastSelectionText = text;
11075 if(this.hiddenField){
11076 this.hiddenField.dom.value = v;
11078 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11082 * @property {Object} the last set data for the element
11087 * Sets the value of the field based on a object which is related to the record format for the store.
11088 * @param {Object} value the value to set as. or false on reset?
11090 setFromData : function(o){
11097 var dv = ''; // display value
11098 var vv = ''; // value value..
11100 if (this.displayField) {
11101 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11103 // this is an error condition!!!
11104 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11107 if(this.valueField){
11108 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11111 if(this.hiddenField){
11112 this.hiddenField.dom.value = vv;
11114 this.lastSelectionText = dv;
11115 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11119 // no hidden field.. - we store the value in 'value', but still display
11120 // display field!!!!
11121 this.lastSelectionText = dv;
11122 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11128 reset : function(){
11129 // overridden so that last data is reset..
11130 this.setValue(this.originalValue);
11131 this.clearInvalid();
11132 this.lastData = false;
11134 this.view.clearSelections();
11138 findRecord : function(prop, value){
11140 if(this.store.getCount() > 0){
11141 this.store.each(function(r){
11142 if(r.data[prop] == value){
11152 getName: function()
11154 // returns hidden if it's set..
11155 if (!this.rendered) {return ''};
11156 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11160 onViewMove : function(e, t){
11161 this.inKeyMode = false;
11165 onViewOver : function(e, t){
11166 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11169 var item = this.view.findItemFromChild(t);
11172 var index = this.view.indexOf(item);
11173 this.select(index, false);
11178 onViewClick : function(view, doFocus, el, e)
11180 var index = this.view.getSelectedIndexes()[0];
11182 var r = this.store.getAt(index);
11186 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11193 Roo.each(this.tickItems, function(v,k){
11195 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11196 _this.tickItems.splice(k, 1);
11206 this.tickItems.push(r.data);
11211 this.onSelect(r, index);
11213 if(doFocus !== false && !this.blockFocus){
11214 this.inputEl().focus();
11219 restrictHeight : function(){
11220 //this.innerList.dom.style.height = '';
11221 //var inner = this.innerList.dom;
11222 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11223 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11224 //this.list.beginUpdate();
11225 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11226 this.list.alignTo(this.inputEl(), this.listAlign);
11227 //this.list.endUpdate();
11231 onEmptyResults : function(){
11236 * Returns true if the dropdown list is expanded, else false.
11238 isExpanded : function(){
11239 return this.list.isVisible();
11243 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11244 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11245 * @param {String} value The data value of the item to select
11246 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11247 * selected item if it is not currently in view (defaults to true)
11248 * @return {Boolean} True if the value matched an item in the list, else false
11250 selectByValue : function(v, scrollIntoView){
11251 if(v !== undefined && v !== null){
11252 var r = this.findRecord(this.valueField || this.displayField, v);
11254 this.select(this.store.indexOf(r), scrollIntoView);
11262 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11263 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11264 * @param {Number} index The zero-based index of the list item to select
11265 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11266 * selected item if it is not currently in view (defaults to true)
11268 select : function(index, scrollIntoView){
11269 this.selectedIndex = index;
11270 this.view.select(index);
11271 if(scrollIntoView !== false){
11272 var el = this.view.getNode(index);
11274 //this.innerList.scrollChildIntoView(el, false);
11281 selectNext : function(){
11282 var ct = this.store.getCount();
11284 if(this.selectedIndex == -1){
11286 }else if(this.selectedIndex < ct-1){
11287 this.select(this.selectedIndex+1);
11293 selectPrev : function(){
11294 var ct = this.store.getCount();
11296 if(this.selectedIndex == -1){
11298 }else if(this.selectedIndex != 0){
11299 this.select(this.selectedIndex-1);
11305 onKeyUp : function(e){
11306 if(this.editable !== false && !e.isSpecialKey()){
11307 this.lastKey = e.getKey();
11308 this.dqTask.delay(this.queryDelay);
11313 validateBlur : function(){
11314 return !this.list || !this.list.isVisible();
11318 initQuery : function(){
11319 this.doQuery(this.getRawValue());
11323 doForce : function(){
11324 if(this.inputEl().dom.value.length > 0){
11325 this.inputEl().dom.value =
11326 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11332 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11333 * query allowing the query action to be canceled if needed.
11334 * @param {String} query The SQL query to execute
11335 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11336 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11337 * saved in the current store (defaults to false)
11339 doQuery : function(q, forceAll){
11341 if(q === undefined || q === null){
11346 forceAll: forceAll,
11350 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11355 forceAll = qe.forceAll;
11356 if(forceAll === true || (q.length >= this.minChars)){
11358 this.hasQuery = true;
11360 if(this.lastQuery != q || this.alwaysQuery){
11361 this.lastQuery = q;
11362 if(this.mode == 'local'){
11363 this.selectedIndex = -1;
11365 this.store.clearFilter();
11367 this.store.filter(this.displayField, q);
11371 this.store.baseParams[this.queryParam] = q;
11373 var options = {params : this.getParams(q)};
11376 options.add = true;
11377 options.params.start = this.page * this.pageSize;
11380 this.store.load(options);
11382 * this code will make the page width larger, at the beginning, the list not align correctly,
11383 * we should expand the list on onLoad
11384 * so command out it
11389 this.selectedIndex = -1;
11394 this.loadNext = false;
11398 getParams : function(q){
11400 //p[this.queryParam] = q;
11404 p.limit = this.pageSize;
11410 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11412 collapse : function(){
11413 if(!this.isExpanded()){
11417 this.hasFocus = false;
11423 this.cancelBtn.hide();
11424 this.trigger.show();
11427 Roo.get(document).un('mousedown', this.collapseIf, this);
11428 Roo.get(document).un('mousewheel', this.collapseIf, this);
11429 if (!this.editable) {
11430 Roo.get(document).un('keydown', this.listKeyPress, this);
11432 this.fireEvent('collapse', this);
11436 collapseIf : function(e){
11437 var in_combo = e.within(this.el);
11438 var in_list = e.within(this.list);
11440 if (in_combo || in_list) {
11441 //e.stopPropagation();
11446 this.onTickableFooterButtonClick(e, false, false);
11454 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11456 expand : function(){
11458 if(this.isExpanded() || !this.hasFocus){
11462 this.list.alignTo(this.inputEl(), this.listAlign);
11467 this.tickItems = Roo.apply([], this.item);
11470 this.cancelBtn.show();
11471 this.trigger.hide();
11475 Roo.get(document).on('mousedown', this.collapseIf, this);
11476 Roo.get(document).on('mousewheel', this.collapseIf, this);
11477 if (!this.editable) {
11478 Roo.get(document).on('keydown', this.listKeyPress, this);
11481 this.fireEvent('expand', this);
11485 // Implements the default empty TriggerField.onTriggerClick function
11486 onTriggerClick : function(e)
11488 Roo.log('trigger click');
11495 this.loadNext = false;
11497 if(this.isExpanded()){
11499 if (!this.blockFocus) {
11500 this.inputEl().focus();
11504 this.hasFocus = true;
11505 if(this.triggerAction == 'all') {
11506 this.doQuery(this.allQuery, true);
11508 this.doQuery(this.getRawValue());
11510 if (!this.blockFocus) {
11511 this.inputEl().focus();
11516 onTickableTriggerClick : function(e)
11523 this.loadNext = false;
11524 this.hasFocus = true;
11526 if(this.triggerAction == 'all') {
11527 this.doQuery(this.allQuery, true);
11529 this.doQuery(this.getRawValue());
11533 onSearchFieldClick : function(e)
11535 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11540 this.loadNext = false;
11541 this.hasFocus = true;
11543 if(this.triggerAction == 'all') {
11544 this.doQuery(this.allQuery, true);
11546 this.doQuery(this.getRawValue());
11550 listKeyPress : function(e)
11552 //Roo.log('listkeypress');
11553 // scroll to first matching element based on key pres..
11554 if (e.isSpecialKey()) {
11557 var k = String.fromCharCode(e.getKey()).toUpperCase();
11560 var csel = this.view.getSelectedNodes();
11561 var cselitem = false;
11563 var ix = this.view.indexOf(csel[0]);
11564 cselitem = this.store.getAt(ix);
11565 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11571 this.store.each(function(v) {
11573 // start at existing selection.
11574 if (cselitem.id == v.id) {
11580 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11581 match = this.store.indexOf(v);
11587 if (match === false) {
11588 return true; // no more action?
11591 this.view.select(match);
11592 var sn = Roo.get(this.view.getSelectedNodes()[0])
11593 //sn.scrollIntoView(sn.dom.parentNode, false);
11596 onViewScroll : function(e, t){
11598 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11602 this.hasQuery = true;
11604 this.loading = this.list.select('.loading', true).first();
11606 if(this.loading === null){
11607 this.list.createChild({
11609 cls: 'loading select2-more-results select2-active',
11610 html: 'Loading more results...'
11613 this.loading = this.list.select('.loading', true).first();
11615 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11617 this.loading.hide();
11620 this.loading.show();
11625 this.loadNext = true;
11627 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11632 addItem : function(o)
11634 var dv = ''; // display value
11636 if (this.displayField) {
11637 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11639 // this is an error condition!!!
11640 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11647 var choice = this.choices.createChild({
11649 cls: 'select2-search-choice',
11658 cls: 'select2-search-choice-close',
11663 }, this.searchField);
11665 var close = choice.select('a.select2-search-choice-close', true).first()
11667 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11675 this.inputEl().dom.value = '';
11679 onRemoveItem : function(e, _self, o)
11681 e.preventDefault();
11682 var index = this.item.indexOf(o.data) * 1;
11685 Roo.log('not this item?!');
11689 this.item.splice(index, 1);
11694 this.fireEvent('remove', this, e);
11698 syncValue : function()
11700 if(!this.item.length){
11707 Roo.each(this.item, function(i){
11708 if(_this.valueField){
11709 value.push(i[_this.valueField]);
11716 this.value = value.join(',');
11718 if(this.hiddenField){
11719 this.hiddenField.dom.value = this.value;
11723 clearItem : function()
11725 if(!this.multiple){
11731 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11738 inputEl: function ()
11741 return this.searchField;
11743 return this.el.select('input.form-control',true).first();
11747 onTickableFooterButtonClick : function(e, btn, el)
11749 e.preventDefault();
11751 if(btn && btn.name == 'cancel'){
11752 this.tickItems = Roo.apply([], this.item);
11761 Roo.each(this.tickItems, function(o){
11772 * @cfg {Boolean} grow
11776 * @cfg {Number} growMin
11780 * @cfg {Number} growMax
11790 * Ext JS Library 1.1.1
11791 * Copyright(c) 2006-2007, Ext JS, LLC.
11793 * Originally Released Under LGPL - original licence link has changed is not relivant.
11796 * <script type="text/javascript">
11801 * @extends Roo.util.Observable
11802 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11803 * This class also supports single and multi selection modes. <br>
11804 * Create a data model bound view:
11806 var store = new Roo.data.Store(...);
11808 var view = new Roo.View({
11810 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11812 singleSelect: true,
11813 selectedClass: "ydataview-selected",
11817 // listen for node click?
11818 view.on("click", function(vw, index, node, e){
11819 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11823 dataModel.load("foobar.xml");
11825 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11827 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11828 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11830 * Note: old style constructor is still suported (container, template, config)
11833 * Create a new View
11834 * @param {Object} config The config object
11837 Roo.View = function(config, depreciated_tpl, depreciated_config){
11839 this.parent = false;
11841 if (typeof(depreciated_tpl) == 'undefined') {
11842 // new way.. - universal constructor.
11843 Roo.apply(this, config);
11844 this.el = Roo.get(this.el);
11847 this.el = Roo.get(config);
11848 this.tpl = depreciated_tpl;
11849 Roo.apply(this, depreciated_config);
11851 this.wrapEl = this.el.wrap().wrap();
11852 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11855 if(typeof(this.tpl) == "string"){
11856 this.tpl = new Roo.Template(this.tpl);
11858 // support xtype ctors..
11859 this.tpl = new Roo.factory(this.tpl, Roo);
11863 this.tpl.compile();
11868 * @event beforeclick
11869 * Fires before a click is processed. Returns false to cancel the default action.
11870 * @param {Roo.View} this
11871 * @param {Number} index The index of the target node
11872 * @param {HTMLElement} node The target node
11873 * @param {Roo.EventObject} e The raw event object
11875 "beforeclick" : true,
11878 * Fires when a template node is clicked.
11879 * @param {Roo.View} this
11880 * @param {Number} index The index of the target node
11881 * @param {HTMLElement} node The target node
11882 * @param {Roo.EventObject} e The raw event object
11887 * Fires when a template node is double clicked.
11888 * @param {Roo.View} this
11889 * @param {Number} index The index of the target node
11890 * @param {HTMLElement} node The target node
11891 * @param {Roo.EventObject} e The raw event object
11895 * @event contextmenu
11896 * Fires when a template node is right clicked.
11897 * @param {Roo.View} this
11898 * @param {Number} index The index of the target node
11899 * @param {HTMLElement} node The target node
11900 * @param {Roo.EventObject} e The raw event object
11902 "contextmenu" : true,
11904 * @event selectionchange
11905 * Fires when the selected nodes change.
11906 * @param {Roo.View} this
11907 * @param {Array} selections Array of the selected nodes
11909 "selectionchange" : true,
11912 * @event beforeselect
11913 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11914 * @param {Roo.View} this
11915 * @param {HTMLElement} node The node to be selected
11916 * @param {Array} selections Array of currently selected nodes
11918 "beforeselect" : true,
11920 * @event preparedata
11921 * Fires on every row to render, to allow you to change the data.
11922 * @param {Roo.View} this
11923 * @param {Object} data to be rendered (change this)
11925 "preparedata" : true
11933 "click": this.onClick,
11934 "dblclick": this.onDblClick,
11935 "contextmenu": this.onContextMenu,
11939 this.selections = [];
11941 this.cmp = new Roo.CompositeElementLite([]);
11943 this.store = Roo.factory(this.store, Roo.data);
11944 this.setStore(this.store, true);
11947 if ( this.footer && this.footer.xtype) {
11949 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11951 this.footer.dataSource = this.store
11952 this.footer.container = fctr;
11953 this.footer = Roo.factory(this.footer, Roo);
11954 fctr.insertFirst(this.el);
11956 // this is a bit insane - as the paging toolbar seems to detach the el..
11957 // dom.parentNode.parentNode.parentNode
11958 // they get detached?
11962 Roo.View.superclass.constructor.call(this);
11967 Roo.extend(Roo.View, Roo.util.Observable, {
11970 * @cfg {Roo.data.Store} store Data store to load data from.
11975 * @cfg {String|Roo.Element} el The container element.
11980 * @cfg {String|Roo.Template} tpl The template used by this View
11984 * @cfg {String} dataName the named area of the template to use as the data area
11985 * Works with domtemplates roo-name="name"
11989 * @cfg {String} selectedClass The css class to add to selected nodes
11991 selectedClass : "x-view-selected",
11993 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11998 * @cfg {String} text to display on mask (default Loading)
12002 * @cfg {Boolean} multiSelect Allow multiple selection
12004 multiSelect : false,
12006 * @cfg {Boolean} singleSelect Allow single selection
12008 singleSelect: false,
12011 * @cfg {Boolean} toggleSelect - selecting
12013 toggleSelect : false,
12016 * @cfg {Boolean} tickable - selecting
12021 * Returns the element this view is bound to.
12022 * @return {Roo.Element}
12024 getEl : function(){
12025 return this.wrapEl;
12031 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12033 refresh : function(){
12034 Roo.log('refresh');
12037 // if we are using something like 'domtemplate', then
12038 // the what gets used is:
12039 // t.applySubtemplate(NAME, data, wrapping data..)
12040 // the outer template then get' applied with
12041 // the store 'extra data'
12042 // and the body get's added to the
12043 // roo-name="data" node?
12044 // <span class='roo-tpl-{name}'></span> ?????
12048 this.clearSelections();
12049 this.el.update("");
12051 var records = this.store.getRange();
12052 if(records.length < 1) {
12054 // is this valid?? = should it render a template??
12056 this.el.update(this.emptyText);
12060 if (this.dataName) {
12061 this.el.update(t.apply(this.store.meta)); //????
12062 el = this.el.child('.roo-tpl-' + this.dataName);
12065 for(var i = 0, len = records.length; i < len; i++){
12066 var data = this.prepareData(records[i].data, i, records[i]);
12067 this.fireEvent("preparedata", this, data, i, records[i]);
12069 var d = Roo.apply({}, data);
12072 Roo.apply(d, {'roo-id' : Roo.id()});
12076 Roo.each(this.parent.item, function(item){
12077 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12080 Roo.apply(d, {'roo-data-checked' : 'checked'});
12084 html[html.length] = Roo.util.Format.trim(
12086 t.applySubtemplate(this.dataName, d, this.store.meta) :
12093 el.update(html.join(""));
12094 this.nodes = el.dom.childNodes;
12095 this.updateIndexes(0);
12100 * Function to override to reformat the data that is sent to
12101 * the template for each node.
12102 * DEPRICATED - use the preparedata event handler.
12103 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12104 * a JSON object for an UpdateManager bound view).
12106 prepareData : function(data, index, record)
12108 this.fireEvent("preparedata", this, data, index, record);
12112 onUpdate : function(ds, record){
12113 Roo.log('on update');
12114 this.clearSelections();
12115 var index = this.store.indexOf(record);
12116 var n = this.nodes[index];
12117 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12118 n.parentNode.removeChild(n);
12119 this.updateIndexes(index, index);
12125 onAdd : function(ds, records, index)
12127 Roo.log(['on Add', ds, records, index] );
12128 this.clearSelections();
12129 if(this.nodes.length == 0){
12133 var n = this.nodes[index];
12134 for(var i = 0, len = records.length; i < len; i++){
12135 var d = this.prepareData(records[i].data, i, records[i]);
12137 this.tpl.insertBefore(n, d);
12140 this.tpl.append(this.el, d);
12143 this.updateIndexes(index);
12146 onRemove : function(ds, record, index){
12147 Roo.log('onRemove');
12148 this.clearSelections();
12149 var el = this.dataName ?
12150 this.el.child('.roo-tpl-' + this.dataName) :
12153 el.dom.removeChild(this.nodes[index]);
12154 this.updateIndexes(index);
12158 * Refresh an individual node.
12159 * @param {Number} index
12161 refreshNode : function(index){
12162 this.onUpdate(this.store, this.store.getAt(index));
12165 updateIndexes : function(startIndex, endIndex){
12166 var ns = this.nodes;
12167 startIndex = startIndex || 0;
12168 endIndex = endIndex || ns.length - 1;
12169 for(var i = startIndex; i <= endIndex; i++){
12170 ns[i].nodeIndex = i;
12175 * Changes the data store this view uses and refresh the view.
12176 * @param {Store} store
12178 setStore : function(store, initial){
12179 if(!initial && this.store){
12180 this.store.un("datachanged", this.refresh);
12181 this.store.un("add", this.onAdd);
12182 this.store.un("remove", this.onRemove);
12183 this.store.un("update", this.onUpdate);
12184 this.store.un("clear", this.refresh);
12185 this.store.un("beforeload", this.onBeforeLoad);
12186 this.store.un("load", this.onLoad);
12187 this.store.un("loadexception", this.onLoad);
12191 store.on("datachanged", this.refresh, this);
12192 store.on("add", this.onAdd, this);
12193 store.on("remove", this.onRemove, this);
12194 store.on("update", this.onUpdate, this);
12195 store.on("clear", this.refresh, this);
12196 store.on("beforeload", this.onBeforeLoad, this);
12197 store.on("load", this.onLoad, this);
12198 store.on("loadexception", this.onLoad, this);
12206 * onbeforeLoad - masks the loading area.
12209 onBeforeLoad : function(store,opts)
12211 Roo.log('onBeforeLoad');
12213 this.el.update("");
12215 this.el.mask(this.mask ? this.mask : "Loading" );
12217 onLoad : function ()
12224 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12225 * @param {HTMLElement} node
12226 * @return {HTMLElement} The template node
12228 findItemFromChild : function(node){
12229 var el = this.dataName ?
12230 this.el.child('.roo-tpl-' + this.dataName,true) :
12233 if(!node || node.parentNode == el){
12236 var p = node.parentNode;
12237 while(p && p != el){
12238 if(p.parentNode == el){
12247 onClick : function(e){
12248 var item = this.findItemFromChild(e.getTarget());
12250 var index = this.indexOf(item);
12251 if(this.onItemClick(item, index, e) !== false){
12252 this.fireEvent("click", this, index, item, e);
12255 this.clearSelections();
12260 onContextMenu : function(e){
12261 var item = this.findItemFromChild(e.getTarget());
12263 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12268 onDblClick : function(e){
12269 var item = this.findItemFromChild(e.getTarget());
12271 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12275 onItemClick : function(item, index, e)
12277 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12280 if (this.toggleSelect) {
12281 var m = this.isSelected(item) ? 'unselect' : 'select';
12284 _t[m](item, true, false);
12287 if(this.multiSelect || this.singleSelect){
12288 if(this.multiSelect && e.shiftKey && this.lastSelection){
12289 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12291 this.select(item, this.multiSelect && e.ctrlKey);
12292 this.lastSelection = item;
12295 if(!this.tickable){
12296 e.preventDefault();
12304 * Get the number of selected nodes.
12307 getSelectionCount : function(){
12308 return this.selections.length;
12312 * Get the currently selected nodes.
12313 * @return {Array} An array of HTMLElements
12315 getSelectedNodes : function(){
12316 return this.selections;
12320 * Get the indexes of the selected nodes.
12323 getSelectedIndexes : function(){
12324 var indexes = [], s = this.selections;
12325 for(var i = 0, len = s.length; i < len; i++){
12326 indexes.push(s[i].nodeIndex);
12332 * Clear all selections
12333 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12335 clearSelections : function(suppressEvent){
12336 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12337 this.cmp.elements = this.selections;
12338 this.cmp.removeClass(this.selectedClass);
12339 this.selections = [];
12340 if(!suppressEvent){
12341 this.fireEvent("selectionchange", this, this.selections);
12347 * Returns true if the passed node is selected
12348 * @param {HTMLElement/Number} node The node or node index
12349 * @return {Boolean}
12351 isSelected : function(node){
12352 var s = this.selections;
12356 node = this.getNode(node);
12357 return s.indexOf(node) !== -1;
12362 * @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
12363 * @param {Boolean} keepExisting (optional) true to keep existing selections
12364 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12366 select : function(nodeInfo, keepExisting, suppressEvent){
12367 if(nodeInfo instanceof Array){
12369 this.clearSelections(true);
12371 for(var i = 0, len = nodeInfo.length; i < len; i++){
12372 this.select(nodeInfo[i], true, true);
12376 var node = this.getNode(nodeInfo);
12377 if(!node || this.isSelected(node)){
12378 return; // already selected.
12381 this.clearSelections(true);
12383 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12384 Roo.fly(node).addClass(this.selectedClass);
12385 this.selections.push(node);
12386 if(!suppressEvent){
12387 this.fireEvent("selectionchange", this, this.selections);
12395 * @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
12396 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12397 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12399 unselect : function(nodeInfo, keepExisting, suppressEvent)
12401 if(nodeInfo instanceof Array){
12402 Roo.each(this.selections, function(s) {
12403 this.unselect(s, nodeInfo);
12407 var node = this.getNode(nodeInfo);
12408 if(!node || !this.isSelected(node)){
12409 Roo.log("not selected");
12410 return; // not selected.
12414 Roo.each(this.selections, function(s) {
12416 Roo.fly(node).removeClass(this.selectedClass);
12423 this.selections= ns;
12424 this.fireEvent("selectionchange", this, this.selections);
12428 * Gets a template node.
12429 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12430 * @return {HTMLElement} The node or null if it wasn't found
12432 getNode : function(nodeInfo){
12433 if(typeof nodeInfo == "string"){
12434 return document.getElementById(nodeInfo);
12435 }else if(typeof nodeInfo == "number"){
12436 return this.nodes[nodeInfo];
12442 * Gets a range template nodes.
12443 * @param {Number} startIndex
12444 * @param {Number} endIndex
12445 * @return {Array} An array of nodes
12447 getNodes : function(start, end){
12448 var ns = this.nodes;
12449 start = start || 0;
12450 end = typeof end == "undefined" ? ns.length - 1 : end;
12453 for(var i = start; i <= end; i++){
12457 for(var i = start; i >= end; i--){
12465 * Finds the index of the passed node
12466 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12467 * @return {Number} The index of the node or -1
12469 indexOf : function(node){
12470 node = this.getNode(node);
12471 if(typeof node.nodeIndex == "number"){
12472 return node.nodeIndex;
12474 var ns = this.nodes;
12475 for(var i = 0, len = ns.length; i < len; i++){
12486 * based on jquery fullcalendar
12490 Roo.bootstrap = Roo.bootstrap || {};
12492 * @class Roo.bootstrap.Calendar
12493 * @extends Roo.bootstrap.Component
12494 * Bootstrap Calendar class
12495 * @cfg {Boolean} loadMask (true|false) default false
12496 * @cfg {Object} header generate the user specific header of the calendar, default false
12499 * Create a new Container
12500 * @param {Object} config The config object
12505 Roo.bootstrap.Calendar = function(config){
12506 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12510 * Fires when a date is selected
12511 * @param {DatePicker} this
12512 * @param {Date} date The selected date
12516 * @event monthchange
12517 * Fires when the displayed month changes
12518 * @param {DatePicker} this
12519 * @param {Date} date The selected month
12521 'monthchange': true,
12523 * @event evententer
12524 * Fires when mouse over an event
12525 * @param {Calendar} this
12526 * @param {event} Event
12528 'evententer': true,
12530 * @event eventleave
12531 * Fires when the mouse leaves an
12532 * @param {Calendar} this
12535 'eventleave': true,
12537 * @event eventclick
12538 * Fires when the mouse click an
12539 * @param {Calendar} this
12548 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12551 * @cfg {Number} startDay
12552 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12560 getAutoCreate : function(){
12563 var fc_button = function(name, corner, style, content ) {
12564 return Roo.apply({},{
12566 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12568 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12571 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12582 style : 'width:100%',
12589 cls : 'fc-header-left',
12591 fc_button('prev', 'left', 'arrow', '‹' ),
12592 fc_button('next', 'right', 'arrow', '›' ),
12593 { tag: 'span', cls: 'fc-header-space' },
12594 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12602 cls : 'fc-header-center',
12606 cls: 'fc-header-title',
12609 html : 'month / year'
12617 cls : 'fc-header-right',
12619 /* fc_button('month', 'left', '', 'month' ),
12620 fc_button('week', '', '', 'week' ),
12621 fc_button('day', 'right', '', 'day' )
12633 header = this.header;
12636 var cal_heads = function() {
12638 // fixme - handle this.
12640 for (var i =0; i < Date.dayNames.length; i++) {
12641 var d = Date.dayNames[i];
12644 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12645 html : d.substring(0,3)
12649 ret[0].cls += ' fc-first';
12650 ret[6].cls += ' fc-last';
12653 var cal_cell = function(n) {
12656 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12661 cls: 'fc-day-number',
12665 cls: 'fc-day-content',
12669 style: 'position: relative;' // height: 17px;
12681 var cal_rows = function() {
12684 for (var r = 0; r < 6; r++) {
12691 for (var i =0; i < Date.dayNames.length; i++) {
12692 var d = Date.dayNames[i];
12693 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12696 row.cn[0].cls+=' fc-first';
12697 row.cn[0].cn[0].style = 'min-height:90px';
12698 row.cn[6].cls+=' fc-last';
12702 ret[0].cls += ' fc-first';
12703 ret[4].cls += ' fc-prev-last';
12704 ret[5].cls += ' fc-last';
12711 cls: 'fc-border-separate',
12712 style : 'width:100%',
12720 cls : 'fc-first fc-last',
12738 cls : 'fc-content',
12739 style : "position: relative;",
12742 cls : 'fc-view fc-view-month fc-grid',
12743 style : 'position: relative',
12744 unselectable : 'on',
12747 cls : 'fc-event-container',
12748 style : 'position:absolute;z-index:8;top:0;left:0;'
12766 initEvents : function()
12769 throw "can not find store for calendar";
12775 style: "text-align:center",
12779 style: "background-color:white;width:50%;margin:250 auto",
12783 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12794 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12796 var size = this.el.select('.fc-content', true).first().getSize();
12797 this.maskEl.setSize(size.width, size.height);
12798 this.maskEl.enableDisplayMode("block");
12799 if(!this.loadMask){
12800 this.maskEl.hide();
12803 this.store = Roo.factory(this.store, Roo.data);
12804 this.store.on('load', this.onLoad, this);
12805 this.store.on('beforeload', this.onBeforeLoad, this);
12809 this.cells = this.el.select('.fc-day',true);
12810 //Roo.log(this.cells);
12811 this.textNodes = this.el.query('.fc-day-number');
12812 this.cells.addClassOnOver('fc-state-hover');
12814 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12815 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12816 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12817 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12819 this.on('monthchange', this.onMonthChange, this);
12821 this.update(new Date().clearTime());
12824 resize : function() {
12825 var sz = this.el.getSize();
12827 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12828 this.el.select('.fc-day-content div',true).setHeight(34);
12833 showPrevMonth : function(e){
12834 this.update(this.activeDate.add("mo", -1));
12836 showToday : function(e){
12837 this.update(new Date().clearTime());
12840 showNextMonth : function(e){
12841 this.update(this.activeDate.add("mo", 1));
12845 showPrevYear : function(){
12846 this.update(this.activeDate.add("y", -1));
12850 showNextYear : function(){
12851 this.update(this.activeDate.add("y", 1));
12856 update : function(date)
12858 var vd = this.activeDate;
12859 this.activeDate = date;
12860 // if(vd && this.el){
12861 // var t = date.getTime();
12862 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12863 // Roo.log('using add remove');
12865 // this.fireEvent('monthchange', this, date);
12867 // this.cells.removeClass("fc-state-highlight");
12868 // this.cells.each(function(c){
12869 // if(c.dateValue == t){
12870 // c.addClass("fc-state-highlight");
12871 // setTimeout(function(){
12872 // try{c.dom.firstChild.focus();}catch(e){}
12882 var days = date.getDaysInMonth();
12884 var firstOfMonth = date.getFirstDateOfMonth();
12885 var startingPos = firstOfMonth.getDay()-this.startDay;
12887 if(startingPos < this.startDay){
12891 var pm = date.add(Date.MONTH, -1);
12892 var prevStart = pm.getDaysInMonth()-startingPos;
12894 this.cells = this.el.select('.fc-day',true);
12895 this.textNodes = this.el.query('.fc-day-number');
12896 this.cells.addClassOnOver('fc-state-hover');
12898 var cells = this.cells.elements;
12899 var textEls = this.textNodes;
12901 Roo.each(cells, function(cell){
12902 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12905 days += startingPos;
12907 // convert everything to numbers so it's fast
12908 var day = 86400000;
12909 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12912 //Roo.log(prevStart);
12914 var today = new Date().clearTime().getTime();
12915 var sel = date.clearTime().getTime();
12916 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12917 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12918 var ddMatch = this.disabledDatesRE;
12919 var ddText = this.disabledDatesText;
12920 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12921 var ddaysText = this.disabledDaysText;
12922 var format = this.format;
12924 var setCellClass = function(cal, cell){
12928 //Roo.log('set Cell Class');
12930 var t = d.getTime();
12934 cell.dateValue = t;
12936 cell.className += " fc-today";
12937 cell.className += " fc-state-highlight";
12938 cell.title = cal.todayText;
12941 // disable highlight in other month..
12942 //cell.className += " fc-state-highlight";
12947 cell.className = " fc-state-disabled";
12948 cell.title = cal.minText;
12952 cell.className = " fc-state-disabled";
12953 cell.title = cal.maxText;
12957 if(ddays.indexOf(d.getDay()) != -1){
12958 cell.title = ddaysText;
12959 cell.className = " fc-state-disabled";
12962 if(ddMatch && format){
12963 var fvalue = d.dateFormat(format);
12964 if(ddMatch.test(fvalue)){
12965 cell.title = ddText.replace("%0", fvalue);
12966 cell.className = " fc-state-disabled";
12970 if (!cell.initialClassName) {
12971 cell.initialClassName = cell.dom.className;
12974 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12979 for(; i < startingPos; i++) {
12980 textEls[i].innerHTML = (++prevStart);
12981 d.setDate(d.getDate()+1);
12983 cells[i].className = "fc-past fc-other-month";
12984 setCellClass(this, cells[i]);
12989 for(; i < days; i++){
12990 intDay = i - startingPos + 1;
12991 textEls[i].innerHTML = (intDay);
12992 d.setDate(d.getDate()+1);
12994 cells[i].className = ''; // "x-date-active";
12995 setCellClass(this, cells[i]);
12999 for(; i < 42; i++) {
13000 textEls[i].innerHTML = (++extraDays);
13001 d.setDate(d.getDate()+1);
13003 cells[i].className = "fc-future fc-other-month";
13004 setCellClass(this, cells[i]);
13007 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13009 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13011 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13012 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13014 if(totalRows != 6){
13015 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13016 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13019 this.fireEvent('monthchange', this, date);
13023 if(!this.internalRender){
13024 var main = this.el.dom.firstChild;
13025 var w = main.offsetWidth;
13026 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13027 Roo.fly(main).setWidth(w);
13028 this.internalRender = true;
13029 // opera does not respect the auto grow header center column
13030 // then, after it gets a width opera refuses to recalculate
13031 // without a second pass
13032 if(Roo.isOpera && !this.secondPass){
13033 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13034 this.secondPass = true;
13035 this.update.defer(10, this, [date]);
13042 findCell : function(dt) {
13043 dt = dt.clearTime().getTime();
13045 this.cells.each(function(c){
13046 //Roo.log("check " +c.dateValue + '?=' + dt);
13047 if(c.dateValue == dt){
13057 findCells : function(ev) {
13058 var s = ev.start.clone().clearTime().getTime();
13060 var e= ev.end.clone().clearTime().getTime();
13063 this.cells.each(function(c){
13064 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13066 if(c.dateValue > e){
13069 if(c.dateValue < s){
13078 // findBestRow: function(cells)
13082 // for (var i =0 ; i < cells.length;i++) {
13083 // ret = Math.max(cells[i].rows || 0,ret);
13090 addItem : function(ev)
13092 // look for vertical location slot in
13093 var cells = this.findCells(ev);
13095 // ev.row = this.findBestRow(cells);
13097 // work out the location.
13101 for(var i =0; i < cells.length; i++) {
13103 cells[i].row = cells[0].row;
13106 cells[i].row = cells[i].row + 1;
13116 if (crow.start.getY() == cells[i].getY()) {
13118 crow.end = cells[i];
13135 cells[0].events.push(ev);
13137 this.calevents.push(ev);
13140 clearEvents: function() {
13142 if(!this.calevents){
13146 Roo.each(this.cells.elements, function(c){
13152 Roo.each(this.calevents, function(e) {
13153 Roo.each(e.els, function(el) {
13154 el.un('mouseenter' ,this.onEventEnter, this);
13155 el.un('mouseleave' ,this.onEventLeave, this);
13160 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13166 renderEvents: function()
13170 this.cells.each(function(c) {
13179 if(c.row != c.events.length){
13180 r = 4 - (4 - (c.row - c.events.length));
13183 c.events = ev.slice(0, r);
13184 c.more = ev.slice(r);
13186 if(c.more.length && c.more.length == 1){
13187 c.events.push(c.more.pop());
13190 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13194 this.cells.each(function(c) {
13196 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13199 for (var e = 0; e < c.events.length; e++){
13200 var ev = c.events[e];
13201 var rows = ev.rows;
13203 for(var i = 0; i < rows.length; i++) {
13205 // how many rows should it span..
13208 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13209 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13211 unselectable : "on",
13214 cls: 'fc-event-inner',
13218 // cls: 'fc-event-time',
13219 // html : cells.length > 1 ? '' : ev.time
13223 cls: 'fc-event-title',
13224 html : String.format('{0}', ev.title)
13231 cls: 'ui-resizable-handle ui-resizable-e',
13232 html : '  '
13239 cfg.cls += ' fc-event-start';
13241 if ((i+1) == rows.length) {
13242 cfg.cls += ' fc-event-end';
13245 var ctr = _this.el.select('.fc-event-container',true).first();
13246 var cg = ctr.createChild(cfg);
13248 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13249 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13251 var r = (c.more.length) ? 1 : 0;
13252 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13253 cg.setWidth(ebox.right - sbox.x -2);
13255 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13256 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13257 cg.on('click', _this.onEventClick, _this, ev);
13268 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13269 style : 'position: absolute',
13270 unselectable : "on",
13273 cls: 'fc-event-inner',
13277 cls: 'fc-event-title',
13285 cls: 'ui-resizable-handle ui-resizable-e',
13286 html : '  '
13292 var ctr = _this.el.select('.fc-event-container',true).first();
13293 var cg = ctr.createChild(cfg);
13295 var sbox = c.select('.fc-day-content',true).first().getBox();
13296 var ebox = c.select('.fc-day-content',true).first().getBox();
13298 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13299 cg.setWidth(ebox.right - sbox.x -2);
13301 cg.on('click', _this.onMoreEventClick, _this, c.more);
13311 onEventEnter: function (e, el,event,d) {
13312 this.fireEvent('evententer', this, el, event);
13315 onEventLeave: function (e, el,event,d) {
13316 this.fireEvent('eventleave', this, el, event);
13319 onEventClick: function (e, el,event,d) {
13320 this.fireEvent('eventclick', this, el, event);
13323 onMonthChange: function () {
13327 onMoreEventClick: function(e, el, more)
13331 this.calpopover.placement = 'right';
13332 this.calpopover.setTitle('More');
13334 this.calpopover.setContent('');
13336 var ctr = this.calpopover.el.select('.popover-content', true).first();
13338 Roo.each(more, function(m){
13340 cls : 'fc-event-hori fc-event-draggable',
13343 var cg = ctr.createChild(cfg);
13345 cg.on('click', _this.onEventClick, _this, m);
13348 this.calpopover.show(el);
13353 onLoad: function ()
13355 this.calevents = [];
13358 if(this.store.getCount() > 0){
13359 this.store.data.each(function(d){
13362 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13363 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13364 time : d.data.start_time,
13365 title : d.data.title,
13366 description : d.data.description,
13367 venue : d.data.venue
13372 this.renderEvents();
13374 if(this.calevents.length && this.loadMask){
13375 this.maskEl.hide();
13379 onBeforeLoad: function()
13381 this.clearEvents();
13383 this.maskEl.show();
13397 * @class Roo.bootstrap.Popover
13398 * @extends Roo.bootstrap.Component
13399 * Bootstrap Popover class
13400 * @cfg {String} html contents of the popover (or false to use children..)
13401 * @cfg {String} title of popover (or false to hide)
13402 * @cfg {String} placement how it is placed
13403 * @cfg {String} trigger click || hover (or false to trigger manually)
13404 * @cfg {String} over what (parent or false to trigger manually.)
13407 * Create a new Popover
13408 * @param {Object} config The config object
13411 Roo.bootstrap.Popover = function(config){
13412 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13415 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13417 title: 'Fill in a title',
13420 placement : 'right',
13421 trigger : 'hover', // hover
13425 can_build_overlaid : false,
13427 getChildContainer : function()
13429 return this.el.select('.popover-content',true).first();
13432 getAutoCreate : function(){
13433 Roo.log('make popover?');
13435 cls : 'popover roo-dynamic',
13436 style: 'display:block',
13442 cls : 'popover-inner',
13446 cls: 'popover-title',
13450 cls : 'popover-content',
13461 setTitle: function(str)
13463 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13465 setContent: function(str)
13467 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13469 // as it get's added to the bottom of the page.
13470 onRender : function(ct, position)
13472 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13474 var cfg = Roo.apply({}, this.getAutoCreate());
13478 cfg.cls += ' ' + this.cls;
13481 cfg.style = this.style;
13483 Roo.log("adding to ")
13484 this.el = Roo.get(document.body).createChild(cfg, position);
13490 initEvents : function()
13492 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13493 this.el.enableDisplayMode('block');
13495 if (this.over === false) {
13498 if (this.triggers === false) {
13501 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13502 var triggers = this.trigger ? this.trigger.split(' ') : [];
13503 Roo.each(triggers, function(trigger) {
13505 if (trigger == 'click') {
13506 on_el.on('click', this.toggle, this);
13507 } else if (trigger != 'manual') {
13508 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13509 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13511 on_el.on(eventIn ,this.enter, this);
13512 on_el.on(eventOut, this.leave, this);
13523 toggle : function () {
13524 this.hoverState == 'in' ? this.leave() : this.enter();
13527 enter : function () {
13530 clearTimeout(this.timeout);
13532 this.hoverState = 'in'
13534 if (!this.delay || !this.delay.show) {
13539 this.timeout = setTimeout(function () {
13540 if (_t.hoverState == 'in') {
13543 }, this.delay.show)
13545 leave : function() {
13546 clearTimeout(this.timeout);
13548 this.hoverState = 'out'
13550 if (!this.delay || !this.delay.hide) {
13555 this.timeout = setTimeout(function () {
13556 if (_t.hoverState == 'out') {
13559 }, this.delay.hide)
13562 show : function (on_el)
13565 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13568 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13569 if (this.html !== false) {
13570 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13572 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13573 if (!this.title.length) {
13574 this.el.select('.popover-title',true).hide();
13577 var placement = typeof this.placement == 'function' ?
13578 this.placement.call(this, this.el, on_el) :
13581 var autoToken = /\s?auto?\s?/i;
13582 var autoPlace = autoToken.test(placement);
13584 placement = placement.replace(autoToken, '') || 'top';
13588 //this.el.setXY([0,0]);
13590 this.el.dom.style.display='block';
13591 this.el.addClass(placement);
13593 //this.el.appendTo(on_el);
13595 var p = this.getPosition();
13596 var box = this.el.getBox();
13601 var align = Roo.bootstrap.Popover.alignment[placement]
13602 this.el.alignTo(on_el, align[0],align[1]);
13603 //var arrow = this.el.select('.arrow',true).first();
13604 //arrow.set(align[2],
13606 this.el.addClass('in');
13607 this.hoverState = null;
13609 if (this.el.hasClass('fade')) {
13616 this.el.setXY([0,0]);
13617 this.el.removeClass('in');
13624 Roo.bootstrap.Popover.alignment = {
13625 'left' : ['r-l', [-10,0], 'right'],
13626 'right' : ['l-r', [10,0], 'left'],
13627 'bottom' : ['t-b', [0,10], 'top'],
13628 'top' : [ 'b-t', [0,-10], 'bottom']
13639 * @class Roo.bootstrap.Progress
13640 * @extends Roo.bootstrap.Component
13641 * Bootstrap Progress class
13642 * @cfg {Boolean} striped striped of the progress bar
13643 * @cfg {Boolean} active animated of the progress bar
13647 * Create a new Progress
13648 * @param {Object} config The config object
13651 Roo.bootstrap.Progress = function(config){
13652 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13655 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13660 getAutoCreate : function(){
13668 cfg.cls += ' progress-striped';
13672 cfg.cls += ' active';
13691 * @class Roo.bootstrap.ProgressBar
13692 * @extends Roo.bootstrap.Component
13693 * Bootstrap ProgressBar class
13694 * @cfg {Number} aria_valuenow aria-value now
13695 * @cfg {Number} aria_valuemin aria-value min
13696 * @cfg {Number} aria_valuemax aria-value max
13697 * @cfg {String} label label for the progress bar
13698 * @cfg {String} panel (success | info | warning | danger )
13699 * @cfg {String} role role of the progress bar
13700 * @cfg {String} sr_only text
13704 * Create a new ProgressBar
13705 * @param {Object} config The config object
13708 Roo.bootstrap.ProgressBar = function(config){
13709 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13712 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13716 aria_valuemax : 100,
13722 getAutoCreate : function()
13727 cls: 'progress-bar',
13728 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13740 cfg.role = this.role;
13743 if(this.aria_valuenow){
13744 cfg['aria-valuenow'] = this.aria_valuenow;
13747 if(this.aria_valuemin){
13748 cfg['aria-valuemin'] = this.aria_valuemin;
13751 if(this.aria_valuemax){
13752 cfg['aria-valuemax'] = this.aria_valuemax;
13755 if(this.label && !this.sr_only){
13756 cfg.html = this.label;
13760 cfg.cls += ' progress-bar-' + this.panel;
13766 update : function(aria_valuenow)
13768 this.aria_valuenow = aria_valuenow;
13770 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13785 * @class Roo.bootstrap.TabGroup
13786 * @extends Roo.bootstrap.Column
13787 * Bootstrap Column class
13788 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13789 * @cfg {Boolean} carousel true to make the group behave like a carousel
13792 * Create a new TabGroup
13793 * @param {Object} config The config object
13796 Roo.bootstrap.TabGroup = function(config){
13797 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13799 this.navId = Roo.id();
13802 Roo.bootstrap.TabGroup.register(this);
13806 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13810 getAutoCreate : function()
13812 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13814 cfg.cls += ' tab-content';
13816 if (this.carousel) {
13817 cfg.cls += ' carousel slide';
13819 cls : 'carousel-inner'
13826 getChildContainer : function()
13828 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13832 * register a Navigation item
13833 * @param {Roo.bootstrap.NavItem} the navitem to add
13835 register : function(item)
13837 this.tabs.push( item);
13838 item.navId = this.navId; // not really needed..
13842 getActivePanel : function()
13845 Roo.each(this.tabs, function(t) {
13855 getPanelByName : function(n)
13858 Roo.each(this.tabs, function(t) {
13859 if (t.tabId == n) {
13867 indexOfPanel : function(p)
13870 Roo.each(this.tabs, function(t,i) {
13871 if (t.tabId == p.tabId) {
13880 * show a specific panel
13881 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13882 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13884 showPanel : function (pan)
13889 if (typeof(pan) == 'number') {
13890 pan = this.tabs[pan];
13892 if (typeof(pan) == 'string') {
13893 pan = this.getPanelByName(pan);
13895 if (pan.tabId == this.getActivePanel().tabId) {
13898 var cur = this.getActivePanel();
13900 if (false === cur.fireEvent('beforedeactivate')) {
13906 if (this.carousel) {
13907 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13908 var lr = dir == 'next' ? 'left' : 'right';
13909 pan.el.addClass(dir); // or prev
13910 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13911 cur.el.addClass(lr); // or right
13912 pan.el.addClass(lr);
13913 cur.el.on('transitionend', function() {
13914 Roo.log("trans end?");
13916 pan.el.removeClass([lr,dir]);
13917 pan.setActive(true);
13919 cur.el.removeClass([lr]);
13920 cur.setActive(false);
13923 }, this, { single: true } );
13927 cur.setActive(false);
13928 pan.setActive(true);
13932 showPanelNext : function()
13934 var i = this.indexOfPanel(this.getActivePanel());
13935 if (i > this.tabs.length) {
13938 this.showPanel(this.tabs[i+1]);
13940 showPanelPrev : function()
13942 var i = this.indexOfPanel(this.getActivePanel());
13946 this.showPanel(this.tabs[i-1]);
13957 Roo.apply(Roo.bootstrap.TabGroup, {
13961 * register a Navigation Group
13962 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13964 register : function(navgrp)
13966 this.groups[navgrp.navId] = navgrp;
13970 * fetch a Navigation Group based on the navigation ID
13971 * if one does not exist , it will get created.
13972 * @param {string} the navgroup to add
13973 * @returns {Roo.bootstrap.NavGroup} the navgroup
13975 get: function(navId) {
13976 if (typeof(this.groups[navId]) == 'undefined') {
13977 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13979 return this.groups[navId] ;
13994 * @class Roo.bootstrap.TabPanel
13995 * @extends Roo.bootstrap.Component
13996 * Bootstrap TabPanel class
13997 * @cfg {Boolean} active panel active
13998 * @cfg {String} html panel content
13999 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14000 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14004 * Create a new TabPanel
14005 * @param {Object} config The config object
14008 Roo.bootstrap.TabPanel = function(config){
14009 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14013 * Fires when the active status changes
14014 * @param {Roo.bootstrap.TabPanel} this
14015 * @param {Boolean} state the new state
14020 * @event beforedeactivate
14021 * Fires before a tab is de-activated - can be used to do validation on a form.
14022 * @param {Roo.bootstrap.TabPanel} this
14023 * @return {Boolean} false if there is an error
14026 'beforedeactivate': true
14029 this.tabId = this.tabId || Roo.id();
14033 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14040 getAutoCreate : function(){
14043 // item is needed for carousel - not sure if it has any effect otherwise
14044 cls: 'tab-pane item',
14045 html: this.html || ''
14049 cfg.cls += ' active';
14053 cfg.tabId = this.tabId;
14060 initEvents: function()
14062 Roo.log('-------- init events on tab panel ---------');
14064 var p = this.parent();
14065 this.navId = this.navId || p.navId;
14067 if (typeof(this.navId) != 'undefined') {
14068 // not really needed.. but just in case.. parent should be a NavGroup.
14069 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14070 Roo.log(['register', tg, this]);
14076 onRender : function(ct, position)
14078 // Roo.log("Call onRender: " + this.xtype);
14080 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14088 setActive: function(state)
14090 Roo.log("panel - set active " + this.tabId + "=" + state);
14092 this.active = state;
14094 this.el.removeClass('active');
14096 } else if (!this.el.hasClass('active')) {
14097 this.el.addClass('active');
14099 this.fireEvent('changed', this, state);
14116 * @class Roo.bootstrap.DateField
14117 * @extends Roo.bootstrap.Input
14118 * Bootstrap DateField class
14119 * @cfg {Number} weekStart default 0
14120 * @cfg {Number} weekStart default 0
14121 * @cfg {Number} viewMode default empty, (months|years)
14122 * @cfg {Number} minViewMode default empty, (months|years)
14123 * @cfg {Number} startDate default -Infinity
14124 * @cfg {Number} endDate default Infinity
14125 * @cfg {Boolean} todayHighlight default false
14126 * @cfg {Boolean} todayBtn default false
14127 * @cfg {Boolean} calendarWeeks default false
14128 * @cfg {Object} daysOfWeekDisabled default empty
14130 * @cfg {Boolean} keyboardNavigation default true
14131 * @cfg {String} language default en
14134 * Create a new DateField
14135 * @param {Object} config The config object
14138 Roo.bootstrap.DateField = function(config){
14139 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14143 * Fires when this field show.
14144 * @param {Roo.bootstrap.DateField} this
14145 * @param {Mixed} date The date value
14150 * Fires when this field hide.
14151 * @param {Roo.bootstrap.DateField} this
14152 * @param {Mixed} date The date value
14157 * Fires when select a date.
14158 * @param {Roo.bootstrap.DateField} this
14159 * @param {Mixed} date The date value
14165 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14168 * @cfg {String} format
14169 * The default date format string which can be overriden for localization support. The format must be
14170 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14174 * @cfg {String} altFormats
14175 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14176 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14178 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14186 todayHighlight : false,
14192 keyboardNavigation: true,
14194 calendarWeeks: false,
14196 startDate: -Infinity,
14200 daysOfWeekDisabled: [],
14204 UTCDate: function()
14206 return new Date(Date.UTC.apply(Date, arguments));
14209 UTCToday: function()
14211 var today = new Date();
14212 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14215 getDate: function() {
14216 var d = this.getUTCDate();
14217 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14220 getUTCDate: function() {
14224 setDate: function(d) {
14225 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14228 setUTCDate: function(d) {
14230 this.setValue(this.formatDate(this.date));
14233 onRender: function(ct, position)
14236 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14238 this.language = this.language || 'en';
14239 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14240 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14242 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14243 this.format = this.format || 'm/d/y';
14244 this.isInline = false;
14245 this.isInput = true;
14246 this.component = this.el.select('.add-on', true).first() || false;
14247 this.component = (this.component && this.component.length === 0) ? false : this.component;
14248 this.hasInput = this.component && this.inputEL().length;
14250 if (typeof(this.minViewMode === 'string')) {
14251 switch (this.minViewMode) {
14253 this.minViewMode = 1;
14256 this.minViewMode = 2;
14259 this.minViewMode = 0;
14264 if (typeof(this.viewMode === 'string')) {
14265 switch (this.viewMode) {
14278 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14280 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14282 this.picker().on('mousedown', this.onMousedown, this);
14283 this.picker().on('click', this.onClick, this);
14285 this.picker().addClass('datepicker-dropdown');
14287 this.startViewMode = this.viewMode;
14290 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14291 if(!this.calendarWeeks){
14296 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14297 v.attr('colspan', function(i, val){
14298 return parseInt(val) + 1;
14303 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14305 this.setStartDate(this.startDate);
14306 this.setEndDate(this.endDate);
14308 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14315 if(this.isInline) {
14320 picker : function()
14322 return this.el.select('.datepicker', true).first();
14325 fillDow: function()
14327 var dowCnt = this.weekStart;
14336 if(this.calendarWeeks){
14344 while (dowCnt < this.weekStart + 7) {
14348 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14352 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14355 fillMonths: function()
14358 var months = this.picker().select('>.datepicker-months td', true).first();
14360 months.dom.innerHTML = '';
14366 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14369 months.createChild(month);
14377 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14379 if (this.date < this.startDate) {
14380 this.viewDate = new Date(this.startDate);
14381 } else if (this.date > this.endDate) {
14382 this.viewDate = new Date(this.endDate);
14384 this.viewDate = new Date(this.date);
14392 var d = new Date(this.viewDate),
14393 year = d.getUTCFullYear(),
14394 month = d.getUTCMonth(),
14395 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14396 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14397 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14398 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14399 currentDate = this.date && this.date.valueOf(),
14400 today = this.UTCToday();
14402 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14404 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14406 // this.picker.select('>tfoot th.today').
14407 // .text(dates[this.language].today)
14408 // .toggle(this.todayBtn !== false);
14410 this.updateNavArrows();
14413 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14415 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14417 prevMonth.setUTCDate(day);
14419 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14421 var nextMonth = new Date(prevMonth);
14423 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14425 nextMonth = nextMonth.valueOf();
14427 var fillMonths = false;
14429 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14431 while(prevMonth.valueOf() < nextMonth) {
14434 if (prevMonth.getUTCDay() === this.weekStart) {
14436 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14444 if(this.calendarWeeks){
14445 // ISO 8601: First week contains first thursday.
14446 // ISO also states week starts on Monday, but we can be more abstract here.
14448 // Start of current week: based on weekstart/current date
14449 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14450 // Thursday of this week
14451 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14452 // First Thursday of year, year from thursday
14453 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14454 // Calendar week: ms between thursdays, div ms per day, div 7 days
14455 calWeek = (th - yth) / 864e5 / 7 + 1;
14457 fillMonths.cn.push({
14465 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14467 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14470 if (this.todayHighlight &&
14471 prevMonth.getUTCFullYear() == today.getFullYear() &&
14472 prevMonth.getUTCMonth() == today.getMonth() &&
14473 prevMonth.getUTCDate() == today.getDate()) {
14474 clsName += ' today';
14477 if (currentDate && prevMonth.valueOf() === currentDate) {
14478 clsName += ' active';
14481 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14482 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14483 clsName += ' disabled';
14486 fillMonths.cn.push({
14488 cls: 'day ' + clsName,
14489 html: prevMonth.getDate()
14492 prevMonth.setDate(prevMonth.getDate()+1);
14495 var currentYear = this.date && this.date.getUTCFullYear();
14496 var currentMonth = this.date && this.date.getUTCMonth();
14498 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14500 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14501 v.removeClass('active');
14503 if(currentYear === year && k === currentMonth){
14504 v.addClass('active');
14507 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14508 v.addClass('disabled');
14514 year = parseInt(year/10, 10) * 10;
14516 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14518 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14521 for (var i = -1; i < 11; i++) {
14522 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14524 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14532 showMode: function(dir)
14535 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14537 Roo.each(this.picker().select('>div',true).elements, function(v){
14538 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14541 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14546 if(this.isInline) return;
14548 this.picker().removeClass(['bottom', 'top']);
14550 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14552 * place to the top of element!
14556 this.picker().addClass('top');
14557 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14562 this.picker().addClass('bottom');
14564 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14567 parseDate : function(value)
14569 if(!value || value instanceof Date){
14572 var v = Date.parseDate(value, this.format);
14573 if (!v && this.useIso) {
14574 v = Date.parseDate(value, 'Y-m-d');
14576 if(!v && this.altFormats){
14577 if(!this.altFormatsArray){
14578 this.altFormatsArray = this.altFormats.split("|");
14580 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14581 v = Date.parseDate(value, this.altFormatsArray[i]);
14587 formatDate : function(date, fmt)
14589 return (!date || !(date instanceof Date)) ?
14590 date : date.dateFormat(fmt || this.format);
14593 onFocus : function()
14595 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14599 onBlur : function()
14601 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14603 var d = this.inputEl().getValue();
14614 this.picker().show();
14618 this.fireEvent('show', this, this.date);
14623 if(this.isInline) return;
14624 this.picker().hide();
14625 this.viewMode = this.startViewMode;
14628 this.fireEvent('hide', this, this.date);
14632 onMousedown: function(e)
14634 e.stopPropagation();
14635 e.preventDefault();
14640 Roo.bootstrap.DateField.superclass.keyup.call(this);
14644 setValue: function(v)
14646 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14648 var d = new Date(v);
14650 if(isNaN(d.getTime())){
14654 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14658 this.fireEvent('select', this, this.date);
14662 getValue: function()
14664 return this.formatDate(this.date);
14667 fireKey: function(e)
14669 if (!this.picker().isVisible()){
14670 if (e.keyCode == 27) // allow escape to hide and re-show picker
14675 var dateChanged = false,
14677 newDate, newViewDate;
14682 e.preventDefault();
14686 if (!this.keyboardNavigation) break;
14687 dir = e.keyCode == 37 ? -1 : 1;
14690 newDate = this.moveYear(this.date, dir);
14691 newViewDate = this.moveYear(this.viewDate, dir);
14692 } else if (e.shiftKey){
14693 newDate = this.moveMonth(this.date, dir);
14694 newViewDate = this.moveMonth(this.viewDate, dir);
14696 newDate = new Date(this.date);
14697 newDate.setUTCDate(this.date.getUTCDate() + dir);
14698 newViewDate = new Date(this.viewDate);
14699 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14701 if (this.dateWithinRange(newDate)){
14702 this.date = newDate;
14703 this.viewDate = newViewDate;
14704 this.setValue(this.formatDate(this.date));
14706 e.preventDefault();
14707 dateChanged = true;
14712 if (!this.keyboardNavigation) break;
14713 dir = e.keyCode == 38 ? -1 : 1;
14715 newDate = this.moveYear(this.date, dir);
14716 newViewDate = this.moveYear(this.viewDate, dir);
14717 } else if (e.shiftKey){
14718 newDate = this.moveMonth(this.date, dir);
14719 newViewDate = this.moveMonth(this.viewDate, dir);
14721 newDate = new Date(this.date);
14722 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14723 newViewDate = new Date(this.viewDate);
14724 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14726 if (this.dateWithinRange(newDate)){
14727 this.date = newDate;
14728 this.viewDate = newViewDate;
14729 this.setValue(this.formatDate(this.date));
14731 e.preventDefault();
14732 dateChanged = true;
14736 this.setValue(this.formatDate(this.date));
14738 e.preventDefault();
14741 this.setValue(this.formatDate(this.date));
14755 onClick: function(e)
14757 e.stopPropagation();
14758 e.preventDefault();
14760 var target = e.getTarget();
14762 if(target.nodeName.toLowerCase() === 'i'){
14763 target = Roo.get(target).dom.parentNode;
14766 var nodeName = target.nodeName;
14767 var className = target.className;
14768 var html = target.innerHTML;
14770 switch(nodeName.toLowerCase()) {
14772 switch(className) {
14778 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14779 switch(this.viewMode){
14781 this.viewDate = this.moveMonth(this.viewDate, dir);
14785 this.viewDate = this.moveYear(this.viewDate, dir);
14791 var date = new Date();
14792 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14794 this.setValue(this.formatDate(this.date));
14801 if (className.indexOf('disabled') === -1) {
14802 this.viewDate.setUTCDate(1);
14803 if (className.indexOf('month') !== -1) {
14804 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14806 var year = parseInt(html, 10) || 0;
14807 this.viewDate.setUTCFullYear(year);
14816 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14817 var day = parseInt(html, 10) || 1;
14818 var year = this.viewDate.getUTCFullYear(),
14819 month = this.viewDate.getUTCMonth();
14821 if (className.indexOf('old') !== -1) {
14828 } else if (className.indexOf('new') !== -1) {
14836 this.date = this.UTCDate(year, month, day,0,0,0,0);
14837 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14839 this.setValue(this.formatDate(this.date));
14846 setStartDate: function(startDate)
14848 this.startDate = startDate || -Infinity;
14849 if (this.startDate !== -Infinity) {
14850 this.startDate = this.parseDate(this.startDate);
14853 this.updateNavArrows();
14856 setEndDate: function(endDate)
14858 this.endDate = endDate || Infinity;
14859 if (this.endDate !== Infinity) {
14860 this.endDate = this.parseDate(this.endDate);
14863 this.updateNavArrows();
14866 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14868 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14869 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14870 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14872 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14873 return parseInt(d, 10);
14876 this.updateNavArrows();
14879 updateNavArrows: function()
14881 var d = new Date(this.viewDate),
14882 year = d.getUTCFullYear(),
14883 month = d.getUTCMonth();
14885 Roo.each(this.picker().select('.prev', true).elements, function(v){
14887 switch (this.viewMode) {
14890 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14896 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14903 Roo.each(this.picker().select('.next', true).elements, function(v){
14905 switch (this.viewMode) {
14908 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14914 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14922 moveMonth: function(date, dir)
14924 if (!dir) return date;
14925 var new_date = new Date(date.valueOf()),
14926 day = new_date.getUTCDate(),
14927 month = new_date.getUTCMonth(),
14928 mag = Math.abs(dir),
14930 dir = dir > 0 ? 1 : -1;
14933 // If going back one month, make sure month is not current month
14934 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14936 return new_date.getUTCMonth() == month;
14938 // If going forward one month, make sure month is as expected
14939 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14941 return new_date.getUTCMonth() != new_month;
14943 new_month = month + dir;
14944 new_date.setUTCMonth(new_month);
14945 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14946 if (new_month < 0 || new_month > 11)
14947 new_month = (new_month + 12) % 12;
14949 // For magnitudes >1, move one month at a time...
14950 for (var i=0; i<mag; i++)
14951 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14952 new_date = this.moveMonth(new_date, dir);
14953 // ...then reset the day, keeping it in the new month
14954 new_month = new_date.getUTCMonth();
14955 new_date.setUTCDate(day);
14957 return new_month != new_date.getUTCMonth();
14960 // Common date-resetting loop -- if date is beyond end of month, make it
14963 new_date.setUTCDate(--day);
14964 new_date.setUTCMonth(new_month);
14969 moveYear: function(date, dir)
14971 return this.moveMonth(date, dir*12);
14974 dateWithinRange: function(date)
14976 return date >= this.startDate && date <= this.endDate;
14982 this.picker().remove();
14987 Roo.apply(Roo.bootstrap.DateField, {
14998 html: '<i class="fa fa-arrow-left"/>'
15008 html: '<i class="fa fa-arrow-right"/>'
15050 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15051 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15052 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15053 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15054 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15067 navFnc: 'FullYear',
15072 navFnc: 'FullYear',
15077 Roo.apply(Roo.bootstrap.DateField, {
15081 cls: 'datepicker dropdown-menu',
15085 cls: 'datepicker-days',
15089 cls: 'table-condensed',
15091 Roo.bootstrap.DateField.head,
15095 Roo.bootstrap.DateField.footer
15102 cls: 'datepicker-months',
15106 cls: 'table-condensed',
15108 Roo.bootstrap.DateField.head,
15109 Roo.bootstrap.DateField.content,
15110 Roo.bootstrap.DateField.footer
15117 cls: 'datepicker-years',
15121 cls: 'table-condensed',
15123 Roo.bootstrap.DateField.head,
15124 Roo.bootstrap.DateField.content,
15125 Roo.bootstrap.DateField.footer
15144 * @class Roo.bootstrap.TimeField
15145 * @extends Roo.bootstrap.Input
15146 * Bootstrap DateField class
15150 * Create a new TimeField
15151 * @param {Object} config The config object
15154 Roo.bootstrap.TimeField = function(config){
15155 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15159 * Fires when this field show.
15160 * @param {Roo.bootstrap.DateField} this
15161 * @param {Mixed} date The date value
15166 * Fires when this field hide.
15167 * @param {Roo.bootstrap.DateField} this
15168 * @param {Mixed} date The date value
15173 * Fires when select a date.
15174 * @param {Roo.bootstrap.DateField} this
15175 * @param {Mixed} date The date value
15181 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15184 * @cfg {String} format
15185 * The default time format string which can be overriden for localization support. The format must be
15186 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15190 onRender: function(ct, position)
15193 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15195 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15197 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15199 this.pop = this.picker().select('>.datepicker-time',true).first();
15200 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15202 this.picker().on('mousedown', this.onMousedown, this);
15203 this.picker().on('click', this.onClick, this);
15205 this.picker().addClass('datepicker-dropdown');
15210 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15211 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15212 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15213 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15214 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15215 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15219 fireKey: function(e){
15220 if (!this.picker().isVisible()){
15221 if (e.keyCode == 27) // allow escape to hide and re-show picker
15226 e.preventDefault();
15234 this.onTogglePeriod();
15237 this.onIncrementMinutes();
15240 this.onDecrementMinutes();
15249 onClick: function(e) {
15250 e.stopPropagation();
15251 e.preventDefault();
15254 picker : function()
15256 return this.el.select('.datepicker', true).first();
15259 fillTime: function()
15261 var time = this.pop.select('tbody', true).first();
15263 time.dom.innerHTML = '';
15278 cls: 'hours-up glyphicon glyphicon-chevron-up'
15298 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15319 cls: 'timepicker-hour',
15334 cls: 'timepicker-minute',
15349 cls: 'btn btn-primary period',
15371 cls: 'hours-down glyphicon glyphicon-chevron-down'
15391 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15409 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15416 var hours = this.time.getHours();
15417 var minutes = this.time.getMinutes();
15430 hours = hours - 12;
15434 hours = '0' + hours;
15438 minutes = '0' + minutes;
15441 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15442 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15443 this.pop.select('button', true).first().dom.innerHTML = period;
15449 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15451 var cls = ['bottom'];
15453 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15460 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15465 this.picker().addClass(cls.join('-'));
15469 Roo.each(cls, function(c){
15471 _this.picker().setTop(_this.inputEl().getHeight());
15475 _this.picker().setTop(0 - _this.picker().getHeight());
15480 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15484 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15491 onFocus : function()
15493 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15497 onBlur : function()
15499 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15505 this.picker().show();
15510 this.fireEvent('show', this, this.date);
15515 this.picker().hide();
15518 this.fireEvent('hide', this, this.date);
15521 setTime : function()
15524 this.setValue(this.time.format(this.format));
15526 this.fireEvent('select', this, this.date);
15531 onMousedown: function(e){
15532 e.stopPropagation();
15533 e.preventDefault();
15536 onIncrementHours: function()
15538 Roo.log('onIncrementHours');
15539 this.time = this.time.add(Date.HOUR, 1);
15544 onDecrementHours: function()
15546 Roo.log('onDecrementHours');
15547 this.time = this.time.add(Date.HOUR, -1);
15551 onIncrementMinutes: function()
15553 Roo.log('onIncrementMinutes');
15554 this.time = this.time.add(Date.MINUTE, 1);
15558 onDecrementMinutes: function()
15560 Roo.log('onDecrementMinutes');
15561 this.time = this.time.add(Date.MINUTE, -1);
15565 onTogglePeriod: function()
15567 Roo.log('onTogglePeriod');
15568 this.time = this.time.add(Date.HOUR, 12);
15575 Roo.apply(Roo.bootstrap.TimeField, {
15605 cls: 'btn btn-info ok',
15617 Roo.apply(Roo.bootstrap.TimeField, {
15621 cls: 'datepicker dropdown-menu',
15625 cls: 'datepicker-time',
15629 cls: 'table-condensed',
15631 Roo.bootstrap.TimeField.content,
15632 Roo.bootstrap.TimeField.footer
15651 * @class Roo.bootstrap.CheckBox
15652 * @extends Roo.bootstrap.Input
15653 * Bootstrap CheckBox class
15655 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15656 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15657 * @cfg {String} boxLabel The text that appears beside the checkbox
15658 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15659 * @cfg {Boolean} checked initnal the element
15663 * Create a new CheckBox
15664 * @param {Object} config The config object
15667 Roo.bootstrap.CheckBox = function(config){
15668 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15673 * Fires when the element is checked or unchecked.
15674 * @param {Roo.bootstrap.CheckBox} this This input
15675 * @param {Boolean} checked The new checked value
15681 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15683 inputType: 'checkbox',
15690 getAutoCreate : function()
15692 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15698 cfg.cls = 'form-group checkbox' //input-group
15706 type : this.inputType,
15707 value : (!this.checked) ? this.valueOff : this.inputValue,
15708 cls : 'roo-checkbox', //'form-box',
15709 placeholder : this.placeholder || ''
15713 if (this.weight) { // Validity check?
15714 cfg.cls += " checkbox-" + this.weight;
15717 if (this.disabled) {
15718 input.disabled=true;
15722 input.checked = this.checked;
15726 input.name = this.name;
15730 input.cls += ' input-' + this.size;
15734 ['xs','sm','md','lg'].map(function(size){
15735 if (settings[size]) {
15736 cfg.cls += ' col-' + size + '-' + settings[size];
15742 var inputblock = input;
15747 if (this.before || this.after) {
15750 cls : 'input-group',
15754 inputblock.cn.push({
15756 cls : 'input-group-addon',
15760 inputblock.cn.push(input);
15762 inputblock.cn.push({
15764 cls : 'input-group-addon',
15771 if (align ==='left' && this.fieldLabel.length) {
15772 Roo.log("left and has label");
15778 cls : 'control-label col-md-' + this.labelWidth,
15779 html : this.fieldLabel
15783 cls : "col-md-" + (12 - this.labelWidth),
15790 } else if ( this.fieldLabel.length) {
15795 tag: this.boxLabel ? 'span' : 'label',
15797 cls: 'control-label box-input-label',
15798 //cls : 'input-group-addon',
15799 html : this.fieldLabel
15809 Roo.log(" no label && no align");
15810 cfg.cn = [ inputblock ] ;
15819 html: this.boxLabel
15831 * return the real input element.
15833 inputEl: function ()
15835 return this.el.select('input.roo-checkbox',true).first();
15840 return this.el.select('label.control-label',true).first();
15843 initEvents : function()
15845 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15847 this.inputEl().on('click', this.onClick, this);
15851 onClick : function()
15853 this.setChecked(!this.checked);
15856 setChecked : function(state,suppressEvent)
15858 this.checked = state;
15860 this.inputEl().dom.checked = state;
15862 if(suppressEvent !== true){
15863 this.fireEvent('check', this, state);
15866 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15870 setValue : function(v,suppressEvent)
15872 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15886 * @class Roo.bootstrap.Radio
15887 * @extends Roo.bootstrap.CheckBox
15888 * Bootstrap Radio class
15891 * Create a new Radio
15892 * @param {Object} config The config object
15895 Roo.bootstrap.Radio = function(config){
15896 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15900 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15902 inputType: 'radio',
15906 getAutoCreate : function()
15908 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15914 cfg.cls = 'form-group radio' //input-group
15919 type : this.inputType,
15920 value : (!this.checked) ? this.valueOff : this.inputValue,
15922 placeholder : this.placeholder || ''
15925 if (this.weight) { // Validity check?
15926 cfg.cls += " radio-" + this.weight;
15928 if (this.disabled) {
15929 input.disabled=true;
15933 input.checked = this.checked;
15937 input.name = this.name;
15941 input.cls += ' input-' + this.size;
15945 ['xs','sm','md','lg'].map(function(size){
15946 if (settings[size]) {
15947 cfg.cls += ' col-' + size + '-' + settings[size];
15951 var inputblock = input;
15953 if (this.before || this.after) {
15956 cls : 'input-group',
15960 inputblock.cn.push({
15962 cls : 'input-group-addon',
15966 inputblock.cn.push(input);
15968 inputblock.cn.push({
15970 cls : 'input-group-addon',
15977 if (align ==='left' && this.fieldLabel.length) {
15978 Roo.log("left and has label");
15984 cls : 'control-label col-md-' + this.labelWidth,
15985 html : this.fieldLabel
15989 cls : "col-md-" + (12 - this.labelWidth),
15996 } else if ( this.fieldLabel.length) {
16003 cls: 'control-label box-input-label',
16004 //cls : 'input-group-addon',
16005 html : this.fieldLabel
16015 Roo.log(" no label && no align");
16030 html: this.boxLabel
16037 inputEl: function ()
16039 return this.el.select('input.roo-radio',true).first();
16041 onClick : function()
16043 this.setChecked(true);
16046 setChecked : function(state,suppressEvent)
16049 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16050 v.dom.checked = false;
16054 this.checked = state;
16055 this.inputEl().dom.checked = state;
16057 if(suppressEvent !== true){
16058 this.fireEvent('check', this, state);
16061 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16065 getGroupValue : function()
16068 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16069 if(v.dom.checked == true){
16070 value = v.dom.value;
16078 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16079 * @return {Mixed} value The field value
16081 getValue : function(){
16082 return this.getGroupValue();
16088 //<script type="text/javascript">
16091 * Based Ext JS Library 1.1.1
16092 * Copyright(c) 2006-2007, Ext JS, LLC.
16098 * @class Roo.HtmlEditorCore
16099 * @extends Roo.Component
16100 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16102 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16105 Roo.HtmlEditorCore = function(config){
16108 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16111 * @event initialize
16112 * Fires when the editor is fully initialized (including the iframe)
16113 * @param {Roo.HtmlEditorCore} this
16118 * Fires when the editor is first receives the focus. Any insertion must wait
16119 * until after this event.
16120 * @param {Roo.HtmlEditorCore} this
16124 * @event beforesync
16125 * Fires before the textarea is updated with content from the editor iframe. Return false
16126 * to cancel the sync.
16127 * @param {Roo.HtmlEditorCore} this
16128 * @param {String} html
16132 * @event beforepush
16133 * Fires before the iframe editor is updated with content from the textarea. Return false
16134 * to cancel the push.
16135 * @param {Roo.HtmlEditorCore} this
16136 * @param {String} html
16141 * Fires when the textarea is updated with content from the editor iframe.
16142 * @param {Roo.HtmlEditorCore} this
16143 * @param {String} html
16148 * Fires when the iframe editor is updated with content from the textarea.
16149 * @param {Roo.HtmlEditorCore} this
16150 * @param {String} html
16155 * @event editorevent
16156 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16157 * @param {Roo.HtmlEditorCore} this
16165 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16169 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16175 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16180 * @cfg {Number} height (in pixels)
16184 * @cfg {Number} width (in pixels)
16189 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16192 stylesheets: false,
16197 // private properties
16198 validationEvent : false,
16200 initialized : false,
16202 sourceEditMode : false,
16203 onFocus : Roo.emptyFn,
16205 hideMode:'offsets',
16213 * Protected method that will not generally be called directly. It
16214 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16215 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16217 getDocMarkup : function(){
16220 Roo.log(this.stylesheets);
16222 // inherit styels from page...??
16223 if (this.stylesheets === false) {
16225 Roo.get(document.head).select('style').each(function(node) {
16226 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16229 Roo.get(document.head).select('link').each(function(node) {
16230 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16233 } else if (!this.stylesheets.length) {
16235 st = '<style type="text/css">' +
16236 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16239 Roo.each(this.stylesheets, function(s) {
16240 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16245 st += '<style type="text/css">' +
16246 'IMG { cursor: pointer } ' +
16250 return '<html><head>' + st +
16251 //<style type="text/css">' +
16252 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16254 ' </head><body class="roo-htmleditor-body"></body></html>';
16258 onRender : function(ct, position)
16261 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16262 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16265 this.el.dom.style.border = '0 none';
16266 this.el.dom.setAttribute('tabIndex', -1);
16267 this.el.addClass('x-hidden hide');
16271 if(Roo.isIE){ // fix IE 1px bogus margin
16272 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16276 this.frameId = Roo.id();
16280 var iframe = this.owner.wrap.createChild({
16282 cls: 'form-control', // bootstrap..
16284 name: this.frameId,
16285 frameBorder : 'no',
16286 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16291 this.iframe = iframe.dom;
16293 this.assignDocWin();
16295 this.doc.designMode = 'on';
16298 this.doc.write(this.getDocMarkup());
16302 var task = { // must defer to wait for browser to be ready
16304 //console.log("run task?" + this.doc.readyState);
16305 this.assignDocWin();
16306 if(this.doc.body || this.doc.readyState == 'complete'){
16308 this.doc.designMode="on";
16312 Roo.TaskMgr.stop(task);
16313 this.initEditor.defer(10, this);
16320 Roo.TaskMgr.start(task);
16327 onResize : function(w, h)
16329 Roo.log('resize: ' +w + ',' + h );
16330 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16334 if(typeof w == 'number'){
16336 this.iframe.style.width = w + 'px';
16338 if(typeof h == 'number'){
16340 this.iframe.style.height = h + 'px';
16342 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16349 * Toggles the editor between standard and source edit mode.
16350 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16352 toggleSourceEdit : function(sourceEditMode){
16354 this.sourceEditMode = sourceEditMode === true;
16356 if(this.sourceEditMode){
16358 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16361 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16362 //this.iframe.className = '';
16365 //this.setSize(this.owner.wrap.getSize());
16366 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16373 * Protected method that will not generally be called directly. If you need/want
16374 * custom HTML cleanup, this is the method you should override.
16375 * @param {String} html The HTML to be cleaned
16376 * return {String} The cleaned HTML
16378 cleanHtml : function(html){
16379 html = String(html);
16380 if(html.length > 5){
16381 if(Roo.isSafari){ // strip safari nonsense
16382 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16385 if(html == ' '){
16392 * HTML Editor -> Textarea
16393 * Protected method that will not generally be called directly. Syncs the contents
16394 * of the editor iframe with the textarea.
16396 syncValue : function(){
16397 if(this.initialized){
16398 var bd = (this.doc.body || this.doc.documentElement);
16399 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16400 var html = bd.innerHTML;
16402 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16403 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16405 html = '<div style="'+m[0]+'">' + html + '</div>';
16408 html = this.cleanHtml(html);
16409 // fix up the special chars.. normaly like back quotes in word...
16410 // however we do not want to do this with chinese..
16411 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16412 var cc = b.charCodeAt();
16414 (cc >= 0x4E00 && cc < 0xA000 ) ||
16415 (cc >= 0x3400 && cc < 0x4E00 ) ||
16416 (cc >= 0xf900 && cc < 0xfb00 )
16422 if(this.owner.fireEvent('beforesync', this, html) !== false){
16423 this.el.dom.value = html;
16424 this.owner.fireEvent('sync', this, html);
16430 * Protected method that will not generally be called directly. Pushes the value of the textarea
16431 * into the iframe editor.
16433 pushValue : function(){
16434 if(this.initialized){
16435 var v = this.el.dom.value.trim();
16437 // if(v.length < 1){
16441 if(this.owner.fireEvent('beforepush', this, v) !== false){
16442 var d = (this.doc.body || this.doc.documentElement);
16444 this.cleanUpPaste();
16445 this.el.dom.value = d.innerHTML;
16446 this.owner.fireEvent('push', this, v);
16452 deferFocus : function(){
16453 this.focus.defer(10, this);
16457 focus : function(){
16458 if(this.win && !this.sourceEditMode){
16465 assignDocWin: function()
16467 var iframe = this.iframe;
16470 this.doc = iframe.contentWindow.document;
16471 this.win = iframe.contentWindow;
16473 if (!Roo.get(this.frameId)) {
16476 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16477 this.win = Roo.get(this.frameId).dom.contentWindow;
16482 initEditor : function(){
16483 //console.log("INIT EDITOR");
16484 this.assignDocWin();
16488 this.doc.designMode="on";
16490 this.doc.write(this.getDocMarkup());
16493 var dbody = (this.doc.body || this.doc.documentElement);
16494 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16495 // this copies styles from the containing element into thsi one..
16496 // not sure why we need all of this..
16497 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16499 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16500 //ss['background-attachment'] = 'fixed'; // w3c
16501 dbody.bgProperties = 'fixed'; // ie
16502 //Roo.DomHelper.applyStyles(dbody, ss);
16503 Roo.EventManager.on(this.doc, {
16504 //'mousedown': this.onEditorEvent,
16505 'mouseup': this.onEditorEvent,
16506 'dblclick': this.onEditorEvent,
16507 'click': this.onEditorEvent,
16508 'keyup': this.onEditorEvent,
16513 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16515 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16516 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16518 this.initialized = true;
16520 this.owner.fireEvent('initialize', this);
16525 onDestroy : function(){
16531 //for (var i =0; i < this.toolbars.length;i++) {
16532 // // fixme - ask toolbars for heights?
16533 // this.toolbars[i].onDestroy();
16536 //this.wrap.dom.innerHTML = '';
16537 //this.wrap.remove();
16542 onFirstFocus : function(){
16544 this.assignDocWin();
16547 this.activated = true;
16550 if(Roo.isGecko){ // prevent silly gecko errors
16552 var s = this.win.getSelection();
16553 if(!s.focusNode || s.focusNode.nodeType != 3){
16554 var r = s.getRangeAt(0);
16555 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16560 this.execCmd('useCSS', true);
16561 this.execCmd('styleWithCSS', false);
16564 this.owner.fireEvent('activate', this);
16568 adjustFont: function(btn){
16569 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16570 //if(Roo.isSafari){ // safari
16573 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16574 if(Roo.isSafari){ // safari
16575 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16576 v = (v < 10) ? 10 : v;
16577 v = (v > 48) ? 48 : v;
16578 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16583 v = Math.max(1, v+adjust);
16585 this.execCmd('FontSize', v );
16588 onEditorEvent : function(e){
16589 this.owner.fireEvent('editorevent', this, e);
16590 // this.updateToolbar();
16591 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16594 insertTag : function(tg)
16596 // could be a bit smarter... -> wrap the current selected tRoo..
16597 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16599 range = this.createRange(this.getSelection());
16600 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16601 wrappingNode.appendChild(range.extractContents());
16602 range.insertNode(wrappingNode);
16609 this.execCmd("formatblock", tg);
16613 insertText : function(txt)
16617 var range = this.createRange();
16618 range.deleteContents();
16619 //alert(Sender.getAttribute('label'));
16621 range.insertNode(this.doc.createTextNode(txt));
16627 * Executes a Midas editor command on the editor document and performs necessary focus and
16628 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16629 * @param {String} cmd The Midas command
16630 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16632 relayCmd : function(cmd, value){
16634 this.execCmd(cmd, value);
16635 this.owner.fireEvent('editorevent', this);
16636 //this.updateToolbar();
16637 this.owner.deferFocus();
16641 * Executes a Midas editor command directly on the editor document.
16642 * For visual commands, you should use {@link #relayCmd} instead.
16643 * <b>This should only be called after the editor is initialized.</b>
16644 * @param {String} cmd The Midas command
16645 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16647 execCmd : function(cmd, value){
16648 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16655 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16657 * @param {String} text | dom node..
16659 insertAtCursor : function(text)
16664 if(!this.activated){
16670 var r = this.doc.selection.createRange();
16681 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16685 // from jquery ui (MIT licenced)
16687 var win = this.win;
16689 if (win.getSelection && win.getSelection().getRangeAt) {
16690 range = win.getSelection().getRangeAt(0);
16691 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16692 range.insertNode(node);
16693 } else if (win.document.selection && win.document.selection.createRange) {
16694 // no firefox support
16695 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16696 win.document.selection.createRange().pasteHTML(txt);
16698 // no firefox support
16699 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16700 this.execCmd('InsertHTML', txt);
16709 mozKeyPress : function(e){
16711 var c = e.getCharCode(), cmd;
16714 c = String.fromCharCode(c).toLowerCase();
16728 this.cleanUpPaste.defer(100, this);
16736 e.preventDefault();
16744 fixKeys : function(){ // load time branching for fastest keydown performance
16746 return function(e){
16747 var k = e.getKey(), r;
16750 r = this.doc.selection.createRange();
16753 r.pasteHTML('    ');
16760 r = this.doc.selection.createRange();
16762 var target = r.parentElement();
16763 if(!target || target.tagName.toLowerCase() != 'li'){
16765 r.pasteHTML('<br />');
16771 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16772 this.cleanUpPaste.defer(100, this);
16778 }else if(Roo.isOpera){
16779 return function(e){
16780 var k = e.getKey();
16784 this.execCmd('InsertHTML','    ');
16787 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16788 this.cleanUpPaste.defer(100, this);
16793 }else if(Roo.isSafari){
16794 return function(e){
16795 var k = e.getKey();
16799 this.execCmd('InsertText','\t');
16803 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16804 this.cleanUpPaste.defer(100, this);
16812 getAllAncestors: function()
16814 var p = this.getSelectedNode();
16817 a.push(p); // push blank onto stack..
16818 p = this.getParentElement();
16822 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16826 a.push(this.doc.body);
16830 lastSelNode : false,
16833 getSelection : function()
16835 this.assignDocWin();
16836 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16839 getSelectedNode: function()
16841 // this may only work on Gecko!!!
16843 // should we cache this!!!!
16848 var range = this.createRange(this.getSelection()).cloneRange();
16851 var parent = range.parentElement();
16853 var testRange = range.duplicate();
16854 testRange.moveToElementText(parent);
16855 if (testRange.inRange(range)) {
16858 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16861 parent = parent.parentElement;
16866 // is ancestor a text element.
16867 var ac = range.commonAncestorContainer;
16868 if (ac.nodeType == 3) {
16869 ac = ac.parentNode;
16872 var ar = ac.childNodes;
16875 var other_nodes = [];
16876 var has_other_nodes = false;
16877 for (var i=0;i<ar.length;i++) {
16878 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16881 // fullly contained node.
16883 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16888 // probably selected..
16889 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16890 other_nodes.push(ar[i]);
16894 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16899 has_other_nodes = true;
16901 if (!nodes.length && other_nodes.length) {
16902 nodes= other_nodes;
16904 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16910 createRange: function(sel)
16912 // this has strange effects when using with
16913 // top toolbar - not sure if it's a great idea.
16914 //this.editor.contentWindow.focus();
16915 if (typeof sel != "undefined") {
16917 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16919 return this.doc.createRange();
16922 return this.doc.createRange();
16925 getParentElement: function()
16928 this.assignDocWin();
16929 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16931 var range = this.createRange(sel);
16934 var p = range.commonAncestorContainer;
16935 while (p.nodeType == 3) { // text node
16946 * Range intersection.. the hard stuff...
16950 * [ -- selected range --- ]
16954 * if end is before start or hits it. fail.
16955 * if start is after end or hits it fail.
16957 * if either hits (but other is outside. - then it's not
16963 // @see http://www.thismuchiknow.co.uk/?p=64.
16964 rangeIntersectsNode : function(range, node)
16966 var nodeRange = node.ownerDocument.createRange();
16968 nodeRange.selectNode(node);
16970 nodeRange.selectNodeContents(node);
16973 var rangeStartRange = range.cloneRange();
16974 rangeStartRange.collapse(true);
16976 var rangeEndRange = range.cloneRange();
16977 rangeEndRange.collapse(false);
16979 var nodeStartRange = nodeRange.cloneRange();
16980 nodeStartRange.collapse(true);
16982 var nodeEndRange = nodeRange.cloneRange();
16983 nodeEndRange.collapse(false);
16985 return rangeStartRange.compareBoundaryPoints(
16986 Range.START_TO_START, nodeEndRange) == -1 &&
16987 rangeEndRange.compareBoundaryPoints(
16988 Range.START_TO_START, nodeStartRange) == 1;
16992 rangeCompareNode : function(range, node)
16994 var nodeRange = node.ownerDocument.createRange();
16996 nodeRange.selectNode(node);
16998 nodeRange.selectNodeContents(node);
17002 range.collapse(true);
17004 nodeRange.collapse(true);
17006 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17007 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17009 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17011 var nodeIsBefore = ss == 1;
17012 var nodeIsAfter = ee == -1;
17014 if (nodeIsBefore && nodeIsAfter)
17016 if (!nodeIsBefore && nodeIsAfter)
17017 return 1; //right trailed.
17019 if (nodeIsBefore && !nodeIsAfter)
17020 return 2; // left trailed.
17025 // private? - in a new class?
17026 cleanUpPaste : function()
17028 // cleans up the whole document..
17029 Roo.log('cleanuppaste');
17031 this.cleanUpChildren(this.doc.body);
17032 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17033 if (clean != this.doc.body.innerHTML) {
17034 this.doc.body.innerHTML = clean;
17039 cleanWordChars : function(input) {// change the chars to hex code
17040 var he = Roo.HtmlEditorCore;
17042 var output = input;
17043 Roo.each(he.swapCodes, function(sw) {
17044 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17046 output = output.replace(swapper, sw[1]);
17053 cleanUpChildren : function (n)
17055 if (!n.childNodes.length) {
17058 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17059 this.cleanUpChild(n.childNodes[i]);
17066 cleanUpChild : function (node)
17069 //console.log(node);
17070 if (node.nodeName == "#text") {
17071 // clean up silly Windows -- stuff?
17074 if (node.nodeName == "#comment") {
17075 node.parentNode.removeChild(node);
17076 // clean up silly Windows -- stuff?
17080 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17082 node.parentNode.removeChild(node);
17087 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17089 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17090 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17092 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17093 // remove_keep_children = true;
17096 if (remove_keep_children) {
17097 this.cleanUpChildren(node);
17098 // inserts everything just before this node...
17099 while (node.childNodes.length) {
17100 var cn = node.childNodes[0];
17101 node.removeChild(cn);
17102 node.parentNode.insertBefore(cn, node);
17104 node.parentNode.removeChild(node);
17108 if (!node.attributes || !node.attributes.length) {
17109 this.cleanUpChildren(node);
17113 function cleanAttr(n,v)
17116 if (v.match(/^\./) || v.match(/^\//)) {
17119 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17122 if (v.match(/^#/)) {
17125 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17126 node.removeAttribute(n);
17130 function cleanStyle(n,v)
17132 if (v.match(/expression/)) { //XSS?? should we even bother..
17133 node.removeAttribute(n);
17136 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17137 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17140 var parts = v.split(/;/);
17143 Roo.each(parts, function(p) {
17144 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17148 var l = p.split(':').shift().replace(/\s+/g,'');
17149 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17151 if ( cblack.indexOf(l) > -1) {
17152 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17153 //node.removeAttribute(n);
17157 // only allow 'c whitelisted system attributes'
17158 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17159 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17160 //node.removeAttribute(n);
17170 if (clean.length) {
17171 node.setAttribute(n, clean.join(';'));
17173 node.removeAttribute(n);
17179 for (var i = node.attributes.length-1; i > -1 ; i--) {
17180 var a = node.attributes[i];
17183 if (a.name.toLowerCase().substr(0,2)=='on') {
17184 node.removeAttribute(a.name);
17187 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17188 node.removeAttribute(a.name);
17191 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17192 cleanAttr(a.name,a.value); // fixme..
17195 if (a.name == 'style') {
17196 cleanStyle(a.name,a.value);
17199 /// clean up MS crap..
17200 // tecnically this should be a list of valid class'es..
17203 if (a.name == 'class') {
17204 if (a.value.match(/^Mso/)) {
17205 node.className = '';
17208 if (a.value.match(/body/)) {
17209 node.className = '';
17220 this.cleanUpChildren(node);
17225 * Clean up MS wordisms...
17227 cleanWord : function(node)
17230 var cleanWordChildren = function()
17232 if (!node.childNodes.length) {
17235 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17236 _t.cleanWord(node.childNodes[i]);
17242 this.cleanWord(this.doc.body);
17245 if (node.nodeName == "#text") {
17246 // clean up silly Windows -- stuff?
17249 if (node.nodeName == "#comment") {
17250 node.parentNode.removeChild(node);
17251 // clean up silly Windows -- stuff?
17255 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17256 node.parentNode.removeChild(node);
17260 // remove - but keep children..
17261 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17262 while (node.childNodes.length) {
17263 var cn = node.childNodes[0];
17264 node.removeChild(cn);
17265 node.parentNode.insertBefore(cn, node);
17267 node.parentNode.removeChild(node);
17268 cleanWordChildren();
17272 if (node.className.length) {
17274 var cn = node.className.split(/\W+/);
17276 Roo.each(cn, function(cls) {
17277 if (cls.match(/Mso[a-zA-Z]+/)) {
17282 node.className = cna.length ? cna.join(' ') : '';
17284 node.removeAttribute("class");
17288 if (node.hasAttribute("lang")) {
17289 node.removeAttribute("lang");
17292 if (node.hasAttribute("style")) {
17294 var styles = node.getAttribute("style").split(";");
17296 Roo.each(styles, function(s) {
17297 if (!s.match(/:/)) {
17300 var kv = s.split(":");
17301 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17304 // what ever is left... we allow.
17307 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17308 if (!nstyle.length) {
17309 node.removeAttribute('style');
17313 cleanWordChildren();
17317 domToHTML : function(currentElement, depth, nopadtext) {
17319 depth = depth || 0;
17320 nopadtext = nopadtext || false;
17322 if (!currentElement) {
17323 return this.domToHTML(this.doc.body);
17326 //Roo.log(currentElement);
17328 var allText = false;
17329 var nodeName = currentElement.nodeName;
17330 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17332 if (nodeName == '#text') {
17333 return currentElement.nodeValue;
17338 if (nodeName != 'BODY') {
17341 // Prints the node tagName, such as <A>, <IMG>, etc
17344 for(i = 0; i < currentElement.attributes.length;i++) {
17346 var aname = currentElement.attributes.item(i).name;
17347 if (!currentElement.attributes.item(i).value.length) {
17350 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17353 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17362 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17365 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17370 // Traverse the tree
17372 var currentElementChild = currentElement.childNodes.item(i);
17373 var allText = true;
17374 var innerHTML = '';
17376 while (currentElementChild) {
17377 // Formatting code (indent the tree so it looks nice on the screen)
17378 var nopad = nopadtext;
17379 if (lastnode == 'SPAN') {
17383 if (currentElementChild.nodeName == '#text') {
17384 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17385 if (!nopad && toadd.length > 80) {
17386 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17388 innerHTML += toadd;
17391 currentElementChild = currentElement.childNodes.item(i);
17397 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17399 // Recursively traverse the tree structure of the child node
17400 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17401 lastnode = currentElementChild.nodeName;
17403 currentElementChild=currentElement.childNodes.item(i);
17409 // The remaining code is mostly for formatting the tree
17410 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17415 ret+= "</"+tagName+">";
17421 // hide stuff that is not compatible
17435 * @event specialkey
17439 * @cfg {String} fieldClass @hide
17442 * @cfg {String} focusClass @hide
17445 * @cfg {String} autoCreate @hide
17448 * @cfg {String} inputType @hide
17451 * @cfg {String} invalidClass @hide
17454 * @cfg {String} invalidText @hide
17457 * @cfg {String} msgFx @hide
17460 * @cfg {String} validateOnBlur @hide
17464 Roo.HtmlEditorCore.white = [
17465 'area', 'br', 'img', 'input', 'hr', 'wbr',
17467 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17468 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17469 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17470 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17471 'table', 'ul', 'xmp',
17473 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17476 'dir', 'menu', 'ol', 'ul', 'dl',
17482 Roo.HtmlEditorCore.black = [
17483 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17485 'base', 'basefont', 'bgsound', 'blink', 'body',
17486 'frame', 'frameset', 'head', 'html', 'ilayer',
17487 'iframe', 'layer', 'link', 'meta', 'object',
17488 'script', 'style' ,'title', 'xml' // clean later..
17490 Roo.HtmlEditorCore.clean = [
17491 'script', 'style', 'title', 'xml'
17493 Roo.HtmlEditorCore.remove = [
17498 Roo.HtmlEditorCore.ablack = [
17502 Roo.HtmlEditorCore.aclean = [
17503 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17507 Roo.HtmlEditorCore.pwhite= [
17508 'http', 'https', 'mailto'
17511 // white listed style attributes.
17512 Roo.HtmlEditorCore.cwhite= [
17513 // 'text-align', /// default is to allow most things..
17519 // black listed style attributes.
17520 Roo.HtmlEditorCore.cblack= [
17521 // 'font-size' -- this can be set by the project
17525 Roo.HtmlEditorCore.swapCodes =[
17544 * @class Roo.bootstrap.HtmlEditor
17545 * @extends Roo.bootstrap.TextArea
17546 * Bootstrap HtmlEditor class
17549 * Create a new HtmlEditor
17550 * @param {Object} config The config object
17553 Roo.bootstrap.HtmlEditor = function(config){
17554 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17555 if (!this.toolbars) {
17556 this.toolbars = [];
17558 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17561 * @event initialize
17562 * Fires when the editor is fully initialized (including the iframe)
17563 * @param {HtmlEditor} this
17568 * Fires when the editor is first receives the focus. Any insertion must wait
17569 * until after this event.
17570 * @param {HtmlEditor} this
17574 * @event beforesync
17575 * Fires before the textarea is updated with content from the editor iframe. Return false
17576 * to cancel the sync.
17577 * @param {HtmlEditor} this
17578 * @param {String} html
17582 * @event beforepush
17583 * Fires before the iframe editor is updated with content from the textarea. Return false
17584 * to cancel the push.
17585 * @param {HtmlEditor} this
17586 * @param {String} html
17591 * Fires when the textarea is updated with content from the editor iframe.
17592 * @param {HtmlEditor} this
17593 * @param {String} html
17598 * Fires when the iframe editor is updated with content from the textarea.
17599 * @param {HtmlEditor} this
17600 * @param {String} html
17604 * @event editmodechange
17605 * Fires when the editor switches edit modes
17606 * @param {HtmlEditor} this
17607 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17609 editmodechange: true,
17611 * @event editorevent
17612 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17613 * @param {HtmlEditor} this
17617 * @event firstfocus
17618 * Fires when on first focus - needed by toolbars..
17619 * @param {HtmlEditor} this
17624 * Auto save the htmlEditor value as a file into Events
17625 * @param {HtmlEditor} this
17629 * @event savedpreview
17630 * preview the saved version of htmlEditor
17631 * @param {HtmlEditor} this
17638 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17642 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17647 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17652 * @cfg {Number} height (in pixels)
17656 * @cfg {Number} width (in pixels)
17661 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17664 stylesheets: false,
17669 // private properties
17670 validationEvent : false,
17672 initialized : false,
17675 onFocus : Roo.emptyFn,
17677 hideMode:'offsets',
17680 tbContainer : false,
17682 toolbarContainer :function() {
17683 return this.wrap.select('.x-html-editor-tb',true).first();
17687 * Protected method that will not generally be called directly. It
17688 * is called when the editor creates its toolbar. Override this method if you need to
17689 * add custom toolbar buttons.
17690 * @param {HtmlEditor} editor
17692 createToolbar : function(){
17694 Roo.log("create toolbars");
17696 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17697 this.toolbars[0].render(this.toolbarContainer());
17701 // if (!editor.toolbars || !editor.toolbars.length) {
17702 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17705 // for (var i =0 ; i < editor.toolbars.length;i++) {
17706 // editor.toolbars[i] = Roo.factory(
17707 // typeof(editor.toolbars[i]) == 'string' ?
17708 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17709 // Roo.bootstrap.HtmlEditor);
17710 // editor.toolbars[i].init(editor);
17716 onRender : function(ct, position)
17718 // Roo.log("Call onRender: " + this.xtype);
17720 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17722 this.wrap = this.inputEl().wrap({
17723 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17726 this.editorcore.onRender(ct, position);
17728 if (this.resizable) {
17729 this.resizeEl = new Roo.Resizable(this.wrap, {
17733 minHeight : this.height,
17734 height: this.height,
17735 handles : this.resizable,
17738 resize : function(r, w, h) {
17739 _t.onResize(w,h); // -something
17745 this.createToolbar(this);
17748 if(!this.width && this.resizable){
17749 this.setSize(this.wrap.getSize());
17751 if (this.resizeEl) {
17752 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17753 // should trigger onReize..
17759 onResize : function(w, h)
17761 Roo.log('resize: ' +w + ',' + h );
17762 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17766 if(this.inputEl() ){
17767 if(typeof w == 'number'){
17768 var aw = w - this.wrap.getFrameWidth('lr');
17769 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17772 if(typeof h == 'number'){
17773 var tbh = -11; // fixme it needs to tool bar size!
17774 for (var i =0; i < this.toolbars.length;i++) {
17775 // fixme - ask toolbars for heights?
17776 tbh += this.toolbars[i].el.getHeight();
17777 //if (this.toolbars[i].footer) {
17778 // tbh += this.toolbars[i].footer.el.getHeight();
17786 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17787 ah -= 5; // knock a few pixes off for look..
17788 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17792 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17793 this.editorcore.onResize(ew,eh);
17798 * Toggles the editor between standard and source edit mode.
17799 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17801 toggleSourceEdit : function(sourceEditMode)
17803 this.editorcore.toggleSourceEdit(sourceEditMode);
17805 if(this.editorcore.sourceEditMode){
17806 Roo.log('editor - showing textarea');
17809 // Roo.log(this.syncValue());
17811 this.inputEl().removeClass(['hide', 'x-hidden']);
17812 this.inputEl().dom.removeAttribute('tabIndex');
17813 this.inputEl().focus();
17815 Roo.log('editor - hiding textarea');
17817 // Roo.log(this.pushValue());
17820 this.inputEl().addClass(['hide', 'x-hidden']);
17821 this.inputEl().dom.setAttribute('tabIndex', -1);
17822 //this.deferFocus();
17825 if(this.resizable){
17826 this.setSize(this.wrap.getSize());
17829 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17832 // private (for BoxComponent)
17833 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17835 // private (for BoxComponent)
17836 getResizeEl : function(){
17840 // private (for BoxComponent)
17841 getPositionEl : function(){
17846 initEvents : function(){
17847 this.originalValue = this.getValue();
17851 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17854 // markInvalid : Roo.emptyFn,
17856 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17859 // clearInvalid : Roo.emptyFn,
17861 setValue : function(v){
17862 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17863 this.editorcore.pushValue();
17868 deferFocus : function(){
17869 this.focus.defer(10, this);
17873 focus : function(){
17874 this.editorcore.focus();
17880 onDestroy : function(){
17886 for (var i =0; i < this.toolbars.length;i++) {
17887 // fixme - ask toolbars for heights?
17888 this.toolbars[i].onDestroy();
17891 this.wrap.dom.innerHTML = '';
17892 this.wrap.remove();
17897 onFirstFocus : function(){
17898 //Roo.log("onFirstFocus");
17899 this.editorcore.onFirstFocus();
17900 for (var i =0; i < this.toolbars.length;i++) {
17901 this.toolbars[i].onFirstFocus();
17907 syncValue : function()
17909 this.editorcore.syncValue();
17912 pushValue : function()
17914 this.editorcore.pushValue();
17918 // hide stuff that is not compatible
17932 * @event specialkey
17936 * @cfg {String} fieldClass @hide
17939 * @cfg {String} focusClass @hide
17942 * @cfg {String} autoCreate @hide
17945 * @cfg {String} inputType @hide
17948 * @cfg {String} invalidClass @hide
17951 * @cfg {String} invalidText @hide
17954 * @cfg {String} msgFx @hide
17957 * @cfg {String} validateOnBlur @hide
17966 Roo.namespace('Roo.bootstrap.htmleditor');
17968 * @class Roo.bootstrap.HtmlEditorToolbar1
17973 new Roo.bootstrap.HtmlEditor({
17976 new Roo.bootstrap.HtmlEditorToolbar1({
17977 disable : { fonts: 1 , format: 1, ..., ... , ...],
17983 * @cfg {Object} disable List of elements to disable..
17984 * @cfg {Array} btns List of additional buttons.
17988 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17991 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17994 Roo.apply(this, config);
17996 // default disabled, based on 'good practice'..
17997 this.disable = this.disable || {};
17998 Roo.applyIf(this.disable, {
18001 specialElements : true
18003 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18005 this.editor = config.editor;
18006 this.editorcore = config.editor.editorcore;
18008 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18010 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18011 // dont call parent... till later.
18013 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18018 editorcore : false,
18023 "h1","h2","h3","h4","h5","h6",
18025 "abbr", "acronym", "address", "cite", "samp", "var",
18029 onRender : function(ct, position)
18031 // Roo.log("Call onRender: " + this.xtype);
18033 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18035 this.el.dom.style.marginBottom = '0';
18037 var editorcore = this.editorcore;
18038 var editor= this.editor;
18041 var btn = function(id,cmd , toggle, handler){
18043 var event = toggle ? 'toggle' : 'click';
18048 xns: Roo.bootstrap,
18051 enableToggle:toggle !== false,
18053 pressed : toggle ? false : null,
18056 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18057 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18066 xns: Roo.bootstrap,
18067 glyphicon : 'font',
18071 xns: Roo.bootstrap,
18075 Roo.each(this.formats, function(f) {
18076 style.menu.items.push({
18078 xns: Roo.bootstrap,
18079 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18084 editorcore.insertTag(this.tagname);
18091 children.push(style);
18094 btn('bold',false,true);
18095 btn('italic',false,true);
18096 btn('align-left', 'justifyleft',true);
18097 btn('align-center', 'justifycenter',true);
18098 btn('align-right' , 'justifyright',true);
18099 btn('link', false, false, function(btn) {
18100 //Roo.log("create link?");
18101 var url = prompt(this.createLinkText, this.defaultLinkValue);
18102 if(url && url != 'http:/'+'/'){
18103 this.editorcore.relayCmd('createlink', url);
18106 btn('list','insertunorderedlist',true);
18107 btn('pencil', false,true, function(btn){
18110 this.toggleSourceEdit(btn.pressed);
18116 xns: Roo.bootstrap,
18121 xns: Roo.bootstrap,
18126 cog.menu.items.push({
18128 xns: Roo.bootstrap,
18129 html : Clean styles,
18134 editorcore.insertTag(this.tagname);
18143 this.xtype = 'NavSimplebar';
18145 for(var i=0;i< children.length;i++) {
18147 this.buttons.add(this.addxtypeChild(children[i]));
18151 editor.on('editorevent', this.updateToolbar, this);
18153 onBtnClick : function(id)
18155 this.editorcore.relayCmd(id);
18156 this.editorcore.focus();
18160 * Protected method that will not generally be called directly. It triggers
18161 * a toolbar update by reading the markup state of the current selection in the editor.
18163 updateToolbar: function(){
18165 if(!this.editorcore.activated){
18166 this.editor.onFirstFocus(); // is this neeed?
18170 var btns = this.buttons;
18171 var doc = this.editorcore.doc;
18172 btns.get('bold').setActive(doc.queryCommandState('bold'));
18173 btns.get('italic').setActive(doc.queryCommandState('italic'));
18174 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18176 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18177 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18178 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18180 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18181 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18184 var ans = this.editorcore.getAllAncestors();
18185 if (this.formatCombo) {
18188 var store = this.formatCombo.store;
18189 this.formatCombo.setValue("");
18190 for (var i =0; i < ans.length;i++) {
18191 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18193 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18201 // hides menus... - so this cant be on a menu...
18202 Roo.bootstrap.MenuMgr.hideAll();
18204 Roo.bootstrap.MenuMgr.hideAll();
18205 //this.editorsyncValue();
18207 onFirstFocus: function() {
18208 this.buttons.each(function(item){
18212 toggleSourceEdit : function(sourceEditMode){
18215 if(sourceEditMode){
18216 Roo.log("disabling buttons");
18217 this.buttons.each( function(item){
18218 if(item.cmd != 'pencil'){
18224 Roo.log("enabling buttons");
18225 if(this.editorcore.initialized){
18226 this.buttons.each( function(item){
18232 Roo.log("calling toggole on editor");
18233 // tell the editor that it's been pressed..
18234 this.editor.toggleSourceEdit(sourceEditMode);
18244 * @class Roo.bootstrap.Table.AbstractSelectionModel
18245 * @extends Roo.util.Observable
18246 * Abstract base class for grid SelectionModels. It provides the interface that should be
18247 * implemented by descendant classes. This class should not be directly instantiated.
18250 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18251 this.locked = false;
18252 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18256 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18257 /** @ignore Called by the grid automatically. Do not call directly. */
18258 init : function(grid){
18264 * Locks the selections.
18267 this.locked = true;
18271 * Unlocks the selections.
18273 unlock : function(){
18274 this.locked = false;
18278 * Returns true if the selections are locked.
18279 * @return {Boolean}
18281 isLocked : function(){
18282 return this.locked;
18286 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18287 * @class Roo.bootstrap.Table.RowSelectionModel
18288 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18289 * It supports multiple selections and keyboard selection/navigation.
18291 * @param {Object} config
18294 Roo.bootstrap.Table.RowSelectionModel = function(config){
18295 Roo.apply(this, config);
18296 this.selections = new Roo.util.MixedCollection(false, function(o){
18301 this.lastActive = false;
18305 * @event selectionchange
18306 * Fires when the selection changes
18307 * @param {SelectionModel} this
18309 "selectionchange" : true,
18311 * @event afterselectionchange
18312 * Fires after the selection changes (eg. by key press or clicking)
18313 * @param {SelectionModel} this
18315 "afterselectionchange" : true,
18317 * @event beforerowselect
18318 * Fires when a row is selected being selected, return false to cancel.
18319 * @param {SelectionModel} this
18320 * @param {Number} rowIndex The selected index
18321 * @param {Boolean} keepExisting False if other selections will be cleared
18323 "beforerowselect" : true,
18326 * Fires when a row is selected.
18327 * @param {SelectionModel} this
18328 * @param {Number} rowIndex The selected index
18329 * @param {Roo.data.Record} r The record
18331 "rowselect" : true,
18333 * @event rowdeselect
18334 * Fires when a row is deselected.
18335 * @param {SelectionModel} this
18336 * @param {Number} rowIndex The selected index
18338 "rowdeselect" : true
18340 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18341 this.locked = false;
18344 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18346 * @cfg {Boolean} singleSelect
18347 * True to allow selection of only one row at a time (defaults to false)
18349 singleSelect : false,
18352 initEvents : function(){
18354 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18355 this.grid.on("mousedown", this.handleMouseDown, this);
18356 }else{ // allow click to work like normal
18357 this.grid.on("rowclick", this.handleDragableRowClick, this);
18360 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18361 "up" : function(e){
18363 this.selectPrevious(e.shiftKey);
18364 }else if(this.last !== false && this.lastActive !== false){
18365 var last = this.last;
18366 this.selectRange(this.last, this.lastActive-1);
18367 this.grid.getView().focusRow(this.lastActive);
18368 if(last !== false){
18372 this.selectFirstRow();
18374 this.fireEvent("afterselectionchange", this);
18376 "down" : function(e){
18378 this.selectNext(e.shiftKey);
18379 }else if(this.last !== false && this.lastActive !== false){
18380 var last = this.last;
18381 this.selectRange(this.last, this.lastActive+1);
18382 this.grid.getView().focusRow(this.lastActive);
18383 if(last !== false){
18387 this.selectFirstRow();
18389 this.fireEvent("afterselectionchange", this);
18394 var view = this.grid.view;
18395 view.on("refresh", this.onRefresh, this);
18396 view.on("rowupdated", this.onRowUpdated, this);
18397 view.on("rowremoved", this.onRemove, this);
18401 onRefresh : function(){
18402 var ds = this.grid.dataSource, i, v = this.grid.view;
18403 var s = this.selections;
18404 s.each(function(r){
18405 if((i = ds.indexOfId(r.id)) != -1){
18414 onRemove : function(v, index, r){
18415 this.selections.remove(r);
18419 onRowUpdated : function(v, index, r){
18420 if(this.isSelected(r)){
18421 v.onRowSelect(index);
18427 * @param {Array} records The records to select
18428 * @param {Boolean} keepExisting (optional) True to keep existing selections
18430 selectRecords : function(records, keepExisting){
18432 this.clearSelections();
18434 var ds = this.grid.dataSource;
18435 for(var i = 0, len = records.length; i < len; i++){
18436 this.selectRow(ds.indexOf(records[i]), true);
18441 * Gets the number of selected rows.
18444 getCount : function(){
18445 return this.selections.length;
18449 * Selects the first row in the grid.
18451 selectFirstRow : function(){
18456 * Select the last row.
18457 * @param {Boolean} keepExisting (optional) True to keep existing selections
18459 selectLastRow : function(keepExisting){
18460 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18464 * Selects the row immediately following the last selected row.
18465 * @param {Boolean} keepExisting (optional) True to keep existing selections
18467 selectNext : function(keepExisting){
18468 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18469 this.selectRow(this.last+1, keepExisting);
18470 this.grid.getView().focusRow(this.last);
18475 * Selects the row that precedes the last selected row.
18476 * @param {Boolean} keepExisting (optional) True to keep existing selections
18478 selectPrevious : function(keepExisting){
18480 this.selectRow(this.last-1, keepExisting);
18481 this.grid.getView().focusRow(this.last);
18486 * Returns the selected records
18487 * @return {Array} Array of selected records
18489 getSelections : function(){
18490 return [].concat(this.selections.items);
18494 * Returns the first selected record.
18497 getSelected : function(){
18498 return this.selections.itemAt(0);
18503 * Clears all selections.
18505 clearSelections : function(fast){
18506 if(this.locked) return;
18508 var ds = this.grid.dataSource;
18509 var s = this.selections;
18510 s.each(function(r){
18511 this.deselectRow(ds.indexOfId(r.id));
18515 this.selections.clear();
18522 * Selects all rows.
18524 selectAll : function(){
18525 if(this.locked) return;
18526 this.selections.clear();
18527 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18528 this.selectRow(i, true);
18533 * Returns True if there is a selection.
18534 * @return {Boolean}
18536 hasSelection : function(){
18537 return this.selections.length > 0;
18541 * Returns True if the specified row is selected.
18542 * @param {Number/Record} record The record or index of the record to check
18543 * @return {Boolean}
18545 isSelected : function(index){
18546 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18547 return (r && this.selections.key(r.id) ? true : false);
18551 * Returns True if the specified record id is selected.
18552 * @param {String} id The id of record to check
18553 * @return {Boolean}
18555 isIdSelected : function(id){
18556 return (this.selections.key(id) ? true : false);
18560 handleMouseDown : function(e, t){
18561 var view = this.grid.getView(), rowIndex;
18562 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18565 if(e.shiftKey && this.last !== false){
18566 var last = this.last;
18567 this.selectRange(last, rowIndex, e.ctrlKey);
18568 this.last = last; // reset the last
18569 view.focusRow(rowIndex);
18571 var isSelected = this.isSelected(rowIndex);
18572 if(e.button !== 0 && isSelected){
18573 view.focusRow(rowIndex);
18574 }else if(e.ctrlKey && isSelected){
18575 this.deselectRow(rowIndex);
18576 }else if(!isSelected){
18577 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18578 view.focusRow(rowIndex);
18581 this.fireEvent("afterselectionchange", this);
18584 handleDragableRowClick : function(grid, rowIndex, e)
18586 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18587 this.selectRow(rowIndex, false);
18588 grid.view.focusRow(rowIndex);
18589 this.fireEvent("afterselectionchange", this);
18594 * Selects multiple rows.
18595 * @param {Array} rows Array of the indexes of the row to select
18596 * @param {Boolean} keepExisting (optional) True to keep existing selections
18598 selectRows : function(rows, keepExisting){
18600 this.clearSelections();
18602 for(var i = 0, len = rows.length; i < len; i++){
18603 this.selectRow(rows[i], true);
18608 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18609 * @param {Number} startRow The index of the first row in the range
18610 * @param {Number} endRow The index of the last row in the range
18611 * @param {Boolean} keepExisting (optional) True to retain existing selections
18613 selectRange : function(startRow, endRow, keepExisting){
18614 if(this.locked) return;
18616 this.clearSelections();
18618 if(startRow <= endRow){
18619 for(var i = startRow; i <= endRow; i++){
18620 this.selectRow(i, true);
18623 for(var i = startRow; i >= endRow; i--){
18624 this.selectRow(i, true);
18630 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18631 * @param {Number} startRow The index of the first row in the range
18632 * @param {Number} endRow The index of the last row in the range
18634 deselectRange : function(startRow, endRow, preventViewNotify){
18635 if(this.locked) return;
18636 for(var i = startRow; i <= endRow; i++){
18637 this.deselectRow(i, preventViewNotify);
18643 * @param {Number} row The index of the row to select
18644 * @param {Boolean} keepExisting (optional) True to keep existing selections
18646 selectRow : function(index, keepExisting, preventViewNotify){
18647 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18648 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18649 if(!keepExisting || this.singleSelect){
18650 this.clearSelections();
18652 var r = this.grid.dataSource.getAt(index);
18653 this.selections.add(r);
18654 this.last = this.lastActive = index;
18655 if(!preventViewNotify){
18656 this.grid.getView().onRowSelect(index);
18658 this.fireEvent("rowselect", this, index, r);
18659 this.fireEvent("selectionchange", this);
18665 * @param {Number} row The index of the row to deselect
18667 deselectRow : function(index, preventViewNotify){
18668 if(this.locked) return;
18669 if(this.last == index){
18672 if(this.lastActive == index){
18673 this.lastActive = false;
18675 var r = this.grid.dataSource.getAt(index);
18676 this.selections.remove(r);
18677 if(!preventViewNotify){
18678 this.grid.getView().onRowDeselect(index);
18680 this.fireEvent("rowdeselect", this, index);
18681 this.fireEvent("selectionchange", this);
18685 restoreLast : function(){
18687 this.last = this._last;
18692 acceptsNav : function(row, col, cm){
18693 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18697 onEditorKey : function(field, e){
18698 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18703 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18705 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18707 }else if(k == e.ENTER && !e.ctrlKey){
18711 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18713 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18715 }else if(k == e.ESC){
18719 g.startEditing(newCell[0], newCell[1]);
18724 * Ext JS Library 1.1.1
18725 * Copyright(c) 2006-2007, Ext JS, LLC.
18727 * Originally Released Under LGPL - original licence link has changed is not relivant.
18730 * <script type="text/javascript">
18734 * @class Roo.bootstrap.PagingToolbar
18736 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18738 * Create a new PagingToolbar
18739 * @param {Object} config The config object
18741 Roo.bootstrap.PagingToolbar = function(config)
18743 // old args format still supported... - xtype is prefered..
18744 // created from xtype...
18745 var ds = config.dataSource;
18746 this.toolbarItems = [];
18747 if (config.items) {
18748 this.toolbarItems = config.items;
18749 // config.items = [];
18752 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18759 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18763 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18765 * @cfg {Roo.data.Store} dataSource
18766 * The underlying data store providing the paged data
18769 * @cfg {String/HTMLElement/Element} container
18770 * container The id or element that will contain the toolbar
18773 * @cfg {Boolean} displayInfo
18774 * True to display the displayMsg (defaults to false)
18777 * @cfg {Number} pageSize
18778 * The number of records to display per page (defaults to 20)
18782 * @cfg {String} displayMsg
18783 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18785 displayMsg : 'Displaying {0} - {1} of {2}',
18787 * @cfg {String} emptyMsg
18788 * The message to display when no records are found (defaults to "No data to display")
18790 emptyMsg : 'No data to display',
18792 * Customizable piece of the default paging text (defaults to "Page")
18795 beforePageText : "Page",
18797 * Customizable piece of the default paging text (defaults to "of %0")
18800 afterPageText : "of {0}",
18802 * Customizable piece of the default paging text (defaults to "First Page")
18805 firstText : "First Page",
18807 * Customizable piece of the default paging text (defaults to "Previous Page")
18810 prevText : "Previous Page",
18812 * Customizable piece of the default paging text (defaults to "Next Page")
18815 nextText : "Next Page",
18817 * Customizable piece of the default paging text (defaults to "Last Page")
18820 lastText : "Last Page",
18822 * Customizable piece of the default paging text (defaults to "Refresh")
18825 refreshText : "Refresh",
18829 onRender : function(ct, position)
18831 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18832 this.navgroup.parentId = this.id;
18833 this.navgroup.onRender(this.el, null);
18834 // add the buttons to the navgroup
18836 if(this.displayInfo){
18837 Roo.log(this.el.select('ul.navbar-nav',true).first());
18838 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18839 this.displayEl = this.el.select('.x-paging-info', true).first();
18840 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18841 // this.displayEl = navel.el.select('span',true).first();
18847 Roo.each(_this.buttons, function(e){
18848 Roo.factory(e).onRender(_this.el, null);
18852 Roo.each(_this.toolbarItems, function(e) {
18853 _this.navgroup.addItem(e);
18856 this.first = this.navgroup.addItem({
18857 tooltip: this.firstText,
18859 icon : 'fa fa-backward',
18861 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18864 this.prev = this.navgroup.addItem({
18865 tooltip: this.prevText,
18867 icon : 'fa fa-step-backward',
18869 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18871 //this.addSeparator();
18874 var field = this.navgroup.addItem( {
18876 cls : 'x-paging-position',
18878 html : this.beforePageText +
18879 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18880 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18883 this.field = field.el.select('input', true).first();
18884 this.field.on("keydown", this.onPagingKeydown, this);
18885 this.field.on("focus", function(){this.dom.select();});
18888 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18889 //this.field.setHeight(18);
18890 //this.addSeparator();
18891 this.next = this.navgroup.addItem({
18892 tooltip: this.nextText,
18894 html : ' <i class="fa fa-step-forward">',
18896 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18898 this.last = this.navgroup.addItem({
18899 tooltip: this.lastText,
18900 icon : 'fa fa-forward',
18903 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18905 //this.addSeparator();
18906 this.loading = this.navgroup.addItem({
18907 tooltip: this.refreshText,
18908 icon: 'fa fa-refresh',
18910 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18916 updateInfo : function(){
18917 if(this.displayEl){
18918 var count = this.ds.getCount();
18919 var msg = count == 0 ?
18923 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18925 this.displayEl.update(msg);
18930 onLoad : function(ds, r, o){
18931 this.cursor = o.params ? o.params.start : 0;
18932 var d = this.getPageData(),
18936 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18937 this.field.dom.value = ap;
18938 this.first.setDisabled(ap == 1);
18939 this.prev.setDisabled(ap == 1);
18940 this.next.setDisabled(ap == ps);
18941 this.last.setDisabled(ap == ps);
18942 this.loading.enable();
18947 getPageData : function(){
18948 var total = this.ds.getTotalCount();
18951 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18952 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18957 onLoadError : function(){
18958 this.loading.enable();
18962 onPagingKeydown : function(e){
18963 var k = e.getKey();
18964 var d = this.getPageData();
18966 var v = this.field.dom.value, pageNum;
18967 if(!v || isNaN(pageNum = parseInt(v, 10))){
18968 this.field.dom.value = d.activePage;
18971 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18972 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18975 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))
18977 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18978 this.field.dom.value = pageNum;
18979 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18982 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18984 var v = this.field.dom.value, pageNum;
18985 var increment = (e.shiftKey) ? 10 : 1;
18986 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18988 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18989 this.field.dom.value = d.activePage;
18992 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18994 this.field.dom.value = parseInt(v, 10) + increment;
18995 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18996 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19003 beforeLoad : function(){
19005 this.loading.disable();
19010 onClick : function(which){
19017 ds.load({params:{start: 0, limit: this.pageSize}});
19020 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19023 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19026 var total = ds.getTotalCount();
19027 var extra = total % this.pageSize;
19028 var lastStart = extra ? (total - extra) : total-this.pageSize;
19029 ds.load({params:{start: lastStart, limit: this.pageSize}});
19032 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19038 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19039 * @param {Roo.data.Store} store The data store to unbind
19041 unbind : function(ds){
19042 ds.un("beforeload", this.beforeLoad, this);
19043 ds.un("load", this.onLoad, this);
19044 ds.un("loadexception", this.onLoadError, this);
19045 ds.un("remove", this.updateInfo, this);
19046 ds.un("add", this.updateInfo, this);
19047 this.ds = undefined;
19051 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19052 * @param {Roo.data.Store} store The data store to bind
19054 bind : function(ds){
19055 ds.on("beforeload", this.beforeLoad, this);
19056 ds.on("load", this.onLoad, this);
19057 ds.on("loadexception", this.onLoadError, this);
19058 ds.on("remove", this.updateInfo, this);
19059 ds.on("add", this.updateInfo, this);
19070 * @class Roo.bootstrap.MessageBar
19071 * @extends Roo.bootstrap.Component
19072 * Bootstrap MessageBar class
19073 * @cfg {String} html contents of the MessageBar
19074 * @cfg {String} weight (info | success | warning | danger) default info
19075 * @cfg {String} beforeClass insert the bar before the given class
19076 * @cfg {Boolean} closable (true | false) default false
19077 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19080 * Create a new Element
19081 * @param {Object} config The config object
19084 Roo.bootstrap.MessageBar = function(config){
19085 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19088 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19094 beforeClass: 'bootstrap-sticky-wrap',
19096 getAutoCreate : function(){
19100 cls: 'alert alert-dismissable alert-' + this.weight,
19105 html: this.html || ''
19111 cfg.cls += ' alert-messages-fixed';
19125 onRender : function(ct, position)
19127 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19130 var cfg = Roo.apply({}, this.getAutoCreate());
19134 cfg.cls += ' ' + this.cls;
19137 cfg.style = this.style;
19139 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19141 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19144 this.el.select('>button.close').on('click', this.hide, this);
19150 if (!this.rendered) {
19156 this.fireEvent('show', this);
19162 if (!this.rendered) {
19168 this.fireEvent('hide', this);
19171 update : function()
19173 // var e = this.el.dom.firstChild;
19175 // if(this.closable){
19176 // e = e.nextSibling;
19179 // e.data = this.html || '';
19181 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19197 * @class Roo.bootstrap.Graph
19198 * @extends Roo.bootstrap.Component
19199 * Bootstrap Graph class
19203 @cfg {String} graphtype bar | vbar | pie
19204 @cfg {number} g_x coodinator | centre x (pie)
19205 @cfg {number} g_y coodinator | centre y (pie)
19206 @cfg {number} g_r radius (pie)
19207 @cfg {number} g_height height of the chart (respected by all elements in the set)
19208 @cfg {number} g_width width of the chart (respected by all elements in the set)
19209 @cfg {Object} title The title of the chart
19212 -opts (object) options for the chart
19214 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19215 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19217 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.
19218 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19220 o stretch (boolean)
19222 -opts (object) options for the pie
19225 o startAngle (number)
19226 o endAngle (number)
19230 * Create a new Input
19231 * @param {Object} config The config object
19234 Roo.bootstrap.Graph = function(config){
19235 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19241 * The img click event for the img.
19242 * @param {Roo.EventObject} e
19248 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19259 //g_colors: this.colors,
19266 getAutoCreate : function(){
19277 onRender : function(ct,position){
19278 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19279 this.raphael = Raphael(this.el.dom);
19281 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19282 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19283 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19284 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19286 r.text(160, 10, "Single Series Chart").attr(txtattr);
19287 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19288 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19289 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19291 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19292 r.barchart(330, 10, 300, 220, data1);
19293 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19294 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19297 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19298 // r.barchart(30, 30, 560, 250, xdata, {
19299 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19300 // axis : "0 0 1 1",
19301 // axisxlabels : xdata
19302 // //yvalues : cols,
19305 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19307 // this.load(null,xdata,{
19308 // axis : "0 0 1 1",
19309 // axisxlabels : xdata
19314 load : function(graphtype,xdata,opts){
19315 this.raphael.clear();
19317 graphtype = this.graphtype;
19322 var r = this.raphael,
19323 fin = function () {
19324 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19326 fout = function () {
19327 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19329 pfin = function() {
19330 this.sector.stop();
19331 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19334 this.label[0].stop();
19335 this.label[0].attr({ r: 7.5 });
19336 this.label[1].attr({ "font-weight": 800 });
19339 pfout = function() {
19340 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19343 this.label[0].animate({ r: 5 }, 500, "bounce");
19344 this.label[1].attr({ "font-weight": 400 });
19350 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19353 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19356 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19357 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19359 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19366 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19371 setTitle: function(o)
19376 initEvents: function() {
19379 this.el.on('click', this.onClick, this);
19383 onClick : function(e)
19385 Roo.log('img onclick');
19386 this.fireEvent('click', this, e);
19398 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19401 * @class Roo.bootstrap.dash.NumberBox
19402 * @extends Roo.bootstrap.Component
19403 * Bootstrap NumberBox class
19404 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19405 * @cfg {String} headline Box headline
19406 * @cfg {String} content Box content
19407 * @cfg {String} icon Box icon
19408 * @cfg {String} footer Footer text
19409 * @cfg {String} fhref Footer href
19412 * Create a new NumberBox
19413 * @param {Object} config The config object
19417 Roo.bootstrap.dash.NumberBox = function(config){
19418 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19422 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19432 getAutoCreate : function(){
19436 cls : 'small-box bg-' + this.bgcolor,
19444 cls : 'roo-headline',
19445 html : this.headline
19449 cls : 'roo-content',
19450 html : this.content
19464 cls : 'ion ' + this.icon
19473 cls : 'small-box-footer',
19474 href : this.fhref || '#',
19478 cfg.cn.push(footer);
19485 onRender : function(ct,position){
19486 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19493 setHeadline: function (value)
19495 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19498 setFooter: function (value, href)
19500 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19503 this.el.select('a.small-box-footer',true).first().attr('href', href);
19508 setContent: function (value)
19510 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19513 initEvents: function()
19527 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19530 * @class Roo.bootstrap.dash.TabBox
19531 * @extends Roo.bootstrap.Component
19532 * Bootstrap TabBox class
19533 * @cfg {String} title Title of the TabBox
19534 * @cfg {String} icon Icon of the TabBox
19537 * Create a new TabBox
19538 * @param {Object} config The config object
19542 Roo.bootstrap.dash.TabBox = function(config){
19543 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19548 * When a pane is added
19549 * @param {Roo.bootstrap.dash.TabPane} pane
19556 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19561 getChildContainer : function()
19563 return this.el.select('.tab-content', true).first();
19566 getAutoCreate : function(){
19570 cls: 'pull-left header',
19578 cls: 'fa ' + this.icon
19585 cls: 'nav-tabs-custom',
19589 cls: 'nav nav-tabs pull-right',
19596 cls: 'tab-content no-padding',
19604 initEvents : function()
19606 //Roo.log('add add pane handler');
19607 this.on('addpane', this.onAddPane, this);
19610 * Updates the box title
19611 * @param {String} html to set the title to.
19613 setTitle : function(value)
19615 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19617 onAddPane : function(pane)
19619 //Roo.log('addpane');
19621 // tabs are rendere left to right..
19622 var ctr = this.el.select('.nav-tabs', true).first();
19625 var existing = ctr.select('.nav-tab',true);
19626 var qty = existing.getCount();;
19629 var tab = ctr.createChild({
19631 cls : 'nav-tab' + (qty ? '' : ' active'),
19639 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19642 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19644 pane.el.addClass('active');
19649 onTabClick : function(ev,un,ob,pane)
19651 //Roo.log('tab - prev default');
19652 ev.preventDefault();
19655 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19656 pane.tab.addClass('active');
19657 //Roo.log(pane.title);
19658 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19659 // technically we should have a deactivate event.. but maybe add later.
19660 // and it should not de-activate the selected tab...
19662 pane.el.addClass('active');
19663 pane.fireEvent('activate');
19678 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19680 * @class Roo.bootstrap.TabPane
19681 * @extends Roo.bootstrap.Component
19682 * Bootstrap TabPane class
19683 * @cfg {Boolean} active (false | true) Default false
19684 * @cfg {String} title title of panel
19688 * Create a new TabPane
19689 * @param {Object} config The config object
19692 Roo.bootstrap.dash.TabPane = function(config){
19693 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19697 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19702 // the tabBox that this is attached to.
19705 getAutoCreate : function()
19713 cfg.cls += ' active';
19718 initEvents : function()
19720 //Roo.log('trigger add pane handler');
19721 this.parent().fireEvent('addpane', this)
19725 * Updates the tab title
19726 * @param {String} html to set the title to.
19728 setTitle: function(str)
19734 this.tab.select('a'.true).first().dom.innerHTML = str;
19751 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19754 * @class Roo.bootstrap.menu.Menu
19755 * @extends Roo.bootstrap.Component
19756 * Bootstrap Menu class - container for Menu
19757 * @cfg {String} html Text of the menu
19758 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19759 * @cfg {String} icon Font awesome icon
19760 * @cfg {String} pos Menu align to (top | bottom) default bottom
19764 * Create a new Menu
19765 * @param {Object} config The config object
19769 Roo.bootstrap.menu.Menu = function(config){
19770 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19774 * @event beforeshow
19775 * Fires before this menu is displayed
19776 * @param {Roo.bootstrap.menu.Menu} this
19780 * @event beforehide
19781 * Fires before this menu is hidden
19782 * @param {Roo.bootstrap.menu.Menu} this
19787 * Fires after this menu is displayed
19788 * @param {Roo.bootstrap.menu.Menu} this
19793 * Fires after this menu is hidden
19794 * @param {Roo.bootstrap.menu.Menu} this
19799 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19800 * @param {Roo.bootstrap.menu.Menu} this
19801 * @param {Roo.EventObject} e
19808 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19812 weight : 'default',
19817 getChildContainer : function() {
19818 if(this.isSubMenu){
19822 return this.el.select('ul.dropdown-menu', true).first();
19825 getAutoCreate : function()
19830 cls : 'roo-menu-text',
19838 cls : 'fa ' + this.icon
19849 cls : 'dropdown-button btn btn-' + this.weight,
19854 cls : 'dropdown-toggle btn btn-' + this.weight,
19864 cls : 'dropdown-menu'
19870 if(this.pos == 'top'){
19871 cfg.cls += ' dropup';
19874 if(this.isSubMenu){
19877 cls : 'dropdown-menu'
19884 onRender : function(ct, position)
19886 this.isSubMenu = ct.hasClass('dropdown-submenu');
19888 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19891 initEvents : function()
19893 if(this.isSubMenu){
19897 this.hidden = true;
19899 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19900 this.triggerEl.on('click', this.onTriggerPress, this);
19902 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19903 this.buttonEl.on('click', this.onClick, this);
19909 if(this.isSubMenu){
19913 return this.el.select('ul.dropdown-menu', true).first();
19916 onClick : function(e)
19918 this.fireEvent("click", this, e);
19921 onTriggerPress : function(e)
19923 if (this.isVisible()) {
19930 isVisible : function(){
19931 return !this.hidden;
19936 this.fireEvent("beforeshow", this);
19938 this.hidden = false;
19939 this.el.addClass('open');
19941 Roo.get(document).on("mouseup", this.onMouseUp, this);
19943 this.fireEvent("show", this);
19950 this.fireEvent("beforehide", this);
19952 this.hidden = true;
19953 this.el.removeClass('open');
19955 Roo.get(document).un("mouseup", this.onMouseUp);
19957 this.fireEvent("hide", this);
19960 onMouseUp : function()
19974 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19977 * @class Roo.bootstrap.menu.Item
19978 * @extends Roo.bootstrap.Component
19979 * Bootstrap MenuItem class
19980 * @cfg {Boolean} submenu (true | false) default false
19981 * @cfg {String} html text of the item
19982 * @cfg {String} href the link
19983 * @cfg {Boolean} disable (true | false) default false
19984 * @cfg {Boolean} preventDefault (true | false) default true
19985 * @cfg {String} icon Font awesome icon
19986 * @cfg {String} pos Submenu align to (left | right) default right
19990 * Create a new Item
19991 * @param {Object} config The config object
19995 Roo.bootstrap.menu.Item = function(config){
19996 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20000 * Fires when the mouse is hovering over this menu
20001 * @param {Roo.bootstrap.menu.Item} this
20002 * @param {Roo.EventObject} e
20007 * Fires when the mouse exits this menu
20008 * @param {Roo.bootstrap.menu.Item} this
20009 * @param {Roo.EventObject} e
20015 * The raw click event for the entire grid.
20016 * @param {Roo.EventObject} e
20022 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20027 preventDefault: true,
20032 getAutoCreate : function()
20037 cls : 'roo-menu-item-text',
20045 cls : 'fa ' + this.icon
20054 href : this.href || '#',
20061 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20065 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20067 if(this.pos == 'left'){
20068 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20075 initEvents : function()
20077 this.el.on('mouseover', this.onMouseOver, this);
20078 this.el.on('mouseout', this.onMouseOut, this);
20080 this.el.select('a', true).first().on('click', this.onClick, this);
20084 onClick : function(e)
20086 if(this.preventDefault){
20087 e.preventDefault();
20090 this.fireEvent("click", this, e);
20093 onMouseOver : function(e)
20095 if(this.submenu && this.pos == 'left'){
20096 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20099 this.fireEvent("mouseover", this, e);
20102 onMouseOut : function(e)
20104 this.fireEvent("mouseout", this, e);
20116 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20119 * @class Roo.bootstrap.menu.Separator
20120 * @extends Roo.bootstrap.Component
20121 * Bootstrap Separator class
20124 * Create a new Separator
20125 * @param {Object} config The config object
20129 Roo.bootstrap.menu.Separator = function(config){
20130 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20133 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20135 getAutoCreate : function(){