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]);
3374 Roo.apply(Roo.bootstrap.NavGroup, {
3378 * register a Navigation Group
3379 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3381 register : function(navgrp)
3383 this.groups[navgrp.navId] = navgrp;
3387 * fetch a Navigation Group based on the navigation ID
3388 * @param {string} the navgroup to add
3389 * @returns {Roo.bootstrap.NavGroup} the navgroup
3391 get: function(navId) {
3392 if (typeof(this.groups[navId]) == 'undefined') {
3394 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3396 return this.groups[navId] ;
3411 * @class Roo.bootstrap.NavItem
3412 * @extends Roo.bootstrap.Component
3413 * Bootstrap Navbar.NavItem class
3414 * @cfg {String} href link to
3415 * @cfg {String} html content of button
3416 * @cfg {String} badge text inside badge
3417 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3418 * @cfg {String} glyphicon name of glyphicon
3419 * @cfg {String} icon name of font awesome icon
3420 * @cfg {Boolean} active Is item active
3421 * @cfg {Boolean} disabled Is item disabled
3423 * @cfg {Boolean} preventDefault (true | false) default false
3424 * @cfg {String} tabId the tab that this item activates.
3425 * @cfg {String} tagtype (a|span) render as a href or span?
3428 * Create a new Navbar Item
3429 * @param {Object} config The config object
3431 Roo.bootstrap.NavItem = function(config){
3432 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3437 * The raw click event for the entire grid.
3438 * @param {Roo.EventObject} e
3443 * Fires when the active item active state changes
3444 * @param {Roo.bootstrap.NavItem} this
3445 * @param {boolean} state the new state
3453 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3461 preventDefault : false,
3466 getAutoCreate : function(){
3474 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3476 if (this.disabled) {
3477 cfg.cls += ' disabled';
3480 if (this.href || this.html || this.glyphicon || this.icon) {
3484 href : this.href || "#",
3485 html: this.html || ''
3490 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3493 if(this.glyphicon) {
3494 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3499 cfg.cn[0].html += " <span class='caret'></span>";
3503 if (this.badge !== '') {
3505 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3513 initEvents: function() {
3514 // Roo.log('init events?');
3515 // Roo.log(this.el.dom);
3516 if (typeof (this.menu) != 'undefined') {
3517 this.menu.parentType = this.xtype;
3518 this.menu.triggerEl = this.el;
3519 this.addxtype(Roo.apply({}, this.menu));
3523 this.el.select('a',true).on('click', this.onClick, this);
3524 // at this point parent should be available..
3525 this.parent().register(this);
3528 onClick : function(e)
3531 if(this.preventDefault){
3534 if (this.disabled) {
3537 Roo.log("fire event clicked");
3538 if(this.fireEvent('click', this, e) === false){
3542 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3543 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3544 this.parent().setActiveItem(this);
3552 isActive: function () {
3555 setActive : function(state, fire)
3557 this.active = state;
3559 this.el.removeClass('active');
3560 } else if (!this.el.hasClass('active')) {
3561 this.el.addClass('active');
3564 this.fireEvent('changed', this, state);
3567 // show a panel if it's registered and related..
3569 if (!this.navId || !this.tabId || !state) {
3573 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3577 var pan = tg.getPanelByName(this.tabId);
3586 // this should not be here...
3587 setDisabled : function(state)
3589 this.disabled = state;
3591 this.el.removeClass('disabled');
3592 } else if (!this.el.hasClass('disabled')) {
3593 this.el.addClass('disabled');
3606 * <span> icon </span>
3607 * <span> text </span>
3608 * <span>badge </span>
3612 * @class Roo.bootstrap.NavSidebarItem
3613 * @extends Roo.bootstrap.NavItem
3614 * Bootstrap Navbar.NavSidebarItem class
3616 * Create a new Navbar Button
3617 * @param {Object} config The config object
3619 Roo.bootstrap.NavSidebarItem = function(config){
3620 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3625 * The raw click event for the entire grid.
3626 * @param {Roo.EventObject} e
3631 * Fires when the active item active state changes
3632 * @param {Roo.bootstrap.NavSidebarItem} this
3633 * @param {boolean} state the new state
3641 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3644 getAutoCreate : function(){
3649 href : this.href || '#',
3661 html : this.html || ''
3666 cfg.cls += ' active';
3670 if (this.glyphicon || this.icon) {
3671 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3672 a.cn.push({ tag : 'i', cls : c }) ;
3677 if (this.badge !== '') {
3678 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3682 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3683 a.cls += 'dropdown-toggle treeview' ;
3707 * @class Roo.bootstrap.Row
3708 * @extends Roo.bootstrap.Component
3709 * Bootstrap Row class (contains columns...)
3713 * @param {Object} config The config object
3716 Roo.bootstrap.Row = function(config){
3717 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3720 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3722 getAutoCreate : function(){
3741 * @class Roo.bootstrap.Element
3742 * @extends Roo.bootstrap.Component
3743 * Bootstrap Element class
3744 * @cfg {String} html contents of the element
3745 * @cfg {String} tag tag of the element
3746 * @cfg {String} cls class of the element
3749 * Create a new Element
3750 * @param {Object} config The config object
3753 Roo.bootstrap.Element = function(config){
3754 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3757 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3764 getAutoCreate : function(){
3789 * @class Roo.bootstrap.Pagination
3790 * @extends Roo.bootstrap.Component
3791 * Bootstrap Pagination class
3792 * @cfg {String} size xs | sm | md | lg
3793 * @cfg {Boolean} inverse false | true
3796 * Create a new Pagination
3797 * @param {Object} config The config object
3800 Roo.bootstrap.Pagination = function(config){
3801 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3804 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3810 getAutoCreate : function(){
3816 cfg.cls += ' inverse';
3822 cfg.cls += " " + this.cls;
3840 * @class Roo.bootstrap.PaginationItem
3841 * @extends Roo.bootstrap.Component
3842 * Bootstrap PaginationItem class
3843 * @cfg {String} html text
3844 * @cfg {String} href the link
3845 * @cfg {Boolean} preventDefault (true | false) default true
3846 * @cfg {Boolean} active (true | false) default false
3850 * Create a new PaginationItem
3851 * @param {Object} config The config object
3855 Roo.bootstrap.PaginationItem = function(config){
3856 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3861 * The raw click event for the entire grid.
3862 * @param {Roo.EventObject} e
3868 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3872 preventDefault: true,
3876 getAutoCreate : function(){
3882 href : this.href ? this.href : '#',
3883 html : this.html ? this.html : ''
3893 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3899 initEvents: function() {
3901 this.el.on('click', this.onClick, this);
3904 onClick : function(e)
3906 Roo.log('PaginationItem on click ');
3907 if(this.preventDefault){
3911 this.fireEvent('click', this, e);
3927 * @class Roo.bootstrap.Slider
3928 * @extends Roo.bootstrap.Component
3929 * Bootstrap Slider class
3932 * Create a new Slider
3933 * @param {Object} config The config object
3936 Roo.bootstrap.Slider = function(config){
3937 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3940 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3942 getAutoCreate : function(){
3946 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3950 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3962 * Ext JS Library 1.1.1
3963 * Copyright(c) 2006-2007, Ext JS, LLC.
3965 * Originally Released Under LGPL - original licence link has changed is not relivant.
3968 * <script type="text/javascript">
3973 * @class Roo.grid.ColumnModel
3974 * @extends Roo.util.Observable
3975 * This is the default implementation of a ColumnModel used by the Grid. It defines
3976 * the columns in the grid.
3979 var colModel = new Roo.grid.ColumnModel([
3980 {header: "Ticker", width: 60, sortable: true, locked: true},
3981 {header: "Company Name", width: 150, sortable: true},
3982 {header: "Market Cap.", width: 100, sortable: true},
3983 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3984 {header: "Employees", width: 100, sortable: true, resizable: false}
3989 * The config options listed for this class are options which may appear in each
3990 * individual column definition.
3991 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3993 * @param {Object} config An Array of column config objects. See this class's
3994 * config objects for details.
3996 Roo.grid.ColumnModel = function(config){
3998 * The config passed into the constructor
4000 this.config = config;
4003 // if no id, create one
4004 // if the column does not have a dataIndex mapping,
4005 // map it to the order it is in the config
4006 for(var i = 0, len = config.length; i < len; i++){
4008 if(typeof c.dataIndex == "undefined"){
4011 if(typeof c.renderer == "string"){
4012 c.renderer = Roo.util.Format[c.renderer];
4014 if(typeof c.id == "undefined"){
4017 if(c.editor && c.editor.xtype){
4018 c.editor = Roo.factory(c.editor, Roo.grid);
4020 if(c.editor && c.editor.isFormField){
4021 c.editor = new Roo.grid.GridEditor(c.editor);
4023 this.lookup[c.id] = c;
4027 * The width of columns which have no width specified (defaults to 100)
4030 this.defaultWidth = 100;
4033 * Default sortable of columns which have no sortable specified (defaults to false)
4036 this.defaultSortable = false;
4040 * @event widthchange
4041 * Fires when the width of a column changes.
4042 * @param {ColumnModel} this
4043 * @param {Number} columnIndex The column index
4044 * @param {Number} newWidth The new width
4046 "widthchange": true,
4048 * @event headerchange
4049 * Fires when the text of a header changes.
4050 * @param {ColumnModel} this
4051 * @param {Number} columnIndex The column index
4052 * @param {Number} newText The new header text
4054 "headerchange": true,
4056 * @event hiddenchange
4057 * Fires when a column is hidden or "unhidden".
4058 * @param {ColumnModel} this
4059 * @param {Number} columnIndex The column index
4060 * @param {Boolean} hidden true if hidden, false otherwise
4062 "hiddenchange": true,
4064 * @event columnmoved
4065 * Fires when a column is moved.
4066 * @param {ColumnModel} this
4067 * @param {Number} oldIndex
4068 * @param {Number} newIndex
4070 "columnmoved" : true,
4072 * @event columlockchange
4073 * Fires when a column's locked state is changed
4074 * @param {ColumnModel} this
4075 * @param {Number} colIndex
4076 * @param {Boolean} locked true if locked
4078 "columnlockchange" : true
4080 Roo.grid.ColumnModel.superclass.constructor.call(this);
4082 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4084 * @cfg {String} header The header text to display in the Grid view.
4087 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4088 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4089 * specified, the column's index is used as an index into the Record's data Array.
4092 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4093 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4096 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4097 * Defaults to the value of the {@link #defaultSortable} property.
4098 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4101 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4104 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4107 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4110 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4113 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4114 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4115 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4116 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4119 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4122 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4126 * Returns the id of the column at the specified index.
4127 * @param {Number} index The column index
4128 * @return {String} the id
4130 getColumnId : function(index){
4131 return this.config[index].id;
4135 * Returns the column for a specified id.
4136 * @param {String} id The column id
4137 * @return {Object} the column
4139 getColumnById : function(id){
4140 return this.lookup[id];
4145 * Returns the column for a specified dataIndex.
4146 * @param {String} dataIndex The column dataIndex
4147 * @return {Object|Boolean} the column or false if not found
4149 getColumnByDataIndex: function(dataIndex){
4150 var index = this.findColumnIndex(dataIndex);
4151 return index > -1 ? this.config[index] : false;
4155 * Returns the index for a specified column id.
4156 * @param {String} id The column id
4157 * @return {Number} the index, or -1 if not found
4159 getIndexById : function(id){
4160 for(var i = 0, len = this.config.length; i < len; i++){
4161 if(this.config[i].id == id){
4169 * Returns the index for a specified column dataIndex.
4170 * @param {String} dataIndex The column dataIndex
4171 * @return {Number} the index, or -1 if not found
4174 findColumnIndex : function(dataIndex){
4175 for(var i = 0, len = this.config.length; i < len; i++){
4176 if(this.config[i].dataIndex == dataIndex){
4184 moveColumn : function(oldIndex, newIndex){
4185 var c = this.config[oldIndex];
4186 this.config.splice(oldIndex, 1);
4187 this.config.splice(newIndex, 0, c);
4188 this.dataMap = null;
4189 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4192 isLocked : function(colIndex){
4193 return this.config[colIndex].locked === true;
4196 setLocked : function(colIndex, value, suppressEvent){
4197 if(this.isLocked(colIndex) == value){
4200 this.config[colIndex].locked = value;
4202 this.fireEvent("columnlockchange", this, colIndex, value);
4206 getTotalLockedWidth : function(){
4208 for(var i = 0; i < this.config.length; i++){
4209 if(this.isLocked(i) && !this.isHidden(i)){
4210 this.totalWidth += this.getColumnWidth(i);
4216 getLockedCount : function(){
4217 for(var i = 0, len = this.config.length; i < len; i++){
4218 if(!this.isLocked(i)){
4225 * Returns the number of columns.
4228 getColumnCount : function(visibleOnly){
4229 if(visibleOnly === true){
4231 for(var i = 0, len = this.config.length; i < len; i++){
4232 if(!this.isHidden(i)){
4238 return this.config.length;
4242 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4243 * @param {Function} fn
4244 * @param {Object} scope (optional)
4245 * @return {Array} result
4247 getColumnsBy : function(fn, scope){
4249 for(var i = 0, len = this.config.length; i < len; i++){
4250 var c = this.config[i];
4251 if(fn.call(scope||this, c, i) === true){
4259 * Returns true if the specified column is sortable.
4260 * @param {Number} col The column index
4263 isSortable : function(col){
4264 if(typeof this.config[col].sortable == "undefined"){
4265 return this.defaultSortable;
4267 return this.config[col].sortable;
4271 * Returns the rendering (formatting) function defined for the column.
4272 * @param {Number} col The column index.
4273 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4275 getRenderer : function(col){
4276 if(!this.config[col].renderer){
4277 return Roo.grid.ColumnModel.defaultRenderer;
4279 return this.config[col].renderer;
4283 * Sets the rendering (formatting) function for a column.
4284 * @param {Number} col The column index
4285 * @param {Function} fn The function to use to process the cell's raw data
4286 * to return HTML markup for the grid view. The render function is called with
4287 * the following parameters:<ul>
4288 * <li>Data value.</li>
4289 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4290 * <li>css A CSS style string to apply to the table cell.</li>
4291 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4292 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4293 * <li>Row index</li>
4294 * <li>Column index</li>
4295 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4297 setRenderer : function(col, fn){
4298 this.config[col].renderer = fn;
4302 * Returns the width for the specified column.
4303 * @param {Number} col The column index
4306 getColumnWidth : function(col){
4307 return this.config[col].width * 1 || this.defaultWidth;
4311 * Sets the width for a column.
4312 * @param {Number} col The column index
4313 * @param {Number} width The new width
4315 setColumnWidth : function(col, width, suppressEvent){
4316 this.config[col].width = width;
4317 this.totalWidth = null;
4319 this.fireEvent("widthchange", this, col, width);
4324 * Returns the total width of all columns.
4325 * @param {Boolean} includeHidden True to include hidden column widths
4328 getTotalWidth : function(includeHidden){
4329 if(!this.totalWidth){
4330 this.totalWidth = 0;
4331 for(var i = 0, len = this.config.length; i < len; i++){
4332 if(includeHidden || !this.isHidden(i)){
4333 this.totalWidth += this.getColumnWidth(i);
4337 return this.totalWidth;
4341 * Returns the header for the specified column.
4342 * @param {Number} col The column index
4345 getColumnHeader : function(col){
4346 return this.config[col].header;
4350 * Sets the header for a column.
4351 * @param {Number} col The column index
4352 * @param {String} header The new header
4354 setColumnHeader : function(col, header){
4355 this.config[col].header = header;
4356 this.fireEvent("headerchange", this, col, header);
4360 * Returns the tooltip for the specified column.
4361 * @param {Number} col The column index
4364 getColumnTooltip : function(col){
4365 return this.config[col].tooltip;
4368 * Sets the tooltip for a column.
4369 * @param {Number} col The column index
4370 * @param {String} tooltip The new tooltip
4372 setColumnTooltip : function(col, tooltip){
4373 this.config[col].tooltip = tooltip;
4377 * Returns the dataIndex for the specified column.
4378 * @param {Number} col The column index
4381 getDataIndex : function(col){
4382 return this.config[col].dataIndex;
4386 * Sets the dataIndex for a column.
4387 * @param {Number} col The column index
4388 * @param {Number} dataIndex The new dataIndex
4390 setDataIndex : function(col, dataIndex){
4391 this.config[col].dataIndex = dataIndex;
4397 * Returns true if the cell is editable.
4398 * @param {Number} colIndex The column index
4399 * @param {Number} rowIndex The row index
4402 isCellEditable : function(colIndex, rowIndex){
4403 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4407 * Returns the editor defined for the cell/column.
4408 * return false or null to disable editing.
4409 * @param {Number} colIndex The column index
4410 * @param {Number} rowIndex The row index
4413 getCellEditor : function(colIndex, rowIndex){
4414 return this.config[colIndex].editor;
4418 * Sets if a column is editable.
4419 * @param {Number} col The column index
4420 * @param {Boolean} editable True if the column is editable
4422 setEditable : function(col, editable){
4423 this.config[col].editable = editable;
4428 * Returns true if the column is hidden.
4429 * @param {Number} colIndex The column index
4432 isHidden : function(colIndex){
4433 return this.config[colIndex].hidden;
4438 * Returns true if the column width cannot be changed
4440 isFixed : function(colIndex){
4441 return this.config[colIndex].fixed;
4445 * Returns true if the column can be resized
4448 isResizable : function(colIndex){
4449 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4452 * Sets if a column is hidden.
4453 * @param {Number} colIndex The column index
4454 * @param {Boolean} hidden True if the column is hidden
4456 setHidden : function(colIndex, hidden){
4457 this.config[colIndex].hidden = hidden;
4458 this.totalWidth = null;
4459 this.fireEvent("hiddenchange", this, colIndex, hidden);
4463 * Sets the editor for a column.
4464 * @param {Number} col The column index
4465 * @param {Object} editor The editor object
4467 setEditor : function(col, editor){
4468 this.config[col].editor = editor;
4472 Roo.grid.ColumnModel.defaultRenderer = function(value){
4473 if(typeof value == "string" && value.length < 1){
4479 // Alias for backwards compatibility
4480 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4483 * Ext JS Library 1.1.1
4484 * Copyright(c) 2006-2007, Ext JS, LLC.
4486 * Originally Released Under LGPL - original licence link has changed is not relivant.
4489 * <script type="text/javascript">
4493 * @class Roo.LoadMask
4494 * A simple utility class for generically masking elements while loading data. If the element being masked has
4495 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4496 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4497 * element's UpdateManager load indicator and will be destroyed after the initial load.
4499 * Create a new LoadMask
4500 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4501 * @param {Object} config The config object
4503 Roo.LoadMask = function(el, config){
4504 this.el = Roo.get(el);
4505 Roo.apply(this, config);
4507 this.store.on('beforeload', this.onBeforeLoad, this);
4508 this.store.on('load', this.onLoad, this);
4509 this.store.on('loadexception', this.onLoadException, this);
4510 this.removeMask = false;
4512 var um = this.el.getUpdateManager();
4513 um.showLoadIndicator = false; // disable the default indicator
4514 um.on('beforeupdate', this.onBeforeLoad, this);
4515 um.on('update', this.onLoad, this);
4516 um.on('failure', this.onLoad, this);
4517 this.removeMask = true;
4521 Roo.LoadMask.prototype = {
4523 * @cfg {Boolean} removeMask
4524 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4525 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4529 * The text to display in a centered loading message box (defaults to 'Loading...')
4533 * @cfg {String} msgCls
4534 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4536 msgCls : 'x-mask-loading',
4539 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4545 * Disables the mask to prevent it from being displayed
4547 disable : function(){
4548 this.disabled = true;
4552 * Enables the mask so that it can be displayed
4554 enable : function(){
4555 this.disabled = false;
4558 onLoadException : function()
4562 if (typeof(arguments[3]) != 'undefined') {
4563 Roo.MessageBox.alert("Error loading",arguments[3]);
4567 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4568 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4577 this.el.unmask(this.removeMask);
4582 this.el.unmask(this.removeMask);
4586 onBeforeLoad : function(){
4588 this.el.mask(this.msg, this.msgCls);
4593 destroy : function(){
4595 this.store.un('beforeload', this.onBeforeLoad, this);
4596 this.store.un('load', this.onLoad, this);
4597 this.store.un('loadexception', this.onLoadException, this);
4599 var um = this.el.getUpdateManager();
4600 um.un('beforeupdate', this.onBeforeLoad, this);
4601 um.un('update', this.onLoad, this);
4602 um.un('failure', this.onLoad, this);
4613 * @class Roo.bootstrap.Table
4614 * @extends Roo.bootstrap.Component
4615 * Bootstrap Table class
4616 * @cfg {String} cls table class
4617 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4618 * @cfg {String} bgcolor Specifies the background color for a table
4619 * @cfg {Number} border Specifies whether the table cells should have borders or not
4620 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4621 * @cfg {Number} cellspacing Specifies the space between cells
4622 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4623 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4624 * @cfg {String} sortable Specifies that the table should be sortable
4625 * @cfg {String} summary Specifies a summary of the content of a table
4626 * @cfg {Number} width Specifies the width of a table
4627 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4629 * @cfg {boolean} striped Should the rows be alternative striped
4630 * @cfg {boolean} bordered Add borders to the table
4631 * @cfg {boolean} hover Add hover highlighting
4632 * @cfg {boolean} condensed Format condensed
4633 * @cfg {boolean} responsive Format condensed
4634 * @cfg {Boolean} loadMask (true|false) default false
4635 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4636 * @cfg {Boolean} thead (true|false) generate thead, default true
4637 * @cfg {Boolean} RowSelection (true|false) default false
4638 * @cfg {Boolean} CellSelection (true|false) default false
4640 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4644 * Create a new Table
4645 * @param {Object} config The config object
4648 Roo.bootstrap.Table = function(config){
4649 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4652 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4653 this.sm = this.selModel;
4654 this.sm.xmodule = this.xmodule || false;
4656 if (this.cm && typeof(this.cm.config) == 'undefined') {
4657 this.colModel = new Roo.grid.ColumnModel(this.cm);
4658 this.cm = this.colModel;
4659 this.cm.xmodule = this.xmodule || false;
4662 this.store= Roo.factory(this.store, Roo.data);
4663 this.ds = this.store;
4664 this.ds.xmodule = this.xmodule || false;
4667 if (this.footer && this.store) {
4668 this.footer.dataSource = this.ds;
4669 this.footer = Roo.factory(this.footer);
4676 * Fires when a cell is clicked
4677 * @param {Roo.bootstrap.Table} this
4678 * @param {Roo.Element} el
4679 * @param {Number} rowIndex
4680 * @param {Number} columnIndex
4681 * @param {Roo.EventObject} e
4685 * @event celldblclick
4686 * Fires when a cell is double clicked
4687 * @param {Roo.bootstrap.Table} this
4688 * @param {Roo.Element} el
4689 * @param {Number} rowIndex
4690 * @param {Number} columnIndex
4691 * @param {Roo.EventObject} e
4693 "celldblclick" : true,
4696 * Fires when a row is clicked
4697 * @param {Roo.bootstrap.Table} this
4698 * @param {Roo.Element} el
4699 * @param {Number} rowIndex
4700 * @param {Roo.EventObject} e
4704 * @event rowdblclick
4705 * Fires when a row is double clicked
4706 * @param {Roo.bootstrap.Table} this
4707 * @param {Roo.Element} el
4708 * @param {Number} rowIndex
4709 * @param {Roo.EventObject} e
4711 "rowdblclick" : true,
4714 * Fires when a mouseover occur
4715 * @param {Roo.bootstrap.Table} this
4716 * @param {Roo.Element} el
4717 * @param {Number} rowIndex
4718 * @param {Number} columnIndex
4719 * @param {Roo.EventObject} e
4724 * Fires when a mouseout occur
4725 * @param {Roo.bootstrap.Table} this
4726 * @param {Roo.Element} el
4727 * @param {Number} rowIndex
4728 * @param {Number} columnIndex
4729 * @param {Roo.EventObject} e
4734 * Fires when a row is rendered, so you can change add a style to it.
4735 * @param {Roo.bootstrap.Table} this
4736 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4743 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4767 RowSelection : false,
4768 CellSelection : false,
4771 // Roo.Element - the tbody
4774 getAutoCreate : function(){
4775 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4784 cfg.cls += ' table-striped';
4788 cfg.cls += ' table-hover';
4790 if (this.bordered) {
4791 cfg.cls += ' table-bordered';
4793 if (this.condensed) {
4794 cfg.cls += ' table-condensed';
4796 if (this.responsive) {
4797 cfg.cls += ' table-responsive';
4801 cfg.cls+= ' ' +this.cls;
4804 // this lot should be simplifed...
4807 cfg.align=this.align;
4810 cfg.bgcolor=this.bgcolor;
4813 cfg.border=this.border;
4815 if (this.cellpadding) {
4816 cfg.cellpadding=this.cellpadding;
4818 if (this.cellspacing) {
4819 cfg.cellspacing=this.cellspacing;
4822 cfg.frame=this.frame;
4825 cfg.rules=this.rules;
4827 if (this.sortable) {
4828 cfg.sortable=this.sortable;
4831 cfg.summary=this.summary;
4834 cfg.width=this.width;
4837 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4840 if(this.store || this.cm){
4842 cfg.cn.push(this.renderHeader());
4845 cfg.cn.push(this.renderBody());
4848 cfg.cn.push(this.renderFooter());
4851 cfg.cls+= ' TableGrid';
4854 return { cn : [ cfg ] };
4857 initEvents : function()
4859 if(!this.store || !this.cm){
4863 //Roo.log('initEvents with ds!!!!');
4865 this.mainBody = this.el.select('tbody', true).first();
4870 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4871 e.on('click', _this.sort, _this);
4874 this.el.on("click", this.onClick, this);
4875 this.el.on("dblclick", this.onDblClick, this);
4877 this.parent().el.setStyle('position', 'relative');
4879 this.footer.parentId = this.id;
4880 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4883 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4885 this.store.on('load', this.onLoad, this);
4886 this.store.on('beforeload', this.onBeforeLoad, this);
4887 this.store.on('update', this.onUpdate, this);
4891 onMouseover : function(e, el)
4893 var cell = Roo.get(el);
4899 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4900 cell = cell.findParent('td', false, true);
4903 var row = cell.findParent('tr', false, true);
4904 var cellIndex = cell.dom.cellIndex;
4905 var rowIndex = row.dom.rowIndex - 1; // start from 0
4907 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4911 onMouseout : function(e, el)
4913 var cell = Roo.get(el);
4919 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4920 cell = cell.findParent('td', false, true);
4923 var row = cell.findParent('tr', false, true);
4924 var cellIndex = cell.dom.cellIndex;
4925 var rowIndex = row.dom.rowIndex - 1; // start from 0
4927 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4931 onClick : function(e, el)
4933 var cell = Roo.get(el);
4935 if(!cell || (!this.CellSelection && !this.RowSelection)){
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;
4948 if(this.CellSelection){
4949 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4952 if(this.RowSelection){
4953 this.fireEvent('rowclick', this, row, rowIndex, e);
4959 onDblClick : function(e,el)
4961 var cell = Roo.get(el);
4963 if(!cell || (!this.CellSelection && !this.RowSelection)){
4967 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4968 cell = cell.findParent('td', false, true);
4971 var row = cell.findParent('tr', false, true);
4972 var cellIndex = cell.dom.cellIndex;
4973 var rowIndex = row.dom.rowIndex - 1;
4975 if(this.CellSelection){
4976 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4979 if(this.RowSelection){
4980 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4984 sort : function(e,el)
4986 var col = Roo.get(el)
4988 if(!col.hasClass('sortable')){
4992 var sort = col.attr('sort');
4995 if(col.hasClass('glyphicon-arrow-up')){
4999 this.store.sortInfo = {field : sort, direction : dir};
5002 Roo.log("calling footer first");
5003 this.footer.onClick('first');
5006 this.store.load({ params : { start : 0 } });
5010 renderHeader : function()
5019 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5021 var config = cm.config[i];
5026 html: cm.getColumnHeader(i)
5029 if(typeof(config.hidden) != 'undefined' && config.hidden){
5030 c.style += ' display:none;';
5033 if(typeof(config.dataIndex) != 'undefined'){
5034 c.sort = config.dataIndex;
5037 if(typeof(config.sortable) != 'undefined' && config.sortable){
5041 // if(typeof(config.align) != 'undefined' && config.align.length){
5042 // c.style += ' text-align:' + config.align + ';';
5045 if(typeof(config.width) != 'undefined'){
5046 c.style += ' width:' + config.width + 'px;';
5055 renderBody : function()
5065 colspan : this.cm.getColumnCount()
5075 renderFooter : function()
5085 colspan : this.cm.getColumnCount()
5099 Roo.log('ds onload');
5104 var ds = this.store;
5106 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5107 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5109 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5110 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5113 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5114 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5118 var tbody = this.mainBody;
5122 if(ds.getCount() > 0){
5123 ds.data.each(function(d,rowIndex){
5124 var row = this.renderRow(cm, ds, rowIndex);
5126 tbody.createChild(row);
5130 if(row.cellObjects.length){
5131 Roo.each(row.cellObjects, function(r){
5132 _this.renderCellObject(r);
5139 Roo.each(this.el.select('tbody td', true).elements, function(e){
5140 e.on('mouseover', _this.onMouseover, _this);
5143 Roo.each(this.el.select('tbody td', true).elements, function(e){
5144 e.on('mouseout', _this.onMouseout, _this);
5147 //if(this.loadMask){
5148 // this.maskEl.hide();
5153 onUpdate : function(ds,record)
5155 this.refreshRow(record);
5157 onRemove : function(ds, record, index, isUpdate){
5158 if(isUpdate !== true){
5159 this.fireEvent("beforerowremoved", this, index, record);
5161 var bt = this.mainBody.dom;
5163 bt.removeChild(bt.rows[index]);
5166 if(isUpdate !== true){
5167 //this.stripeRows(index);
5168 //this.syncRowHeights(index, index);
5170 this.fireEvent("rowremoved", this, index, record);
5175 refreshRow : function(record){
5176 var ds = this.store, index;
5177 if(typeof record == 'number'){
5179 record = ds.getAt(index);
5181 index = ds.indexOf(record);
5183 this.insertRow(ds, index, true);
5184 this.onRemove(ds, record, index+1, true);
5185 //this.syncRowHeights(index, index);
5187 this.fireEvent("rowupdated", this, index, record);
5190 insertRow : function(dm, rowIndex, isUpdate){
5193 this.fireEvent("beforerowsinserted", this, rowIndex);
5195 //var s = this.getScrollState();
5196 var row = this.renderRow(this.cm, this.store, rowIndex);
5197 // insert before rowIndex..
5198 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5203 if(row.cellObjects.length){
5204 Roo.each(row.cellObjects, function(r){
5205 _this.renderCellObject(r);
5210 this.fireEvent("rowsinserted", this, rowIndex);
5211 //this.syncRowHeights(firstRow, lastRow);
5212 //this.stripeRows(firstRow);
5219 getRowDom : function(rowIndex)
5221 // not sure if I need to check this.. but let's do it anyway..
5222 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5223 this.mainBody.dom.rows[rowIndex] : false
5225 // returns the object tree for a tr..
5228 renderRow : function(cm, ds, rowIndex) {
5230 var d = ds.getAt(rowIndex);
5237 var cellObjects = [];
5239 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5240 var config = cm.config[i];
5242 var renderer = cm.getRenderer(i);
5246 if(typeof(renderer) !== 'undefined'){
5247 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5249 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5250 // and are rendered into the cells after the row is rendered - using the id for the element.
5252 if(typeof(value) === 'object'){
5262 rowIndex : rowIndex,
5267 this.fireEvent('rowclass', this, rowcfg);
5271 cls : rowcfg.rowClass,
5273 html: (typeof(value) === 'object') ? '' : value
5280 if(typeof(config.hidden) != 'undefined' && config.hidden){
5281 td.style += ' display:none;';
5284 if(typeof(config.align) != 'undefined' && config.align.length){
5285 td.style += ' text-align:' + config.align + ';';
5288 if(typeof(config.width) != 'undefined'){
5289 td.style += ' width:' + config.width + 'px;';
5296 row.cellObjects = cellObjects;
5304 onBeforeLoad : function()
5306 //Roo.log('ds onBeforeLoad');
5310 //if(this.loadMask){
5311 // this.maskEl.show();
5317 this.el.select('tbody', true).first().dom.innerHTML = '';
5320 getSelectionModel : function(){
5322 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5324 return this.selModel;
5327 * Render the Roo.bootstrap object from renderder
5329 renderCellObject : function(r)
5333 var t = r.cfg.render(r.container);
5336 Roo.each(r.cfg.cn, function(c){
5338 container: t.getChildContainer(),
5341 _this.renderCellObject(child);
5358 * @class Roo.bootstrap.TableCell
5359 * @extends Roo.bootstrap.Component
5360 * Bootstrap TableCell class
5361 * @cfg {String} html cell contain text
5362 * @cfg {String} cls cell class
5363 * @cfg {String} tag cell tag (td|th) default td
5364 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5365 * @cfg {String} align Aligns the content in a cell
5366 * @cfg {String} axis Categorizes cells
5367 * @cfg {String} bgcolor Specifies the background color of a cell
5368 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5369 * @cfg {Number} colspan Specifies the number of columns a cell should span
5370 * @cfg {String} headers Specifies one or more header cells a cell is related to
5371 * @cfg {Number} height Sets the height of a cell
5372 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5373 * @cfg {Number} rowspan Sets the number of rows a cell should span
5374 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5375 * @cfg {String} valign Vertical aligns the content in a cell
5376 * @cfg {Number} width Specifies the width of a cell
5379 * Create a new TableCell
5380 * @param {Object} config The config object
5383 Roo.bootstrap.TableCell = function(config){
5384 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5387 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5407 getAutoCreate : function(){
5408 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5428 cfg.align=this.align
5434 cfg.bgcolor=this.bgcolor
5437 cfg.charoff=this.charoff
5440 cfg.colspan=this.colspan
5443 cfg.headers=this.headers
5446 cfg.height=this.height
5449 cfg.nowrap=this.nowrap
5452 cfg.rowspan=this.rowspan
5455 cfg.scope=this.scope
5458 cfg.valign=this.valign
5461 cfg.width=this.width
5480 * @class Roo.bootstrap.TableRow
5481 * @extends Roo.bootstrap.Component
5482 * Bootstrap TableRow class
5483 * @cfg {String} cls row class
5484 * @cfg {String} align Aligns the content in a table row
5485 * @cfg {String} bgcolor Specifies a background color for a table row
5486 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5487 * @cfg {String} valign Vertical aligns the content in a table row
5490 * Create a new TableRow
5491 * @param {Object} config The config object
5494 Roo.bootstrap.TableRow = function(config){
5495 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5498 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5506 getAutoCreate : function(){
5507 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5517 cfg.align = this.align;
5520 cfg.bgcolor = this.bgcolor;
5523 cfg.charoff = this.charoff;
5526 cfg.valign = this.valign;
5544 * @class Roo.bootstrap.TableBody
5545 * @extends Roo.bootstrap.Component
5546 * Bootstrap TableBody class
5547 * @cfg {String} cls element class
5548 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5549 * @cfg {String} align Aligns the content inside the element
5550 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5551 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5554 * Create a new TableBody
5555 * @param {Object} config The config object
5558 Roo.bootstrap.TableBody = function(config){
5559 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5562 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5570 getAutoCreate : function(){
5571 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5585 cfg.align = this.align;
5588 cfg.charoff = this.charoff;
5591 cfg.valign = this.valign;
5598 // initEvents : function()
5605 // this.store = Roo.factory(this.store, Roo.data);
5606 // this.store.on('load', this.onLoad, this);
5608 // this.store.load();
5612 // onLoad: function ()
5614 // this.fireEvent('load', this);
5624 * Ext JS Library 1.1.1
5625 * Copyright(c) 2006-2007, Ext JS, LLC.
5627 * Originally Released Under LGPL - original licence link has changed is not relivant.
5630 * <script type="text/javascript">
5633 // as we use this in bootstrap.
5634 Roo.namespace('Roo.form');
5636 * @class Roo.form.Action
5637 * Internal Class used to handle form actions
5639 * @param {Roo.form.BasicForm} el The form element or its id
5640 * @param {Object} config Configuration options
5645 // define the action interface
5646 Roo.form.Action = function(form, options){
5648 this.options = options || {};
5651 * Client Validation Failed
5654 Roo.form.Action.CLIENT_INVALID = 'client';
5656 * Server Validation Failed
5659 Roo.form.Action.SERVER_INVALID = 'server';
5661 * Connect to Server Failed
5664 Roo.form.Action.CONNECT_FAILURE = 'connect';
5666 * Reading Data from Server Failed
5669 Roo.form.Action.LOAD_FAILURE = 'load';
5671 Roo.form.Action.prototype = {
5673 failureType : undefined,
5674 response : undefined,
5678 run : function(options){
5683 success : function(response){
5688 handleResponse : function(response){
5692 // default connection failure
5693 failure : function(response){
5695 this.response = response;
5696 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5697 this.form.afterAction(this, false);
5700 processResponse : function(response){
5701 this.response = response;
5702 if(!response.responseText){
5705 this.result = this.handleResponse(response);
5709 // utility functions used internally
5710 getUrl : function(appendParams){
5711 var url = this.options.url || this.form.url || this.form.el.dom.action;
5713 var p = this.getParams();
5715 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5721 getMethod : function(){
5722 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5725 getParams : function(){
5726 var bp = this.form.baseParams;
5727 var p = this.options.params;
5729 if(typeof p == "object"){
5730 p = Roo.urlEncode(Roo.applyIf(p, bp));
5731 }else if(typeof p == 'string' && bp){
5732 p += '&' + Roo.urlEncode(bp);
5735 p = Roo.urlEncode(bp);
5740 createCallback : function(){
5742 success: this.success,
5743 failure: this.failure,
5745 timeout: (this.form.timeout*1000),
5746 upload: this.form.fileUpload ? this.success : undefined
5751 Roo.form.Action.Submit = function(form, options){
5752 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5755 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5758 haveProgress : false,
5759 uploadComplete : false,
5761 // uploadProgress indicator.
5762 uploadProgress : function()
5764 if (!this.form.progressUrl) {
5768 if (!this.haveProgress) {
5769 Roo.MessageBox.progress("Uploading", "Uploading");
5771 if (this.uploadComplete) {
5772 Roo.MessageBox.hide();
5776 this.haveProgress = true;
5778 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5780 var c = new Roo.data.Connection();
5782 url : this.form.progressUrl,
5787 success : function(req){
5788 //console.log(data);
5792 rdata = Roo.decode(req.responseText)
5794 Roo.log("Invalid data from server..");
5798 if (!rdata || !rdata.success) {
5800 Roo.MessageBox.alert(Roo.encode(rdata));
5803 var data = rdata.data;
5805 if (this.uploadComplete) {
5806 Roo.MessageBox.hide();
5811 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5812 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5815 this.uploadProgress.defer(2000,this);
5818 failure: function(data) {
5819 Roo.log('progress url failed ');
5830 // run get Values on the form, so it syncs any secondary forms.
5831 this.form.getValues();
5833 var o = this.options;
5834 var method = this.getMethod();
5835 var isPost = method == 'POST';
5836 if(o.clientValidation === false || this.form.isValid()){
5838 if (this.form.progressUrl) {
5839 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5840 (new Date() * 1) + '' + Math.random());
5845 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5846 form:this.form.el.dom,
5847 url:this.getUrl(!isPost),
5849 params:isPost ? this.getParams() : null,
5850 isUpload: this.form.fileUpload
5853 this.uploadProgress();
5855 }else if (o.clientValidation !== false){ // client validation failed
5856 this.failureType = Roo.form.Action.CLIENT_INVALID;
5857 this.form.afterAction(this, false);
5861 success : function(response)
5863 this.uploadComplete= true;
5864 if (this.haveProgress) {
5865 Roo.MessageBox.hide();
5869 var result = this.processResponse(response);
5870 if(result === true || result.success){
5871 this.form.afterAction(this, true);
5875 this.form.markInvalid(result.errors);
5876 this.failureType = Roo.form.Action.SERVER_INVALID;
5878 this.form.afterAction(this, false);
5880 failure : function(response)
5882 this.uploadComplete= true;
5883 if (this.haveProgress) {
5884 Roo.MessageBox.hide();
5887 this.response = response;
5888 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5889 this.form.afterAction(this, false);
5892 handleResponse : function(response){
5893 if(this.form.errorReader){
5894 var rs = this.form.errorReader.read(response);
5897 for(var i = 0, len = rs.records.length; i < len; i++) {
5898 var r = rs.records[i];
5902 if(errors.length < 1){
5906 success : rs.success,
5912 ret = Roo.decode(response.responseText);
5916 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5926 Roo.form.Action.Load = function(form, options){
5927 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5928 this.reader = this.form.reader;
5931 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5936 Roo.Ajax.request(Roo.apply(
5937 this.createCallback(), {
5938 method:this.getMethod(),
5939 url:this.getUrl(false),
5940 params:this.getParams()
5944 success : function(response){
5946 var result = this.processResponse(response);
5947 if(result === true || !result.success || !result.data){
5948 this.failureType = Roo.form.Action.LOAD_FAILURE;
5949 this.form.afterAction(this, false);
5952 this.form.clearInvalid();
5953 this.form.setValues(result.data);
5954 this.form.afterAction(this, true);
5957 handleResponse : function(response){
5958 if(this.form.reader){
5959 var rs = this.form.reader.read(response);
5960 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5962 success : rs.success,
5966 return Roo.decode(response.responseText);
5970 Roo.form.Action.ACTION_TYPES = {
5971 'load' : Roo.form.Action.Load,
5972 'submit' : Roo.form.Action.Submit
5981 * @class Roo.bootstrap.Form
5982 * @extends Roo.bootstrap.Component
5983 * Bootstrap Form class
5984 * @cfg {String} method GET | POST (default POST)
5985 * @cfg {String} labelAlign top | left (default top)
5986 * @cfg {String} align left | right - for navbars
5991 * @param {Object} config The config object
5995 Roo.bootstrap.Form = function(config){
5996 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5999 * @event clientvalidation
6000 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6001 * @param {Form} this
6002 * @param {Boolean} valid true if the form has passed client-side validation
6004 clientvalidation: true,
6006 * @event beforeaction
6007 * Fires before any action is performed. Return false to cancel the action.
6008 * @param {Form} this
6009 * @param {Action} action The action to be performed
6013 * @event actionfailed
6014 * Fires when an action fails.
6015 * @param {Form} this
6016 * @param {Action} action The action that failed
6018 actionfailed : true,
6020 * @event actioncomplete
6021 * Fires when an action is completed.
6022 * @param {Form} this
6023 * @param {Action} action The action that completed
6025 actioncomplete : true
6030 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6033 * @cfg {String} method
6034 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6039 * The URL to use for form actions if one isn't supplied in the action options.
6042 * @cfg {Boolean} fileUpload
6043 * Set to true if this form is a file upload.
6047 * @cfg {Object} baseParams
6048 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6052 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6056 * @cfg {Sting} align (left|right) for navbar forms
6061 activeAction : null,
6064 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6065 * element by passing it or its id or mask the form itself by passing in true.
6068 waitMsgTarget : false,
6073 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6074 * element by passing it or its id or mask the form itself by passing in true.
6078 getAutoCreate : function(){
6082 method : this.method || 'POST',
6083 id : this.id || Roo.id(),
6086 if (this.parent().xtype.match(/^Nav/)) {
6087 cfg.cls = 'navbar-form navbar-' + this.align;
6091 if (this.labelAlign == 'left' ) {
6092 cfg.cls += ' form-horizontal';
6098 initEvents : function()
6100 this.el.on('submit', this.onSubmit, this);
6101 // this was added as random key presses on the form where triggering form submit.
6102 this.el.on('keypress', function(e) {
6103 if (e.getCharCode() != 13) {
6106 // we might need to allow it for textareas.. and some other items.
6107 // check e.getTarget().
6109 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6113 Roo.log("keypress blocked");
6121 onSubmit : function(e){
6126 * Returns true if client-side validation on the form is successful.
6129 isValid : function(){
6130 var items = this.getItems();
6132 items.each(function(f){
6141 * Returns true if any fields in this form have changed since their original load.
6144 isDirty : function(){
6146 var items = this.getItems();
6147 items.each(function(f){
6157 * Performs a predefined action (submit or load) or custom actions you define on this form.
6158 * @param {String} actionName The name of the action type
6159 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6160 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6161 * accept other config options):
6163 Property Type Description
6164 ---------------- --------------- ----------------------------------------------------------------------------------
6165 url String The url for the action (defaults to the form's url)
6166 method String The form method to use (defaults to the form's method, or POST if not defined)
6167 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6168 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6169 validate the form on the client (defaults to false)
6171 * @return {BasicForm} this
6173 doAction : function(action, options){
6174 if(typeof action == 'string'){
6175 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6177 if(this.fireEvent('beforeaction', this, action) !== false){
6178 this.beforeAction(action);
6179 action.run.defer(100, action);
6185 beforeAction : function(action){
6186 var o = action.options;
6188 // not really supported yet.. ??
6190 //if(this.waitMsgTarget === true){
6191 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6192 //}else if(this.waitMsgTarget){
6193 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6194 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6196 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6202 afterAction : function(action, success){
6203 this.activeAction = null;
6204 var o = action.options;
6206 //if(this.waitMsgTarget === true){
6208 //}else if(this.waitMsgTarget){
6209 // this.waitMsgTarget.unmask();
6211 // Roo.MessageBox.updateProgress(1);
6212 // Roo.MessageBox.hide();
6219 Roo.callback(o.success, o.scope, [this, action]);
6220 this.fireEvent('actioncomplete', this, action);
6224 // failure condition..
6225 // we have a scenario where updates need confirming.
6226 // eg. if a locking scenario exists..
6227 // we look for { errors : { needs_confirm : true }} in the response.
6229 (typeof(action.result) != 'undefined') &&
6230 (typeof(action.result.errors) != 'undefined') &&
6231 (typeof(action.result.errors.needs_confirm) != 'undefined')
6234 Roo.log("not supported yet");
6237 Roo.MessageBox.confirm(
6238 "Change requires confirmation",
6239 action.result.errorMsg,
6244 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6254 Roo.callback(o.failure, o.scope, [this, action]);
6255 // show an error message if no failed handler is set..
6256 if (!this.hasListener('actionfailed')) {
6257 Roo.log("need to add dialog support");
6259 Roo.MessageBox.alert("Error",
6260 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6261 action.result.errorMsg :
6262 "Saving Failed, please check your entries or try again"
6267 this.fireEvent('actionfailed', this, action);
6272 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6273 * @param {String} id The value to search for
6276 findField : function(id){
6277 var items = this.getItems();
6278 var field = items.get(id);
6280 items.each(function(f){
6281 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6288 return field || null;
6291 * Mark fields in this form invalid in bulk.
6292 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6293 * @return {BasicForm} this
6295 markInvalid : function(errors){
6296 if(errors instanceof Array){
6297 for(var i = 0, len = errors.length; i < len; i++){
6298 var fieldError = errors[i];
6299 var f = this.findField(fieldError.id);
6301 f.markInvalid(fieldError.msg);
6307 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6308 field.markInvalid(errors[id]);
6312 //Roo.each(this.childForms || [], function (f) {
6313 // f.markInvalid(errors);
6320 * Set values for fields in this form in bulk.
6321 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6322 * @return {BasicForm} this
6324 setValues : function(values){
6325 if(values instanceof Array){ // array of objects
6326 for(var i = 0, len = values.length; i < len; i++){
6328 var f = this.findField(v.id);
6330 f.setValue(v.value);
6331 if(this.trackResetOnLoad){
6332 f.originalValue = f.getValue();
6336 }else{ // object hash
6339 if(typeof values[id] != 'function' && (field = this.findField(id))){
6341 if (field.setFromData &&
6343 field.displayField &&
6344 // combos' with local stores can
6345 // be queried via setValue()
6346 // to set their value..
6347 (field.store && !field.store.isLocal)
6351 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6352 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6353 field.setFromData(sd);
6356 field.setValue(values[id]);
6360 if(this.trackResetOnLoad){
6361 field.originalValue = field.getValue();
6367 //Roo.each(this.childForms || [], function (f) {
6368 // f.setValues(values);
6375 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6376 * they are returned as an array.
6377 * @param {Boolean} asString
6380 getValues : function(asString){
6381 //if (this.childForms) {
6382 // copy values from the child forms
6383 // Roo.each(this.childForms, function (f) {
6384 // this.setValues(f.getValues());
6390 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6391 if(asString === true){
6394 return Roo.urlDecode(fs);
6398 * Returns the fields in this form as an object with key/value pairs.
6399 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6402 getFieldValues : function(with_hidden)
6404 var items = this.getItems();
6406 items.each(function(f){
6410 var v = f.getValue();
6411 if (f.inputType =='radio') {
6412 if (typeof(ret[f.getName()]) == 'undefined') {
6413 ret[f.getName()] = ''; // empty..
6416 if (!f.el.dom.checked) {
6424 // not sure if this supported any more..
6425 if ((typeof(v) == 'object') && f.getRawValue) {
6426 v = f.getRawValue() ; // dates..
6428 // combo boxes where name != hiddenName...
6429 if (f.name != f.getName()) {
6430 ret[f.name] = f.getRawValue();
6432 ret[f.getName()] = v;
6439 * Clears all invalid messages in this form.
6440 * @return {BasicForm} this
6442 clearInvalid : function(){
6443 var items = this.getItems();
6445 items.each(function(f){
6456 * @return {BasicForm} this
6459 var items = this.getItems();
6460 items.each(function(f){
6464 Roo.each(this.childForms || [], function (f) {
6471 getItems : function()
6473 var r=new Roo.util.MixedCollection(false, function(o){
6474 return o.id || (o.id = Roo.id());
6476 var iter = function(el) {
6483 Roo.each(el.items,function(e) {
6502 * Ext JS Library 1.1.1
6503 * Copyright(c) 2006-2007, Ext JS, LLC.
6505 * Originally Released Under LGPL - original licence link has changed is not relivant.
6508 * <script type="text/javascript">
6511 * @class Roo.form.VTypes
6512 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6515 Roo.form.VTypes = function(){
6516 // closure these in so they are only created once.
6517 var alpha = /^[a-zA-Z_]+$/;
6518 var alphanum = /^[a-zA-Z0-9_]+$/;
6519 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6520 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6522 // All these messages and functions are configurable
6525 * The function used to validate email addresses
6526 * @param {String} value The email address
6528 'email' : function(v){
6529 return email.test(v);
6532 * The error text to display when the email validation function returns false
6535 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6537 * The keystroke filter mask to be applied on email input
6540 'emailMask' : /[a-z0-9_\.\-@]/i,
6543 * The function used to validate URLs
6544 * @param {String} value The URL
6546 'url' : function(v){
6550 * The error text to display when the url validation function returns false
6553 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6556 * The function used to validate alpha values
6557 * @param {String} value The value
6559 'alpha' : function(v){
6560 return alpha.test(v);
6563 * The error text to display when the alpha validation function returns false
6566 'alphaText' : 'This field should only contain letters and _',
6568 * The keystroke filter mask to be applied on alpha input
6571 'alphaMask' : /[a-z_]/i,
6574 * The function used to validate alphanumeric values
6575 * @param {String} value The value
6577 'alphanum' : function(v){
6578 return alphanum.test(v);
6581 * The error text to display when the alphanumeric validation function returns false
6584 'alphanumText' : 'This field should only contain letters, numbers and _',
6586 * The keystroke filter mask to be applied on alphanumeric input
6589 'alphanumMask' : /[a-z0-9_]/i
6599 * @class Roo.bootstrap.Input
6600 * @extends Roo.bootstrap.Component
6601 * Bootstrap Input class
6602 * @cfg {Boolean} disabled is it disabled
6603 * @cfg {String} fieldLabel - the label associated
6604 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6605 * @cfg {String} name name of the input
6606 * @cfg {string} fieldLabel - the label associated
6607 * @cfg {string} inputType - input / file submit ...
6608 * @cfg {string} placeholder - placeholder to put in text.
6609 * @cfg {string} before - input group add on before
6610 * @cfg {string} after - input group add on after
6611 * @cfg {string} size - (lg|sm) or leave empty..
6612 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6613 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6614 * @cfg {Number} md colspan out of 12 for computer-sized screens
6615 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6616 * @cfg {string} value default value of the input
6617 * @cfg {Number} labelWidth set the width of label (0-12)
6618 * @cfg {String} labelAlign (top|left)
6619 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6620 * @cfg {String} align (left|center|right) Default left
6624 * Create a new Input
6625 * @param {Object} config The config object
6628 Roo.bootstrap.Input = function(config){
6629 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6634 * Fires when this field receives input focus.
6635 * @param {Roo.form.Field} this
6640 * Fires when this field loses input focus.
6641 * @param {Roo.form.Field} this
6646 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6647 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6648 * @param {Roo.form.Field} this
6649 * @param {Roo.EventObject} e The event object
6654 * Fires just before the field blurs if the field value has changed.
6655 * @param {Roo.form.Field} this
6656 * @param {Mixed} newValue The new value
6657 * @param {Mixed} oldValue The original value
6662 * Fires after the field has been marked as invalid.
6663 * @param {Roo.form.Field} this
6664 * @param {String} msg The validation message
6669 * Fires after the field has been validated with no errors.
6670 * @param {Roo.form.Field} this
6675 * Fires after the key up
6676 * @param {Roo.form.Field} this
6677 * @param {Roo.EventObject} e The event Object
6683 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6685 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6686 automatic validation (defaults to "keyup").
6688 validationEvent : "keyup",
6690 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6692 validateOnBlur : true,
6694 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6696 validationDelay : 250,
6698 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6700 focusClass : "x-form-focus", // not needed???
6704 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6706 invalidClass : "has-error",
6709 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6711 selectOnFocus : false,
6714 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6718 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6723 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6725 disableKeyFilter : false,
6728 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6732 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6736 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6738 blankText : "This field is required",
6741 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6745 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6747 maxLength : Number.MAX_VALUE,
6749 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6751 minLengthText : "The minimum length for this field is {0}",
6753 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6755 maxLengthText : "The maximum length for this field is {0}",
6759 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6760 * If available, this function will be called only after the basic validators all return true, and will be passed the
6761 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6765 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6766 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6767 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6771 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6794 formatedValue : false,
6796 parentLabelAlign : function()
6799 while (parent.parent()) {
6800 parent = parent.parent();
6801 if (typeof(parent.labelAlign) !='undefined') {
6802 return parent.labelAlign;
6809 getAutoCreate : function(){
6811 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6817 if(this.inputType != 'hidden'){
6818 cfg.cls = 'form-group' //input-group
6824 type : this.inputType,
6826 cls : 'form-control',
6827 placeholder : this.placeholder || ''
6832 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6835 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6836 input.maxLength = this.maxLength;
6839 if (this.disabled) {
6840 input.disabled=true;
6843 if (this.readOnly) {
6844 input.readonly=true;
6848 input.name = this.name;
6851 input.cls += ' input-' + this.size;
6854 ['xs','sm','md','lg'].map(function(size){
6855 if (settings[size]) {
6856 cfg.cls += ' col-' + size + '-' + settings[size];
6860 var inputblock = input;
6862 if (this.before || this.after) {
6865 cls : 'input-group',
6868 if (this.before && typeof(this.before) == 'string') {
6870 inputblock.cn.push({
6872 cls : 'roo-input-before input-group-addon',
6876 if (this.before && typeof(this.before) == 'object') {
6877 this.before = Roo.factory(this.before);
6878 Roo.log(this.before);
6879 inputblock.cn.push({
6881 cls : 'roo-input-before input-group-' +
6882 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6886 inputblock.cn.push(input);
6888 if (this.after && typeof(this.after) == 'string') {
6889 inputblock.cn.push({
6891 cls : 'roo-input-after input-group-addon',
6895 if (this.after && typeof(this.after) == 'object') {
6896 this.after = Roo.factory(this.after);
6897 Roo.log(this.after);
6898 inputblock.cn.push({
6900 cls : 'roo-input-after input-group-' +
6901 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6906 if (align ==='left' && this.fieldLabel.length) {
6907 Roo.log("left and has label");
6913 cls : 'control-label col-sm-' + this.labelWidth,
6914 html : this.fieldLabel
6918 cls : "col-sm-" + (12 - this.labelWidth),
6925 } else if ( this.fieldLabel.length) {
6931 //cls : 'input-group-addon',
6932 html : this.fieldLabel
6942 Roo.log(" no label && no align");
6951 Roo.log('input-parentType: ' + this.parentType);
6953 if (this.parentType === 'Navbar' && this.parent().bar) {
6954 cfg.cls += ' navbar-form';
6962 * return the real input element.
6964 inputEl: function ()
6966 return this.el.select('input.form-control',true).first();
6968 setDisabled : function(v)
6970 var i = this.inputEl().dom;
6972 i.removeAttribute('disabled');
6976 i.setAttribute('disabled','true');
6978 initEvents : function()
6981 this.inputEl().on("keydown" , this.fireKey, this);
6982 this.inputEl().on("focus", this.onFocus, this);
6983 this.inputEl().on("blur", this.onBlur, this);
6985 this.inputEl().relayEvent('keyup', this);
6987 // reference to original value for reset
6988 this.originalValue = this.getValue();
6989 //Roo.form.TextField.superclass.initEvents.call(this);
6990 if(this.validationEvent == 'keyup'){
6991 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6992 this.inputEl().on('keyup', this.filterValidation, this);
6994 else if(this.validationEvent !== false){
6995 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6998 if(this.selectOnFocus){
6999 this.on("focus", this.preFocus, this);
7002 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7003 this.inputEl().on("keypress", this.filterKeys, this);
7006 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7007 this.el.on("click", this.autoSize, this);
7010 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7011 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7014 if (typeof(this.before) == 'object') {
7015 this.before.render(this.el.select('.roo-input-before',true).first());
7017 if (typeof(this.after) == 'object') {
7018 this.after.render(this.el.select('.roo-input-after',true).first());
7023 filterValidation : function(e){
7024 if(!e.isNavKeyPress()){
7025 this.validationTask.delay(this.validationDelay);
7029 * Validates the field value
7030 * @return {Boolean} True if the value is valid, else false
7032 validate : function(){
7033 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7034 if(this.disabled || this.validateValue(this.getRawValue())){
7035 this.clearInvalid();
7043 * Validates a value according to the field's validation rules and marks the field as invalid
7044 * if the validation fails
7045 * @param {Mixed} value The value to validate
7046 * @return {Boolean} True if the value is valid, else false
7048 validateValue : function(value){
7049 if(value.length < 1) { // if it's blank
7050 if(this.allowBlank){
7051 this.clearInvalid();
7054 this.markInvalid(this.blankText);
7058 if(value.length < this.minLength){
7059 this.markInvalid(String.format(this.minLengthText, this.minLength));
7062 if(value.length > this.maxLength){
7063 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7067 var vt = Roo.form.VTypes;
7068 if(!vt[this.vtype](value, this)){
7069 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7073 if(typeof this.validator == "function"){
7074 var msg = this.validator(value);
7076 this.markInvalid(msg);
7080 if(this.regex && !this.regex.test(value)){
7081 this.markInvalid(this.regexText);
7090 fireKey : function(e){
7091 //Roo.log('field ' + e.getKey());
7092 if(e.isNavKeyPress()){
7093 this.fireEvent("specialkey", this, e);
7096 focus : function (selectText){
7098 this.inputEl().focus();
7099 if(selectText === true){
7100 this.inputEl().dom.select();
7106 onFocus : function(){
7107 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7108 // this.el.addClass(this.focusClass);
7111 this.hasFocus = true;
7112 this.startValue = this.getValue();
7113 this.fireEvent("focus", this);
7117 beforeBlur : Roo.emptyFn,
7121 onBlur : function(){
7123 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7124 //this.el.removeClass(this.focusClass);
7126 this.hasFocus = false;
7127 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7130 var v = this.getValue();
7131 if(String(v) !== String(this.startValue)){
7132 this.fireEvent('change', this, v, this.startValue);
7134 this.fireEvent("blur", this);
7138 * Resets the current field value to the originally loaded value and clears any validation messages
7141 this.setValue(this.originalValue);
7142 this.clearInvalid();
7145 * Returns the name of the field
7146 * @return {Mixed} name The name field
7148 getName: function(){
7152 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7153 * @return {Mixed} value The field value
7155 getValue : function(){
7157 var v = this.inputEl().getValue();
7162 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7163 * @return {Mixed} value The field value
7165 getRawValue : function(){
7166 var v = this.inputEl().getValue();
7172 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7173 * @param {Mixed} value The value to set
7175 setRawValue : function(v){
7176 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7179 selectText : function(start, end){
7180 var v = this.getRawValue();
7182 start = start === undefined ? 0 : start;
7183 end = end === undefined ? v.length : end;
7184 var d = this.inputEl().dom;
7185 if(d.setSelectionRange){
7186 d.setSelectionRange(start, end);
7187 }else if(d.createTextRange){
7188 var range = d.createTextRange();
7189 range.moveStart("character", start);
7190 range.moveEnd("character", v.length-end);
7197 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7198 * @param {Mixed} value The value to set
7200 setValue : function(v){
7203 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7209 processValue : function(value){
7210 if(this.stripCharsRe){
7211 var newValue = value.replace(this.stripCharsRe, '');
7212 if(newValue !== value){
7213 this.setRawValue(newValue);
7220 preFocus : function(){
7222 if(this.selectOnFocus){
7223 this.inputEl().dom.select();
7226 filterKeys : function(e){
7228 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7231 var c = e.getCharCode(), cc = String.fromCharCode(c);
7232 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7235 if(!this.maskRe.test(cc)){
7240 * Clear any invalid styles/messages for this field
7242 clearInvalid : function(){
7244 if(!this.el || this.preventMark){ // not rendered
7247 this.el.removeClass(this.invalidClass);
7249 switch(this.msgTarget){
7251 this.el.dom.qtip = '';
7254 this.el.dom.title = '';
7258 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7263 this.errorIcon.dom.qtip = '';
7264 this.errorIcon.hide();
7265 this.un('resize', this.alignErrorIcon, this);
7269 var t = Roo.getDom(this.msgTarget);
7271 t.style.display = 'none';
7275 this.fireEvent('valid', this);
7278 * Mark this field as invalid
7279 * @param {String} msg The validation message
7281 markInvalid : function(msg){
7282 if(!this.el || this.preventMark){ // not rendered
7285 this.el.addClass(this.invalidClass);
7287 msg = msg || this.invalidText;
7288 switch(this.msgTarget){
7290 this.el.dom.qtip = msg;
7291 this.el.dom.qclass = 'x-form-invalid-tip';
7292 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7293 Roo.QuickTips.enable();
7297 this.el.dom.title = msg;
7301 var elp = this.el.findParent('.x-form-element', 5, true);
7302 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7303 this.errorEl.setWidth(elp.getWidth(true)-20);
7305 this.errorEl.update(msg);
7306 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7309 if(!this.errorIcon){
7310 var elp = this.el.findParent('.x-form-element', 5, true);
7311 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7313 this.alignErrorIcon();
7314 this.errorIcon.dom.qtip = msg;
7315 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7316 this.errorIcon.show();
7317 this.on('resize', this.alignErrorIcon, this);
7320 var t = Roo.getDom(this.msgTarget);
7322 t.style.display = this.msgDisplay;
7326 this.fireEvent('invalid', this, msg);
7329 SafariOnKeyDown : function(event)
7331 // this is a workaround for a password hang bug on chrome/ webkit.
7333 var isSelectAll = false;
7335 if(this.inputEl().dom.selectionEnd > 0){
7336 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7338 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7339 event.preventDefault();
7344 if(isSelectAll){ // backspace and delete key
7346 event.preventDefault();
7347 // this is very hacky as keydown always get's upper case.
7349 var cc = String.fromCharCode(event.getCharCode());
7350 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7354 adjustWidth : function(tag, w){
7355 tag = tag.toLowerCase();
7356 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7357 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7361 if(tag == 'textarea'){
7364 }else if(Roo.isOpera){
7368 if(tag == 'textarea'){
7387 * @class Roo.bootstrap.TextArea
7388 * @extends Roo.bootstrap.Input
7389 * Bootstrap TextArea class
7390 * @cfg {Number} cols Specifies the visible width of a text area
7391 * @cfg {Number} rows Specifies the visible number of lines in a text area
7392 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7393 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7394 * @cfg {string} html text
7397 * Create a new TextArea
7398 * @param {Object} config The config object
7401 Roo.bootstrap.TextArea = function(config){
7402 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7406 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7416 getAutoCreate : function(){
7418 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7429 value : this.value || '',
7430 html: this.html || '',
7431 cls : 'form-control',
7432 placeholder : this.placeholder || ''
7436 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7437 input.maxLength = this.maxLength;
7441 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7445 input.cols = this.cols;
7448 if (this.readOnly) {
7449 input.readonly = true;
7453 input.name = this.name;
7457 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7461 ['xs','sm','md','lg'].map(function(size){
7462 if (settings[size]) {
7463 cfg.cls += ' col-' + size + '-' + settings[size];
7467 var inputblock = input;
7469 if (this.before || this.after) {
7472 cls : 'input-group',
7476 inputblock.cn.push({
7478 cls : 'input-group-addon',
7482 inputblock.cn.push(input);
7484 inputblock.cn.push({
7486 cls : 'input-group-addon',
7493 if (align ==='left' && this.fieldLabel.length) {
7494 Roo.log("left and has label");
7500 cls : 'control-label col-sm-' + this.labelWidth,
7501 html : this.fieldLabel
7505 cls : "col-sm-" + (12 - this.labelWidth),
7512 } else if ( this.fieldLabel.length) {
7518 //cls : 'input-group-addon',
7519 html : this.fieldLabel
7529 Roo.log(" no label && no align");
7539 if (this.disabled) {
7540 input.disabled=true;
7547 * return the real textarea element.
7549 inputEl: function ()
7551 return this.el.select('textarea.form-control',true).first();
7559 * trigger field - base class for combo..
7564 * @class Roo.bootstrap.TriggerField
7565 * @extends Roo.bootstrap.Input
7566 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7567 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7568 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7569 * for which you can provide a custom implementation. For example:
7571 var trigger = new Roo.bootstrap.TriggerField();
7572 trigger.onTriggerClick = myTriggerFn;
7573 trigger.applyTo('my-field');
7576 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7577 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7578 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7579 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7581 * Create a new TriggerField.
7582 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7583 * to the base TextField)
7585 Roo.bootstrap.TriggerField = function(config){
7586 this.mimicing = false;
7587 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7590 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7592 * @cfg {String} triggerClass A CSS class to apply to the trigger
7595 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7599 /** @cfg {Boolean} grow @hide */
7600 /** @cfg {Number} growMin @hide */
7601 /** @cfg {Number} growMax @hide */
7607 autoSize: Roo.emptyFn,
7614 actionMode : 'wrap',
7618 getAutoCreate : function(){
7620 var parent = this.parent();
7622 var align = this.labelAlign || this.parentLabelAlign();
7627 cls: 'form-group' //input-group
7634 type : this.inputType,
7635 cls : 'form-control',
7636 autocomplete: 'off',
7637 placeholder : this.placeholder || ''
7641 input.name = this.name;
7644 input.cls += ' input-' + this.size;
7647 if (this.disabled) {
7648 input.disabled=true;
7651 var inputblock = input;
7653 if (this.before || this.after) {
7656 cls : 'input-group',
7660 inputblock.cn.push({
7662 cls : 'input-group-addon',
7666 inputblock.cn.push(input);
7668 inputblock.cn.push({
7670 cls : 'input-group-addon',
7683 cls: 'form-hidden-field'
7691 Roo.log('multiple');
7699 cls: 'form-hidden-field'
7703 cls: 'select2-choices',
7707 cls: 'select2-search-field',
7720 cls: 'select2-container input-group',
7725 cls: 'typeahead typeahead-long dropdown-menu',
7726 style: 'display:none'
7734 cls : 'input-group-addon btn dropdown-toggle',
7742 cls: 'combobox-clear',
7756 combobox.cls += ' select2-container-multi';
7759 if (align ==='left' && this.fieldLabel.length) {
7761 Roo.log("left and has label");
7767 cls : 'control-label col-sm-' + this.labelWidth,
7768 html : this.fieldLabel
7772 cls : "col-sm-" + (12 - this.labelWidth),
7779 } else if ( this.fieldLabel.length) {
7785 //cls : 'input-group-addon',
7786 html : this.fieldLabel
7796 Roo.log(" no label && no align");
7803 ['xs','sm','md','lg'].map(function(size){
7804 if (settings[size]) {
7805 cfg.cls += ' col-' + size + '-' + settings[size];
7816 onResize : function(w, h){
7817 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7818 // if(typeof w == 'number'){
7819 // var x = w - this.trigger.getWidth();
7820 // this.inputEl().setWidth(this.adjustWidth('input', x));
7821 // this.trigger.setStyle('left', x+'px');
7826 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7829 getResizeEl : function(){
7830 return this.inputEl();
7834 getPositionEl : function(){
7835 return this.inputEl();
7839 alignErrorIcon : function(){
7840 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7844 initEvents : function(){
7846 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7847 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7849 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7850 if(this.hideTrigger){
7851 this.trigger.setDisplayed(false);
7853 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7857 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7860 //this.trigger.addClassOnOver('x-form-trigger-over');
7861 //this.trigger.addClassOnClick('x-form-trigger-click');
7864 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7869 initTrigger : function(){
7874 onDestroy : function(){
7876 this.trigger.removeAllListeners();
7877 // this.trigger.remove();
7880 // this.wrap.remove();
7882 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7886 onFocus : function(){
7887 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7890 this.wrap.addClass('x-trigger-wrap-focus');
7891 this.mimicing = true;
7892 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7893 if(this.monitorTab){
7894 this.el.on("keydown", this.checkTab, this);
7901 checkTab : function(e){
7902 if(e.getKey() == e.TAB){
7908 onBlur : function(){
7913 mimicBlur : function(e, t){
7915 if(!this.wrap.contains(t) && this.validateBlur()){
7922 triggerBlur : function(){
7923 this.mimicing = false;
7924 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7925 if(this.monitorTab){
7926 this.el.un("keydown", this.checkTab, this);
7928 //this.wrap.removeClass('x-trigger-wrap-focus');
7929 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7933 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7934 validateBlur : function(e, t){
7939 onDisable : function(){
7940 this.inputEl().dom.disabled = true;
7941 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7943 // this.wrap.addClass('x-item-disabled');
7948 onEnable : function(){
7949 this.inputEl().dom.disabled = false;
7950 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7952 // this.el.removeClass('x-item-disabled');
7957 onShow : function(){
7958 var ae = this.getActionEl();
7961 ae.dom.style.display = '';
7962 ae.dom.style.visibility = 'visible';
7968 onHide : function(){
7969 var ae = this.getActionEl();
7970 ae.dom.style.display = 'none';
7974 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7975 * by an implementing function.
7977 * @param {EventObject} e
7979 onTriggerClick : Roo.emptyFn
7983 * Ext JS Library 1.1.1
7984 * Copyright(c) 2006-2007, Ext JS, LLC.
7986 * Originally Released Under LGPL - original licence link has changed is not relivant.
7989 * <script type="text/javascript">
7994 * @class Roo.data.SortTypes
7996 * Defines the default sorting (casting?) comparison functions used when sorting data.
7998 Roo.data.SortTypes = {
8000 * Default sort that does nothing
8001 * @param {Mixed} s The value being converted
8002 * @return {Mixed} The comparison value
8009 * The regular expression used to strip tags
8013 stripTagsRE : /<\/?[^>]+>/gi,
8016 * Strips all HTML tags to sort on text only
8017 * @param {Mixed} s The value being converted
8018 * @return {String} The comparison value
8020 asText : function(s){
8021 return String(s).replace(this.stripTagsRE, "");
8025 * Strips all HTML tags to sort on text only - Case insensitive
8026 * @param {Mixed} s The value being converted
8027 * @return {String} The comparison value
8029 asUCText : function(s){
8030 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8034 * Case insensitive string
8035 * @param {Mixed} s The value being converted
8036 * @return {String} The comparison value
8038 asUCString : function(s) {
8039 return String(s).toUpperCase();
8044 * @param {Mixed} s The value being converted
8045 * @return {Number} The comparison value
8047 asDate : function(s) {
8051 if(s instanceof Date){
8054 return Date.parse(String(s));
8059 * @param {Mixed} s The value being converted
8060 * @return {Float} The comparison value
8062 asFloat : function(s) {
8063 var val = parseFloat(String(s).replace(/,/g, ""));
8064 if(isNaN(val)) val = 0;
8070 * @param {Mixed} s The value being converted
8071 * @return {Number} The comparison value
8073 asInt : function(s) {
8074 var val = parseInt(String(s).replace(/,/g, ""));
8075 if(isNaN(val)) val = 0;
8080 * Ext JS Library 1.1.1
8081 * Copyright(c) 2006-2007, Ext JS, LLC.
8083 * Originally Released Under LGPL - original licence link has changed is not relivant.
8086 * <script type="text/javascript">
8090 * @class Roo.data.Record
8091 * Instances of this class encapsulate both record <em>definition</em> information, and record
8092 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8093 * to access Records cached in an {@link Roo.data.Store} object.<br>
8095 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8096 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8099 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8101 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8102 * {@link #create}. The parameters are the same.
8103 * @param {Array} data An associative Array of data values keyed by the field name.
8104 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8105 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8106 * not specified an integer id is generated.
8108 Roo.data.Record = function(data, id){
8109 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8114 * Generate a constructor for a specific record layout.
8115 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8116 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8117 * Each field definition object may contain the following properties: <ul>
8118 * <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,
8119 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8120 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8121 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8122 * is being used, then this is a string containing the javascript expression to reference the data relative to
8123 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8124 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8125 * this may be omitted.</p></li>
8126 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8127 * <ul><li>auto (Default, implies no conversion)</li>
8132 * <li>date</li></ul></p></li>
8133 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8134 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8135 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8136 * by the Reader into an object that will be stored in the Record. It is passed the
8137 * following parameters:<ul>
8138 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8140 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8142 * <br>usage:<br><pre><code>
8143 var TopicRecord = Roo.data.Record.create(
8144 {name: 'title', mapping: 'topic_title'},
8145 {name: 'author', mapping: 'username'},
8146 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8147 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8148 {name: 'lastPoster', mapping: 'user2'},
8149 {name: 'excerpt', mapping: 'post_text'}
8152 var myNewRecord = new TopicRecord({
8153 title: 'Do my job please',
8156 lastPost: new Date(),
8157 lastPoster: 'Animal',
8158 excerpt: 'No way dude!'
8160 myStore.add(myNewRecord);
8165 Roo.data.Record.create = function(o){
8167 f.superclass.constructor.apply(this, arguments);
8169 Roo.extend(f, Roo.data.Record);
8170 var p = f.prototype;
8171 p.fields = new Roo.util.MixedCollection(false, function(field){
8174 for(var i = 0, len = o.length; i < len; i++){
8175 p.fields.add(new Roo.data.Field(o[i]));
8177 f.getField = function(name){
8178 return p.fields.get(name);
8183 Roo.data.Record.AUTO_ID = 1000;
8184 Roo.data.Record.EDIT = 'edit';
8185 Roo.data.Record.REJECT = 'reject';
8186 Roo.data.Record.COMMIT = 'commit';
8188 Roo.data.Record.prototype = {
8190 * Readonly flag - true if this record has been modified.
8199 join : function(store){
8204 * Set the named field to the specified value.
8205 * @param {String} name The name of the field to set.
8206 * @param {Object} value The value to set the field to.
8208 set : function(name, value){
8209 if(this.data[name] == value){
8216 if(typeof this.modified[name] == 'undefined'){
8217 this.modified[name] = this.data[name];
8219 this.data[name] = value;
8220 if(!this.editing && this.store){
8221 this.store.afterEdit(this);
8226 * Get the value of the named field.
8227 * @param {String} name The name of the field to get the value of.
8228 * @return {Object} The value of the field.
8230 get : function(name){
8231 return this.data[name];
8235 beginEdit : function(){
8236 this.editing = true;
8241 cancelEdit : function(){
8242 this.editing = false;
8243 delete this.modified;
8247 endEdit : function(){
8248 this.editing = false;
8249 if(this.dirty && this.store){
8250 this.store.afterEdit(this);
8255 * Usually called by the {@link Roo.data.Store} which owns the Record.
8256 * Rejects all changes made to the Record since either creation, or the last commit operation.
8257 * Modified fields are reverted to their original values.
8259 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8260 * of reject operations.
8262 reject : function(){
8263 var m = this.modified;
8265 if(typeof m[n] != "function"){
8266 this.data[n] = m[n];
8270 delete this.modified;
8271 this.editing = false;
8273 this.store.afterReject(this);
8278 * Usually called by the {@link Roo.data.Store} which owns the Record.
8279 * Commits all changes made to the Record since either creation, or the last commit operation.
8281 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8282 * of commit operations.
8284 commit : function(){
8286 delete this.modified;
8287 this.editing = false;
8289 this.store.afterCommit(this);
8294 hasError : function(){
8295 return this.error != null;
8299 clearError : function(){
8304 * Creates a copy of this record.
8305 * @param {String} id (optional) A new record id if you don't want to use this record's id
8308 copy : function(newId) {
8309 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8313 * Ext JS Library 1.1.1
8314 * Copyright(c) 2006-2007, Ext JS, LLC.
8316 * Originally Released Under LGPL - original licence link has changed is not relivant.
8319 * <script type="text/javascript">
8325 * @class Roo.data.Store
8326 * @extends Roo.util.Observable
8327 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8328 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8330 * 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
8331 * has no knowledge of the format of the data returned by the Proxy.<br>
8333 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8334 * instances from the data object. These records are cached and made available through accessor functions.
8336 * Creates a new Store.
8337 * @param {Object} config A config object containing the objects needed for the Store to access data,
8338 * and read the data into Records.
8340 Roo.data.Store = function(config){
8341 this.data = new Roo.util.MixedCollection(false);
8342 this.data.getKey = function(o){
8345 this.baseParams = {};
8352 "multisort" : "_multisort"
8355 if(config && config.data){
8356 this.inlineData = config.data;
8360 Roo.apply(this, config);
8362 if(this.reader){ // reader passed
8363 this.reader = Roo.factory(this.reader, Roo.data);
8364 this.reader.xmodule = this.xmodule || false;
8365 if(!this.recordType){
8366 this.recordType = this.reader.recordType;
8368 if(this.reader.onMetaChange){
8369 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8373 if(this.recordType){
8374 this.fields = this.recordType.prototype.fields;
8380 * @event datachanged
8381 * Fires when the data cache has changed, and a widget which is using this Store
8382 * as a Record cache should refresh its view.
8383 * @param {Store} this
8388 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8389 * @param {Store} this
8390 * @param {Object} meta The JSON metadata
8395 * Fires when Records have been added to the Store
8396 * @param {Store} this
8397 * @param {Roo.data.Record[]} records The array of Records added
8398 * @param {Number} index The index at which the record(s) were added
8403 * Fires when a Record has been removed from the Store
8404 * @param {Store} this
8405 * @param {Roo.data.Record} record The Record that was removed
8406 * @param {Number} index The index at which the record was removed
8411 * Fires when a Record has been updated
8412 * @param {Store} this
8413 * @param {Roo.data.Record} record The Record that was updated
8414 * @param {String} operation The update operation being performed. Value may be one of:
8416 Roo.data.Record.EDIT
8417 Roo.data.Record.REJECT
8418 Roo.data.Record.COMMIT
8424 * Fires when the data cache has been cleared.
8425 * @param {Store} this
8430 * Fires before a request is made for a new data object. If the beforeload handler returns false
8431 * the load action will be canceled.
8432 * @param {Store} this
8433 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8437 * @event beforeloadadd
8438 * Fires after a new set of Records has been loaded.
8439 * @param {Store} this
8440 * @param {Roo.data.Record[]} records The Records that were loaded
8441 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8443 beforeloadadd : true,
8446 * Fires after a new set of Records has been loaded, before they are added to the store.
8447 * @param {Store} this
8448 * @param {Roo.data.Record[]} records The Records that were loaded
8449 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8450 * @params {Object} return from reader
8454 * @event loadexception
8455 * Fires if an exception occurs in the Proxy during loading.
8456 * Called with the signature of the Proxy's "loadexception" event.
8457 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8460 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8461 * @param {Object} load options
8462 * @param {Object} jsonData from your request (normally this contains the Exception)
8464 loadexception : true
8468 this.proxy = Roo.factory(this.proxy, Roo.data);
8469 this.proxy.xmodule = this.xmodule || false;
8470 this.relayEvents(this.proxy, ["loadexception"]);
8472 this.sortToggle = {};
8473 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8475 Roo.data.Store.superclass.constructor.call(this);
8477 if(this.inlineData){
8478 this.loadData(this.inlineData);
8479 delete this.inlineData;
8483 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8485 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8486 * without a remote query - used by combo/forms at present.
8490 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8493 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8496 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8497 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8500 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8501 * on any HTTP request
8504 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8507 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8511 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8512 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8517 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8518 * loaded or when a record is removed. (defaults to false).
8520 pruneModifiedRecords : false,
8526 * Add Records to the Store and fires the add event.
8527 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8529 add : function(records){
8530 records = [].concat(records);
8531 for(var i = 0, len = records.length; i < len; i++){
8532 records[i].join(this);
8534 var index = this.data.length;
8535 this.data.addAll(records);
8536 this.fireEvent("add", this, records, index);
8540 * Remove a Record from the Store and fires the remove event.
8541 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8543 remove : function(record){
8544 var index = this.data.indexOf(record);
8545 this.data.removeAt(index);
8546 if(this.pruneModifiedRecords){
8547 this.modified.remove(record);
8549 this.fireEvent("remove", this, record, index);
8553 * Remove all Records from the Store and fires the clear event.
8555 removeAll : function(){
8557 if(this.pruneModifiedRecords){
8560 this.fireEvent("clear", this);
8564 * Inserts Records to the Store at the given index and fires the add event.
8565 * @param {Number} index The start index at which to insert the passed Records.
8566 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8568 insert : function(index, records){
8569 records = [].concat(records);
8570 for(var i = 0, len = records.length; i < len; i++){
8571 this.data.insert(index, records[i]);
8572 records[i].join(this);
8574 this.fireEvent("add", this, records, index);
8578 * Get the index within the cache of the passed Record.
8579 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8580 * @return {Number} The index of the passed Record. Returns -1 if not found.
8582 indexOf : function(record){
8583 return this.data.indexOf(record);
8587 * Get the index within the cache of the Record with the passed id.
8588 * @param {String} id The id of the Record to find.
8589 * @return {Number} The index of the Record. Returns -1 if not found.
8591 indexOfId : function(id){
8592 return this.data.indexOfKey(id);
8596 * Get the Record with the specified id.
8597 * @param {String} id The id of the Record to find.
8598 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8600 getById : function(id){
8601 return this.data.key(id);
8605 * Get the Record at the specified index.
8606 * @param {Number} index The index of the Record to find.
8607 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8609 getAt : function(index){
8610 return this.data.itemAt(index);
8614 * Returns a range of Records between specified indices.
8615 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8616 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8617 * @return {Roo.data.Record[]} An array of Records
8619 getRange : function(start, end){
8620 return this.data.getRange(start, end);
8624 storeOptions : function(o){
8625 o = Roo.apply({}, o);
8628 this.lastOptions = o;
8632 * Loads the Record cache from the configured Proxy using the configured Reader.
8634 * If using remote paging, then the first load call must specify the <em>start</em>
8635 * and <em>limit</em> properties in the options.params property to establish the initial
8636 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8638 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8639 * and this call will return before the new data has been loaded. Perform any post-processing
8640 * in a callback function, or in a "load" event handler.</strong>
8642 * @param {Object} options An object containing properties which control loading options:<ul>
8643 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8644 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8645 * passed the following arguments:<ul>
8646 * <li>r : Roo.data.Record[]</li>
8647 * <li>options: Options object from the load call</li>
8648 * <li>success: Boolean success indicator</li></ul></li>
8649 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8650 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8653 load : function(options){
8654 options = options || {};
8655 if(this.fireEvent("beforeload", this, options) !== false){
8656 this.storeOptions(options);
8657 var p = Roo.apply(options.params || {}, this.baseParams);
8658 // if meta was not loaded from remote source.. try requesting it.
8659 if (!this.reader.metaFromRemote) {
8662 if(this.sortInfo && this.remoteSort){
8663 var pn = this.paramNames;
8664 p[pn["sort"]] = this.sortInfo.field;
8665 p[pn["dir"]] = this.sortInfo.direction;
8667 if (this.multiSort) {
8668 var pn = this.paramNames;
8669 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8672 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8677 * Reloads the Record cache from the configured Proxy using the configured Reader and
8678 * the options from the last load operation performed.
8679 * @param {Object} options (optional) An object containing properties which may override the options
8680 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8681 * the most recently used options are reused).
8683 reload : function(options){
8684 this.load(Roo.applyIf(options||{}, this.lastOptions));
8688 // Called as a callback by the Reader during a load operation.
8689 loadRecords : function(o, options, success){
8690 if(!o || success === false){
8691 if(success !== false){
8692 this.fireEvent("load", this, [], options, o);
8694 if(options.callback){
8695 options.callback.call(options.scope || this, [], options, false);
8699 // if data returned failure - throw an exception.
8700 if (o.success === false) {
8701 // show a message if no listener is registered.
8702 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8703 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8705 // loadmask wil be hooked into this..
8706 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8709 var r = o.records, t = o.totalRecords || r.length;
8711 this.fireEvent("beforeloadadd", this, r, options, o);
8713 if(!options || options.add !== true){
8714 if(this.pruneModifiedRecords){
8717 for(var i = 0, len = r.length; i < len; i++){
8721 this.data = this.snapshot;
8722 delete this.snapshot;
8725 this.data.addAll(r);
8726 this.totalLength = t;
8728 this.fireEvent("datachanged", this);
8730 this.totalLength = Math.max(t, this.data.length+r.length);
8733 this.fireEvent("load", this, r, options, o);
8734 if(options.callback){
8735 options.callback.call(options.scope || this, r, options, true);
8741 * Loads data from a passed data block. A Reader which understands the format of the data
8742 * must have been configured in the constructor.
8743 * @param {Object} data The data block from which to read the Records. The format of the data expected
8744 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8745 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8747 loadData : function(o, append){
8748 var r = this.reader.readRecords(o);
8749 this.loadRecords(r, {add: append}, true);
8753 * Gets the number of cached records.
8755 * <em>If using paging, this may not be the total size of the dataset. If the data object
8756 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8757 * the data set size</em>
8759 getCount : function(){
8760 return this.data.length || 0;
8764 * Gets the total number of records in the dataset as returned by the server.
8766 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8767 * the dataset size</em>
8769 getTotalCount : function(){
8770 return this.totalLength || 0;
8774 * Returns the sort state of the Store as an object with two properties:
8776 field {String} The name of the field by which the Records are sorted
8777 direction {String} The sort order, "ASC" or "DESC"
8780 getSortState : function(){
8781 return this.sortInfo;
8785 applySort : function(){
8786 if(this.sortInfo && !this.remoteSort){
8787 var s = this.sortInfo, f = s.field;
8788 var st = this.fields.get(f).sortType;
8789 var fn = function(r1, r2){
8790 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8791 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8793 this.data.sort(s.direction, fn);
8794 if(this.snapshot && this.snapshot != this.data){
8795 this.snapshot.sort(s.direction, fn);
8801 * Sets the default sort column and order to be used by the next load operation.
8802 * @param {String} fieldName The name of the field to sort by.
8803 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8805 setDefaultSort : function(field, dir){
8806 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8811 * If remote sorting is used, the sort is performed on the server, and the cache is
8812 * reloaded. If local sorting is used, the cache is sorted internally.
8813 * @param {String} fieldName The name of the field to sort by.
8814 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8816 sort : function(fieldName, dir){
8817 var f = this.fields.get(fieldName);
8819 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8821 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8822 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8827 this.sortToggle[f.name] = dir;
8828 this.sortInfo = {field: f.name, direction: dir};
8829 if(!this.remoteSort){
8831 this.fireEvent("datachanged", this);
8833 this.load(this.lastOptions);
8838 * Calls the specified function for each of the Records in the cache.
8839 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8840 * Returning <em>false</em> aborts and exits the iteration.
8841 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8843 each : function(fn, scope){
8844 this.data.each(fn, scope);
8848 * Gets all records modified since the last commit. Modified records are persisted across load operations
8849 * (e.g., during paging).
8850 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8852 getModifiedRecords : function(){
8853 return this.modified;
8857 createFilterFn : function(property, value, anyMatch){
8858 if(!value.exec){ // not a regex
8859 value = String(value);
8860 if(value.length == 0){
8863 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8866 return value.test(r.data[property]);
8871 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8872 * @param {String} property A field on your records
8873 * @param {Number} start The record index to start at (defaults to 0)
8874 * @param {Number} end The last record index to include (defaults to length - 1)
8875 * @return {Number} The sum
8877 sum : function(property, start, end){
8878 var rs = this.data.items, v = 0;
8880 end = (end || end === 0) ? end : rs.length-1;
8882 for(var i = start; i <= end; i++){
8883 v += (rs[i].data[property] || 0);
8889 * Filter the records by a specified property.
8890 * @param {String} field A field on your records
8891 * @param {String/RegExp} value Either a string that the field
8892 * should start with or a RegExp to test against the field
8893 * @param {Boolean} anyMatch True to match any part not just the beginning
8895 filter : function(property, value, anyMatch){
8896 var fn = this.createFilterFn(property, value, anyMatch);
8897 return fn ? this.filterBy(fn) : this.clearFilter();
8901 * Filter by a function. The specified function will be called with each
8902 * record in this data source. If the function returns true the record is included,
8903 * otherwise it is filtered.
8904 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8905 * @param {Object} scope (optional) The scope of the function (defaults to this)
8907 filterBy : function(fn, scope){
8908 this.snapshot = this.snapshot || this.data;
8909 this.data = this.queryBy(fn, scope||this);
8910 this.fireEvent("datachanged", this);
8914 * Query the records by a specified property.
8915 * @param {String} field A field on your records
8916 * @param {String/RegExp} value Either a string that the field
8917 * should start with or a RegExp to test against the field
8918 * @param {Boolean} anyMatch True to match any part not just the beginning
8919 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8921 query : function(property, value, anyMatch){
8922 var fn = this.createFilterFn(property, value, anyMatch);
8923 return fn ? this.queryBy(fn) : this.data.clone();
8927 * Query by a function. The specified function will be called with each
8928 * record in this data source. If the function returns true the record is included
8930 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8931 * @param {Object} scope (optional) The scope of the function (defaults to this)
8932 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8934 queryBy : function(fn, scope){
8935 var data = this.snapshot || this.data;
8936 return data.filterBy(fn, scope||this);
8940 * Collects unique values for a particular dataIndex from this store.
8941 * @param {String} dataIndex The property to collect
8942 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8943 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8944 * @return {Array} An array of the unique values
8946 collect : function(dataIndex, allowNull, bypassFilter){
8947 var d = (bypassFilter === true && this.snapshot) ?
8948 this.snapshot.items : this.data.items;
8949 var v, sv, r = [], l = {};
8950 for(var i = 0, len = d.length; i < len; i++){
8951 v = d[i].data[dataIndex];
8953 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8962 * Revert to a view of the Record cache with no filtering applied.
8963 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8965 clearFilter : function(suppressEvent){
8966 if(this.snapshot && this.snapshot != this.data){
8967 this.data = this.snapshot;
8968 delete this.snapshot;
8969 if(suppressEvent !== true){
8970 this.fireEvent("datachanged", this);
8976 afterEdit : function(record){
8977 if(this.modified.indexOf(record) == -1){
8978 this.modified.push(record);
8980 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8984 afterReject : function(record){
8985 this.modified.remove(record);
8986 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8990 afterCommit : function(record){
8991 this.modified.remove(record);
8992 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8996 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8997 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8999 commitChanges : function(){
9000 var m = this.modified.slice(0);
9002 for(var i = 0, len = m.length; i < len; i++){
9008 * Cancel outstanding changes on all changed records.
9010 rejectChanges : function(){
9011 var m = this.modified.slice(0);
9013 for(var i = 0, len = m.length; i < len; i++){
9018 onMetaChange : function(meta, rtype, o){
9019 this.recordType = rtype;
9020 this.fields = rtype.prototype.fields;
9021 delete this.snapshot;
9022 this.sortInfo = meta.sortInfo || this.sortInfo;
9024 this.fireEvent('metachange', this, this.reader.meta);
9027 moveIndex : function(data, type)
9029 var index = this.indexOf(data);
9031 var newIndex = index + type;
9035 this.insert(newIndex, data);
9040 * Ext JS Library 1.1.1
9041 * Copyright(c) 2006-2007, Ext JS, LLC.
9043 * Originally Released Under LGPL - original licence link has changed is not relivant.
9046 * <script type="text/javascript">
9050 * @class Roo.data.SimpleStore
9051 * @extends Roo.data.Store
9052 * Small helper class to make creating Stores from Array data easier.
9053 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9054 * @cfg {Array} fields An array of field definition objects, or field name strings.
9055 * @cfg {Array} data The multi-dimensional array of data
9057 * @param {Object} config
9059 Roo.data.SimpleStore = function(config){
9060 Roo.data.SimpleStore.superclass.constructor.call(this, {
9062 reader: new Roo.data.ArrayReader({
9065 Roo.data.Record.create(config.fields)
9067 proxy : new Roo.data.MemoryProxy(config.data)
9071 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9073 * Ext JS Library 1.1.1
9074 * Copyright(c) 2006-2007, Ext JS, LLC.
9076 * Originally Released Under LGPL - original licence link has changed is not relivant.
9079 * <script type="text/javascript">
9084 * @extends Roo.data.Store
9085 * @class Roo.data.JsonStore
9086 * Small helper class to make creating Stores for JSON data easier. <br/>
9088 var store = new Roo.data.JsonStore({
9089 url: 'get-images.php',
9091 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9094 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9095 * JsonReader and HttpProxy (unless inline data is provided).</b>
9096 * @cfg {Array} fields An array of field definition objects, or field name strings.
9098 * @param {Object} config
9100 Roo.data.JsonStore = function(c){
9101 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9102 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9103 reader: new Roo.data.JsonReader(c, c.fields)
9106 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9108 * Ext JS Library 1.1.1
9109 * Copyright(c) 2006-2007, Ext JS, LLC.
9111 * Originally Released Under LGPL - original licence link has changed is not relivant.
9114 * <script type="text/javascript">
9118 Roo.data.Field = function(config){
9119 if(typeof config == "string"){
9120 config = {name: config};
9122 Roo.apply(this, config);
9128 var st = Roo.data.SortTypes;
9129 // named sortTypes are supported, here we look them up
9130 if(typeof this.sortType == "string"){
9131 this.sortType = st[this.sortType];
9134 // set default sortType for strings and dates
9138 this.sortType = st.asUCString;
9141 this.sortType = st.asDate;
9144 this.sortType = st.none;
9149 var stripRe = /[\$,%]/g;
9151 // prebuilt conversion function for this field, instead of
9152 // switching every time we're reading a value
9154 var cv, dateFormat = this.dateFormat;
9159 cv = function(v){ return v; };
9162 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9166 return v !== undefined && v !== null && v !== '' ?
9167 parseInt(String(v).replace(stripRe, ""), 10) : '';
9172 return v !== undefined && v !== null && v !== '' ?
9173 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9178 cv = function(v){ return v === true || v === "true" || v == 1; };
9185 if(v instanceof Date){
9189 if(dateFormat == "timestamp"){
9190 return new Date(v*1000);
9192 return Date.parseDate(v, dateFormat);
9194 var parsed = Date.parse(v);
9195 return parsed ? new Date(parsed) : null;
9204 Roo.data.Field.prototype = {
9212 * Ext JS Library 1.1.1
9213 * Copyright(c) 2006-2007, Ext JS, LLC.
9215 * Originally Released Under LGPL - original licence link has changed is not relivant.
9218 * <script type="text/javascript">
9221 // Base class for reading structured data from a data source. This class is intended to be
9222 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9225 * @class Roo.data.DataReader
9226 * Base class for reading structured data from a data source. This class is intended to be
9227 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9230 Roo.data.DataReader = function(meta, recordType){
9234 this.recordType = recordType instanceof Array ?
9235 Roo.data.Record.create(recordType) : recordType;
9238 Roo.data.DataReader.prototype = {
9240 * Create an empty record
9241 * @param {Object} data (optional) - overlay some values
9242 * @return {Roo.data.Record} record created.
9244 newRow : function(d) {
9246 this.recordType.prototype.fields.each(function(c) {
9248 case 'int' : da[c.name] = 0; break;
9249 case 'date' : da[c.name] = new Date(); break;
9250 case 'float' : da[c.name] = 0.0; break;
9251 case 'boolean' : da[c.name] = false; break;
9252 default : da[c.name] = ""; break;
9256 return new this.recordType(Roo.apply(da, d));
9261 * Ext JS Library 1.1.1
9262 * Copyright(c) 2006-2007, Ext JS, LLC.
9264 * Originally Released Under LGPL - original licence link has changed is not relivant.
9267 * <script type="text/javascript">
9271 * @class Roo.data.DataProxy
9272 * @extends Roo.data.Observable
9273 * This class is an abstract base class for implementations which provide retrieval of
9274 * unformatted data objects.<br>
9276 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9277 * (of the appropriate type which knows how to parse the data object) to provide a block of
9278 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9280 * Custom implementations must implement the load method as described in
9281 * {@link Roo.data.HttpProxy#load}.
9283 Roo.data.DataProxy = function(){
9287 * Fires before a network request is made to retrieve a data object.
9288 * @param {Object} This DataProxy object.
9289 * @param {Object} params The params parameter to the load function.
9294 * Fires before the load method's callback is called.
9295 * @param {Object} This DataProxy object.
9296 * @param {Object} o The data object.
9297 * @param {Object} arg The callback argument object passed to the load function.
9301 * @event loadexception
9302 * Fires if an Exception occurs during data retrieval.
9303 * @param {Object} This DataProxy object.
9304 * @param {Object} o The data object.
9305 * @param {Object} arg The callback argument object passed to the load function.
9306 * @param {Object} e The Exception.
9308 loadexception : true
9310 Roo.data.DataProxy.superclass.constructor.call(this);
9313 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9316 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9320 * Ext JS Library 1.1.1
9321 * Copyright(c) 2006-2007, Ext JS, LLC.
9323 * Originally Released Under LGPL - original licence link has changed is not relivant.
9326 * <script type="text/javascript">
9329 * @class Roo.data.MemoryProxy
9330 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9331 * to the Reader when its load method is called.
9333 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9335 Roo.data.MemoryProxy = function(data){
9339 Roo.data.MemoryProxy.superclass.constructor.call(this);
9343 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9345 * Load data from the requested source (in this case an in-memory
9346 * data object passed to the constructor), read the data object into
9347 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9348 * process that block using the passed callback.
9349 * @param {Object} params This parameter is not used by the MemoryProxy class.
9350 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9351 * object into a block of Roo.data.Records.
9352 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9353 * The function must be passed <ul>
9354 * <li>The Record block object</li>
9355 * <li>The "arg" argument from the load function</li>
9356 * <li>A boolean success indicator</li>
9358 * @param {Object} scope The scope in which to call the callback
9359 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9361 load : function(params, reader, callback, scope, arg){
9362 params = params || {};
9365 result = reader.readRecords(this.data);
9367 this.fireEvent("loadexception", this, arg, null, e);
9368 callback.call(scope, null, arg, false);
9371 callback.call(scope, result, arg, true);
9375 update : function(params, records){
9380 * Ext JS Library 1.1.1
9381 * Copyright(c) 2006-2007, Ext JS, LLC.
9383 * Originally Released Under LGPL - original licence link has changed is not relivant.
9386 * <script type="text/javascript">
9389 * @class Roo.data.HttpProxy
9390 * @extends Roo.data.DataProxy
9391 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9392 * configured to reference a certain URL.<br><br>
9394 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9395 * from which the running page was served.<br><br>
9397 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9399 * Be aware that to enable the browser to parse an XML document, the server must set
9400 * the Content-Type header in the HTTP response to "text/xml".
9402 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9403 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9404 * will be used to make the request.
9406 Roo.data.HttpProxy = function(conn){
9407 Roo.data.HttpProxy.superclass.constructor.call(this);
9408 // is conn a conn config or a real conn?
9410 this.useAjax = !conn || !conn.events;
9414 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9415 // thse are take from connection...
9418 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9421 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9422 * extra parameters to each request made by this object. (defaults to undefined)
9425 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9426 * to each request made by this object. (defaults to undefined)
9429 * @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)
9432 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9435 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9441 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9445 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9446 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9447 * a finer-grained basis than the DataProxy events.
9449 getConnection : function(){
9450 return this.useAjax ? Roo.Ajax : this.conn;
9454 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9455 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9456 * process that block using the passed callback.
9457 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9458 * for the request to the remote server.
9459 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9460 * object into a block of Roo.data.Records.
9461 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9462 * The function must be passed <ul>
9463 * <li>The Record block object</li>
9464 * <li>The "arg" argument from the load function</li>
9465 * <li>A boolean success indicator</li>
9467 * @param {Object} scope The scope in which to call the callback
9468 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9470 load : function(params, reader, callback, scope, arg){
9471 if(this.fireEvent("beforeload", this, params) !== false){
9473 params : params || {},
9475 callback : callback,
9480 callback : this.loadResponse,
9484 Roo.applyIf(o, this.conn);
9485 if(this.activeRequest){
9486 Roo.Ajax.abort(this.activeRequest);
9488 this.activeRequest = Roo.Ajax.request(o);
9490 this.conn.request(o);
9493 callback.call(scope||this, null, arg, false);
9498 loadResponse : function(o, success, response){
9499 delete this.activeRequest;
9501 this.fireEvent("loadexception", this, o, response);
9502 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9507 result = o.reader.read(response);
9509 this.fireEvent("loadexception", this, o, response, e);
9510 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9514 this.fireEvent("load", this, o, o.request.arg);
9515 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9519 update : function(dataSet){
9524 updateResponse : function(dataSet){
9529 * Ext JS Library 1.1.1
9530 * Copyright(c) 2006-2007, Ext JS, LLC.
9532 * Originally Released Under LGPL - original licence link has changed is not relivant.
9535 * <script type="text/javascript">
9539 * @class Roo.data.ScriptTagProxy
9540 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9541 * other than the originating domain of the running page.<br><br>
9543 * <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
9544 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9546 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9547 * source code that is used as the source inside a <script> tag.<br><br>
9549 * In order for the browser to process the returned data, the server must wrap the data object
9550 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9551 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9552 * depending on whether the callback name was passed:
9555 boolean scriptTag = false;
9556 String cb = request.getParameter("callback");
9559 response.setContentType("text/javascript");
9561 response.setContentType("application/x-json");
9563 Writer out = response.getWriter();
9565 out.write(cb + "(");
9567 out.print(dataBlock.toJsonString());
9574 * @param {Object} config A configuration object.
9576 Roo.data.ScriptTagProxy = function(config){
9577 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9578 Roo.apply(this, config);
9579 this.head = document.getElementsByTagName("head")[0];
9582 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9584 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9586 * @cfg {String} url The URL from which to request the data object.
9589 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9593 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9594 * the server the name of the callback function set up by the load call to process the returned data object.
9595 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9596 * javascript output which calls this named function passing the data object as its only parameter.
9598 callbackParam : "callback",
9600 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9601 * name to the request.
9606 * Load data from the configured URL, read the data object into
9607 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9608 * process that block using the passed callback.
9609 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9610 * for the request to the remote server.
9611 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9612 * object into a block of Roo.data.Records.
9613 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9614 * The function must be passed <ul>
9615 * <li>The Record block object</li>
9616 * <li>The "arg" argument from the load function</li>
9617 * <li>A boolean success indicator</li>
9619 * @param {Object} scope The scope in which to call the callback
9620 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9622 load : function(params, reader, callback, scope, arg){
9623 if(this.fireEvent("beforeload", this, params) !== false){
9625 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9628 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9630 url += "&_dc=" + (new Date().getTime());
9632 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9635 cb : "stcCallback"+transId,
9636 scriptId : "stcScript"+transId,
9640 callback : callback,
9646 window[trans.cb] = function(o){
9647 conn.handleResponse(o, trans);
9650 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9652 if(this.autoAbort !== false){
9656 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9658 var script = document.createElement("script");
9659 script.setAttribute("src", url);
9660 script.setAttribute("type", "text/javascript");
9661 script.setAttribute("id", trans.scriptId);
9662 this.head.appendChild(script);
9666 callback.call(scope||this, null, arg, false);
9671 isLoading : function(){
9672 return this.trans ? true : false;
9676 * Abort the current server request.
9679 if(this.isLoading()){
9680 this.destroyTrans(this.trans);
9685 destroyTrans : function(trans, isLoaded){
9686 this.head.removeChild(document.getElementById(trans.scriptId));
9687 clearTimeout(trans.timeoutId);
9689 window[trans.cb] = undefined;
9691 delete window[trans.cb];
9694 // if hasn't been loaded, wait for load to remove it to prevent script error
9695 window[trans.cb] = function(){
9696 window[trans.cb] = undefined;
9698 delete window[trans.cb];
9705 handleResponse : function(o, trans){
9707 this.destroyTrans(trans, true);
9710 result = trans.reader.readRecords(o);
9712 this.fireEvent("loadexception", this, o, trans.arg, e);
9713 trans.callback.call(trans.scope||window, null, trans.arg, false);
9716 this.fireEvent("load", this, o, trans.arg);
9717 trans.callback.call(trans.scope||window, result, trans.arg, true);
9721 handleFailure : function(trans){
9723 this.destroyTrans(trans, false);
9724 this.fireEvent("loadexception", this, null, trans.arg);
9725 trans.callback.call(trans.scope||window, null, trans.arg, false);
9729 * Ext JS Library 1.1.1
9730 * Copyright(c) 2006-2007, Ext JS, LLC.
9732 * Originally Released Under LGPL - original licence link has changed is not relivant.
9735 * <script type="text/javascript">
9739 * @class Roo.data.JsonReader
9740 * @extends Roo.data.DataReader
9741 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9742 * based on mappings in a provided Roo.data.Record constructor.
9744 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9745 * in the reply previously.
9750 var RecordDef = Roo.data.Record.create([
9751 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9752 {name: 'occupation'} // This field will use "occupation" as the mapping.
9754 var myReader = new Roo.data.JsonReader({
9755 totalProperty: "results", // The property which contains the total dataset size (optional)
9756 root: "rows", // The property which contains an Array of row objects
9757 id: "id" // The property within each row object that provides an ID for the record (optional)
9761 * This would consume a JSON file like this:
9763 { 'results': 2, 'rows': [
9764 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9765 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9768 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9769 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9770 * paged from the remote server.
9771 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9772 * @cfg {String} root name of the property which contains the Array of row objects.
9773 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9775 * Create a new JsonReader
9776 * @param {Object} meta Metadata configuration options
9777 * @param {Object} recordType Either an Array of field definition objects,
9778 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9780 Roo.data.JsonReader = function(meta, recordType){
9783 // set some defaults:
9785 totalProperty: 'total',
9786 successProperty : 'success',
9791 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9793 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9796 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9797 * Used by Store query builder to append _requestMeta to params.
9800 metaFromRemote : false,
9802 * This method is only used by a DataProxy which has retrieved data from a remote server.
9803 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9804 * @return {Object} data A data block which is used by an Roo.data.Store object as
9805 * a cache of Roo.data.Records.
9807 read : function(response){
9808 var json = response.responseText;
9810 var o = /* eval:var:o */ eval("("+json+")");
9812 throw {message: "JsonReader.read: Json object not found"};
9818 this.metaFromRemote = true;
9819 this.meta = o.metaData;
9820 this.recordType = Roo.data.Record.create(o.metaData.fields);
9821 this.onMetaChange(this.meta, this.recordType, o);
9823 return this.readRecords(o);
9826 // private function a store will implement
9827 onMetaChange : function(meta, recordType, o){
9834 simpleAccess: function(obj, subsc) {
9841 getJsonAccessor: function(){
9843 return function(expr) {
9845 return(re.test(expr))
9846 ? new Function("obj", "return obj." + expr)
9856 * Create a data block containing Roo.data.Records from an XML document.
9857 * @param {Object} o An object which contains an Array of row objects in the property specified
9858 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9859 * which contains the total size of the dataset.
9860 * @return {Object} data A data block which is used by an Roo.data.Store object as
9861 * a cache of Roo.data.Records.
9863 readRecords : function(o){
9865 * After any data loads, the raw JSON data is available for further custom processing.
9869 var s = this.meta, Record = this.recordType,
9870 f = Record.prototype.fields, fi = f.items, fl = f.length;
9872 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9874 if(s.totalProperty) {
9875 this.getTotal = this.getJsonAccessor(s.totalProperty);
9877 if(s.successProperty) {
9878 this.getSuccess = this.getJsonAccessor(s.successProperty);
9880 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9882 var g = this.getJsonAccessor(s.id);
9883 this.getId = function(rec) {
9885 return (r === undefined || r === "") ? null : r;
9888 this.getId = function(){return null;};
9891 for(var jj = 0; jj < fl; jj++){
9893 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9894 this.ef[jj] = this.getJsonAccessor(map);
9898 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9899 if(s.totalProperty){
9900 var vt = parseInt(this.getTotal(o), 10);
9905 if(s.successProperty){
9906 var vs = this.getSuccess(o);
9907 if(vs === false || vs === 'false'){
9912 for(var i = 0; i < c; i++){
9915 var id = this.getId(n);
9916 for(var j = 0; j < fl; j++){
9918 var v = this.ef[j](n);
9920 Roo.log('missing convert for ' + f.name);
9924 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9926 var record = new Record(values, id);
9928 records[i] = record;
9934 totalRecords : totalRecords
9939 * Ext JS Library 1.1.1
9940 * Copyright(c) 2006-2007, Ext JS, LLC.
9942 * Originally Released Under LGPL - original licence link has changed is not relivant.
9945 * <script type="text/javascript">
9949 * @class Roo.data.ArrayReader
9950 * @extends Roo.data.DataReader
9951 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9952 * Each element of that Array represents a row of data fields. The
9953 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9954 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9958 var RecordDef = Roo.data.Record.create([
9959 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9960 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9962 var myReader = new Roo.data.ArrayReader({
9963 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9967 * This would consume an Array like this:
9969 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9971 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9973 * Create a new JsonReader
9974 * @param {Object} meta Metadata configuration options.
9975 * @param {Object} recordType Either an Array of field definition objects
9976 * as specified to {@link Roo.data.Record#create},
9977 * or an {@link Roo.data.Record} object
9978 * created using {@link Roo.data.Record#create}.
9980 Roo.data.ArrayReader = function(meta, recordType){
9981 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9984 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9986 * Create a data block containing Roo.data.Records from an XML document.
9987 * @param {Object} o An Array of row objects which represents the dataset.
9988 * @return {Object} data A data block which is used by an Roo.data.Store object as
9989 * a cache of Roo.data.Records.
9991 readRecords : function(o){
9992 var sid = this.meta ? this.meta.id : null;
9993 var recordType = this.recordType, fields = recordType.prototype.fields;
9996 for(var i = 0; i < root.length; i++){
9999 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10000 for(var j = 0, jlen = fields.length; j < jlen; j++){
10001 var f = fields.items[j];
10002 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10003 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10005 values[f.name] = v;
10007 var record = new recordType(values, id);
10009 records[records.length] = record;
10013 totalRecords : records.length
10022 * @class Roo.bootstrap.ComboBox
10023 * @extends Roo.bootstrap.TriggerField
10024 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10025 * @cfg {Boolean} append (true|false) default false
10026 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10027 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10028 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10030 * Create a new ComboBox.
10031 * @param {Object} config Configuration options
10033 Roo.bootstrap.ComboBox = function(config){
10034 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10038 * Fires when the dropdown list is expanded
10039 * @param {Roo.bootstrap.ComboBox} combo This combo box
10044 * Fires when the dropdown list is collapsed
10045 * @param {Roo.bootstrap.ComboBox} combo This combo box
10049 * @event beforeselect
10050 * Fires before a list item is selected. Return false to cancel the selection.
10051 * @param {Roo.bootstrap.ComboBox} combo This combo box
10052 * @param {Roo.data.Record} record The data record returned from the underlying store
10053 * @param {Number} index The index of the selected item in the dropdown list
10055 'beforeselect' : true,
10058 * Fires when a list item is selected
10059 * @param {Roo.bootstrap.ComboBox} combo This combo box
10060 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10061 * @param {Number} index The index of the selected item in the dropdown list
10065 * @event beforequery
10066 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10067 * The event object passed has these properties:
10068 * @param {Roo.bootstrap.ComboBox} combo This combo box
10069 * @param {String} query The query
10070 * @param {Boolean} forceAll true to force "all" query
10071 * @param {Boolean} cancel true to cancel the query
10072 * @param {Object} e The query event object
10074 'beforequery': true,
10077 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10078 * @param {Roo.bootstrap.ComboBox} combo This combo box
10083 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10084 * @param {Roo.bootstrap.ComboBox} combo This combo box
10085 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10090 * Fires when the remove value from the combobox array
10091 * @param {Roo.bootstrap.ComboBox} combo This combo box
10098 this.tickItems = [];
10100 this.selectedIndex = -1;
10101 if(this.mode == 'local'){
10102 if(config.queryDelay === undefined){
10103 this.queryDelay = 10;
10105 if(config.minChars === undefined){
10111 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10114 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10115 * rendering into an Roo.Editor, defaults to false)
10118 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10119 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10122 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10125 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10126 * the dropdown list (defaults to undefined, with no header element)
10130 * @cfg {String/Roo.Template} tpl The template to use to render the output
10134 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10136 listWidth: undefined,
10138 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10139 * mode = 'remote' or 'text' if mode = 'local')
10141 displayField: undefined,
10143 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10144 * mode = 'remote' or 'value' if mode = 'local').
10145 * Note: use of a valueField requires the user make a selection
10146 * in order for a value to be mapped.
10148 valueField: undefined,
10152 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10153 * field's data value (defaults to the underlying DOM element's name)
10155 hiddenName: undefined,
10157 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10161 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10163 selectedClass: 'active',
10166 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10170 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10171 * anchor positions (defaults to 'tl-bl')
10173 listAlign: 'tl-bl?',
10175 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10179 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10180 * query specified by the allQuery config option (defaults to 'query')
10182 triggerAction: 'query',
10184 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10185 * (defaults to 4, does not apply if editable = false)
10189 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10190 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10194 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10195 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10199 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10200 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10204 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10205 * when editable = true (defaults to false)
10207 selectOnFocus:false,
10209 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10211 queryParam: 'query',
10213 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10214 * when mode = 'remote' (defaults to 'Loading...')
10216 loadingText: 'Loading...',
10218 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10222 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10226 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10227 * traditional select (defaults to true)
10231 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10235 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10239 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10240 * listWidth has a higher value)
10244 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10245 * allow the user to set arbitrary text into the field (defaults to false)
10247 forceSelection:false,
10249 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10250 * if typeAhead = true (defaults to 250)
10252 typeAheadDelay : 250,
10254 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10255 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10257 valueNotFoundText : undefined,
10259 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10261 blockFocus : false,
10264 * @cfg {Boolean} disableClear Disable showing of clear button.
10266 disableClear : false,
10268 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10270 alwaysQuery : false,
10273 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10287 btnPosition : 'right',
10289 // element that contains real text value.. (when hidden is used..)
10291 getAutoCreate : function()
10298 if(!this.tickable){
10299 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10304 * ComboBox with tickable selections
10307 var align = this.labelAlign || this.parentLabelAlign();
10310 cls : 'form-group roo-combobox-tickable' //input-group
10316 cls : 'tickable-buttons',
10321 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10328 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10335 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10342 Roo.each(buttons.cn, function(c){
10344 c.cls += ' btn-' + _this.size;
10347 if (_this.disabled) {
10358 cls: 'form-hidden-field'
10362 cls: 'select2-choices',
10366 cls: 'select2-search-field',
10378 cls: 'select2-container input-group select2-container-multi',
10383 cls: 'typeahead typeahead-long dropdown-menu',
10384 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10389 if (align ==='left' && this.fieldLabel.length) {
10391 Roo.log("left and has label");
10397 cls : 'control-label col-sm-' + this.labelWidth,
10398 html : this.fieldLabel
10402 cls : "col-sm-" + (12 - this.labelWidth),
10409 } else if ( this.fieldLabel.length) {
10415 //cls : 'input-group-addon',
10416 html : this.fieldLabel
10426 Roo.log(" no label && no align");
10433 ['xs','sm','md','lg'].map(function(size){
10434 if (settings[size]) {
10435 cfg.cls += ' col-' + size + '-' + settings[size];
10444 initEvents: function()
10448 throw "can not find store for combo";
10450 this.store = Roo.factory(this.store, Roo.data);
10453 this.initTickableEvnets();
10457 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10460 if(this.hiddenName){
10462 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10464 this.hiddenField.dom.value =
10465 this.hiddenValue !== undefined ? this.hiddenValue :
10466 this.value !== undefined ? this.value : '';
10468 // prevent input submission
10469 this.el.dom.removeAttribute('name');
10470 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10475 // this.el.dom.setAttribute('autocomplete', 'off');
10478 var cls = 'x-combo-list';
10479 this.list = this.el.select('ul.dropdown-menu',true).first();
10481 //this.list = new Roo.Layer({
10482 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10488 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10489 _this.list.setWidth(lw);
10492 this.list.on('mouseover', this.onViewOver, this);
10493 this.list.on('mousemove', this.onViewMove, this);
10495 this.list.on('scroll', this.onViewScroll, this);
10498 this.list.swallowEvent('mousewheel');
10499 this.assetHeight = 0;
10502 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10503 this.assetHeight += this.header.getHeight();
10506 this.innerList = this.list.createChild({cls:cls+'-inner'});
10507 this.innerList.on('mouseover', this.onViewOver, this);
10508 this.innerList.on('mousemove', this.onViewMove, this);
10509 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10511 if(this.allowBlank && !this.pageSize && !this.disableClear){
10512 this.footer = this.list.createChild({cls:cls+'-ft'});
10513 this.pageTb = new Roo.Toolbar(this.footer);
10517 this.footer = this.list.createChild({cls:cls+'-ft'});
10518 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10519 {pageSize: this.pageSize});
10523 if (this.pageTb && this.allowBlank && !this.disableClear) {
10525 this.pageTb.add(new Roo.Toolbar.Fill(), {
10526 cls: 'x-btn-icon x-btn-clear',
10528 handler: function()
10531 _this.clearValue();
10532 _this.onSelect(false, -1);
10537 this.assetHeight += this.footer.getHeight();
10542 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10545 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10546 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10548 //this.view.wrapEl.setDisplayed(false);
10549 this.view.on('click', this.onViewClick, this);
10553 this.store.on('beforeload', this.onBeforeLoad, this);
10554 this.store.on('load', this.onLoad, this);
10555 this.store.on('loadexception', this.onLoadException, this);
10557 if(this.resizable){
10558 this.resizer = new Roo.Resizable(this.list, {
10559 pinned:true, handles:'se'
10561 this.resizer.on('resize', function(r, w, h){
10562 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10563 this.listWidth = w;
10564 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10565 this.restrictHeight();
10567 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10570 if(!this.editable){
10571 this.editable = true;
10572 this.setEditable(false);
10577 if (typeof(this.events.add.listeners) != 'undefined') {
10579 this.addicon = this.wrap.createChild(
10580 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10582 this.addicon.on('click', function(e) {
10583 this.fireEvent('add', this);
10586 if (typeof(this.events.edit.listeners) != 'undefined') {
10588 this.editicon = this.wrap.createChild(
10589 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10590 if (this.addicon) {
10591 this.editicon.setStyle('margin-left', '40px');
10593 this.editicon.on('click', function(e) {
10595 // we fire even if inothing is selected..
10596 this.fireEvent('edit', this, this.lastData );
10602 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10603 "up" : function(e){
10604 this.inKeyMode = true;
10608 "down" : function(e){
10609 if(!this.isExpanded()){
10610 this.onTriggerClick();
10612 this.inKeyMode = true;
10617 "enter" : function(e){
10618 // this.onViewClick();
10622 if(this.fireEvent("specialkey", this, e)){
10623 this.onViewClick(false);
10629 "esc" : function(e){
10633 "tab" : function(e){
10636 if(this.fireEvent("specialkey", this, e)){
10637 this.onViewClick(false);
10645 doRelay : function(foo, bar, hname){
10646 if(hname == 'down' || this.scope.isExpanded()){
10647 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10656 this.queryDelay = Math.max(this.queryDelay || 10,
10657 this.mode == 'local' ? 10 : 250);
10660 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10662 if(this.typeAhead){
10663 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10665 if(this.editable !== false){
10666 this.inputEl().on("keyup", this.onKeyUp, this);
10668 if(this.forceSelection){
10669 this.inputEl().on('blur', this.doForce, this);
10673 this.choices = this.el.select('ul.select2-choices', true).first();
10674 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10678 initTickableEvnets: function()
10680 if(this.hiddenName){
10682 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10684 this.hiddenField.dom.value =
10685 this.hiddenValue !== undefined ? this.hiddenValue :
10686 this.value !== undefined ? this.value : '';
10688 // prevent input submission
10689 this.el.dom.removeAttribute('name');
10690 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10695 this.list = this.el.select('ul.dropdown-menu',true).first();
10697 this.choices = this.el.select('ul.select2-choices', true).first();
10698 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10700 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10702 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10703 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10705 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10706 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10708 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10709 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10711 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10712 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10713 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10716 this.cancelBtn.hide();
10721 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10722 _this.list.setWidth(lw);
10725 this.list.on('mouseover', this.onViewOver, this);
10726 this.list.on('mousemove', this.onViewMove, this);
10728 this.list.on('scroll', this.onViewScroll, this);
10731 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>';
10734 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10735 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10738 //this.view.wrapEl.setDisplayed(false);
10739 this.view.on('click', this.onViewClick, this);
10743 this.store.on('beforeload', this.onBeforeLoad, this);
10744 this.store.on('load', this.onLoad, this);
10745 this.store.on('loadexception', this.onLoadException, this);
10747 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10748 // "up" : function(e){
10749 // this.inKeyMode = true;
10750 // this.selectPrev();
10753 // "down" : function(e){
10754 // if(!this.isExpanded()){
10755 // this.onTriggerClick();
10757 // this.inKeyMode = true;
10758 // this.selectNext();
10762 // "enter" : function(e){
10763 //// this.onViewClick();
10765 // this.collapse();
10767 // if(this.fireEvent("specialkey", this, e)){
10768 // this.onViewClick(false);
10774 // "esc" : function(e){
10775 // this.collapse();
10778 // "tab" : function(e){
10779 // this.collapse();
10781 // if(this.fireEvent("specialkey", this, e)){
10782 // this.onViewClick(false);
10790 // doRelay : function(foo, bar, hname){
10791 // if(hname == 'down' || this.scope.isExpanded()){
10792 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10797 // forceKeyDown: true
10801 this.queryDelay = Math.max(this.queryDelay || 10,
10802 this.mode == 'local' ? 10 : 250);
10805 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10807 if(this.typeAhead){
10808 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10812 onDestroy : function(){
10814 this.view.setStore(null);
10815 this.view.el.removeAllListeners();
10816 this.view.el.remove();
10817 this.view.purgeListeners();
10820 this.list.dom.innerHTML = '';
10824 this.store.un('beforeload', this.onBeforeLoad, this);
10825 this.store.un('load', this.onLoad, this);
10826 this.store.un('loadexception', this.onLoadException, this);
10828 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10832 fireKey : function(e){
10833 if(e.isNavKeyPress() && !this.list.isVisible()){
10834 this.fireEvent("specialkey", this, e);
10839 onResize: function(w, h){
10840 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10842 // if(typeof w != 'number'){
10843 // // we do not handle it!?!?
10846 // var tw = this.trigger.getWidth();
10847 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10848 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10850 // this.inputEl().setWidth( this.adjustWidth('input', x));
10852 // //this.trigger.setStyle('left', x+'px');
10854 // if(this.list && this.listWidth === undefined){
10855 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10856 // this.list.setWidth(lw);
10857 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10865 * Allow or prevent the user from directly editing the field text. If false is passed,
10866 * the user will only be able to select from the items defined in the dropdown list. This method
10867 * is the runtime equivalent of setting the 'editable' config option at config time.
10868 * @param {Boolean} value True to allow the user to directly edit the field text
10870 setEditable : function(value){
10871 if(value == this.editable){
10874 this.editable = value;
10876 this.inputEl().dom.setAttribute('readOnly', true);
10877 this.inputEl().on('mousedown', this.onTriggerClick, this);
10878 this.inputEl().addClass('x-combo-noedit');
10880 this.inputEl().dom.setAttribute('readOnly', false);
10881 this.inputEl().un('mousedown', this.onTriggerClick, this);
10882 this.inputEl().removeClass('x-combo-noedit');
10888 onBeforeLoad : function(combo,opts){
10889 if(!this.hasFocus){
10893 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10895 this.restrictHeight();
10896 this.selectedIndex = -1;
10900 onLoad : function(){
10902 this.hasQuery = false;
10904 if(!this.hasFocus){
10908 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10909 this.loading.hide();
10912 if(this.store.getCount() > 0){
10914 this.restrictHeight();
10915 if(this.lastQuery == this.allQuery){
10916 if(this.editable && !this.tickable){
10917 this.inputEl().dom.select();
10919 if(!this.selectByValue(this.value, true) && this.autoFocus){
10920 this.select(0, true);
10923 if(this.autoFocus){
10926 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10927 this.taTask.delay(this.typeAheadDelay);
10931 this.onEmptyResults();
10937 onLoadException : function()
10939 this.hasQuery = false;
10941 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10942 this.loading.hide();
10946 Roo.log(this.store.reader.jsonData);
10947 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10949 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10955 onTypeAhead : function(){
10956 if(this.store.getCount() > 0){
10957 var r = this.store.getAt(0);
10958 var newValue = r.data[this.displayField];
10959 var len = newValue.length;
10960 var selStart = this.getRawValue().length;
10962 if(selStart != len){
10963 this.setRawValue(newValue);
10964 this.selectText(selStart, newValue.length);
10970 onSelect : function(record, index){
10972 if(this.fireEvent('beforeselect', this, record, index) !== false){
10974 this.setFromData(index > -1 ? record.data : false);
10977 this.fireEvent('select', this, record, index);
10982 * Returns the currently selected field value or empty string if no value is set.
10983 * @return {String} value The selected value
10985 getValue : function(){
10988 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10991 if(this.valueField){
10992 return typeof this.value != 'undefined' ? this.value : '';
10994 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10999 * Clears any text/value currently set in the field
11001 clearValue : function(){
11002 if(this.hiddenField){
11003 this.hiddenField.dom.value = '';
11006 this.setRawValue('');
11007 this.lastSelectionText = '';
11012 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11013 * will be displayed in the field. If the value does not match the data value of an existing item,
11014 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11015 * Otherwise the field will be blank (although the value will still be set).
11016 * @param {String} value The value to match
11018 setValue : function(v){
11025 if(this.valueField){
11026 var r = this.findRecord(this.valueField, v);
11028 text = r.data[this.displayField];
11029 }else if(this.valueNotFoundText !== undefined){
11030 text = this.valueNotFoundText;
11033 this.lastSelectionText = text;
11034 if(this.hiddenField){
11035 this.hiddenField.dom.value = v;
11037 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11041 * @property {Object} the last set data for the element
11046 * Sets the value of the field based on a object which is related to the record format for the store.
11047 * @param {Object} value the value to set as. or false on reset?
11049 setFromData : function(o){
11056 var dv = ''; // display value
11057 var vv = ''; // value value..
11059 if (this.displayField) {
11060 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11062 // this is an error condition!!!
11063 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11066 if(this.valueField){
11067 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11070 if(this.hiddenField){
11071 this.hiddenField.dom.value = vv;
11073 this.lastSelectionText = dv;
11074 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11078 // no hidden field.. - we store the value in 'value', but still display
11079 // display field!!!!
11080 this.lastSelectionText = dv;
11081 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11087 reset : function(){
11088 // overridden so that last data is reset..
11089 this.setValue(this.originalValue);
11090 this.clearInvalid();
11091 this.lastData = false;
11093 this.view.clearSelections();
11097 findRecord : function(prop, value){
11099 if(this.store.getCount() > 0){
11100 this.store.each(function(r){
11101 if(r.data[prop] == value){
11111 getName: function()
11113 // returns hidden if it's set..
11114 if (!this.rendered) {return ''};
11115 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11119 onViewMove : function(e, t){
11120 this.inKeyMode = false;
11124 onViewOver : function(e, t){
11125 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11128 var item = this.view.findItemFromChild(t);
11131 var index = this.view.indexOf(item);
11132 this.select(index, false);
11137 onViewClick : function(view, doFocus, el, e)
11139 var index = this.view.getSelectedIndexes()[0];
11141 var r = this.store.getAt(index);
11145 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11152 Roo.each(this.tickItems, function(v,k){
11154 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11155 _this.tickItems.splice(k, 1);
11165 this.tickItems.push(r.data);
11170 this.onSelect(r, index);
11172 if(doFocus !== false && !this.blockFocus){
11173 this.inputEl().focus();
11178 restrictHeight : function(){
11179 //this.innerList.dom.style.height = '';
11180 //var inner = this.innerList.dom;
11181 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11182 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11183 //this.list.beginUpdate();
11184 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11185 this.list.alignTo(this.inputEl(), this.listAlign);
11186 //this.list.endUpdate();
11190 onEmptyResults : function(){
11195 * Returns true if the dropdown list is expanded, else false.
11197 isExpanded : function(){
11198 return this.list.isVisible();
11202 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11203 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11204 * @param {String} value The data value of the item to select
11205 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11206 * selected item if it is not currently in view (defaults to true)
11207 * @return {Boolean} True if the value matched an item in the list, else false
11209 selectByValue : function(v, scrollIntoView){
11210 if(v !== undefined && v !== null){
11211 var r = this.findRecord(this.valueField || this.displayField, v);
11213 this.select(this.store.indexOf(r), scrollIntoView);
11221 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11222 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11223 * @param {Number} index The zero-based index of the list item to select
11224 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11225 * selected item if it is not currently in view (defaults to true)
11227 select : function(index, scrollIntoView){
11228 this.selectedIndex = index;
11229 this.view.select(index);
11230 if(scrollIntoView !== false){
11231 var el = this.view.getNode(index);
11233 //this.innerList.scrollChildIntoView(el, false);
11240 selectNext : function(){
11241 var ct = this.store.getCount();
11243 if(this.selectedIndex == -1){
11245 }else if(this.selectedIndex < ct-1){
11246 this.select(this.selectedIndex+1);
11252 selectPrev : function(){
11253 var ct = this.store.getCount();
11255 if(this.selectedIndex == -1){
11257 }else if(this.selectedIndex != 0){
11258 this.select(this.selectedIndex-1);
11264 onKeyUp : function(e){
11265 if(this.editable !== false && !e.isSpecialKey()){
11266 this.lastKey = e.getKey();
11267 this.dqTask.delay(this.queryDelay);
11272 validateBlur : function(){
11273 return !this.list || !this.list.isVisible();
11277 initQuery : function(){
11278 this.doQuery(this.getRawValue());
11282 doForce : function(){
11283 if(this.inputEl().dom.value.length > 0){
11284 this.inputEl().dom.value =
11285 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11291 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11292 * query allowing the query action to be canceled if needed.
11293 * @param {String} query The SQL query to execute
11294 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11295 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11296 * saved in the current store (defaults to false)
11298 doQuery : function(q, forceAll){
11300 if(q === undefined || q === null){
11305 forceAll: forceAll,
11309 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11314 forceAll = qe.forceAll;
11315 if(forceAll === true || (q.length >= this.minChars)){
11317 this.hasQuery = true;
11319 if(this.lastQuery != q || this.alwaysQuery){
11320 this.lastQuery = q;
11321 if(this.mode == 'local'){
11322 this.selectedIndex = -1;
11324 this.store.clearFilter();
11326 this.store.filter(this.displayField, q);
11330 this.store.baseParams[this.queryParam] = q;
11332 var options = {params : this.getParams(q)};
11335 options.add = true;
11336 options.params.start = this.page * this.pageSize;
11339 this.store.load(options);
11341 * this code will make the page width larger, at the beginning, the list not align correctly,
11342 * we should expand the list on onLoad
11343 * so command out it
11348 this.selectedIndex = -1;
11353 this.loadNext = false;
11357 getParams : function(q){
11359 //p[this.queryParam] = q;
11363 p.limit = this.pageSize;
11369 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11371 collapse : function(){
11372 if(!this.isExpanded()){
11376 this.hasFocus = false;
11382 this.cancelBtn.hide();
11383 this.trigger.show();
11386 Roo.get(document).un('mousedown', this.collapseIf, this);
11387 Roo.get(document).un('mousewheel', this.collapseIf, this);
11388 if (!this.editable) {
11389 Roo.get(document).un('keydown', this.listKeyPress, this);
11391 this.fireEvent('collapse', this);
11395 collapseIf : function(e){
11396 var in_combo = e.within(this.el);
11397 var in_list = e.within(this.list);
11399 if (in_combo || in_list) {
11400 //e.stopPropagation();
11405 this.onTickableFooterButtonClick(e, false, false);
11413 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11415 expand : function(){
11417 if(this.isExpanded() || !this.hasFocus){
11421 this.list.alignTo(this.inputEl(), this.listAlign);
11426 this.tickItems = Roo.apply([], this.item);
11429 this.cancelBtn.show();
11430 this.trigger.hide();
11434 Roo.get(document).on('mousedown', this.collapseIf, this);
11435 Roo.get(document).on('mousewheel', this.collapseIf, this);
11436 if (!this.editable) {
11437 Roo.get(document).on('keydown', this.listKeyPress, this);
11440 this.fireEvent('expand', this);
11444 // Implements the default empty TriggerField.onTriggerClick function
11445 onTriggerClick : function(e)
11447 Roo.log('trigger click');
11454 this.loadNext = false;
11456 if(this.isExpanded()){
11458 if (!this.blockFocus) {
11459 this.inputEl().focus();
11463 this.hasFocus = true;
11464 if(this.triggerAction == 'all') {
11465 this.doQuery(this.allQuery, true);
11467 this.doQuery(this.getRawValue());
11469 if (!this.blockFocus) {
11470 this.inputEl().focus();
11475 onTickableTriggerClick : function(e)
11482 this.loadNext = false;
11483 this.hasFocus = true;
11485 if(this.triggerAction == 'all') {
11486 this.doQuery(this.allQuery, true);
11488 this.doQuery(this.getRawValue());
11492 onSearchFieldClick : function(e)
11494 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11499 this.loadNext = false;
11500 this.hasFocus = true;
11502 if(this.triggerAction == 'all') {
11503 this.doQuery(this.allQuery, true);
11505 this.doQuery(this.getRawValue());
11509 listKeyPress : function(e)
11511 //Roo.log('listkeypress');
11512 // scroll to first matching element based on key pres..
11513 if (e.isSpecialKey()) {
11516 var k = String.fromCharCode(e.getKey()).toUpperCase();
11519 var csel = this.view.getSelectedNodes();
11520 var cselitem = false;
11522 var ix = this.view.indexOf(csel[0]);
11523 cselitem = this.store.getAt(ix);
11524 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11530 this.store.each(function(v) {
11532 // start at existing selection.
11533 if (cselitem.id == v.id) {
11539 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11540 match = this.store.indexOf(v);
11546 if (match === false) {
11547 return true; // no more action?
11550 this.view.select(match);
11551 var sn = Roo.get(this.view.getSelectedNodes()[0])
11552 //sn.scrollIntoView(sn.dom.parentNode, false);
11555 onViewScroll : function(e, t){
11557 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11561 this.hasQuery = true;
11563 this.loading = this.list.select('.loading', true).first();
11565 if(this.loading === null){
11566 this.list.createChild({
11568 cls: 'loading select2-more-results select2-active',
11569 html: 'Loading more results...'
11572 this.loading = this.list.select('.loading', true).first();
11574 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11576 this.loading.hide();
11579 this.loading.show();
11584 this.loadNext = true;
11586 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11591 addItem : function(o)
11593 var dv = ''; // display value
11595 if (this.displayField) {
11596 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11598 // this is an error condition!!!
11599 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11606 var choice = this.choices.createChild({
11608 cls: 'select2-search-choice',
11617 cls: 'select2-search-choice-close',
11622 }, this.searchField);
11624 var close = choice.select('a.select2-search-choice-close', true).first()
11626 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11634 this.inputEl().dom.value = '';
11638 onRemoveItem : function(e, _self, o)
11640 e.preventDefault();
11641 var index = this.item.indexOf(o.data) * 1;
11644 Roo.log('not this item?!');
11648 this.item.splice(index, 1);
11653 this.fireEvent('remove', this, e);
11657 syncValue : function()
11659 if(!this.item.length){
11666 Roo.each(this.item, function(i){
11667 if(_this.valueField){
11668 value.push(i[_this.valueField]);
11675 this.value = value.join(',');
11677 if(this.hiddenField){
11678 this.hiddenField.dom.value = this.value;
11682 clearItem : function()
11684 if(!this.multiple){
11690 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11697 inputEl: function ()
11700 return this.searchField;
11702 return this.el.select('input.form-control',true).first();
11706 onTickableFooterButtonClick : function(e, btn, el)
11708 e.preventDefault();
11710 if(btn && btn.name == 'cancel'){
11711 this.tickItems = Roo.apply([], this.item);
11720 Roo.each(this.tickItems, function(o){
11731 * @cfg {Boolean} grow
11735 * @cfg {Number} growMin
11739 * @cfg {Number} growMax
11749 * Ext JS Library 1.1.1
11750 * Copyright(c) 2006-2007, Ext JS, LLC.
11752 * Originally Released Under LGPL - original licence link has changed is not relivant.
11755 * <script type="text/javascript">
11760 * @extends Roo.util.Observable
11761 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11762 * This class also supports single and multi selection modes. <br>
11763 * Create a data model bound view:
11765 var store = new Roo.data.Store(...);
11767 var view = new Roo.View({
11769 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11771 singleSelect: true,
11772 selectedClass: "ydataview-selected",
11776 // listen for node click?
11777 view.on("click", function(vw, index, node, e){
11778 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11782 dataModel.load("foobar.xml");
11784 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11786 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11787 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11789 * Note: old style constructor is still suported (container, template, config)
11792 * Create a new View
11793 * @param {Object} config The config object
11796 Roo.View = function(config, depreciated_tpl, depreciated_config){
11798 this.parent = false;
11800 if (typeof(depreciated_tpl) == 'undefined') {
11801 // new way.. - universal constructor.
11802 Roo.apply(this, config);
11803 this.el = Roo.get(this.el);
11806 this.el = Roo.get(config);
11807 this.tpl = depreciated_tpl;
11808 Roo.apply(this, depreciated_config);
11810 this.wrapEl = this.el.wrap().wrap();
11811 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11814 if(typeof(this.tpl) == "string"){
11815 this.tpl = new Roo.Template(this.tpl);
11817 // support xtype ctors..
11818 this.tpl = new Roo.factory(this.tpl, Roo);
11822 this.tpl.compile();
11827 * @event beforeclick
11828 * Fires before a click is processed. Returns false to cancel the default action.
11829 * @param {Roo.View} this
11830 * @param {Number} index The index of the target node
11831 * @param {HTMLElement} node The target node
11832 * @param {Roo.EventObject} e The raw event object
11834 "beforeclick" : true,
11837 * Fires when a template node is clicked.
11838 * @param {Roo.View} this
11839 * @param {Number} index The index of the target node
11840 * @param {HTMLElement} node The target node
11841 * @param {Roo.EventObject} e The raw event object
11846 * Fires when a template node is double clicked.
11847 * @param {Roo.View} this
11848 * @param {Number} index The index of the target node
11849 * @param {HTMLElement} node The target node
11850 * @param {Roo.EventObject} e The raw event object
11854 * @event contextmenu
11855 * Fires when a template node is right clicked.
11856 * @param {Roo.View} this
11857 * @param {Number} index The index of the target node
11858 * @param {HTMLElement} node The target node
11859 * @param {Roo.EventObject} e The raw event object
11861 "contextmenu" : true,
11863 * @event selectionchange
11864 * Fires when the selected nodes change.
11865 * @param {Roo.View} this
11866 * @param {Array} selections Array of the selected nodes
11868 "selectionchange" : true,
11871 * @event beforeselect
11872 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11873 * @param {Roo.View} this
11874 * @param {HTMLElement} node The node to be selected
11875 * @param {Array} selections Array of currently selected nodes
11877 "beforeselect" : true,
11879 * @event preparedata
11880 * Fires on every row to render, to allow you to change the data.
11881 * @param {Roo.View} this
11882 * @param {Object} data to be rendered (change this)
11884 "preparedata" : true
11892 "click": this.onClick,
11893 "dblclick": this.onDblClick,
11894 "contextmenu": this.onContextMenu,
11898 this.selections = [];
11900 this.cmp = new Roo.CompositeElementLite([]);
11902 this.store = Roo.factory(this.store, Roo.data);
11903 this.setStore(this.store, true);
11906 if ( this.footer && this.footer.xtype) {
11908 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11910 this.footer.dataSource = this.store
11911 this.footer.container = fctr;
11912 this.footer = Roo.factory(this.footer, Roo);
11913 fctr.insertFirst(this.el);
11915 // this is a bit insane - as the paging toolbar seems to detach the el..
11916 // dom.parentNode.parentNode.parentNode
11917 // they get detached?
11921 Roo.View.superclass.constructor.call(this);
11926 Roo.extend(Roo.View, Roo.util.Observable, {
11929 * @cfg {Roo.data.Store} store Data store to load data from.
11934 * @cfg {String|Roo.Element} el The container element.
11939 * @cfg {String|Roo.Template} tpl The template used by this View
11943 * @cfg {String} dataName the named area of the template to use as the data area
11944 * Works with domtemplates roo-name="name"
11948 * @cfg {String} selectedClass The css class to add to selected nodes
11950 selectedClass : "x-view-selected",
11952 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11957 * @cfg {String} text to display on mask (default Loading)
11961 * @cfg {Boolean} multiSelect Allow multiple selection
11963 multiSelect : false,
11965 * @cfg {Boolean} singleSelect Allow single selection
11967 singleSelect: false,
11970 * @cfg {Boolean} toggleSelect - selecting
11972 toggleSelect : false,
11975 * @cfg {Boolean} tickable - selecting
11980 * Returns the element this view is bound to.
11981 * @return {Roo.Element}
11983 getEl : function(){
11984 return this.wrapEl;
11990 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11992 refresh : function(){
11993 Roo.log('refresh');
11996 // if we are using something like 'domtemplate', then
11997 // the what gets used is:
11998 // t.applySubtemplate(NAME, data, wrapping data..)
11999 // the outer template then get' applied with
12000 // the store 'extra data'
12001 // and the body get's added to the
12002 // roo-name="data" node?
12003 // <span class='roo-tpl-{name}'></span> ?????
12007 this.clearSelections();
12008 this.el.update("");
12010 var records = this.store.getRange();
12011 if(records.length < 1) {
12013 // is this valid?? = should it render a template??
12015 this.el.update(this.emptyText);
12019 if (this.dataName) {
12020 this.el.update(t.apply(this.store.meta)); //????
12021 el = this.el.child('.roo-tpl-' + this.dataName);
12024 for(var i = 0, len = records.length; i < len; i++){
12025 var data = this.prepareData(records[i].data, i, records[i]);
12026 this.fireEvent("preparedata", this, data, i, records[i]);
12028 var d = Roo.apply({}, data);
12031 Roo.apply(d, {'roo-id' : Roo.id()});
12035 Roo.each(this.parent.item, function(item){
12036 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12039 Roo.apply(d, {'roo-data-checked' : 'checked'});
12043 html[html.length] = Roo.util.Format.trim(
12045 t.applySubtemplate(this.dataName, d, this.store.meta) :
12052 el.update(html.join(""));
12053 this.nodes = el.dom.childNodes;
12054 this.updateIndexes(0);
12059 * Function to override to reformat the data that is sent to
12060 * the template for each node.
12061 * DEPRICATED - use the preparedata event handler.
12062 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12063 * a JSON object for an UpdateManager bound view).
12065 prepareData : function(data, index, record)
12067 this.fireEvent("preparedata", this, data, index, record);
12071 onUpdate : function(ds, record){
12072 Roo.log('on update');
12073 this.clearSelections();
12074 var index = this.store.indexOf(record);
12075 var n = this.nodes[index];
12076 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12077 n.parentNode.removeChild(n);
12078 this.updateIndexes(index, index);
12084 onAdd : function(ds, records, index)
12086 Roo.log(['on Add', ds, records, index] );
12087 this.clearSelections();
12088 if(this.nodes.length == 0){
12092 var n = this.nodes[index];
12093 for(var i = 0, len = records.length; i < len; i++){
12094 var d = this.prepareData(records[i].data, i, records[i]);
12096 this.tpl.insertBefore(n, d);
12099 this.tpl.append(this.el, d);
12102 this.updateIndexes(index);
12105 onRemove : function(ds, record, index){
12106 Roo.log('onRemove');
12107 this.clearSelections();
12108 var el = this.dataName ?
12109 this.el.child('.roo-tpl-' + this.dataName) :
12112 el.dom.removeChild(this.nodes[index]);
12113 this.updateIndexes(index);
12117 * Refresh an individual node.
12118 * @param {Number} index
12120 refreshNode : function(index){
12121 this.onUpdate(this.store, this.store.getAt(index));
12124 updateIndexes : function(startIndex, endIndex){
12125 var ns = this.nodes;
12126 startIndex = startIndex || 0;
12127 endIndex = endIndex || ns.length - 1;
12128 for(var i = startIndex; i <= endIndex; i++){
12129 ns[i].nodeIndex = i;
12134 * Changes the data store this view uses and refresh the view.
12135 * @param {Store} store
12137 setStore : function(store, initial){
12138 if(!initial && this.store){
12139 this.store.un("datachanged", this.refresh);
12140 this.store.un("add", this.onAdd);
12141 this.store.un("remove", this.onRemove);
12142 this.store.un("update", this.onUpdate);
12143 this.store.un("clear", this.refresh);
12144 this.store.un("beforeload", this.onBeforeLoad);
12145 this.store.un("load", this.onLoad);
12146 this.store.un("loadexception", this.onLoad);
12150 store.on("datachanged", this.refresh, this);
12151 store.on("add", this.onAdd, this);
12152 store.on("remove", this.onRemove, this);
12153 store.on("update", this.onUpdate, this);
12154 store.on("clear", this.refresh, this);
12155 store.on("beforeload", this.onBeforeLoad, this);
12156 store.on("load", this.onLoad, this);
12157 store.on("loadexception", this.onLoad, this);
12165 * onbeforeLoad - masks the loading area.
12168 onBeforeLoad : function(store,opts)
12170 Roo.log('onBeforeLoad');
12172 this.el.update("");
12174 this.el.mask(this.mask ? this.mask : "Loading" );
12176 onLoad : function ()
12183 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12184 * @param {HTMLElement} node
12185 * @return {HTMLElement} The template node
12187 findItemFromChild : function(node){
12188 var el = this.dataName ?
12189 this.el.child('.roo-tpl-' + this.dataName,true) :
12192 if(!node || node.parentNode == el){
12195 var p = node.parentNode;
12196 while(p && p != el){
12197 if(p.parentNode == el){
12206 onClick : function(e){
12207 var item = this.findItemFromChild(e.getTarget());
12209 var index = this.indexOf(item);
12210 if(this.onItemClick(item, index, e) !== false){
12211 this.fireEvent("click", this, index, item, e);
12214 this.clearSelections();
12219 onContextMenu : function(e){
12220 var item = this.findItemFromChild(e.getTarget());
12222 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12227 onDblClick : function(e){
12228 var item = this.findItemFromChild(e.getTarget());
12230 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12234 onItemClick : function(item, index, e)
12236 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12239 if (this.toggleSelect) {
12240 var m = this.isSelected(item) ? 'unselect' : 'select';
12243 _t[m](item, true, false);
12246 if(this.multiSelect || this.singleSelect){
12247 if(this.multiSelect && e.shiftKey && this.lastSelection){
12248 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12250 this.select(item, this.multiSelect && e.ctrlKey);
12251 this.lastSelection = item;
12254 if(!this.tickable){
12255 e.preventDefault();
12263 * Get the number of selected nodes.
12266 getSelectionCount : function(){
12267 return this.selections.length;
12271 * Get the currently selected nodes.
12272 * @return {Array} An array of HTMLElements
12274 getSelectedNodes : function(){
12275 return this.selections;
12279 * Get the indexes of the selected nodes.
12282 getSelectedIndexes : function(){
12283 var indexes = [], s = this.selections;
12284 for(var i = 0, len = s.length; i < len; i++){
12285 indexes.push(s[i].nodeIndex);
12291 * Clear all selections
12292 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12294 clearSelections : function(suppressEvent){
12295 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12296 this.cmp.elements = this.selections;
12297 this.cmp.removeClass(this.selectedClass);
12298 this.selections = [];
12299 if(!suppressEvent){
12300 this.fireEvent("selectionchange", this, this.selections);
12306 * Returns true if the passed node is selected
12307 * @param {HTMLElement/Number} node The node or node index
12308 * @return {Boolean}
12310 isSelected : function(node){
12311 var s = this.selections;
12315 node = this.getNode(node);
12316 return s.indexOf(node) !== -1;
12321 * @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
12322 * @param {Boolean} keepExisting (optional) true to keep existing selections
12323 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12325 select : function(nodeInfo, keepExisting, suppressEvent){
12326 if(nodeInfo instanceof Array){
12328 this.clearSelections(true);
12330 for(var i = 0, len = nodeInfo.length; i < len; i++){
12331 this.select(nodeInfo[i], true, true);
12335 var node = this.getNode(nodeInfo);
12336 if(!node || this.isSelected(node)){
12337 return; // already selected.
12340 this.clearSelections(true);
12342 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12343 Roo.fly(node).addClass(this.selectedClass);
12344 this.selections.push(node);
12345 if(!suppressEvent){
12346 this.fireEvent("selectionchange", this, this.selections);
12354 * @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
12355 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12356 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12358 unselect : function(nodeInfo, keepExisting, suppressEvent)
12360 if(nodeInfo instanceof Array){
12361 Roo.each(this.selections, function(s) {
12362 this.unselect(s, nodeInfo);
12366 var node = this.getNode(nodeInfo);
12367 if(!node || !this.isSelected(node)){
12368 Roo.log("not selected");
12369 return; // not selected.
12373 Roo.each(this.selections, function(s) {
12375 Roo.fly(node).removeClass(this.selectedClass);
12382 this.selections= ns;
12383 this.fireEvent("selectionchange", this, this.selections);
12387 * Gets a template node.
12388 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12389 * @return {HTMLElement} The node or null if it wasn't found
12391 getNode : function(nodeInfo){
12392 if(typeof nodeInfo == "string"){
12393 return document.getElementById(nodeInfo);
12394 }else if(typeof nodeInfo == "number"){
12395 return this.nodes[nodeInfo];
12401 * Gets a range template nodes.
12402 * @param {Number} startIndex
12403 * @param {Number} endIndex
12404 * @return {Array} An array of nodes
12406 getNodes : function(start, end){
12407 var ns = this.nodes;
12408 start = start || 0;
12409 end = typeof end == "undefined" ? ns.length - 1 : end;
12412 for(var i = start; i <= end; i++){
12416 for(var i = start; i >= end; i--){
12424 * Finds the index of the passed node
12425 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12426 * @return {Number} The index of the node or -1
12428 indexOf : function(node){
12429 node = this.getNode(node);
12430 if(typeof node.nodeIndex == "number"){
12431 return node.nodeIndex;
12433 var ns = this.nodes;
12434 for(var i = 0, len = ns.length; i < len; i++){
12445 * based on jquery fullcalendar
12449 Roo.bootstrap = Roo.bootstrap || {};
12451 * @class Roo.bootstrap.Calendar
12452 * @extends Roo.bootstrap.Component
12453 * Bootstrap Calendar class
12454 * @cfg {Boolean} loadMask (true|false) default false
12455 * @cfg {Object} header generate the user specific header of the calendar, default false
12458 * Create a new Container
12459 * @param {Object} config The config object
12464 Roo.bootstrap.Calendar = function(config){
12465 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12469 * Fires when a date is selected
12470 * @param {DatePicker} this
12471 * @param {Date} date The selected date
12475 * @event monthchange
12476 * Fires when the displayed month changes
12477 * @param {DatePicker} this
12478 * @param {Date} date The selected month
12480 'monthchange': true,
12482 * @event evententer
12483 * Fires when mouse over an event
12484 * @param {Calendar} this
12485 * @param {event} Event
12487 'evententer': true,
12489 * @event eventleave
12490 * Fires when the mouse leaves an
12491 * @param {Calendar} this
12494 'eventleave': true,
12496 * @event eventclick
12497 * Fires when the mouse click an
12498 * @param {Calendar} this
12507 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12510 * @cfg {Number} startDay
12511 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12519 getAutoCreate : function(){
12522 var fc_button = function(name, corner, style, content ) {
12523 return Roo.apply({},{
12525 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12527 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12530 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12541 style : 'width:100%',
12548 cls : 'fc-header-left',
12550 fc_button('prev', 'left', 'arrow', '‹' ),
12551 fc_button('next', 'right', 'arrow', '›' ),
12552 { tag: 'span', cls: 'fc-header-space' },
12553 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12561 cls : 'fc-header-center',
12565 cls: 'fc-header-title',
12568 html : 'month / year'
12576 cls : 'fc-header-right',
12578 /* fc_button('month', 'left', '', 'month' ),
12579 fc_button('week', '', '', 'week' ),
12580 fc_button('day', 'right', '', 'day' )
12592 header = this.header;
12595 var cal_heads = function() {
12597 // fixme - handle this.
12599 for (var i =0; i < Date.dayNames.length; i++) {
12600 var d = Date.dayNames[i];
12603 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12604 html : d.substring(0,3)
12608 ret[0].cls += ' fc-first';
12609 ret[6].cls += ' fc-last';
12612 var cal_cell = function(n) {
12615 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12620 cls: 'fc-day-number',
12624 cls: 'fc-day-content',
12628 style: 'position: relative;' // height: 17px;
12640 var cal_rows = function() {
12643 for (var r = 0; r < 6; r++) {
12650 for (var i =0; i < Date.dayNames.length; i++) {
12651 var d = Date.dayNames[i];
12652 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12655 row.cn[0].cls+=' fc-first';
12656 row.cn[0].cn[0].style = 'min-height:90px';
12657 row.cn[6].cls+=' fc-last';
12661 ret[0].cls += ' fc-first';
12662 ret[4].cls += ' fc-prev-last';
12663 ret[5].cls += ' fc-last';
12670 cls: 'fc-border-separate',
12671 style : 'width:100%',
12679 cls : 'fc-first fc-last',
12697 cls : 'fc-content',
12698 style : "position: relative;",
12701 cls : 'fc-view fc-view-month fc-grid',
12702 style : 'position: relative',
12703 unselectable : 'on',
12706 cls : 'fc-event-container',
12707 style : 'position:absolute;z-index:8;top:0;left:0;'
12725 initEvents : function()
12728 throw "can not find store for calendar";
12734 style: "text-align:center",
12738 style: "background-color:white;width:50%;margin:250 auto",
12742 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12753 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12755 var size = this.el.select('.fc-content', true).first().getSize();
12756 this.maskEl.setSize(size.width, size.height);
12757 this.maskEl.enableDisplayMode("block");
12758 if(!this.loadMask){
12759 this.maskEl.hide();
12762 this.store = Roo.factory(this.store, Roo.data);
12763 this.store.on('load', this.onLoad, this);
12764 this.store.on('beforeload', this.onBeforeLoad, this);
12768 this.cells = this.el.select('.fc-day',true);
12769 //Roo.log(this.cells);
12770 this.textNodes = this.el.query('.fc-day-number');
12771 this.cells.addClassOnOver('fc-state-hover');
12773 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12774 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12775 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12776 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12778 this.on('monthchange', this.onMonthChange, this);
12780 this.update(new Date().clearTime());
12783 resize : function() {
12784 var sz = this.el.getSize();
12786 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12787 this.el.select('.fc-day-content div',true).setHeight(34);
12792 showPrevMonth : function(e){
12793 this.update(this.activeDate.add("mo", -1));
12795 showToday : function(e){
12796 this.update(new Date().clearTime());
12799 showNextMonth : function(e){
12800 this.update(this.activeDate.add("mo", 1));
12804 showPrevYear : function(){
12805 this.update(this.activeDate.add("y", -1));
12809 showNextYear : function(){
12810 this.update(this.activeDate.add("y", 1));
12815 update : function(date)
12817 var vd = this.activeDate;
12818 this.activeDate = date;
12819 // if(vd && this.el){
12820 // var t = date.getTime();
12821 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12822 // Roo.log('using add remove');
12824 // this.fireEvent('monthchange', this, date);
12826 // this.cells.removeClass("fc-state-highlight");
12827 // this.cells.each(function(c){
12828 // if(c.dateValue == t){
12829 // c.addClass("fc-state-highlight");
12830 // setTimeout(function(){
12831 // try{c.dom.firstChild.focus();}catch(e){}
12841 var days = date.getDaysInMonth();
12843 var firstOfMonth = date.getFirstDateOfMonth();
12844 var startingPos = firstOfMonth.getDay()-this.startDay;
12846 if(startingPos < this.startDay){
12850 var pm = date.add(Date.MONTH, -1);
12851 var prevStart = pm.getDaysInMonth()-startingPos;
12853 this.cells = this.el.select('.fc-day',true);
12854 this.textNodes = this.el.query('.fc-day-number');
12855 this.cells.addClassOnOver('fc-state-hover');
12857 var cells = this.cells.elements;
12858 var textEls = this.textNodes;
12860 Roo.each(cells, function(cell){
12861 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12864 days += startingPos;
12866 // convert everything to numbers so it's fast
12867 var day = 86400000;
12868 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12871 //Roo.log(prevStart);
12873 var today = new Date().clearTime().getTime();
12874 var sel = date.clearTime().getTime();
12875 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12876 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12877 var ddMatch = this.disabledDatesRE;
12878 var ddText = this.disabledDatesText;
12879 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12880 var ddaysText = this.disabledDaysText;
12881 var format = this.format;
12883 var setCellClass = function(cal, cell){
12887 //Roo.log('set Cell Class');
12889 var t = d.getTime();
12893 cell.dateValue = t;
12895 cell.className += " fc-today";
12896 cell.className += " fc-state-highlight";
12897 cell.title = cal.todayText;
12900 // disable highlight in other month..
12901 //cell.className += " fc-state-highlight";
12906 cell.className = " fc-state-disabled";
12907 cell.title = cal.minText;
12911 cell.className = " fc-state-disabled";
12912 cell.title = cal.maxText;
12916 if(ddays.indexOf(d.getDay()) != -1){
12917 cell.title = ddaysText;
12918 cell.className = " fc-state-disabled";
12921 if(ddMatch && format){
12922 var fvalue = d.dateFormat(format);
12923 if(ddMatch.test(fvalue)){
12924 cell.title = ddText.replace("%0", fvalue);
12925 cell.className = " fc-state-disabled";
12929 if (!cell.initialClassName) {
12930 cell.initialClassName = cell.dom.className;
12933 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12938 for(; i < startingPos; i++) {
12939 textEls[i].innerHTML = (++prevStart);
12940 d.setDate(d.getDate()+1);
12942 cells[i].className = "fc-past fc-other-month";
12943 setCellClass(this, cells[i]);
12948 for(; i < days; i++){
12949 intDay = i - startingPos + 1;
12950 textEls[i].innerHTML = (intDay);
12951 d.setDate(d.getDate()+1);
12953 cells[i].className = ''; // "x-date-active";
12954 setCellClass(this, cells[i]);
12958 for(; i < 42; i++) {
12959 textEls[i].innerHTML = (++extraDays);
12960 d.setDate(d.getDate()+1);
12962 cells[i].className = "fc-future fc-other-month";
12963 setCellClass(this, cells[i]);
12966 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12968 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12970 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12971 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12973 if(totalRows != 6){
12974 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12975 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12978 this.fireEvent('monthchange', this, date);
12982 if(!this.internalRender){
12983 var main = this.el.dom.firstChild;
12984 var w = main.offsetWidth;
12985 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12986 Roo.fly(main).setWidth(w);
12987 this.internalRender = true;
12988 // opera does not respect the auto grow header center column
12989 // then, after it gets a width opera refuses to recalculate
12990 // without a second pass
12991 if(Roo.isOpera && !this.secondPass){
12992 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12993 this.secondPass = true;
12994 this.update.defer(10, this, [date]);
13001 findCell : function(dt) {
13002 dt = dt.clearTime().getTime();
13004 this.cells.each(function(c){
13005 //Roo.log("check " +c.dateValue + '?=' + dt);
13006 if(c.dateValue == dt){
13016 findCells : function(ev) {
13017 var s = ev.start.clone().clearTime().getTime();
13019 var e= ev.end.clone().clearTime().getTime();
13022 this.cells.each(function(c){
13023 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13025 if(c.dateValue > e){
13028 if(c.dateValue < s){
13037 // findBestRow: function(cells)
13041 // for (var i =0 ; i < cells.length;i++) {
13042 // ret = Math.max(cells[i].rows || 0,ret);
13049 addItem : function(ev)
13051 // look for vertical location slot in
13052 var cells = this.findCells(ev);
13054 // ev.row = this.findBestRow(cells);
13056 // work out the location.
13060 for(var i =0; i < cells.length; i++) {
13062 cells[i].row = cells[0].row;
13065 cells[i].row = cells[i].row + 1;
13075 if (crow.start.getY() == cells[i].getY()) {
13077 crow.end = cells[i];
13094 cells[0].events.push(ev);
13096 this.calevents.push(ev);
13099 clearEvents: function() {
13101 if(!this.calevents){
13105 Roo.each(this.cells.elements, function(c){
13111 Roo.each(this.calevents, function(e) {
13112 Roo.each(e.els, function(el) {
13113 el.un('mouseenter' ,this.onEventEnter, this);
13114 el.un('mouseleave' ,this.onEventLeave, this);
13119 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13125 renderEvents: function()
13129 this.cells.each(function(c) {
13138 if(c.row != c.events.length){
13139 r = 4 - (4 - (c.row - c.events.length));
13142 c.events = ev.slice(0, r);
13143 c.more = ev.slice(r);
13145 if(c.more.length && c.more.length == 1){
13146 c.events.push(c.more.pop());
13149 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13153 this.cells.each(function(c) {
13155 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13158 for (var e = 0; e < c.events.length; e++){
13159 var ev = c.events[e];
13160 var rows = ev.rows;
13162 for(var i = 0; i < rows.length; i++) {
13164 // how many rows should it span..
13167 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13168 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13170 unselectable : "on",
13173 cls: 'fc-event-inner',
13177 // cls: 'fc-event-time',
13178 // html : cells.length > 1 ? '' : ev.time
13182 cls: 'fc-event-title',
13183 html : String.format('{0}', ev.title)
13190 cls: 'ui-resizable-handle ui-resizable-e',
13191 html : '  '
13198 cfg.cls += ' fc-event-start';
13200 if ((i+1) == rows.length) {
13201 cfg.cls += ' fc-event-end';
13204 var ctr = _this.el.select('.fc-event-container',true).first();
13205 var cg = ctr.createChild(cfg);
13207 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13208 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13210 var r = (c.more.length) ? 1 : 0;
13211 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13212 cg.setWidth(ebox.right - sbox.x -2);
13214 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13215 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13216 cg.on('click', _this.onEventClick, _this, ev);
13227 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13228 style : 'position: absolute',
13229 unselectable : "on",
13232 cls: 'fc-event-inner',
13236 cls: 'fc-event-title',
13244 cls: 'ui-resizable-handle ui-resizable-e',
13245 html : '  '
13251 var ctr = _this.el.select('.fc-event-container',true).first();
13252 var cg = ctr.createChild(cfg);
13254 var sbox = c.select('.fc-day-content',true).first().getBox();
13255 var ebox = c.select('.fc-day-content',true).first().getBox();
13257 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13258 cg.setWidth(ebox.right - sbox.x -2);
13260 cg.on('click', _this.onMoreEventClick, _this, c.more);
13270 onEventEnter: function (e, el,event,d) {
13271 this.fireEvent('evententer', this, el, event);
13274 onEventLeave: function (e, el,event,d) {
13275 this.fireEvent('eventleave', this, el, event);
13278 onEventClick: function (e, el,event,d) {
13279 this.fireEvent('eventclick', this, el, event);
13282 onMonthChange: function () {
13286 onMoreEventClick: function(e, el, more)
13290 this.calpopover.placement = 'right';
13291 this.calpopover.setTitle('More');
13293 this.calpopover.setContent('');
13295 var ctr = this.calpopover.el.select('.popover-content', true).first();
13297 Roo.each(more, function(m){
13299 cls : 'fc-event-hori fc-event-draggable',
13302 var cg = ctr.createChild(cfg);
13304 cg.on('click', _this.onEventClick, _this, m);
13307 this.calpopover.show(el);
13312 onLoad: function ()
13314 this.calevents = [];
13317 if(this.store.getCount() > 0){
13318 this.store.data.each(function(d){
13321 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13322 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13323 time : d.data.start_time,
13324 title : d.data.title,
13325 description : d.data.description,
13326 venue : d.data.venue
13331 this.renderEvents();
13333 if(this.calevents.length && this.loadMask){
13334 this.maskEl.hide();
13338 onBeforeLoad: function()
13340 this.clearEvents();
13342 this.maskEl.show();
13356 * @class Roo.bootstrap.Popover
13357 * @extends Roo.bootstrap.Component
13358 * Bootstrap Popover class
13359 * @cfg {String} html contents of the popover (or false to use children..)
13360 * @cfg {String} title of popover (or false to hide)
13361 * @cfg {String} placement how it is placed
13362 * @cfg {String} trigger click || hover (or false to trigger manually)
13363 * @cfg {String} over what (parent or false to trigger manually.)
13366 * Create a new Popover
13367 * @param {Object} config The config object
13370 Roo.bootstrap.Popover = function(config){
13371 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13374 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13376 title: 'Fill in a title',
13379 placement : 'right',
13380 trigger : 'hover', // hover
13384 can_build_overlaid : false,
13386 getChildContainer : function()
13388 return this.el.select('.popover-content',true).first();
13391 getAutoCreate : function(){
13392 Roo.log('make popover?');
13394 cls : 'popover roo-dynamic',
13395 style: 'display:block',
13401 cls : 'popover-inner',
13405 cls: 'popover-title',
13409 cls : 'popover-content',
13420 setTitle: function(str)
13422 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13424 setContent: function(str)
13426 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13428 // as it get's added to the bottom of the page.
13429 onRender : function(ct, position)
13431 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13433 var cfg = Roo.apply({}, this.getAutoCreate());
13437 cfg.cls += ' ' + this.cls;
13440 cfg.style = this.style;
13442 Roo.log("adding to ")
13443 this.el = Roo.get(document.body).createChild(cfg, position);
13449 initEvents : function()
13451 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13452 this.el.enableDisplayMode('block');
13454 if (this.over === false) {
13457 if (this.triggers === false) {
13460 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13461 var triggers = this.trigger ? this.trigger.split(' ') : [];
13462 Roo.each(triggers, function(trigger) {
13464 if (trigger == 'click') {
13465 on_el.on('click', this.toggle, this);
13466 } else if (trigger != 'manual') {
13467 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13468 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13470 on_el.on(eventIn ,this.enter, this);
13471 on_el.on(eventOut, this.leave, this);
13482 toggle : function () {
13483 this.hoverState == 'in' ? this.leave() : this.enter();
13486 enter : function () {
13489 clearTimeout(this.timeout);
13491 this.hoverState = 'in'
13493 if (!this.delay || !this.delay.show) {
13498 this.timeout = setTimeout(function () {
13499 if (_t.hoverState == 'in') {
13502 }, this.delay.show)
13504 leave : function() {
13505 clearTimeout(this.timeout);
13507 this.hoverState = 'out'
13509 if (!this.delay || !this.delay.hide) {
13514 this.timeout = setTimeout(function () {
13515 if (_t.hoverState == 'out') {
13518 }, this.delay.hide)
13521 show : function (on_el)
13524 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13527 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13528 if (this.html !== false) {
13529 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13531 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13532 if (!this.title.length) {
13533 this.el.select('.popover-title',true).hide();
13536 var placement = typeof this.placement == 'function' ?
13537 this.placement.call(this, this.el, on_el) :
13540 var autoToken = /\s?auto?\s?/i;
13541 var autoPlace = autoToken.test(placement);
13543 placement = placement.replace(autoToken, '') || 'top';
13547 //this.el.setXY([0,0]);
13549 this.el.dom.style.display='block';
13550 this.el.addClass(placement);
13552 //this.el.appendTo(on_el);
13554 var p = this.getPosition();
13555 var box = this.el.getBox();
13560 var align = Roo.bootstrap.Popover.alignment[placement]
13561 this.el.alignTo(on_el, align[0],align[1]);
13562 //var arrow = this.el.select('.arrow',true).first();
13563 //arrow.set(align[2],
13565 this.el.addClass('in');
13566 this.hoverState = null;
13568 if (this.el.hasClass('fade')) {
13575 this.el.setXY([0,0]);
13576 this.el.removeClass('in');
13583 Roo.bootstrap.Popover.alignment = {
13584 'left' : ['r-l', [-10,0], 'right'],
13585 'right' : ['l-r', [10,0], 'left'],
13586 'bottom' : ['t-b', [0,10], 'top'],
13587 'top' : [ 'b-t', [0,-10], 'bottom']
13598 * @class Roo.bootstrap.Progress
13599 * @extends Roo.bootstrap.Component
13600 * Bootstrap Progress class
13601 * @cfg {Boolean} striped striped of the progress bar
13602 * @cfg {Boolean} active animated of the progress bar
13606 * Create a new Progress
13607 * @param {Object} config The config object
13610 Roo.bootstrap.Progress = function(config){
13611 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13614 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13619 getAutoCreate : function(){
13627 cfg.cls += ' progress-striped';
13631 cfg.cls += ' active';
13650 * @class Roo.bootstrap.ProgressBar
13651 * @extends Roo.bootstrap.Component
13652 * Bootstrap ProgressBar class
13653 * @cfg {Number} aria_valuenow aria-value now
13654 * @cfg {Number} aria_valuemin aria-value min
13655 * @cfg {Number} aria_valuemax aria-value max
13656 * @cfg {String} label label for the progress bar
13657 * @cfg {String} panel (success | info | warning | danger )
13658 * @cfg {String} role role of the progress bar
13659 * @cfg {String} sr_only text
13663 * Create a new ProgressBar
13664 * @param {Object} config The config object
13667 Roo.bootstrap.ProgressBar = function(config){
13668 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13671 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13675 aria_valuemax : 100,
13681 getAutoCreate : function()
13686 cls: 'progress-bar',
13687 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13699 cfg.role = this.role;
13702 if(this.aria_valuenow){
13703 cfg['aria-valuenow'] = this.aria_valuenow;
13706 if(this.aria_valuemin){
13707 cfg['aria-valuemin'] = this.aria_valuemin;
13710 if(this.aria_valuemax){
13711 cfg['aria-valuemax'] = this.aria_valuemax;
13714 if(this.label && !this.sr_only){
13715 cfg.html = this.label;
13719 cfg.cls += ' progress-bar-' + this.panel;
13725 update : function(aria_valuenow)
13727 this.aria_valuenow = aria_valuenow;
13729 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13744 * @class Roo.bootstrap.TabGroup
13745 * @extends Roo.bootstrap.Column
13746 * Bootstrap Column class
13747 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13748 * @cfg {Boolean} carousel true to make the group behave like a carousel
13751 * Create a new TabGroup
13752 * @param {Object} config The config object
13755 Roo.bootstrap.TabGroup = function(config){
13756 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13758 this.navId = Roo.id();
13761 Roo.bootstrap.TabGroup.register(this);
13765 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13769 getAutoCreate : function()
13771 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13773 cfg.cls += ' tab-content';
13775 if (this.carousel) {
13776 cfg.cls += ' carousel slide';
13778 cls : 'carousel-inner'
13785 getChildContainer : function()
13787 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13791 * register a Navigation item
13792 * @param {Roo.bootstrap.NavItem} the navitem to add
13794 register : function(item)
13796 this.tabs.push( item);
13797 item.navId = this.navId; // not really needed..
13801 getActivePanel : function()
13804 Roo.each(this.tabs, function(t) {
13814 getPanelByName : function(n)
13817 Roo.each(this.tabs, function(t) {
13818 if (t.tabId == n) {
13826 indexOfPanel : function(p)
13829 Roo.each(this.tabs, function(t,i) {
13830 if (t.tabId == p.tabId) {
13838 showPanel : function (pan)
13840 if (typeof(pan) == 'number') {
13841 pan = this.tabs[pan];
13843 if (typeof(pan) == 'string') {
13844 pan = this.getPanelByName(pan);
13846 if (pan.tabId == this.getActivePanel().tabId) {
13849 var cur = this.getActivePanel();
13850 if (this.carousel) {
13851 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13852 var lr = dir == 'next' ? 'left' : 'right';
13853 pan.el.addClass(dir); // or prev
13854 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13855 cur.el.addClass(lr); // or right
13856 pan.el.addClass(lr);
13857 cur.el.on('transitionend', function() {
13858 Roo.log("trans end?");
13860 pan.el.removeClass([lr,dir]);
13861 pan.setActive(true);
13863 cur.el.removeClass([lr]);
13864 cur.setActive(false);
13867 }, this, { single: true } );
13871 cur.setActive(false);
13872 pan.setActive(true);
13875 showPanelNext : function()
13877 var i = this.indexOfPanel(this.getActivePanel());
13878 if (i > this.tabs.length) {
13881 this.showPanel(this.tabs[i+1]);
13883 showPanelPrev : function()
13885 var i = this.indexOfPanel(this.getActivePanel());
13889 this.showPanel(this.tabs[i-1]);
13900 Roo.apply(Roo.bootstrap.TabGroup, {
13904 * register a Navigation Group
13905 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13907 register : function(navgrp)
13909 this.groups[navgrp.navId] = navgrp;
13913 * fetch a Navigation Group based on the navigation ID
13914 * if one does not exist , it will get created.
13915 * @param {string} the navgroup to add
13916 * @returns {Roo.bootstrap.NavGroup} the navgroup
13918 get: function(navId) {
13919 if (typeof(this.groups[navId]) == 'undefined') {
13920 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13922 return this.groups[navId] ;
13937 * @class Roo.bootstrap.TabPanel
13938 * @extends Roo.bootstrap.Component
13939 * Bootstrap TabPanel class
13940 * @cfg {Boolean} active panel active
13941 * @cfg {String} html panel content
13942 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
13943 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13947 * Create a new TabPanel
13948 * @param {Object} config The config object
13951 Roo.bootstrap.TabPanel = function(config){
13952 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13956 * Fires when the active status changes
13957 * @param {Roo.bootstrap.TabPanel} this
13958 * @param {Boolean} state the new state
13963 this.tabId = this.tabId || Roo.id();
13967 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13974 getAutoCreate : function(){
13977 // item is needed for carousel - not sure if it has any effect otherwise
13978 cls: 'tab-pane item',
13979 html: this.html || ''
13983 cfg.cls += ' active';
13987 cfg.tabId = this.tabId;
13994 initEvents: function()
13996 Roo.log('-------- init events on tab panel ---------');
13998 var p = this.parent();
13999 this.navId = this.navId || p.navId;
14001 if (typeof(this.navId) != 'undefined') {
14002 // not really needed.. but just in case.. parent should be a NavGroup.
14003 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14004 Roo.log(['register', tg, this]);
14010 onRender : function(ct, position)
14012 // Roo.log("Call onRender: " + this.xtype);
14014 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14021 setActive: function(state)
14023 Roo.log("panel - set active " + this.tabId + "=" + state);
14025 this.active = state;
14027 this.el.removeClass('active');
14029 } else if (!this.el.hasClass('active')) {
14030 this.el.addClass('active');
14032 this.fireEvent('changed', this, state);
14049 * @class Roo.bootstrap.DateField
14050 * @extends Roo.bootstrap.Input
14051 * Bootstrap DateField class
14052 * @cfg {Number} weekStart default 0
14053 * @cfg {Number} weekStart default 0
14054 * @cfg {Number} viewMode default empty, (months|years)
14055 * @cfg {Number} minViewMode default empty, (months|years)
14056 * @cfg {Number} startDate default -Infinity
14057 * @cfg {Number} endDate default Infinity
14058 * @cfg {Boolean} todayHighlight default false
14059 * @cfg {Boolean} todayBtn default false
14060 * @cfg {Boolean} calendarWeeks default false
14061 * @cfg {Object} daysOfWeekDisabled default empty
14063 * @cfg {Boolean} keyboardNavigation default true
14064 * @cfg {String} language default en
14067 * Create a new DateField
14068 * @param {Object} config The config object
14071 Roo.bootstrap.DateField = function(config){
14072 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14076 * Fires when this field show.
14077 * @param {Roo.bootstrap.DateField} this
14078 * @param {Mixed} date The date value
14083 * Fires when this field hide.
14084 * @param {Roo.bootstrap.DateField} this
14085 * @param {Mixed} date The date value
14090 * Fires when select a date.
14091 * @param {Roo.bootstrap.DateField} this
14092 * @param {Mixed} date The date value
14098 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14101 * @cfg {String} format
14102 * The default date format string which can be overriden for localization support. The format must be
14103 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14107 * @cfg {String} altFormats
14108 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14109 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14111 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14119 todayHighlight : false,
14125 keyboardNavigation: true,
14127 calendarWeeks: false,
14129 startDate: -Infinity,
14133 daysOfWeekDisabled: [],
14137 UTCDate: function()
14139 return new Date(Date.UTC.apply(Date, arguments));
14142 UTCToday: function()
14144 var today = new Date();
14145 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14148 getDate: function() {
14149 var d = this.getUTCDate();
14150 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14153 getUTCDate: function() {
14157 setDate: function(d) {
14158 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14161 setUTCDate: function(d) {
14163 this.setValue(this.formatDate(this.date));
14166 onRender: function(ct, position)
14169 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14171 this.language = this.language || 'en';
14172 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14173 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14175 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14176 this.format = this.format || 'm/d/y';
14177 this.isInline = false;
14178 this.isInput = true;
14179 this.component = this.el.select('.add-on', true).first() || false;
14180 this.component = (this.component && this.component.length === 0) ? false : this.component;
14181 this.hasInput = this.component && this.inputEL().length;
14183 if (typeof(this.minViewMode === 'string')) {
14184 switch (this.minViewMode) {
14186 this.minViewMode = 1;
14189 this.minViewMode = 2;
14192 this.minViewMode = 0;
14197 if (typeof(this.viewMode === 'string')) {
14198 switch (this.viewMode) {
14211 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14213 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14215 this.picker().on('mousedown', this.onMousedown, this);
14216 this.picker().on('click', this.onClick, this);
14218 this.picker().addClass('datepicker-dropdown');
14220 this.startViewMode = this.viewMode;
14223 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14224 if(!this.calendarWeeks){
14229 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14230 v.attr('colspan', function(i, val){
14231 return parseInt(val) + 1;
14236 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14238 this.setStartDate(this.startDate);
14239 this.setEndDate(this.endDate);
14241 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14248 if(this.isInline) {
14253 picker : function()
14255 return this.el.select('.datepicker', true).first();
14258 fillDow: function()
14260 var dowCnt = this.weekStart;
14269 if(this.calendarWeeks){
14277 while (dowCnt < this.weekStart + 7) {
14281 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14285 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14288 fillMonths: function()
14291 var months = this.picker().select('>.datepicker-months td', true).first();
14293 months.dom.innerHTML = '';
14299 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14302 months.createChild(month);
14310 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14312 if (this.date < this.startDate) {
14313 this.viewDate = new Date(this.startDate);
14314 } else if (this.date > this.endDate) {
14315 this.viewDate = new Date(this.endDate);
14317 this.viewDate = new Date(this.date);
14325 var d = new Date(this.viewDate),
14326 year = d.getUTCFullYear(),
14327 month = d.getUTCMonth(),
14328 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14329 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14330 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14331 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14332 currentDate = this.date && this.date.valueOf(),
14333 today = this.UTCToday();
14335 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14337 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14339 // this.picker.select('>tfoot th.today').
14340 // .text(dates[this.language].today)
14341 // .toggle(this.todayBtn !== false);
14343 this.updateNavArrows();
14346 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14348 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14350 prevMonth.setUTCDate(day);
14352 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14354 var nextMonth = new Date(prevMonth);
14356 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14358 nextMonth = nextMonth.valueOf();
14360 var fillMonths = false;
14362 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14364 while(prevMonth.valueOf() < nextMonth) {
14367 if (prevMonth.getUTCDay() === this.weekStart) {
14369 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14377 if(this.calendarWeeks){
14378 // ISO 8601: First week contains first thursday.
14379 // ISO also states week starts on Monday, but we can be more abstract here.
14381 // Start of current week: based on weekstart/current date
14382 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14383 // Thursday of this week
14384 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14385 // First Thursday of year, year from thursday
14386 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14387 // Calendar week: ms between thursdays, div ms per day, div 7 days
14388 calWeek = (th - yth) / 864e5 / 7 + 1;
14390 fillMonths.cn.push({
14398 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14400 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14403 if (this.todayHighlight &&
14404 prevMonth.getUTCFullYear() == today.getFullYear() &&
14405 prevMonth.getUTCMonth() == today.getMonth() &&
14406 prevMonth.getUTCDate() == today.getDate()) {
14407 clsName += ' today';
14410 if (currentDate && prevMonth.valueOf() === currentDate) {
14411 clsName += ' active';
14414 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14415 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14416 clsName += ' disabled';
14419 fillMonths.cn.push({
14421 cls: 'day ' + clsName,
14422 html: prevMonth.getDate()
14425 prevMonth.setDate(prevMonth.getDate()+1);
14428 var currentYear = this.date && this.date.getUTCFullYear();
14429 var currentMonth = this.date && this.date.getUTCMonth();
14431 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14433 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14434 v.removeClass('active');
14436 if(currentYear === year && k === currentMonth){
14437 v.addClass('active');
14440 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14441 v.addClass('disabled');
14447 year = parseInt(year/10, 10) * 10;
14449 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14451 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14454 for (var i = -1; i < 11; i++) {
14455 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14457 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14465 showMode: function(dir)
14468 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14470 Roo.each(this.picker().select('>div',true).elements, function(v){
14471 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14474 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14479 if(this.isInline) return;
14481 this.picker().removeClass(['bottom', 'top']);
14483 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14485 * place to the top of element!
14489 this.picker().addClass('top');
14490 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14495 this.picker().addClass('bottom');
14497 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14500 parseDate : function(value)
14502 if(!value || value instanceof Date){
14505 var v = Date.parseDate(value, this.format);
14506 if (!v && this.useIso) {
14507 v = Date.parseDate(value, 'Y-m-d');
14509 if(!v && this.altFormats){
14510 if(!this.altFormatsArray){
14511 this.altFormatsArray = this.altFormats.split("|");
14513 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14514 v = Date.parseDate(value, this.altFormatsArray[i]);
14520 formatDate : function(date, fmt)
14522 return (!date || !(date instanceof Date)) ?
14523 date : date.dateFormat(fmt || this.format);
14526 onFocus : function()
14528 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14532 onBlur : function()
14534 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14536 var d = this.inputEl().getValue();
14547 this.picker().show();
14551 this.fireEvent('show', this, this.date);
14556 if(this.isInline) return;
14557 this.picker().hide();
14558 this.viewMode = this.startViewMode;
14561 this.fireEvent('hide', this, this.date);
14565 onMousedown: function(e)
14567 e.stopPropagation();
14568 e.preventDefault();
14573 Roo.bootstrap.DateField.superclass.keyup.call(this);
14577 setValue: function(v)
14579 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14581 var d = new Date(v);
14583 if(isNaN(d.getTime())){
14587 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14591 this.fireEvent('select', this, this.date);
14595 getValue: function()
14597 return this.formatDate(this.date);
14600 fireKey: function(e)
14602 if (!this.picker().isVisible()){
14603 if (e.keyCode == 27) // allow escape to hide and re-show picker
14608 var dateChanged = false,
14610 newDate, newViewDate;
14615 e.preventDefault();
14619 if (!this.keyboardNavigation) break;
14620 dir = e.keyCode == 37 ? -1 : 1;
14623 newDate = this.moveYear(this.date, dir);
14624 newViewDate = this.moveYear(this.viewDate, dir);
14625 } else if (e.shiftKey){
14626 newDate = this.moveMonth(this.date, dir);
14627 newViewDate = this.moveMonth(this.viewDate, dir);
14629 newDate = new Date(this.date);
14630 newDate.setUTCDate(this.date.getUTCDate() + dir);
14631 newViewDate = new Date(this.viewDate);
14632 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14634 if (this.dateWithinRange(newDate)){
14635 this.date = newDate;
14636 this.viewDate = newViewDate;
14637 this.setValue(this.formatDate(this.date));
14639 e.preventDefault();
14640 dateChanged = true;
14645 if (!this.keyboardNavigation) break;
14646 dir = e.keyCode == 38 ? -1 : 1;
14648 newDate = this.moveYear(this.date, dir);
14649 newViewDate = this.moveYear(this.viewDate, dir);
14650 } else if (e.shiftKey){
14651 newDate = this.moveMonth(this.date, dir);
14652 newViewDate = this.moveMonth(this.viewDate, dir);
14654 newDate = new Date(this.date);
14655 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14656 newViewDate = new Date(this.viewDate);
14657 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14659 if (this.dateWithinRange(newDate)){
14660 this.date = newDate;
14661 this.viewDate = newViewDate;
14662 this.setValue(this.formatDate(this.date));
14664 e.preventDefault();
14665 dateChanged = true;
14669 this.setValue(this.formatDate(this.date));
14671 e.preventDefault();
14674 this.setValue(this.formatDate(this.date));
14688 onClick: function(e)
14690 e.stopPropagation();
14691 e.preventDefault();
14693 var target = e.getTarget();
14695 if(target.nodeName.toLowerCase() === 'i'){
14696 target = Roo.get(target).dom.parentNode;
14699 var nodeName = target.nodeName;
14700 var className = target.className;
14701 var html = target.innerHTML;
14703 switch(nodeName.toLowerCase()) {
14705 switch(className) {
14711 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14712 switch(this.viewMode){
14714 this.viewDate = this.moveMonth(this.viewDate, dir);
14718 this.viewDate = this.moveYear(this.viewDate, dir);
14724 var date = new Date();
14725 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14727 this.setValue(this.formatDate(this.date));
14734 if (className.indexOf('disabled') === -1) {
14735 this.viewDate.setUTCDate(1);
14736 if (className.indexOf('month') !== -1) {
14737 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14739 var year = parseInt(html, 10) || 0;
14740 this.viewDate.setUTCFullYear(year);
14749 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14750 var day = parseInt(html, 10) || 1;
14751 var year = this.viewDate.getUTCFullYear(),
14752 month = this.viewDate.getUTCMonth();
14754 if (className.indexOf('old') !== -1) {
14761 } else if (className.indexOf('new') !== -1) {
14769 this.date = this.UTCDate(year, month, day,0,0,0,0);
14770 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14772 this.setValue(this.formatDate(this.date));
14779 setStartDate: function(startDate)
14781 this.startDate = startDate || -Infinity;
14782 if (this.startDate !== -Infinity) {
14783 this.startDate = this.parseDate(this.startDate);
14786 this.updateNavArrows();
14789 setEndDate: function(endDate)
14791 this.endDate = endDate || Infinity;
14792 if (this.endDate !== Infinity) {
14793 this.endDate = this.parseDate(this.endDate);
14796 this.updateNavArrows();
14799 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14801 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14802 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14803 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14805 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14806 return parseInt(d, 10);
14809 this.updateNavArrows();
14812 updateNavArrows: function()
14814 var d = new Date(this.viewDate),
14815 year = d.getUTCFullYear(),
14816 month = d.getUTCMonth();
14818 Roo.each(this.picker().select('.prev', true).elements, function(v){
14820 switch (this.viewMode) {
14823 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14829 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14836 Roo.each(this.picker().select('.next', true).elements, function(v){
14838 switch (this.viewMode) {
14841 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14847 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14855 moveMonth: function(date, dir)
14857 if (!dir) return date;
14858 var new_date = new Date(date.valueOf()),
14859 day = new_date.getUTCDate(),
14860 month = new_date.getUTCMonth(),
14861 mag = Math.abs(dir),
14863 dir = dir > 0 ? 1 : -1;
14866 // If going back one month, make sure month is not current month
14867 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14869 return new_date.getUTCMonth() == month;
14871 // If going forward one month, make sure month is as expected
14872 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14874 return new_date.getUTCMonth() != new_month;
14876 new_month = month + dir;
14877 new_date.setUTCMonth(new_month);
14878 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14879 if (new_month < 0 || new_month > 11)
14880 new_month = (new_month + 12) % 12;
14882 // For magnitudes >1, move one month at a time...
14883 for (var i=0; i<mag; i++)
14884 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14885 new_date = this.moveMonth(new_date, dir);
14886 // ...then reset the day, keeping it in the new month
14887 new_month = new_date.getUTCMonth();
14888 new_date.setUTCDate(day);
14890 return new_month != new_date.getUTCMonth();
14893 // Common date-resetting loop -- if date is beyond end of month, make it
14896 new_date.setUTCDate(--day);
14897 new_date.setUTCMonth(new_month);
14902 moveYear: function(date, dir)
14904 return this.moveMonth(date, dir*12);
14907 dateWithinRange: function(date)
14909 return date >= this.startDate && date <= this.endDate;
14915 this.picker().remove();
14920 Roo.apply(Roo.bootstrap.DateField, {
14931 html: '<i class="fa fa-arrow-left"/>'
14941 html: '<i class="fa fa-arrow-right"/>'
14983 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14984 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14985 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14986 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14987 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15000 navFnc: 'FullYear',
15005 navFnc: 'FullYear',
15010 Roo.apply(Roo.bootstrap.DateField, {
15014 cls: 'datepicker dropdown-menu',
15018 cls: 'datepicker-days',
15022 cls: 'table-condensed',
15024 Roo.bootstrap.DateField.head,
15028 Roo.bootstrap.DateField.footer
15035 cls: 'datepicker-months',
15039 cls: 'table-condensed',
15041 Roo.bootstrap.DateField.head,
15042 Roo.bootstrap.DateField.content,
15043 Roo.bootstrap.DateField.footer
15050 cls: 'datepicker-years',
15054 cls: 'table-condensed',
15056 Roo.bootstrap.DateField.head,
15057 Roo.bootstrap.DateField.content,
15058 Roo.bootstrap.DateField.footer
15077 * @class Roo.bootstrap.TimeField
15078 * @extends Roo.bootstrap.Input
15079 * Bootstrap DateField class
15083 * Create a new TimeField
15084 * @param {Object} config The config object
15087 Roo.bootstrap.TimeField = function(config){
15088 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15092 * Fires when this field show.
15093 * @param {Roo.bootstrap.DateField} this
15094 * @param {Mixed} date The date value
15099 * Fires when this field hide.
15100 * @param {Roo.bootstrap.DateField} this
15101 * @param {Mixed} date The date value
15106 * Fires when select a date.
15107 * @param {Roo.bootstrap.DateField} this
15108 * @param {Mixed} date The date value
15114 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15117 * @cfg {String} format
15118 * The default time format string which can be overriden for localization support. The format must be
15119 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15123 onRender: function(ct, position)
15126 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15128 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15130 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15132 this.pop = this.picker().select('>.datepicker-time',true).first();
15133 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15135 this.picker().on('mousedown', this.onMousedown, this);
15136 this.picker().on('click', this.onClick, this);
15138 this.picker().addClass('datepicker-dropdown');
15143 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15144 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15145 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15146 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15147 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15148 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15152 fireKey: function(e){
15153 if (!this.picker().isVisible()){
15154 if (e.keyCode == 27) // allow escape to hide and re-show picker
15159 e.preventDefault();
15167 this.onTogglePeriod();
15170 this.onIncrementMinutes();
15173 this.onDecrementMinutes();
15182 onClick: function(e) {
15183 e.stopPropagation();
15184 e.preventDefault();
15187 picker : function()
15189 return this.el.select('.datepicker', true).first();
15192 fillTime: function()
15194 var time = this.pop.select('tbody', true).first();
15196 time.dom.innerHTML = '';
15211 cls: 'hours-up glyphicon glyphicon-chevron-up'
15231 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15252 cls: 'timepicker-hour',
15267 cls: 'timepicker-minute',
15282 cls: 'btn btn-primary period',
15304 cls: 'hours-down glyphicon glyphicon-chevron-down'
15324 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15342 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15349 var hours = this.time.getHours();
15350 var minutes = this.time.getMinutes();
15363 hours = hours - 12;
15367 hours = '0' + hours;
15371 minutes = '0' + minutes;
15374 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15375 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15376 this.pop.select('button', true).first().dom.innerHTML = period;
15382 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15384 var cls = ['bottom'];
15386 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15393 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15398 this.picker().addClass(cls.join('-'));
15402 Roo.each(cls, function(c){
15404 _this.picker().setTop(_this.inputEl().getHeight());
15408 _this.picker().setTop(0 - _this.picker().getHeight());
15413 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15417 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15424 onFocus : function()
15426 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15430 onBlur : function()
15432 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15438 this.picker().show();
15443 this.fireEvent('show', this, this.date);
15448 this.picker().hide();
15451 this.fireEvent('hide', this, this.date);
15454 setTime : function()
15457 this.setValue(this.time.format(this.format));
15459 this.fireEvent('select', this, this.date);
15464 onMousedown: function(e){
15465 e.stopPropagation();
15466 e.preventDefault();
15469 onIncrementHours: function()
15471 Roo.log('onIncrementHours');
15472 this.time = this.time.add(Date.HOUR, 1);
15477 onDecrementHours: function()
15479 Roo.log('onDecrementHours');
15480 this.time = this.time.add(Date.HOUR, -1);
15484 onIncrementMinutes: function()
15486 Roo.log('onIncrementMinutes');
15487 this.time = this.time.add(Date.MINUTE, 1);
15491 onDecrementMinutes: function()
15493 Roo.log('onDecrementMinutes');
15494 this.time = this.time.add(Date.MINUTE, -1);
15498 onTogglePeriod: function()
15500 Roo.log('onTogglePeriod');
15501 this.time = this.time.add(Date.HOUR, 12);
15508 Roo.apply(Roo.bootstrap.TimeField, {
15538 cls: 'btn btn-info ok',
15550 Roo.apply(Roo.bootstrap.TimeField, {
15554 cls: 'datepicker dropdown-menu',
15558 cls: 'datepicker-time',
15562 cls: 'table-condensed',
15564 Roo.bootstrap.TimeField.content,
15565 Roo.bootstrap.TimeField.footer
15584 * @class Roo.bootstrap.CheckBox
15585 * @extends Roo.bootstrap.Input
15586 * Bootstrap CheckBox class
15588 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15589 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15590 * @cfg {String} boxLabel The text that appears beside the checkbox
15591 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15592 * @cfg {Boolean} checked initnal the element
15596 * Create a new CheckBox
15597 * @param {Object} config The config object
15600 Roo.bootstrap.CheckBox = function(config){
15601 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15606 * Fires when the element is checked or unchecked.
15607 * @param {Roo.bootstrap.CheckBox} this This input
15608 * @param {Boolean} checked The new checked value
15614 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15616 inputType: 'checkbox',
15623 getAutoCreate : function()
15625 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15631 cfg.cls = 'form-group checkbox' //input-group
15639 type : this.inputType,
15640 value : (!this.checked) ? this.valueOff : this.inputValue,
15641 cls : 'roo-checkbox', //'form-box',
15642 placeholder : this.placeholder || ''
15646 if (this.weight) { // Validity check?
15647 cfg.cls += " checkbox-" + this.weight;
15650 if (this.disabled) {
15651 input.disabled=true;
15655 input.checked = this.checked;
15659 input.name = this.name;
15663 input.cls += ' input-' + this.size;
15667 ['xs','sm','md','lg'].map(function(size){
15668 if (settings[size]) {
15669 cfg.cls += ' col-' + size + '-' + settings[size];
15675 var inputblock = input;
15680 if (this.before || this.after) {
15683 cls : 'input-group',
15687 inputblock.cn.push({
15689 cls : 'input-group-addon',
15693 inputblock.cn.push(input);
15695 inputblock.cn.push({
15697 cls : 'input-group-addon',
15704 if (align ==='left' && this.fieldLabel.length) {
15705 Roo.log("left and has label");
15711 cls : 'control-label col-md-' + this.labelWidth,
15712 html : this.fieldLabel
15716 cls : "col-md-" + (12 - this.labelWidth),
15723 } else if ( this.fieldLabel.length) {
15728 tag: this.boxLabel ? 'span' : 'label',
15730 cls: 'control-label box-input-label',
15731 //cls : 'input-group-addon',
15732 html : this.fieldLabel
15742 Roo.log(" no label && no align");
15743 cfg.cn = [ inputblock ] ;
15752 html: this.boxLabel
15764 * return the real input element.
15766 inputEl: function ()
15768 return this.el.select('input.roo-checkbox',true).first();
15773 return this.el.select('label.control-label',true).first();
15776 initEvents : function()
15778 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15780 this.inputEl().on('click', this.onClick, this);
15784 onClick : function()
15786 this.setChecked(!this.checked);
15789 setChecked : function(state,suppressEvent)
15791 this.checked = state;
15793 this.inputEl().dom.checked = state;
15795 if(suppressEvent !== true){
15796 this.fireEvent('check', this, state);
15799 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15803 setValue : function(v,suppressEvent)
15805 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15819 * @class Roo.bootstrap.Radio
15820 * @extends Roo.bootstrap.CheckBox
15821 * Bootstrap Radio class
15824 * Create a new Radio
15825 * @param {Object} config The config object
15828 Roo.bootstrap.Radio = function(config){
15829 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15833 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15835 inputType: 'radio',
15839 getAutoCreate : function()
15841 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15847 cfg.cls = 'form-group radio' //input-group
15852 type : this.inputType,
15853 value : (!this.checked) ? this.valueOff : this.inputValue,
15855 placeholder : this.placeholder || ''
15858 if (this.weight) { // Validity check?
15859 cfg.cls += " radio-" + this.weight;
15861 if (this.disabled) {
15862 input.disabled=true;
15866 input.checked = this.checked;
15870 input.name = this.name;
15874 input.cls += ' input-' + this.size;
15878 ['xs','sm','md','lg'].map(function(size){
15879 if (settings[size]) {
15880 cfg.cls += ' col-' + size + '-' + settings[size];
15884 var inputblock = input;
15886 if (this.before || this.after) {
15889 cls : 'input-group',
15893 inputblock.cn.push({
15895 cls : 'input-group-addon',
15899 inputblock.cn.push(input);
15901 inputblock.cn.push({
15903 cls : 'input-group-addon',
15910 if (align ==='left' && this.fieldLabel.length) {
15911 Roo.log("left and has label");
15917 cls : 'control-label col-md-' + this.labelWidth,
15918 html : this.fieldLabel
15922 cls : "col-md-" + (12 - this.labelWidth),
15929 } else if ( this.fieldLabel.length) {
15936 cls: 'control-label box-input-label',
15937 //cls : 'input-group-addon',
15938 html : this.fieldLabel
15948 Roo.log(" no label && no align");
15963 html: this.boxLabel
15970 inputEl: function ()
15972 return this.el.select('input.roo-radio',true).first();
15974 onClick : function()
15976 this.setChecked(true);
15979 setChecked : function(state,suppressEvent)
15982 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15983 v.dom.checked = false;
15987 this.checked = state;
15988 this.inputEl().dom.checked = state;
15990 if(suppressEvent !== true){
15991 this.fireEvent('check', this, state);
15994 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15998 getGroupValue : function()
16001 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16002 if(v.dom.checked == true){
16003 value = v.dom.value;
16011 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16012 * @return {Mixed} value The field value
16014 getValue : function(){
16015 return this.getGroupValue();
16021 //<script type="text/javascript">
16024 * Based Ext JS Library 1.1.1
16025 * Copyright(c) 2006-2007, Ext JS, LLC.
16031 * @class Roo.HtmlEditorCore
16032 * @extends Roo.Component
16033 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16035 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16038 Roo.HtmlEditorCore = function(config){
16041 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16044 * @event initialize
16045 * Fires when the editor is fully initialized (including the iframe)
16046 * @param {Roo.HtmlEditorCore} this
16051 * Fires when the editor is first receives the focus. Any insertion must wait
16052 * until after this event.
16053 * @param {Roo.HtmlEditorCore} this
16057 * @event beforesync
16058 * Fires before the textarea is updated with content from the editor iframe. Return false
16059 * to cancel the sync.
16060 * @param {Roo.HtmlEditorCore} this
16061 * @param {String} html
16065 * @event beforepush
16066 * Fires before the iframe editor is updated with content from the textarea. Return false
16067 * to cancel the push.
16068 * @param {Roo.HtmlEditorCore} this
16069 * @param {String} html
16074 * Fires when the textarea is updated with content from the editor iframe.
16075 * @param {Roo.HtmlEditorCore} this
16076 * @param {String} html
16081 * Fires when the iframe editor is updated with content from the textarea.
16082 * @param {Roo.HtmlEditorCore} this
16083 * @param {String} html
16088 * @event editorevent
16089 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16090 * @param {Roo.HtmlEditorCore} this
16098 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16102 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16108 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16113 * @cfg {Number} height (in pixels)
16117 * @cfg {Number} width (in pixels)
16122 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16125 stylesheets: false,
16130 // private properties
16131 validationEvent : false,
16133 initialized : false,
16135 sourceEditMode : false,
16136 onFocus : Roo.emptyFn,
16138 hideMode:'offsets',
16146 * Protected method that will not generally be called directly. It
16147 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16148 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16150 getDocMarkup : function(){
16153 Roo.log(this.stylesheets);
16155 // inherit styels from page...??
16156 if (this.stylesheets === false) {
16158 Roo.get(document.head).select('style').each(function(node) {
16159 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16162 Roo.get(document.head).select('link').each(function(node) {
16163 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16166 } else if (!this.stylesheets.length) {
16168 st = '<style type="text/css">' +
16169 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16172 Roo.each(this.stylesheets, function(s) {
16173 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16178 st += '<style type="text/css">' +
16179 'IMG { cursor: pointer } ' +
16183 return '<html><head>' + st +
16184 //<style type="text/css">' +
16185 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16187 ' </head><body class="roo-htmleditor-body"></body></html>';
16191 onRender : function(ct, position)
16194 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16195 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16198 this.el.dom.style.border = '0 none';
16199 this.el.dom.setAttribute('tabIndex', -1);
16200 this.el.addClass('x-hidden hide');
16204 if(Roo.isIE){ // fix IE 1px bogus margin
16205 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16209 this.frameId = Roo.id();
16213 var iframe = this.owner.wrap.createChild({
16215 cls: 'form-control', // bootstrap..
16217 name: this.frameId,
16218 frameBorder : 'no',
16219 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16224 this.iframe = iframe.dom;
16226 this.assignDocWin();
16228 this.doc.designMode = 'on';
16231 this.doc.write(this.getDocMarkup());
16235 var task = { // must defer to wait for browser to be ready
16237 //console.log("run task?" + this.doc.readyState);
16238 this.assignDocWin();
16239 if(this.doc.body || this.doc.readyState == 'complete'){
16241 this.doc.designMode="on";
16245 Roo.TaskMgr.stop(task);
16246 this.initEditor.defer(10, this);
16253 Roo.TaskMgr.start(task);
16260 onResize : function(w, h)
16262 Roo.log('resize: ' +w + ',' + h );
16263 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16267 if(typeof w == 'number'){
16269 this.iframe.style.width = w + 'px';
16271 if(typeof h == 'number'){
16273 this.iframe.style.height = h + 'px';
16275 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16282 * Toggles the editor between standard and source edit mode.
16283 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16285 toggleSourceEdit : function(sourceEditMode){
16287 this.sourceEditMode = sourceEditMode === true;
16289 if(this.sourceEditMode){
16291 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16294 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16295 //this.iframe.className = '';
16298 //this.setSize(this.owner.wrap.getSize());
16299 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16306 * Protected method that will not generally be called directly. If you need/want
16307 * custom HTML cleanup, this is the method you should override.
16308 * @param {String} html The HTML to be cleaned
16309 * return {String} The cleaned HTML
16311 cleanHtml : function(html){
16312 html = String(html);
16313 if(html.length > 5){
16314 if(Roo.isSafari){ // strip safari nonsense
16315 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16318 if(html == ' '){
16325 * HTML Editor -> Textarea
16326 * Protected method that will not generally be called directly. Syncs the contents
16327 * of the editor iframe with the textarea.
16329 syncValue : function(){
16330 if(this.initialized){
16331 var bd = (this.doc.body || this.doc.documentElement);
16332 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16333 var html = bd.innerHTML;
16335 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16336 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16338 html = '<div style="'+m[0]+'">' + html + '</div>';
16341 html = this.cleanHtml(html);
16342 // fix up the special chars.. normaly like back quotes in word...
16343 // however we do not want to do this with chinese..
16344 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16345 var cc = b.charCodeAt();
16347 (cc >= 0x4E00 && cc < 0xA000 ) ||
16348 (cc >= 0x3400 && cc < 0x4E00 ) ||
16349 (cc >= 0xf900 && cc < 0xfb00 )
16355 if(this.owner.fireEvent('beforesync', this, html) !== false){
16356 this.el.dom.value = html;
16357 this.owner.fireEvent('sync', this, html);
16363 * Protected method that will not generally be called directly. Pushes the value of the textarea
16364 * into the iframe editor.
16366 pushValue : function(){
16367 if(this.initialized){
16368 var v = this.el.dom.value.trim();
16370 // if(v.length < 1){
16374 if(this.owner.fireEvent('beforepush', this, v) !== false){
16375 var d = (this.doc.body || this.doc.documentElement);
16377 this.cleanUpPaste();
16378 this.el.dom.value = d.innerHTML;
16379 this.owner.fireEvent('push', this, v);
16385 deferFocus : function(){
16386 this.focus.defer(10, this);
16390 focus : function(){
16391 if(this.win && !this.sourceEditMode){
16398 assignDocWin: function()
16400 var iframe = this.iframe;
16403 this.doc = iframe.contentWindow.document;
16404 this.win = iframe.contentWindow;
16406 if (!Roo.get(this.frameId)) {
16409 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16410 this.win = Roo.get(this.frameId).dom.contentWindow;
16415 initEditor : function(){
16416 //console.log("INIT EDITOR");
16417 this.assignDocWin();
16421 this.doc.designMode="on";
16423 this.doc.write(this.getDocMarkup());
16426 var dbody = (this.doc.body || this.doc.documentElement);
16427 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16428 // this copies styles from the containing element into thsi one..
16429 // not sure why we need all of this..
16430 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16432 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16433 //ss['background-attachment'] = 'fixed'; // w3c
16434 dbody.bgProperties = 'fixed'; // ie
16435 //Roo.DomHelper.applyStyles(dbody, ss);
16436 Roo.EventManager.on(this.doc, {
16437 //'mousedown': this.onEditorEvent,
16438 'mouseup': this.onEditorEvent,
16439 'dblclick': this.onEditorEvent,
16440 'click': this.onEditorEvent,
16441 'keyup': this.onEditorEvent,
16446 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16448 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16449 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16451 this.initialized = true;
16453 this.owner.fireEvent('initialize', this);
16458 onDestroy : function(){
16464 //for (var i =0; i < this.toolbars.length;i++) {
16465 // // fixme - ask toolbars for heights?
16466 // this.toolbars[i].onDestroy();
16469 //this.wrap.dom.innerHTML = '';
16470 //this.wrap.remove();
16475 onFirstFocus : function(){
16477 this.assignDocWin();
16480 this.activated = true;
16483 if(Roo.isGecko){ // prevent silly gecko errors
16485 var s = this.win.getSelection();
16486 if(!s.focusNode || s.focusNode.nodeType != 3){
16487 var r = s.getRangeAt(0);
16488 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16493 this.execCmd('useCSS', true);
16494 this.execCmd('styleWithCSS', false);
16497 this.owner.fireEvent('activate', this);
16501 adjustFont: function(btn){
16502 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16503 //if(Roo.isSafari){ // safari
16506 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16507 if(Roo.isSafari){ // safari
16508 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16509 v = (v < 10) ? 10 : v;
16510 v = (v > 48) ? 48 : v;
16511 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16516 v = Math.max(1, v+adjust);
16518 this.execCmd('FontSize', v );
16521 onEditorEvent : function(e){
16522 this.owner.fireEvent('editorevent', this, e);
16523 // this.updateToolbar();
16524 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16527 insertTag : function(tg)
16529 // could be a bit smarter... -> wrap the current selected tRoo..
16530 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16532 range = this.createRange(this.getSelection());
16533 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16534 wrappingNode.appendChild(range.extractContents());
16535 range.insertNode(wrappingNode);
16542 this.execCmd("formatblock", tg);
16546 insertText : function(txt)
16550 var range = this.createRange();
16551 range.deleteContents();
16552 //alert(Sender.getAttribute('label'));
16554 range.insertNode(this.doc.createTextNode(txt));
16560 * Executes a Midas editor command on the editor document and performs necessary focus and
16561 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16562 * @param {String} cmd The Midas command
16563 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16565 relayCmd : function(cmd, value){
16567 this.execCmd(cmd, value);
16568 this.owner.fireEvent('editorevent', this);
16569 //this.updateToolbar();
16570 this.owner.deferFocus();
16574 * Executes a Midas editor command directly on the editor document.
16575 * For visual commands, you should use {@link #relayCmd} instead.
16576 * <b>This should only be called after the editor is initialized.</b>
16577 * @param {String} cmd The Midas command
16578 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16580 execCmd : function(cmd, value){
16581 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16588 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16590 * @param {String} text | dom node..
16592 insertAtCursor : function(text)
16597 if(!this.activated){
16603 var r = this.doc.selection.createRange();
16614 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16618 // from jquery ui (MIT licenced)
16620 var win = this.win;
16622 if (win.getSelection && win.getSelection().getRangeAt) {
16623 range = win.getSelection().getRangeAt(0);
16624 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16625 range.insertNode(node);
16626 } else if (win.document.selection && win.document.selection.createRange) {
16627 // no firefox support
16628 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16629 win.document.selection.createRange().pasteHTML(txt);
16631 // no firefox support
16632 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16633 this.execCmd('InsertHTML', txt);
16642 mozKeyPress : function(e){
16644 var c = e.getCharCode(), cmd;
16647 c = String.fromCharCode(c).toLowerCase();
16661 this.cleanUpPaste.defer(100, this);
16669 e.preventDefault();
16677 fixKeys : function(){ // load time branching for fastest keydown performance
16679 return function(e){
16680 var k = e.getKey(), r;
16683 r = this.doc.selection.createRange();
16686 r.pasteHTML('    ');
16693 r = this.doc.selection.createRange();
16695 var target = r.parentElement();
16696 if(!target || target.tagName.toLowerCase() != 'li'){
16698 r.pasteHTML('<br />');
16704 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16705 this.cleanUpPaste.defer(100, this);
16711 }else if(Roo.isOpera){
16712 return function(e){
16713 var k = e.getKey();
16717 this.execCmd('InsertHTML','    ');
16720 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16721 this.cleanUpPaste.defer(100, this);
16726 }else if(Roo.isSafari){
16727 return function(e){
16728 var k = e.getKey();
16732 this.execCmd('InsertText','\t');
16736 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16737 this.cleanUpPaste.defer(100, this);
16745 getAllAncestors: function()
16747 var p = this.getSelectedNode();
16750 a.push(p); // push blank onto stack..
16751 p = this.getParentElement();
16755 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16759 a.push(this.doc.body);
16763 lastSelNode : false,
16766 getSelection : function()
16768 this.assignDocWin();
16769 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16772 getSelectedNode: function()
16774 // this may only work on Gecko!!!
16776 // should we cache this!!!!
16781 var range = this.createRange(this.getSelection()).cloneRange();
16784 var parent = range.parentElement();
16786 var testRange = range.duplicate();
16787 testRange.moveToElementText(parent);
16788 if (testRange.inRange(range)) {
16791 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16794 parent = parent.parentElement;
16799 // is ancestor a text element.
16800 var ac = range.commonAncestorContainer;
16801 if (ac.nodeType == 3) {
16802 ac = ac.parentNode;
16805 var ar = ac.childNodes;
16808 var other_nodes = [];
16809 var has_other_nodes = false;
16810 for (var i=0;i<ar.length;i++) {
16811 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16814 // fullly contained node.
16816 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16821 // probably selected..
16822 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16823 other_nodes.push(ar[i]);
16827 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16832 has_other_nodes = true;
16834 if (!nodes.length && other_nodes.length) {
16835 nodes= other_nodes;
16837 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16843 createRange: function(sel)
16845 // this has strange effects when using with
16846 // top toolbar - not sure if it's a great idea.
16847 //this.editor.contentWindow.focus();
16848 if (typeof sel != "undefined") {
16850 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16852 return this.doc.createRange();
16855 return this.doc.createRange();
16858 getParentElement: function()
16861 this.assignDocWin();
16862 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16864 var range = this.createRange(sel);
16867 var p = range.commonAncestorContainer;
16868 while (p.nodeType == 3) { // text node
16879 * Range intersection.. the hard stuff...
16883 * [ -- selected range --- ]
16887 * if end is before start or hits it. fail.
16888 * if start is after end or hits it fail.
16890 * if either hits (but other is outside. - then it's not
16896 // @see http://www.thismuchiknow.co.uk/?p=64.
16897 rangeIntersectsNode : function(range, node)
16899 var nodeRange = node.ownerDocument.createRange();
16901 nodeRange.selectNode(node);
16903 nodeRange.selectNodeContents(node);
16906 var rangeStartRange = range.cloneRange();
16907 rangeStartRange.collapse(true);
16909 var rangeEndRange = range.cloneRange();
16910 rangeEndRange.collapse(false);
16912 var nodeStartRange = nodeRange.cloneRange();
16913 nodeStartRange.collapse(true);
16915 var nodeEndRange = nodeRange.cloneRange();
16916 nodeEndRange.collapse(false);
16918 return rangeStartRange.compareBoundaryPoints(
16919 Range.START_TO_START, nodeEndRange) == -1 &&
16920 rangeEndRange.compareBoundaryPoints(
16921 Range.START_TO_START, nodeStartRange) == 1;
16925 rangeCompareNode : function(range, node)
16927 var nodeRange = node.ownerDocument.createRange();
16929 nodeRange.selectNode(node);
16931 nodeRange.selectNodeContents(node);
16935 range.collapse(true);
16937 nodeRange.collapse(true);
16939 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16940 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16942 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16944 var nodeIsBefore = ss == 1;
16945 var nodeIsAfter = ee == -1;
16947 if (nodeIsBefore && nodeIsAfter)
16949 if (!nodeIsBefore && nodeIsAfter)
16950 return 1; //right trailed.
16952 if (nodeIsBefore && !nodeIsAfter)
16953 return 2; // left trailed.
16958 // private? - in a new class?
16959 cleanUpPaste : function()
16961 // cleans up the whole document..
16962 Roo.log('cleanuppaste');
16964 this.cleanUpChildren(this.doc.body);
16965 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16966 if (clean != this.doc.body.innerHTML) {
16967 this.doc.body.innerHTML = clean;
16972 cleanWordChars : function(input) {// change the chars to hex code
16973 var he = Roo.HtmlEditorCore;
16975 var output = input;
16976 Roo.each(he.swapCodes, function(sw) {
16977 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16979 output = output.replace(swapper, sw[1]);
16986 cleanUpChildren : function (n)
16988 if (!n.childNodes.length) {
16991 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16992 this.cleanUpChild(n.childNodes[i]);
16999 cleanUpChild : function (node)
17002 //console.log(node);
17003 if (node.nodeName == "#text") {
17004 // clean up silly Windows -- stuff?
17007 if (node.nodeName == "#comment") {
17008 node.parentNode.removeChild(node);
17009 // clean up silly Windows -- stuff?
17013 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17015 node.parentNode.removeChild(node);
17020 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17022 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17023 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17025 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17026 // remove_keep_children = true;
17029 if (remove_keep_children) {
17030 this.cleanUpChildren(node);
17031 // inserts everything just before this node...
17032 while (node.childNodes.length) {
17033 var cn = node.childNodes[0];
17034 node.removeChild(cn);
17035 node.parentNode.insertBefore(cn, node);
17037 node.parentNode.removeChild(node);
17041 if (!node.attributes || !node.attributes.length) {
17042 this.cleanUpChildren(node);
17046 function cleanAttr(n,v)
17049 if (v.match(/^\./) || v.match(/^\//)) {
17052 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17055 if (v.match(/^#/)) {
17058 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17059 node.removeAttribute(n);
17063 function cleanStyle(n,v)
17065 if (v.match(/expression/)) { //XSS?? should we even bother..
17066 node.removeAttribute(n);
17069 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17070 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17073 var parts = v.split(/;/);
17076 Roo.each(parts, function(p) {
17077 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17081 var l = p.split(':').shift().replace(/\s+/g,'');
17082 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17084 if ( cblack.indexOf(l) > -1) {
17085 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17086 //node.removeAttribute(n);
17090 // only allow 'c whitelisted system attributes'
17091 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17092 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17093 //node.removeAttribute(n);
17103 if (clean.length) {
17104 node.setAttribute(n, clean.join(';'));
17106 node.removeAttribute(n);
17112 for (var i = node.attributes.length-1; i > -1 ; i--) {
17113 var a = node.attributes[i];
17116 if (a.name.toLowerCase().substr(0,2)=='on') {
17117 node.removeAttribute(a.name);
17120 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17121 node.removeAttribute(a.name);
17124 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17125 cleanAttr(a.name,a.value); // fixme..
17128 if (a.name == 'style') {
17129 cleanStyle(a.name,a.value);
17132 /// clean up MS crap..
17133 // tecnically this should be a list of valid class'es..
17136 if (a.name == 'class') {
17137 if (a.value.match(/^Mso/)) {
17138 node.className = '';
17141 if (a.value.match(/body/)) {
17142 node.className = '';
17153 this.cleanUpChildren(node);
17158 * Clean up MS wordisms...
17160 cleanWord : function(node)
17163 var cleanWordChildren = function()
17165 if (!node.childNodes.length) {
17168 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17169 _t.cleanWord(node.childNodes[i]);
17175 this.cleanWord(this.doc.body);
17178 if (node.nodeName == "#text") {
17179 // clean up silly Windows -- stuff?
17182 if (node.nodeName == "#comment") {
17183 node.parentNode.removeChild(node);
17184 // clean up silly Windows -- stuff?
17188 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17189 node.parentNode.removeChild(node);
17193 // remove - but keep children..
17194 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17195 while (node.childNodes.length) {
17196 var cn = node.childNodes[0];
17197 node.removeChild(cn);
17198 node.parentNode.insertBefore(cn, node);
17200 node.parentNode.removeChild(node);
17201 cleanWordChildren();
17205 if (node.className.length) {
17207 var cn = node.className.split(/\W+/);
17209 Roo.each(cn, function(cls) {
17210 if (cls.match(/Mso[a-zA-Z]+/)) {
17215 node.className = cna.length ? cna.join(' ') : '';
17217 node.removeAttribute("class");
17221 if (node.hasAttribute("lang")) {
17222 node.removeAttribute("lang");
17225 if (node.hasAttribute("style")) {
17227 var styles = node.getAttribute("style").split(";");
17229 Roo.each(styles, function(s) {
17230 if (!s.match(/:/)) {
17233 var kv = s.split(":");
17234 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17237 // what ever is left... we allow.
17240 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17241 if (!nstyle.length) {
17242 node.removeAttribute('style');
17246 cleanWordChildren();
17250 domToHTML : function(currentElement, depth, nopadtext) {
17252 depth = depth || 0;
17253 nopadtext = nopadtext || false;
17255 if (!currentElement) {
17256 return this.domToHTML(this.doc.body);
17259 //Roo.log(currentElement);
17261 var allText = false;
17262 var nodeName = currentElement.nodeName;
17263 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17265 if (nodeName == '#text') {
17266 return currentElement.nodeValue;
17271 if (nodeName != 'BODY') {
17274 // Prints the node tagName, such as <A>, <IMG>, etc
17277 for(i = 0; i < currentElement.attributes.length;i++) {
17279 var aname = currentElement.attributes.item(i).name;
17280 if (!currentElement.attributes.item(i).value.length) {
17283 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17286 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17295 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17298 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17303 // Traverse the tree
17305 var currentElementChild = currentElement.childNodes.item(i);
17306 var allText = true;
17307 var innerHTML = '';
17309 while (currentElementChild) {
17310 // Formatting code (indent the tree so it looks nice on the screen)
17311 var nopad = nopadtext;
17312 if (lastnode == 'SPAN') {
17316 if (currentElementChild.nodeName == '#text') {
17317 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17318 if (!nopad && toadd.length > 80) {
17319 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17321 innerHTML += toadd;
17324 currentElementChild = currentElement.childNodes.item(i);
17330 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17332 // Recursively traverse the tree structure of the child node
17333 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17334 lastnode = currentElementChild.nodeName;
17336 currentElementChild=currentElement.childNodes.item(i);
17342 // The remaining code is mostly for formatting the tree
17343 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17348 ret+= "</"+tagName+">";
17354 // hide stuff that is not compatible
17368 * @event specialkey
17372 * @cfg {String} fieldClass @hide
17375 * @cfg {String} focusClass @hide
17378 * @cfg {String} autoCreate @hide
17381 * @cfg {String} inputType @hide
17384 * @cfg {String} invalidClass @hide
17387 * @cfg {String} invalidText @hide
17390 * @cfg {String} msgFx @hide
17393 * @cfg {String} validateOnBlur @hide
17397 Roo.HtmlEditorCore.white = [
17398 'area', 'br', 'img', 'input', 'hr', 'wbr',
17400 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17401 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17402 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17403 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17404 'table', 'ul', 'xmp',
17406 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17409 'dir', 'menu', 'ol', 'ul', 'dl',
17415 Roo.HtmlEditorCore.black = [
17416 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17418 'base', 'basefont', 'bgsound', 'blink', 'body',
17419 'frame', 'frameset', 'head', 'html', 'ilayer',
17420 'iframe', 'layer', 'link', 'meta', 'object',
17421 'script', 'style' ,'title', 'xml' // clean later..
17423 Roo.HtmlEditorCore.clean = [
17424 'script', 'style', 'title', 'xml'
17426 Roo.HtmlEditorCore.remove = [
17431 Roo.HtmlEditorCore.ablack = [
17435 Roo.HtmlEditorCore.aclean = [
17436 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17440 Roo.HtmlEditorCore.pwhite= [
17441 'http', 'https', 'mailto'
17444 // white listed style attributes.
17445 Roo.HtmlEditorCore.cwhite= [
17446 // 'text-align', /// default is to allow most things..
17452 // black listed style attributes.
17453 Roo.HtmlEditorCore.cblack= [
17454 // 'font-size' -- this can be set by the project
17458 Roo.HtmlEditorCore.swapCodes =[
17477 * @class Roo.bootstrap.HtmlEditor
17478 * @extends Roo.bootstrap.TextArea
17479 * Bootstrap HtmlEditor class
17482 * Create a new HtmlEditor
17483 * @param {Object} config The config object
17486 Roo.bootstrap.HtmlEditor = function(config){
17487 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17488 if (!this.toolbars) {
17489 this.toolbars = [];
17491 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17494 * @event initialize
17495 * Fires when the editor is fully initialized (including the iframe)
17496 * @param {HtmlEditor} this
17501 * Fires when the editor is first receives the focus. Any insertion must wait
17502 * until after this event.
17503 * @param {HtmlEditor} this
17507 * @event beforesync
17508 * Fires before the textarea is updated with content from the editor iframe. Return false
17509 * to cancel the sync.
17510 * @param {HtmlEditor} this
17511 * @param {String} html
17515 * @event beforepush
17516 * Fires before the iframe editor is updated with content from the textarea. Return false
17517 * to cancel the push.
17518 * @param {HtmlEditor} this
17519 * @param {String} html
17524 * Fires when the textarea is updated with content from the editor iframe.
17525 * @param {HtmlEditor} this
17526 * @param {String} html
17531 * Fires when the iframe editor is updated with content from the textarea.
17532 * @param {HtmlEditor} this
17533 * @param {String} html
17537 * @event editmodechange
17538 * Fires when the editor switches edit modes
17539 * @param {HtmlEditor} this
17540 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17542 editmodechange: true,
17544 * @event editorevent
17545 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17546 * @param {HtmlEditor} this
17550 * @event firstfocus
17551 * Fires when on first focus - needed by toolbars..
17552 * @param {HtmlEditor} this
17557 * Auto save the htmlEditor value as a file into Events
17558 * @param {HtmlEditor} this
17562 * @event savedpreview
17563 * preview the saved version of htmlEditor
17564 * @param {HtmlEditor} this
17571 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17575 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17580 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17585 * @cfg {Number} height (in pixels)
17589 * @cfg {Number} width (in pixels)
17594 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17597 stylesheets: false,
17602 // private properties
17603 validationEvent : false,
17605 initialized : false,
17608 onFocus : Roo.emptyFn,
17610 hideMode:'offsets',
17613 tbContainer : false,
17615 toolbarContainer :function() {
17616 return this.wrap.select('.x-html-editor-tb',true).first();
17620 * Protected method that will not generally be called directly. It
17621 * is called when the editor creates its toolbar. Override this method if you need to
17622 * add custom toolbar buttons.
17623 * @param {HtmlEditor} editor
17625 createToolbar : function(){
17627 Roo.log("create toolbars");
17629 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17630 this.toolbars[0].render(this.toolbarContainer());
17634 // if (!editor.toolbars || !editor.toolbars.length) {
17635 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17638 // for (var i =0 ; i < editor.toolbars.length;i++) {
17639 // editor.toolbars[i] = Roo.factory(
17640 // typeof(editor.toolbars[i]) == 'string' ?
17641 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17642 // Roo.bootstrap.HtmlEditor);
17643 // editor.toolbars[i].init(editor);
17649 onRender : function(ct, position)
17651 // Roo.log("Call onRender: " + this.xtype);
17653 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17655 this.wrap = this.inputEl().wrap({
17656 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17659 this.editorcore.onRender(ct, position);
17661 if (this.resizable) {
17662 this.resizeEl = new Roo.Resizable(this.wrap, {
17666 minHeight : this.height,
17667 height: this.height,
17668 handles : this.resizable,
17671 resize : function(r, w, h) {
17672 _t.onResize(w,h); // -something
17678 this.createToolbar(this);
17681 if(!this.width && this.resizable){
17682 this.setSize(this.wrap.getSize());
17684 if (this.resizeEl) {
17685 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17686 // should trigger onReize..
17692 onResize : function(w, h)
17694 Roo.log('resize: ' +w + ',' + h );
17695 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17699 if(this.inputEl() ){
17700 if(typeof w == 'number'){
17701 var aw = w - this.wrap.getFrameWidth('lr');
17702 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17705 if(typeof h == 'number'){
17706 var tbh = -11; // fixme it needs to tool bar size!
17707 for (var i =0; i < this.toolbars.length;i++) {
17708 // fixme - ask toolbars for heights?
17709 tbh += this.toolbars[i].el.getHeight();
17710 //if (this.toolbars[i].footer) {
17711 // tbh += this.toolbars[i].footer.el.getHeight();
17719 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17720 ah -= 5; // knock a few pixes off for look..
17721 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17725 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17726 this.editorcore.onResize(ew,eh);
17731 * Toggles the editor between standard and source edit mode.
17732 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17734 toggleSourceEdit : function(sourceEditMode)
17736 this.editorcore.toggleSourceEdit(sourceEditMode);
17738 if(this.editorcore.sourceEditMode){
17739 Roo.log('editor - showing textarea');
17742 // Roo.log(this.syncValue());
17744 this.inputEl().removeClass(['hide', 'x-hidden']);
17745 this.inputEl().dom.removeAttribute('tabIndex');
17746 this.inputEl().focus();
17748 Roo.log('editor - hiding textarea');
17750 // Roo.log(this.pushValue());
17753 this.inputEl().addClass(['hide', 'x-hidden']);
17754 this.inputEl().dom.setAttribute('tabIndex', -1);
17755 //this.deferFocus();
17758 if(this.resizable){
17759 this.setSize(this.wrap.getSize());
17762 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17765 // private (for BoxComponent)
17766 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17768 // private (for BoxComponent)
17769 getResizeEl : function(){
17773 // private (for BoxComponent)
17774 getPositionEl : function(){
17779 initEvents : function(){
17780 this.originalValue = this.getValue();
17784 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17787 // markInvalid : Roo.emptyFn,
17789 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17792 // clearInvalid : Roo.emptyFn,
17794 setValue : function(v){
17795 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17796 this.editorcore.pushValue();
17801 deferFocus : function(){
17802 this.focus.defer(10, this);
17806 focus : function(){
17807 this.editorcore.focus();
17813 onDestroy : function(){
17819 for (var i =0; i < this.toolbars.length;i++) {
17820 // fixme - ask toolbars for heights?
17821 this.toolbars[i].onDestroy();
17824 this.wrap.dom.innerHTML = '';
17825 this.wrap.remove();
17830 onFirstFocus : function(){
17831 //Roo.log("onFirstFocus");
17832 this.editorcore.onFirstFocus();
17833 for (var i =0; i < this.toolbars.length;i++) {
17834 this.toolbars[i].onFirstFocus();
17840 syncValue : function()
17842 this.editorcore.syncValue();
17845 pushValue : function()
17847 this.editorcore.pushValue();
17851 // hide stuff that is not compatible
17865 * @event specialkey
17869 * @cfg {String} fieldClass @hide
17872 * @cfg {String} focusClass @hide
17875 * @cfg {String} autoCreate @hide
17878 * @cfg {String} inputType @hide
17881 * @cfg {String} invalidClass @hide
17884 * @cfg {String} invalidText @hide
17887 * @cfg {String} msgFx @hide
17890 * @cfg {String} validateOnBlur @hide
17899 Roo.namespace('Roo.bootstrap.htmleditor');
17901 * @class Roo.bootstrap.HtmlEditorToolbar1
17906 new Roo.bootstrap.HtmlEditor({
17909 new Roo.bootstrap.HtmlEditorToolbar1({
17910 disable : { fonts: 1 , format: 1, ..., ... , ...],
17916 * @cfg {Object} disable List of elements to disable..
17917 * @cfg {Array} btns List of additional buttons.
17921 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17924 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17927 Roo.apply(this, config);
17929 // default disabled, based on 'good practice'..
17930 this.disable = this.disable || {};
17931 Roo.applyIf(this.disable, {
17934 specialElements : true
17936 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17938 this.editor = config.editor;
17939 this.editorcore = config.editor.editorcore;
17941 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17943 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17944 // dont call parent... till later.
17946 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17951 editorcore : false,
17956 "h1","h2","h3","h4","h5","h6",
17958 "abbr", "acronym", "address", "cite", "samp", "var",
17962 onRender : function(ct, position)
17964 // Roo.log("Call onRender: " + this.xtype);
17966 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17968 this.el.dom.style.marginBottom = '0';
17970 var editorcore = this.editorcore;
17971 var editor= this.editor;
17974 var btn = function(id,cmd , toggle, handler){
17976 var event = toggle ? 'toggle' : 'click';
17981 xns: Roo.bootstrap,
17984 enableToggle:toggle !== false,
17986 pressed : toggle ? false : null,
17989 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17990 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17999 xns: Roo.bootstrap,
18000 glyphicon : 'font',
18004 xns: Roo.bootstrap,
18008 Roo.each(this.formats, function(f) {
18009 style.menu.items.push({
18011 xns: Roo.bootstrap,
18012 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18017 editorcore.insertTag(this.tagname);
18024 children.push(style);
18027 btn('bold',false,true);
18028 btn('italic',false,true);
18029 btn('align-left', 'justifyleft',true);
18030 btn('align-center', 'justifycenter',true);
18031 btn('align-right' , 'justifyright',true);
18032 btn('link', false, false, function(btn) {
18033 //Roo.log("create link?");
18034 var url = prompt(this.createLinkText, this.defaultLinkValue);
18035 if(url && url != 'http:/'+'/'){
18036 this.editorcore.relayCmd('createlink', url);
18039 btn('list','insertunorderedlist',true);
18040 btn('pencil', false,true, function(btn){
18043 this.toggleSourceEdit(btn.pressed);
18049 xns: Roo.bootstrap,
18054 xns: Roo.bootstrap,
18059 cog.menu.items.push({
18061 xns: Roo.bootstrap,
18062 html : Clean styles,
18067 editorcore.insertTag(this.tagname);
18076 this.xtype = 'NavSimplebar';
18078 for(var i=0;i< children.length;i++) {
18080 this.buttons.add(this.addxtypeChild(children[i]));
18084 editor.on('editorevent', this.updateToolbar, this);
18086 onBtnClick : function(id)
18088 this.editorcore.relayCmd(id);
18089 this.editorcore.focus();
18093 * Protected method that will not generally be called directly. It triggers
18094 * a toolbar update by reading the markup state of the current selection in the editor.
18096 updateToolbar: function(){
18098 if(!this.editorcore.activated){
18099 this.editor.onFirstFocus(); // is this neeed?
18103 var btns = this.buttons;
18104 var doc = this.editorcore.doc;
18105 btns.get('bold').setActive(doc.queryCommandState('bold'));
18106 btns.get('italic').setActive(doc.queryCommandState('italic'));
18107 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18109 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18110 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18111 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18113 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18114 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18117 var ans = this.editorcore.getAllAncestors();
18118 if (this.formatCombo) {
18121 var store = this.formatCombo.store;
18122 this.formatCombo.setValue("");
18123 for (var i =0; i < ans.length;i++) {
18124 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18126 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18134 // hides menus... - so this cant be on a menu...
18135 Roo.bootstrap.MenuMgr.hideAll();
18137 Roo.bootstrap.MenuMgr.hideAll();
18138 //this.editorsyncValue();
18140 onFirstFocus: function() {
18141 this.buttons.each(function(item){
18145 toggleSourceEdit : function(sourceEditMode){
18148 if(sourceEditMode){
18149 Roo.log("disabling buttons");
18150 this.buttons.each( function(item){
18151 if(item.cmd != 'pencil'){
18157 Roo.log("enabling buttons");
18158 if(this.editorcore.initialized){
18159 this.buttons.each( function(item){
18165 Roo.log("calling toggole on editor");
18166 // tell the editor that it's been pressed..
18167 this.editor.toggleSourceEdit(sourceEditMode);
18177 * @class Roo.bootstrap.Table.AbstractSelectionModel
18178 * @extends Roo.util.Observable
18179 * Abstract base class for grid SelectionModels. It provides the interface that should be
18180 * implemented by descendant classes. This class should not be directly instantiated.
18183 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18184 this.locked = false;
18185 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18189 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18190 /** @ignore Called by the grid automatically. Do not call directly. */
18191 init : function(grid){
18197 * Locks the selections.
18200 this.locked = true;
18204 * Unlocks the selections.
18206 unlock : function(){
18207 this.locked = false;
18211 * Returns true if the selections are locked.
18212 * @return {Boolean}
18214 isLocked : function(){
18215 return this.locked;
18219 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18220 * @class Roo.bootstrap.Table.RowSelectionModel
18221 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18222 * It supports multiple selections and keyboard selection/navigation.
18224 * @param {Object} config
18227 Roo.bootstrap.Table.RowSelectionModel = function(config){
18228 Roo.apply(this, config);
18229 this.selections = new Roo.util.MixedCollection(false, function(o){
18234 this.lastActive = false;
18238 * @event selectionchange
18239 * Fires when the selection changes
18240 * @param {SelectionModel} this
18242 "selectionchange" : true,
18244 * @event afterselectionchange
18245 * Fires after the selection changes (eg. by key press or clicking)
18246 * @param {SelectionModel} this
18248 "afterselectionchange" : true,
18250 * @event beforerowselect
18251 * Fires when a row is selected being selected, return false to cancel.
18252 * @param {SelectionModel} this
18253 * @param {Number} rowIndex The selected index
18254 * @param {Boolean} keepExisting False if other selections will be cleared
18256 "beforerowselect" : true,
18259 * Fires when a row is selected.
18260 * @param {SelectionModel} this
18261 * @param {Number} rowIndex The selected index
18262 * @param {Roo.data.Record} r The record
18264 "rowselect" : true,
18266 * @event rowdeselect
18267 * Fires when a row is deselected.
18268 * @param {SelectionModel} this
18269 * @param {Number} rowIndex The selected index
18271 "rowdeselect" : true
18273 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18274 this.locked = false;
18277 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18279 * @cfg {Boolean} singleSelect
18280 * True to allow selection of only one row at a time (defaults to false)
18282 singleSelect : false,
18285 initEvents : function(){
18287 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18288 this.grid.on("mousedown", this.handleMouseDown, this);
18289 }else{ // allow click to work like normal
18290 this.grid.on("rowclick", this.handleDragableRowClick, this);
18293 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18294 "up" : function(e){
18296 this.selectPrevious(e.shiftKey);
18297 }else if(this.last !== false && this.lastActive !== false){
18298 var last = this.last;
18299 this.selectRange(this.last, this.lastActive-1);
18300 this.grid.getView().focusRow(this.lastActive);
18301 if(last !== false){
18305 this.selectFirstRow();
18307 this.fireEvent("afterselectionchange", this);
18309 "down" : function(e){
18311 this.selectNext(e.shiftKey);
18312 }else if(this.last !== false && this.lastActive !== false){
18313 var last = this.last;
18314 this.selectRange(this.last, this.lastActive+1);
18315 this.grid.getView().focusRow(this.lastActive);
18316 if(last !== false){
18320 this.selectFirstRow();
18322 this.fireEvent("afterselectionchange", this);
18327 var view = this.grid.view;
18328 view.on("refresh", this.onRefresh, this);
18329 view.on("rowupdated", this.onRowUpdated, this);
18330 view.on("rowremoved", this.onRemove, this);
18334 onRefresh : function(){
18335 var ds = this.grid.dataSource, i, v = this.grid.view;
18336 var s = this.selections;
18337 s.each(function(r){
18338 if((i = ds.indexOfId(r.id)) != -1){
18347 onRemove : function(v, index, r){
18348 this.selections.remove(r);
18352 onRowUpdated : function(v, index, r){
18353 if(this.isSelected(r)){
18354 v.onRowSelect(index);
18360 * @param {Array} records The records to select
18361 * @param {Boolean} keepExisting (optional) True to keep existing selections
18363 selectRecords : function(records, keepExisting){
18365 this.clearSelections();
18367 var ds = this.grid.dataSource;
18368 for(var i = 0, len = records.length; i < len; i++){
18369 this.selectRow(ds.indexOf(records[i]), true);
18374 * Gets the number of selected rows.
18377 getCount : function(){
18378 return this.selections.length;
18382 * Selects the first row in the grid.
18384 selectFirstRow : function(){
18389 * Select the last row.
18390 * @param {Boolean} keepExisting (optional) True to keep existing selections
18392 selectLastRow : function(keepExisting){
18393 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18397 * Selects the row immediately following the last selected row.
18398 * @param {Boolean} keepExisting (optional) True to keep existing selections
18400 selectNext : function(keepExisting){
18401 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18402 this.selectRow(this.last+1, keepExisting);
18403 this.grid.getView().focusRow(this.last);
18408 * Selects the row that precedes the last selected row.
18409 * @param {Boolean} keepExisting (optional) True to keep existing selections
18411 selectPrevious : function(keepExisting){
18413 this.selectRow(this.last-1, keepExisting);
18414 this.grid.getView().focusRow(this.last);
18419 * Returns the selected records
18420 * @return {Array} Array of selected records
18422 getSelections : function(){
18423 return [].concat(this.selections.items);
18427 * Returns the first selected record.
18430 getSelected : function(){
18431 return this.selections.itemAt(0);
18436 * Clears all selections.
18438 clearSelections : function(fast){
18439 if(this.locked) return;
18441 var ds = this.grid.dataSource;
18442 var s = this.selections;
18443 s.each(function(r){
18444 this.deselectRow(ds.indexOfId(r.id));
18448 this.selections.clear();
18455 * Selects all rows.
18457 selectAll : function(){
18458 if(this.locked) return;
18459 this.selections.clear();
18460 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18461 this.selectRow(i, true);
18466 * Returns True if there is a selection.
18467 * @return {Boolean}
18469 hasSelection : function(){
18470 return this.selections.length > 0;
18474 * Returns True if the specified row is selected.
18475 * @param {Number/Record} record The record or index of the record to check
18476 * @return {Boolean}
18478 isSelected : function(index){
18479 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18480 return (r && this.selections.key(r.id) ? true : false);
18484 * Returns True if the specified record id is selected.
18485 * @param {String} id The id of record to check
18486 * @return {Boolean}
18488 isIdSelected : function(id){
18489 return (this.selections.key(id) ? true : false);
18493 handleMouseDown : function(e, t){
18494 var view = this.grid.getView(), rowIndex;
18495 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18498 if(e.shiftKey && this.last !== false){
18499 var last = this.last;
18500 this.selectRange(last, rowIndex, e.ctrlKey);
18501 this.last = last; // reset the last
18502 view.focusRow(rowIndex);
18504 var isSelected = this.isSelected(rowIndex);
18505 if(e.button !== 0 && isSelected){
18506 view.focusRow(rowIndex);
18507 }else if(e.ctrlKey && isSelected){
18508 this.deselectRow(rowIndex);
18509 }else if(!isSelected){
18510 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18511 view.focusRow(rowIndex);
18514 this.fireEvent("afterselectionchange", this);
18517 handleDragableRowClick : function(grid, rowIndex, e)
18519 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18520 this.selectRow(rowIndex, false);
18521 grid.view.focusRow(rowIndex);
18522 this.fireEvent("afterselectionchange", this);
18527 * Selects multiple rows.
18528 * @param {Array} rows Array of the indexes of the row to select
18529 * @param {Boolean} keepExisting (optional) True to keep existing selections
18531 selectRows : function(rows, keepExisting){
18533 this.clearSelections();
18535 for(var i = 0, len = rows.length; i < len; i++){
18536 this.selectRow(rows[i], true);
18541 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18542 * @param {Number} startRow The index of the first row in the range
18543 * @param {Number} endRow The index of the last row in the range
18544 * @param {Boolean} keepExisting (optional) True to retain existing selections
18546 selectRange : function(startRow, endRow, keepExisting){
18547 if(this.locked) return;
18549 this.clearSelections();
18551 if(startRow <= endRow){
18552 for(var i = startRow; i <= endRow; i++){
18553 this.selectRow(i, true);
18556 for(var i = startRow; i >= endRow; i--){
18557 this.selectRow(i, true);
18563 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18564 * @param {Number} startRow The index of the first row in the range
18565 * @param {Number} endRow The index of the last row in the range
18567 deselectRange : function(startRow, endRow, preventViewNotify){
18568 if(this.locked) return;
18569 for(var i = startRow; i <= endRow; i++){
18570 this.deselectRow(i, preventViewNotify);
18576 * @param {Number} row The index of the row to select
18577 * @param {Boolean} keepExisting (optional) True to keep existing selections
18579 selectRow : function(index, keepExisting, preventViewNotify){
18580 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18581 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18582 if(!keepExisting || this.singleSelect){
18583 this.clearSelections();
18585 var r = this.grid.dataSource.getAt(index);
18586 this.selections.add(r);
18587 this.last = this.lastActive = index;
18588 if(!preventViewNotify){
18589 this.grid.getView().onRowSelect(index);
18591 this.fireEvent("rowselect", this, index, r);
18592 this.fireEvent("selectionchange", this);
18598 * @param {Number} row The index of the row to deselect
18600 deselectRow : function(index, preventViewNotify){
18601 if(this.locked) return;
18602 if(this.last == index){
18605 if(this.lastActive == index){
18606 this.lastActive = false;
18608 var r = this.grid.dataSource.getAt(index);
18609 this.selections.remove(r);
18610 if(!preventViewNotify){
18611 this.grid.getView().onRowDeselect(index);
18613 this.fireEvent("rowdeselect", this, index);
18614 this.fireEvent("selectionchange", this);
18618 restoreLast : function(){
18620 this.last = this._last;
18625 acceptsNav : function(row, col, cm){
18626 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18630 onEditorKey : function(field, e){
18631 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18636 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18638 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18640 }else if(k == e.ENTER && !e.ctrlKey){
18644 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18646 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18648 }else if(k == e.ESC){
18652 g.startEditing(newCell[0], newCell[1]);
18657 * Ext JS Library 1.1.1
18658 * Copyright(c) 2006-2007, Ext JS, LLC.
18660 * Originally Released Under LGPL - original licence link has changed is not relivant.
18663 * <script type="text/javascript">
18667 * @class Roo.bootstrap.PagingToolbar
18669 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18671 * Create a new PagingToolbar
18672 * @param {Object} config The config object
18674 Roo.bootstrap.PagingToolbar = function(config)
18676 // old args format still supported... - xtype is prefered..
18677 // created from xtype...
18678 var ds = config.dataSource;
18679 this.toolbarItems = [];
18680 if (config.items) {
18681 this.toolbarItems = config.items;
18682 // config.items = [];
18685 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18692 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18696 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18698 * @cfg {Roo.data.Store} dataSource
18699 * The underlying data store providing the paged data
18702 * @cfg {String/HTMLElement/Element} container
18703 * container The id or element that will contain the toolbar
18706 * @cfg {Boolean} displayInfo
18707 * True to display the displayMsg (defaults to false)
18710 * @cfg {Number} pageSize
18711 * The number of records to display per page (defaults to 20)
18715 * @cfg {String} displayMsg
18716 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18718 displayMsg : 'Displaying {0} - {1} of {2}',
18720 * @cfg {String} emptyMsg
18721 * The message to display when no records are found (defaults to "No data to display")
18723 emptyMsg : 'No data to display',
18725 * Customizable piece of the default paging text (defaults to "Page")
18728 beforePageText : "Page",
18730 * Customizable piece of the default paging text (defaults to "of %0")
18733 afterPageText : "of {0}",
18735 * Customizable piece of the default paging text (defaults to "First Page")
18738 firstText : "First Page",
18740 * Customizable piece of the default paging text (defaults to "Previous Page")
18743 prevText : "Previous Page",
18745 * Customizable piece of the default paging text (defaults to "Next Page")
18748 nextText : "Next Page",
18750 * Customizable piece of the default paging text (defaults to "Last Page")
18753 lastText : "Last Page",
18755 * Customizable piece of the default paging text (defaults to "Refresh")
18758 refreshText : "Refresh",
18762 onRender : function(ct, position)
18764 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18765 this.navgroup.parentId = this.id;
18766 this.navgroup.onRender(this.el, null);
18767 // add the buttons to the navgroup
18769 if(this.displayInfo){
18770 Roo.log(this.el.select('ul.navbar-nav',true).first());
18771 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18772 this.displayEl = this.el.select('.x-paging-info', true).first();
18773 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18774 // this.displayEl = navel.el.select('span',true).first();
18780 Roo.each(_this.buttons, function(e){
18781 Roo.factory(e).onRender(_this.el, null);
18785 Roo.each(_this.toolbarItems, function(e) {
18786 _this.navgroup.addItem(e);
18789 this.first = this.navgroup.addItem({
18790 tooltip: this.firstText,
18792 icon : 'fa fa-backward',
18794 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18797 this.prev = this.navgroup.addItem({
18798 tooltip: this.prevText,
18800 icon : 'fa fa-step-backward',
18802 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18804 //this.addSeparator();
18807 var field = this.navgroup.addItem( {
18809 cls : 'x-paging-position',
18811 html : this.beforePageText +
18812 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18813 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18816 this.field = field.el.select('input', true).first();
18817 this.field.on("keydown", this.onPagingKeydown, this);
18818 this.field.on("focus", function(){this.dom.select();});
18821 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18822 //this.field.setHeight(18);
18823 //this.addSeparator();
18824 this.next = this.navgroup.addItem({
18825 tooltip: this.nextText,
18827 html : ' <i class="fa fa-step-forward">',
18829 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18831 this.last = this.navgroup.addItem({
18832 tooltip: this.lastText,
18833 icon : 'fa fa-forward',
18836 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18838 //this.addSeparator();
18839 this.loading = this.navgroup.addItem({
18840 tooltip: this.refreshText,
18841 icon: 'fa fa-refresh',
18843 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18849 updateInfo : function(){
18850 if(this.displayEl){
18851 var count = this.ds.getCount();
18852 var msg = count == 0 ?
18856 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18858 this.displayEl.update(msg);
18863 onLoad : function(ds, r, o){
18864 this.cursor = o.params ? o.params.start : 0;
18865 var d = this.getPageData(),
18869 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18870 this.field.dom.value = ap;
18871 this.first.setDisabled(ap == 1);
18872 this.prev.setDisabled(ap == 1);
18873 this.next.setDisabled(ap == ps);
18874 this.last.setDisabled(ap == ps);
18875 this.loading.enable();
18880 getPageData : function(){
18881 var total = this.ds.getTotalCount();
18884 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18885 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18890 onLoadError : function(){
18891 this.loading.enable();
18895 onPagingKeydown : function(e){
18896 var k = e.getKey();
18897 var d = this.getPageData();
18899 var v = this.field.dom.value, pageNum;
18900 if(!v || isNaN(pageNum = parseInt(v, 10))){
18901 this.field.dom.value = d.activePage;
18904 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18905 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18908 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))
18910 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18911 this.field.dom.value = pageNum;
18912 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18915 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18917 var v = this.field.dom.value, pageNum;
18918 var increment = (e.shiftKey) ? 10 : 1;
18919 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18921 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18922 this.field.dom.value = d.activePage;
18925 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18927 this.field.dom.value = parseInt(v, 10) + increment;
18928 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18929 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18936 beforeLoad : function(){
18938 this.loading.disable();
18943 onClick : function(which){
18950 ds.load({params:{start: 0, limit: this.pageSize}});
18953 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18956 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18959 var total = ds.getTotalCount();
18960 var extra = total % this.pageSize;
18961 var lastStart = extra ? (total - extra) : total-this.pageSize;
18962 ds.load({params:{start: lastStart, limit: this.pageSize}});
18965 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18971 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18972 * @param {Roo.data.Store} store The data store to unbind
18974 unbind : function(ds){
18975 ds.un("beforeload", this.beforeLoad, this);
18976 ds.un("load", this.onLoad, this);
18977 ds.un("loadexception", this.onLoadError, this);
18978 ds.un("remove", this.updateInfo, this);
18979 ds.un("add", this.updateInfo, this);
18980 this.ds = undefined;
18984 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18985 * @param {Roo.data.Store} store The data store to bind
18987 bind : function(ds){
18988 ds.on("beforeload", this.beforeLoad, this);
18989 ds.on("load", this.onLoad, this);
18990 ds.on("loadexception", this.onLoadError, this);
18991 ds.on("remove", this.updateInfo, this);
18992 ds.on("add", this.updateInfo, this);
19003 * @class Roo.bootstrap.MessageBar
19004 * @extends Roo.bootstrap.Component
19005 * Bootstrap MessageBar class
19006 * @cfg {String} html contents of the MessageBar
19007 * @cfg {String} weight (info | success | warning | danger) default info
19008 * @cfg {String} beforeClass insert the bar before the given class
19009 * @cfg {Boolean} closable (true | false) default false
19010 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19013 * Create a new Element
19014 * @param {Object} config The config object
19017 Roo.bootstrap.MessageBar = function(config){
19018 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19021 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19027 beforeClass: 'bootstrap-sticky-wrap',
19029 getAutoCreate : function(){
19033 cls: 'alert alert-dismissable alert-' + this.weight,
19038 html: this.html || ''
19044 cfg.cls += ' alert-messages-fixed';
19058 onRender : function(ct, position)
19060 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19063 var cfg = Roo.apply({}, this.getAutoCreate());
19067 cfg.cls += ' ' + this.cls;
19070 cfg.style = this.style;
19072 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19074 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19077 this.el.select('>button.close').on('click', this.hide, this);
19083 if (!this.rendered) {
19089 this.fireEvent('show', this);
19095 if (!this.rendered) {
19101 this.fireEvent('hide', this);
19104 update : function()
19106 // var e = this.el.dom.firstChild;
19108 // if(this.closable){
19109 // e = e.nextSibling;
19112 // e.data = this.html || '';
19114 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19130 * @class Roo.bootstrap.Graph
19131 * @extends Roo.bootstrap.Component
19132 * Bootstrap Graph class
19136 @cfg {String} graphtype bar | vbar | pie
19137 @cfg {number} g_x coodinator | centre x (pie)
19138 @cfg {number} g_y coodinator | centre y (pie)
19139 @cfg {number} g_r radius (pie)
19140 @cfg {number} g_height height of the chart (respected by all elements in the set)
19141 @cfg {number} g_width width of the chart (respected by all elements in the set)
19142 @cfg {Object} title The title of the chart
19145 -opts (object) options for the chart
19147 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19148 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19150 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.
19151 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19153 o stretch (boolean)
19155 -opts (object) options for the pie
19158 o startAngle (number)
19159 o endAngle (number)
19163 * Create a new Input
19164 * @param {Object} config The config object
19167 Roo.bootstrap.Graph = function(config){
19168 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19174 * The img click event for the img.
19175 * @param {Roo.EventObject} e
19181 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19192 //g_colors: this.colors,
19199 getAutoCreate : function(){
19210 onRender : function(ct,position){
19211 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19212 this.raphael = Raphael(this.el.dom);
19214 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19215 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19216 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19217 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19219 r.text(160, 10, "Single Series Chart").attr(txtattr);
19220 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19221 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19222 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19224 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19225 r.barchart(330, 10, 300, 220, data1);
19226 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19227 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19230 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19231 // r.barchart(30, 30, 560, 250, xdata, {
19232 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19233 // axis : "0 0 1 1",
19234 // axisxlabels : xdata
19235 // //yvalues : cols,
19238 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19240 // this.load(null,xdata,{
19241 // axis : "0 0 1 1",
19242 // axisxlabels : xdata
19247 load : function(graphtype,xdata,opts){
19248 this.raphael.clear();
19250 graphtype = this.graphtype;
19255 var r = this.raphael,
19256 fin = function () {
19257 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19259 fout = function () {
19260 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19262 pfin = function() {
19263 this.sector.stop();
19264 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19267 this.label[0].stop();
19268 this.label[0].attr({ r: 7.5 });
19269 this.label[1].attr({ "font-weight": 800 });
19272 pfout = function() {
19273 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19276 this.label[0].animate({ r: 5 }, 500, "bounce");
19277 this.label[1].attr({ "font-weight": 400 });
19283 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19286 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19289 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19290 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19292 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19299 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19304 setTitle: function(o)
19309 initEvents: function() {
19312 this.el.on('click', this.onClick, this);
19316 onClick : function(e)
19318 Roo.log('img onclick');
19319 this.fireEvent('click', this, e);
19331 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19334 * @class Roo.bootstrap.dash.NumberBox
19335 * @extends Roo.bootstrap.Component
19336 * Bootstrap NumberBox class
19337 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19338 * @cfg {String} headline Box headline
19339 * @cfg {String} content Box content
19340 * @cfg {String} icon Box icon
19341 * @cfg {String} footer Footer text
19342 * @cfg {String} fhref Footer href
19345 * Create a new NumberBox
19346 * @param {Object} config The config object
19350 Roo.bootstrap.dash.NumberBox = function(config){
19351 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19355 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19365 getAutoCreate : function(){
19369 cls : 'small-box bg-' + this.bgcolor,
19377 cls : 'roo-headline',
19378 html : this.headline
19382 cls : 'roo-content',
19383 html : this.content
19397 cls : 'ion ' + this.icon
19406 cls : 'small-box-footer',
19407 href : this.fhref || '#',
19411 cfg.cn.push(footer);
19418 onRender : function(ct,position){
19419 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19426 setHeadline: function (value)
19428 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19431 setFooter: function (value, href)
19433 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19436 this.el.select('a.small-box-footer',true).first().attr('href', href);
19441 setContent: function (value)
19443 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19446 initEvents: function()
19460 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19463 * @class Roo.bootstrap.dash.TabBox
19464 * @extends Roo.bootstrap.Component
19465 * Bootstrap TabBox class
19466 * @cfg {String} title Title of the TabBox
19467 * @cfg {String} icon Icon of the TabBox
19470 * Create a new TabBox
19471 * @param {Object} config The config object
19475 Roo.bootstrap.dash.TabBox = function(config){
19476 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19481 * When a pane is added
19482 * @param {Roo.bootstrap.dash.TabPane} pane
19489 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19494 getChildContainer : function()
19496 return this.el.select('.tab-content', true).first();
19499 getAutoCreate : function(){
19503 cls: 'pull-left header',
19511 cls: 'fa ' + this.icon
19518 cls: 'nav-tabs-custom',
19522 cls: 'nav nav-tabs pull-right',
19529 cls: 'tab-content no-padding',
19537 initEvents : function()
19539 //Roo.log('add add pane handler');
19540 this.on('addpane', this.onAddPane, this);
19543 * Updates the box title
19544 * @param {String} html to set the title to.
19546 setTitle : function(value)
19548 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19550 onAddPane : function(pane)
19552 //Roo.log('addpane');
19554 // tabs are rendere left to right..
19555 var ctr = this.el.select('.nav-tabs', true).first();
19558 var existing = ctr.select('.nav-tab',true);
19559 var qty = existing.getCount();;
19562 var tab = ctr.createChild({
19564 cls : 'nav-tab' + (qty ? '' : ' active'),
19572 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19575 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19577 pane.el.addClass('active');
19582 onTabClick : function(ev,un,ob,pane)
19584 //Roo.log('tab - prev default');
19585 ev.preventDefault();
19588 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19589 pane.tab.addClass('active');
19590 //Roo.log(pane.title);
19591 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19592 // technically we should have a deactivate event.. but maybe add later.
19593 // and it should not de-activate the selected tab...
19595 pane.el.addClass('active');
19596 pane.fireEvent('activate');
19611 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19613 * @class Roo.bootstrap.TabPane
19614 * @extends Roo.bootstrap.Component
19615 * Bootstrap TabPane class
19616 * @cfg {Boolean} active (false | true) Default false
19617 * @cfg {String} title title of panel
19621 * Create a new TabPane
19622 * @param {Object} config The config object
19625 Roo.bootstrap.dash.TabPane = function(config){
19626 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19630 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19635 // the tabBox that this is attached to.
19638 getAutoCreate : function()
19646 cfg.cls += ' active';
19651 initEvents : function()
19653 //Roo.log('trigger add pane handler');
19654 this.parent().fireEvent('addpane', this)
19658 * Updates the tab title
19659 * @param {String} html to set the title to.
19661 setTitle: function(str)
19667 this.tab.select('a'.true).first().dom.innerHTML = str;
19684 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19687 * @class Roo.bootstrap.menu.Menu
19688 * @extends Roo.bootstrap.Component
19689 * Bootstrap Menu class - container for Menu
19690 * @cfg {String} html Text of the menu
19691 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19692 * @cfg {String} icon Font awesome icon
19693 * @cfg {String} pos Menu align to (top | bottom) default bottom
19697 * Create a new Menu
19698 * @param {Object} config The config object
19702 Roo.bootstrap.menu.Menu = function(config){
19703 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19707 * @event beforeshow
19708 * Fires before this menu is displayed
19709 * @param {Roo.bootstrap.menu.Menu} this
19713 * @event beforehide
19714 * Fires before this menu is hidden
19715 * @param {Roo.bootstrap.menu.Menu} this
19720 * Fires after this menu is displayed
19721 * @param {Roo.bootstrap.menu.Menu} this
19726 * Fires after this menu is hidden
19727 * @param {Roo.bootstrap.menu.Menu} this
19732 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19733 * @param {Roo.bootstrap.menu.Menu} this
19734 * @param {Roo.EventObject} e
19741 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19745 weight : 'default',
19750 getChildContainer : function() {
19751 if(this.isSubMenu){
19755 return this.el.select('ul.dropdown-menu', true).first();
19758 getAutoCreate : function()
19763 cls : 'roo-menu-text',
19771 cls : 'fa ' + this.icon
19782 cls : 'dropdown-button btn btn-' + this.weight,
19787 cls : 'dropdown-toggle btn btn-' + this.weight,
19797 cls : 'dropdown-menu'
19803 if(this.pos == 'top'){
19804 cfg.cls += ' dropup';
19807 if(this.isSubMenu){
19810 cls : 'dropdown-menu'
19817 onRender : function(ct, position)
19819 this.isSubMenu = ct.hasClass('dropdown-submenu');
19821 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19824 initEvents : function()
19826 if(this.isSubMenu){
19830 this.hidden = true;
19832 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19833 this.triggerEl.on('click', this.onTriggerPress, this);
19835 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19836 this.buttonEl.on('click', this.onClick, this);
19842 if(this.isSubMenu){
19846 return this.el.select('ul.dropdown-menu', true).first();
19849 onClick : function(e)
19851 this.fireEvent("click", this, e);
19854 onTriggerPress : function(e)
19856 if (this.isVisible()) {
19863 isVisible : function(){
19864 return !this.hidden;
19869 this.fireEvent("beforeshow", this);
19871 this.hidden = false;
19872 this.el.addClass('open');
19874 Roo.get(document).on("mouseup", this.onMouseUp, this);
19876 this.fireEvent("show", this);
19883 this.fireEvent("beforehide", this);
19885 this.hidden = true;
19886 this.el.removeClass('open');
19888 Roo.get(document).un("mouseup", this.onMouseUp);
19890 this.fireEvent("hide", this);
19893 onMouseUp : function()
19907 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19910 * @class Roo.bootstrap.menu.Item
19911 * @extends Roo.bootstrap.Component
19912 * Bootstrap MenuItem class
19913 * @cfg {Boolean} submenu (true | false) default false
19914 * @cfg {String} html text of the item
19915 * @cfg {String} href the link
19916 * @cfg {Boolean} disable (true | false) default false
19917 * @cfg {Boolean} preventDefault (true | false) default true
19918 * @cfg {String} icon Font awesome icon
19919 * @cfg {String} pos Submenu align to (left | right) default right
19923 * Create a new Item
19924 * @param {Object} config The config object
19928 Roo.bootstrap.menu.Item = function(config){
19929 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19933 * Fires when the mouse is hovering over this menu
19934 * @param {Roo.bootstrap.menu.Item} this
19935 * @param {Roo.EventObject} e
19940 * Fires when the mouse exits this menu
19941 * @param {Roo.bootstrap.menu.Item} this
19942 * @param {Roo.EventObject} e
19948 * The raw click event for the entire grid.
19949 * @param {Roo.EventObject} e
19955 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19960 preventDefault: true,
19965 getAutoCreate : function()
19970 cls : 'roo-menu-item-text',
19978 cls : 'fa ' + this.icon
19987 href : this.href || '#',
19994 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19998 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20000 if(this.pos == 'left'){
20001 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20008 initEvents : function()
20010 this.el.on('mouseover', this.onMouseOver, this);
20011 this.el.on('mouseout', this.onMouseOut, this);
20013 this.el.select('a', true).first().on('click', this.onClick, this);
20017 onClick : function(e)
20019 if(this.preventDefault){
20020 e.preventDefault();
20023 this.fireEvent("click", this, e);
20026 onMouseOver : function(e)
20028 if(this.submenu && this.pos == 'left'){
20029 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20032 this.fireEvent("mouseover", this, e);
20035 onMouseOut : function(e)
20037 this.fireEvent("mouseout", this, e);
20049 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20052 * @class Roo.bootstrap.menu.Separator
20053 * @extends Roo.bootstrap.Component
20054 * Bootstrap Separator class
20057 * Create a new Separator
20058 * @param {Object} config The config object
20062 Roo.bootstrap.menu.Separator = function(config){
20063 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20066 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20068 getAutoCreate : function(){