4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1160 if(!this.href || this.preventDefault){
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3181 Roo.bootstrap.NavGroup.register(this);
3185 * Fires when the active item changes
3186 * @param {Roo.bootstrap.NavGroup} this
3187 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3188 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3195 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3206 getAutoCreate : function()
3208 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3215 if (['tabs','pills'].indexOf(this.type)!==-1) {
3216 cfg.cls += ' nav-' + this.type
3218 if (this.type!=='nav') {
3219 Roo.log('nav type must be nav/tabs/pills')
3221 cfg.cls += ' navbar-nav'
3224 if (this.parent().sidebar) {
3227 cls: 'dashboard-menu sidebar-menu'
3233 if (this.form === true) {
3239 if (this.align === 'right') {
3240 cfg.cls += ' navbar-right';
3242 cfg.cls += ' navbar-left';
3246 if (this.align === 'right') {
3247 cfg.cls += ' navbar-right';
3251 cfg.cls += ' navbar-inverse';
3259 * sets the active Navigation item
3260 * @param {Roo.bootstrap.NavItem} the new current navitem
3262 setActiveItem : function(item)
3265 Roo.each(this.navItems, function(v){
3270 v.setActive(false, true);
3277 item.setActive(true, true);
3278 this.fireEvent('changed', this, item, prev);
3283 * gets the active Navigation item
3284 * @return {Roo.bootstrap.NavItem} the current navitem
3286 getActive : function()
3290 Roo.each(this.navItems, function(v){
3301 indexOfNav : function()
3305 Roo.each(this.navItems, function(v,i){
3316 * adds a Navigation item
3317 * @param {Roo.bootstrap.NavItem} the navitem to add
3319 addItem : function(cfg)
3321 var cn = new Roo.bootstrap.NavItem(cfg);
3323 cn.parentId = this.id;
3324 cn.onRender(this.el, null);
3328 * register a Navigation item
3329 * @param {Roo.bootstrap.NavItem} the navitem to add
3331 register : function(item)
3333 this.navItems.push( item);
3334 item.navId = this.navId;
3339 getNavItem: function(tabId)
3342 Roo.each(this.navItems, function(e) {
3343 if (e.tabId == tabId) {
3353 setActiveNext : function()
3355 var i = this.indexOfNav(this.getActive());
3356 if (i > this.navItems.length) {
3359 this.setActiveItem(this.navItems[i+1]);
3361 setActivePrev : function()
3363 var i = this.indexOfNav(this.getActive());
3367 this.setActiveItem(this.navItems[i-1]);
3369 clearWasActive : function(except) {
3370 Roo.each(this.navItems, function(e) {
3371 if (e.tabId != except.tabId && e.was_active) {
3372 e.was_active = false;
3379 getWasActive : function ()
3382 Roo.each(this.navItems, function(e) {
3397 Roo.apply(Roo.bootstrap.NavGroup, {
3401 * register a Navigation Group
3402 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3404 register : function(navgrp)
3406 this.groups[navgrp.navId] = navgrp;
3410 * fetch a Navigation Group based on the navigation ID
3411 * @param {string} the navgroup to add
3412 * @returns {Roo.bootstrap.NavGroup} the navgroup
3414 get: function(navId) {
3415 if (typeof(this.groups[navId]) == 'undefined') {
3417 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3419 return this.groups[navId] ;
3434 * @class Roo.bootstrap.NavItem
3435 * @extends Roo.bootstrap.Component
3436 * Bootstrap Navbar.NavItem class
3437 * @cfg {String} href link to
3438 * @cfg {String} html content of button
3439 * @cfg {String} badge text inside badge
3440 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3441 * @cfg {String} glyphicon name of glyphicon
3442 * @cfg {String} icon name of font awesome icon
3443 * @cfg {Boolean} active Is item active
3444 * @cfg {Boolean} disabled Is item disabled
3446 * @cfg {Boolean} preventDefault (true | false) default false
3447 * @cfg {String} tabId the tab that this item activates.
3448 * @cfg {String} tagtype (a|span) render as a href or span?
3451 * Create a new Navbar Item
3452 * @param {Object} config The config object
3454 Roo.bootstrap.NavItem = function(config){
3455 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3460 * The raw click event for the entire grid.
3461 * @param {Roo.EventObject} e
3466 * Fires when the active item active state changes
3467 * @param {Roo.bootstrap.NavItem} this
3468 * @param {boolean} state the new state
3476 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3484 preventDefault : false,
3491 getAutoCreate : function(){
3499 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3501 if (this.disabled) {
3502 cfg.cls += ' disabled';
3505 if (this.href || this.html || this.glyphicon || this.icon) {
3509 href : this.href || "#",
3510 html: this.html || ''
3515 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3518 if(this.glyphicon) {
3519 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3524 cfg.cn[0].html += " <span class='caret'></span>";
3528 if (this.badge !== '') {
3530 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3538 initEvents: function() {
3539 // Roo.log('init events?');
3540 // Roo.log(this.el.dom);
3541 if (typeof (this.menu) != 'undefined') {
3542 this.menu.parentType = this.xtype;
3543 this.menu.triggerEl = this.el;
3544 this.addxtype(Roo.apply({}, this.menu));
3548 this.el.select('a',true).on('click', this.onClick, this);
3549 // at this point parent should be available..
3550 this.parent().register(this);
3553 onClick : function(e)
3556 if(this.preventDefault){
3559 if (this.disabled) {
3563 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3564 if (tg && tg.transition) {
3565 Roo.log("waiting for the transitionend");
3569 Roo.log("fire event clicked");
3570 if(this.fireEvent('click', this, e) === false){
3574 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3575 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3576 this.parent().setActiveItem(this);
3581 isActive: function () {
3584 setActive : function(state, fire, is_was_active)
3586 if (this.active && !state & this.navId) {
3587 this.was_active = true;
3588 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3590 nv.clearWasActive(this);
3594 this.active = state;
3597 this.el.removeClass('active');
3598 } else if (!this.el.hasClass('active')) {
3599 this.el.addClass('active');
3602 this.fireEvent('changed', this, state);
3605 // show a panel if it's registered and related..
3607 if (!this.navId || !this.tabId || !state || is_was_active) {
3611 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3615 var pan = tg.getPanelByName(this.tabId);
3619 // if we can not flip to new panel - go back to old nav highlight..
3620 if (false == tg.showPanel(pan)) {
3621 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3623 var onav = nv.getWasActive();
3625 onav.setActive(true, false, true);
3634 // this should not be here...
3635 setDisabled : function(state)
3637 this.disabled = state;
3639 this.el.removeClass('disabled');
3640 } else if (!this.el.hasClass('disabled')) {
3641 this.el.addClass('disabled');
3654 * <span> icon </span>
3655 * <span> text </span>
3656 * <span>badge </span>
3660 * @class Roo.bootstrap.NavSidebarItem
3661 * @extends Roo.bootstrap.NavItem
3662 * Bootstrap Navbar.NavSidebarItem class
3664 * Create a new Navbar Button
3665 * @param {Object} config The config object
3667 Roo.bootstrap.NavSidebarItem = function(config){
3668 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3673 * The raw click event for the entire grid.
3674 * @param {Roo.EventObject} e
3679 * Fires when the active item active state changes
3680 * @param {Roo.bootstrap.NavSidebarItem} this
3681 * @param {boolean} state the new state
3689 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3692 getAutoCreate : function(){
3697 href : this.href || '#',
3709 html : this.html || ''
3714 cfg.cls += ' active';
3718 if (this.glyphicon || this.icon) {
3719 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3720 a.cn.push({ tag : 'i', cls : c }) ;
3725 if (this.badge !== '') {
3726 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3730 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3731 a.cls += 'dropdown-toggle treeview' ;
3755 * @class Roo.bootstrap.Row
3756 * @extends Roo.bootstrap.Component
3757 * Bootstrap Row class (contains columns...)
3761 * @param {Object} config The config object
3764 Roo.bootstrap.Row = function(config){
3765 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3768 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3770 getAutoCreate : function(){
3789 * @class Roo.bootstrap.Element
3790 * @extends Roo.bootstrap.Component
3791 * Bootstrap Element class
3792 * @cfg {String} html contents of the element
3793 * @cfg {String} tag tag of the element
3794 * @cfg {String} cls class of the element
3797 * Create a new Element
3798 * @param {Object} config The config object
3801 Roo.bootstrap.Element = function(config){
3802 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3805 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3812 getAutoCreate : function(){
3837 * @class Roo.bootstrap.Pagination
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Pagination class
3840 * @cfg {String} size xs | sm | md | lg
3841 * @cfg {Boolean} inverse false | true
3844 * Create a new Pagination
3845 * @param {Object} config The config object
3848 Roo.bootstrap.Pagination = function(config){
3849 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3852 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3858 getAutoCreate : function(){
3864 cfg.cls += ' inverse';
3870 cfg.cls += " " + this.cls;
3888 * @class Roo.bootstrap.PaginationItem
3889 * @extends Roo.bootstrap.Component
3890 * Bootstrap PaginationItem class
3891 * @cfg {String} html text
3892 * @cfg {String} href the link
3893 * @cfg {Boolean} preventDefault (true | false) default true
3894 * @cfg {Boolean} active (true | false) default false
3898 * Create a new PaginationItem
3899 * @param {Object} config The config object
3903 Roo.bootstrap.PaginationItem = function(config){
3904 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3909 * The raw click event for the entire grid.
3910 * @param {Roo.EventObject} e
3916 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3920 preventDefault: true,
3924 getAutoCreate : function(){
3930 href : this.href ? this.href : '#',
3931 html : this.html ? this.html : ''
3941 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3947 initEvents: function() {
3949 this.el.on('click', this.onClick, this);
3952 onClick : function(e)
3954 Roo.log('PaginationItem on click ');
3955 if(this.preventDefault){
3959 this.fireEvent('click', this, e);
3975 * @class Roo.bootstrap.Slider
3976 * @extends Roo.bootstrap.Component
3977 * Bootstrap Slider class
3980 * Create a new Slider
3981 * @param {Object} config The config object
3984 Roo.bootstrap.Slider = function(config){
3985 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3988 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3990 getAutoCreate : function(){
3994 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3998 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4010 * Ext JS Library 1.1.1
4011 * Copyright(c) 2006-2007, Ext JS, LLC.
4013 * Originally Released Under LGPL - original licence link has changed is not relivant.
4016 * <script type="text/javascript">
4021 * @class Roo.grid.ColumnModel
4022 * @extends Roo.util.Observable
4023 * This is the default implementation of a ColumnModel used by the Grid. It defines
4024 * the columns in the grid.
4027 var colModel = new Roo.grid.ColumnModel([
4028 {header: "Ticker", width: 60, sortable: true, locked: true},
4029 {header: "Company Name", width: 150, sortable: true},
4030 {header: "Market Cap.", width: 100, sortable: true},
4031 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4032 {header: "Employees", width: 100, sortable: true, resizable: false}
4037 * The config options listed for this class are options which may appear in each
4038 * individual column definition.
4039 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4041 * @param {Object} config An Array of column config objects. See this class's
4042 * config objects for details.
4044 Roo.grid.ColumnModel = function(config){
4046 * The config passed into the constructor
4048 this.config = config;
4051 // if no id, create one
4052 // if the column does not have a dataIndex mapping,
4053 // map it to the order it is in the config
4054 for(var i = 0, len = config.length; i < len; i++){
4056 if(typeof c.dataIndex == "undefined"){
4059 if(typeof c.renderer == "string"){
4060 c.renderer = Roo.util.Format[c.renderer];
4062 if(typeof c.id == "undefined"){
4065 if(c.editor && c.editor.xtype){
4066 c.editor = Roo.factory(c.editor, Roo.grid);
4068 if(c.editor && c.editor.isFormField){
4069 c.editor = new Roo.grid.GridEditor(c.editor);
4071 this.lookup[c.id] = c;
4075 * The width of columns which have no width specified (defaults to 100)
4078 this.defaultWidth = 100;
4081 * Default sortable of columns which have no sortable specified (defaults to false)
4084 this.defaultSortable = false;
4088 * @event widthchange
4089 * Fires when the width of a column changes.
4090 * @param {ColumnModel} this
4091 * @param {Number} columnIndex The column index
4092 * @param {Number} newWidth The new width
4094 "widthchange": true,
4096 * @event headerchange
4097 * Fires when the text of a header changes.
4098 * @param {ColumnModel} this
4099 * @param {Number} columnIndex The column index
4100 * @param {Number} newText The new header text
4102 "headerchange": true,
4104 * @event hiddenchange
4105 * Fires when a column is hidden or "unhidden".
4106 * @param {ColumnModel} this
4107 * @param {Number} columnIndex The column index
4108 * @param {Boolean} hidden true if hidden, false otherwise
4110 "hiddenchange": true,
4112 * @event columnmoved
4113 * Fires when a column is moved.
4114 * @param {ColumnModel} this
4115 * @param {Number} oldIndex
4116 * @param {Number} newIndex
4118 "columnmoved" : true,
4120 * @event columlockchange
4121 * Fires when a column's locked state is changed
4122 * @param {ColumnModel} this
4123 * @param {Number} colIndex
4124 * @param {Boolean} locked true if locked
4126 "columnlockchange" : true
4128 Roo.grid.ColumnModel.superclass.constructor.call(this);
4130 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4132 * @cfg {String} header The header text to display in the Grid view.
4135 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4136 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4137 * specified, the column's index is used as an index into the Record's data Array.
4140 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4141 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4144 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4145 * Defaults to the value of the {@link #defaultSortable} property.
4146 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4149 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4152 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4155 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4158 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4161 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4162 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4163 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4164 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4167 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4170 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4174 * Returns the id of the column at the specified index.
4175 * @param {Number} index The column index
4176 * @return {String} the id
4178 getColumnId : function(index){
4179 return this.config[index].id;
4183 * Returns the column for a specified id.
4184 * @param {String} id The column id
4185 * @return {Object} the column
4187 getColumnById : function(id){
4188 return this.lookup[id];
4193 * Returns the column for a specified dataIndex.
4194 * @param {String} dataIndex The column dataIndex
4195 * @return {Object|Boolean} the column or false if not found
4197 getColumnByDataIndex: function(dataIndex){
4198 var index = this.findColumnIndex(dataIndex);
4199 return index > -1 ? this.config[index] : false;
4203 * Returns the index for a specified column id.
4204 * @param {String} id The column id
4205 * @return {Number} the index, or -1 if not found
4207 getIndexById : function(id){
4208 for(var i = 0, len = this.config.length; i < len; i++){
4209 if(this.config[i].id == id){
4217 * Returns the index for a specified column dataIndex.
4218 * @param {String} dataIndex The column dataIndex
4219 * @return {Number} the index, or -1 if not found
4222 findColumnIndex : function(dataIndex){
4223 for(var i = 0, len = this.config.length; i < len; i++){
4224 if(this.config[i].dataIndex == dataIndex){
4232 moveColumn : function(oldIndex, newIndex){
4233 var c = this.config[oldIndex];
4234 this.config.splice(oldIndex, 1);
4235 this.config.splice(newIndex, 0, c);
4236 this.dataMap = null;
4237 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4240 isLocked : function(colIndex){
4241 return this.config[colIndex].locked === true;
4244 setLocked : function(colIndex, value, suppressEvent){
4245 if(this.isLocked(colIndex) == value){
4248 this.config[colIndex].locked = value;
4250 this.fireEvent("columnlockchange", this, colIndex, value);
4254 getTotalLockedWidth : function(){
4256 for(var i = 0; i < this.config.length; i++){
4257 if(this.isLocked(i) && !this.isHidden(i)){
4258 this.totalWidth += this.getColumnWidth(i);
4264 getLockedCount : function(){
4265 for(var i = 0, len = this.config.length; i < len; i++){
4266 if(!this.isLocked(i)){
4273 * Returns the number of columns.
4276 getColumnCount : function(visibleOnly){
4277 if(visibleOnly === true){
4279 for(var i = 0, len = this.config.length; i < len; i++){
4280 if(!this.isHidden(i)){
4286 return this.config.length;
4290 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4291 * @param {Function} fn
4292 * @param {Object} scope (optional)
4293 * @return {Array} result
4295 getColumnsBy : function(fn, scope){
4297 for(var i = 0, len = this.config.length; i < len; i++){
4298 var c = this.config[i];
4299 if(fn.call(scope||this, c, i) === true){
4307 * Returns true if the specified column is sortable.
4308 * @param {Number} col The column index
4311 isSortable : function(col){
4312 if(typeof this.config[col].sortable == "undefined"){
4313 return this.defaultSortable;
4315 return this.config[col].sortable;
4319 * Returns the rendering (formatting) function defined for the column.
4320 * @param {Number} col The column index.
4321 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4323 getRenderer : function(col){
4324 if(!this.config[col].renderer){
4325 return Roo.grid.ColumnModel.defaultRenderer;
4327 return this.config[col].renderer;
4331 * Sets the rendering (formatting) function for a column.
4332 * @param {Number} col The column index
4333 * @param {Function} fn The function to use to process the cell's raw data
4334 * to return HTML markup for the grid view. The render function is called with
4335 * the following parameters:<ul>
4336 * <li>Data value.</li>
4337 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4338 * <li>css A CSS style string to apply to the table cell.</li>
4339 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4340 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4341 * <li>Row index</li>
4342 * <li>Column index</li>
4343 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4345 setRenderer : function(col, fn){
4346 this.config[col].renderer = fn;
4350 * Returns the width for the specified column.
4351 * @param {Number} col The column index
4354 getColumnWidth : function(col){
4355 return this.config[col].width * 1 || this.defaultWidth;
4359 * Sets the width for a column.
4360 * @param {Number} col The column index
4361 * @param {Number} width The new width
4363 setColumnWidth : function(col, width, suppressEvent){
4364 this.config[col].width = width;
4365 this.totalWidth = null;
4367 this.fireEvent("widthchange", this, col, width);
4372 * Returns the total width of all columns.
4373 * @param {Boolean} includeHidden True to include hidden column widths
4376 getTotalWidth : function(includeHidden){
4377 if(!this.totalWidth){
4378 this.totalWidth = 0;
4379 for(var i = 0, len = this.config.length; i < len; i++){
4380 if(includeHidden || !this.isHidden(i)){
4381 this.totalWidth += this.getColumnWidth(i);
4385 return this.totalWidth;
4389 * Returns the header for the specified column.
4390 * @param {Number} col The column index
4393 getColumnHeader : function(col){
4394 return this.config[col].header;
4398 * Sets the header for a column.
4399 * @param {Number} col The column index
4400 * @param {String} header The new header
4402 setColumnHeader : function(col, header){
4403 this.config[col].header = header;
4404 this.fireEvent("headerchange", this, col, header);
4408 * Returns the tooltip for the specified column.
4409 * @param {Number} col The column index
4412 getColumnTooltip : function(col){
4413 return this.config[col].tooltip;
4416 * Sets the tooltip for a column.
4417 * @param {Number} col The column index
4418 * @param {String} tooltip The new tooltip
4420 setColumnTooltip : function(col, tooltip){
4421 this.config[col].tooltip = tooltip;
4425 * Returns the dataIndex for the specified column.
4426 * @param {Number} col The column index
4429 getDataIndex : function(col){
4430 return this.config[col].dataIndex;
4434 * Sets the dataIndex for a column.
4435 * @param {Number} col The column index
4436 * @param {Number} dataIndex The new dataIndex
4438 setDataIndex : function(col, dataIndex){
4439 this.config[col].dataIndex = dataIndex;
4445 * Returns true if the cell is editable.
4446 * @param {Number} colIndex The column index
4447 * @param {Number} rowIndex The row index
4450 isCellEditable : function(colIndex, rowIndex){
4451 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4455 * Returns the editor defined for the cell/column.
4456 * return false or null to disable editing.
4457 * @param {Number} colIndex The column index
4458 * @param {Number} rowIndex The row index
4461 getCellEditor : function(colIndex, rowIndex){
4462 return this.config[colIndex].editor;
4466 * Sets if a column is editable.
4467 * @param {Number} col The column index
4468 * @param {Boolean} editable True if the column is editable
4470 setEditable : function(col, editable){
4471 this.config[col].editable = editable;
4476 * Returns true if the column is hidden.
4477 * @param {Number} colIndex The column index
4480 isHidden : function(colIndex){
4481 return this.config[colIndex].hidden;
4486 * Returns true if the column width cannot be changed
4488 isFixed : function(colIndex){
4489 return this.config[colIndex].fixed;
4493 * Returns true if the column can be resized
4496 isResizable : function(colIndex){
4497 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4500 * Sets if a column is hidden.
4501 * @param {Number} colIndex The column index
4502 * @param {Boolean} hidden True if the column is hidden
4504 setHidden : function(colIndex, hidden){
4505 this.config[colIndex].hidden = hidden;
4506 this.totalWidth = null;
4507 this.fireEvent("hiddenchange", this, colIndex, hidden);
4511 * Sets the editor for a column.
4512 * @param {Number} col The column index
4513 * @param {Object} editor The editor object
4515 setEditor : function(col, editor){
4516 this.config[col].editor = editor;
4520 Roo.grid.ColumnModel.defaultRenderer = function(value){
4521 if(typeof value == "string" && value.length < 1){
4527 // Alias for backwards compatibility
4528 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4531 * Ext JS Library 1.1.1
4532 * Copyright(c) 2006-2007, Ext JS, LLC.
4534 * Originally Released Under LGPL - original licence link has changed is not relivant.
4537 * <script type="text/javascript">
4541 * @class Roo.LoadMask
4542 * A simple utility class for generically masking elements while loading data. If the element being masked has
4543 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4544 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4545 * element's UpdateManager load indicator and will be destroyed after the initial load.
4547 * Create a new LoadMask
4548 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4549 * @param {Object} config The config object
4551 Roo.LoadMask = function(el, config){
4552 this.el = Roo.get(el);
4553 Roo.apply(this, config);
4555 this.store.on('beforeload', this.onBeforeLoad, this);
4556 this.store.on('load', this.onLoad, this);
4557 this.store.on('loadexception', this.onLoadException, this);
4558 this.removeMask = false;
4560 var um = this.el.getUpdateManager();
4561 um.showLoadIndicator = false; // disable the default indicator
4562 um.on('beforeupdate', this.onBeforeLoad, this);
4563 um.on('update', this.onLoad, this);
4564 um.on('failure', this.onLoad, this);
4565 this.removeMask = true;
4569 Roo.LoadMask.prototype = {
4571 * @cfg {Boolean} removeMask
4572 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4573 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4577 * The text to display in a centered loading message box (defaults to 'Loading...')
4581 * @cfg {String} msgCls
4582 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4584 msgCls : 'x-mask-loading',
4587 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4593 * Disables the mask to prevent it from being displayed
4595 disable : function(){
4596 this.disabled = true;
4600 * Enables the mask so that it can be displayed
4602 enable : function(){
4603 this.disabled = false;
4606 onLoadException : function()
4610 if (typeof(arguments[3]) != 'undefined') {
4611 Roo.MessageBox.alert("Error loading",arguments[3]);
4615 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4616 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4625 this.el.unmask(this.removeMask);
4630 this.el.unmask(this.removeMask);
4634 onBeforeLoad : function(){
4636 this.el.mask(this.msg, this.msgCls);
4641 destroy : function(){
4643 this.store.un('beforeload', this.onBeforeLoad, this);
4644 this.store.un('load', this.onLoad, this);
4645 this.store.un('loadexception', this.onLoadException, this);
4647 var um = this.el.getUpdateManager();
4648 um.un('beforeupdate', this.onBeforeLoad, this);
4649 um.un('update', this.onLoad, this);
4650 um.un('failure', this.onLoad, this);
4661 * @class Roo.bootstrap.Table
4662 * @extends Roo.bootstrap.Component
4663 * Bootstrap Table class
4664 * @cfg {String} cls table class
4665 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4666 * @cfg {String} bgcolor Specifies the background color for a table
4667 * @cfg {Number} border Specifies whether the table cells should have borders or not
4668 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4669 * @cfg {Number} cellspacing Specifies the space between cells
4670 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4671 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4672 * @cfg {String} sortable Specifies that the table should be sortable
4673 * @cfg {String} summary Specifies a summary of the content of a table
4674 * @cfg {Number} width Specifies the width of a table
4675 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4677 * @cfg {boolean} striped Should the rows be alternative striped
4678 * @cfg {boolean} bordered Add borders to the table
4679 * @cfg {boolean} hover Add hover highlighting
4680 * @cfg {boolean} condensed Format condensed
4681 * @cfg {boolean} responsive Format condensed
4682 * @cfg {Boolean} loadMask (true|false) default false
4683 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4684 * @cfg {Boolean} thead (true|false) generate thead, default true
4685 * @cfg {Boolean} RowSelection (true|false) default false
4686 * @cfg {Boolean} CellSelection (true|false) default false
4688 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4692 * Create a new Table
4693 * @param {Object} config The config object
4696 Roo.bootstrap.Table = function(config){
4697 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4700 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4701 this.sm = this.selModel;
4702 this.sm.xmodule = this.xmodule || false;
4704 if (this.cm && typeof(this.cm.config) == 'undefined') {
4705 this.colModel = new Roo.grid.ColumnModel(this.cm);
4706 this.cm = this.colModel;
4707 this.cm.xmodule = this.xmodule || false;
4710 this.store= Roo.factory(this.store, Roo.data);
4711 this.ds = this.store;
4712 this.ds.xmodule = this.xmodule || false;
4715 if (this.footer && this.store) {
4716 this.footer.dataSource = this.ds;
4717 this.footer = Roo.factory(this.footer);
4724 * Fires when a cell is clicked
4725 * @param {Roo.bootstrap.Table} this
4726 * @param {Roo.Element} el
4727 * @param {Number} rowIndex
4728 * @param {Number} columnIndex
4729 * @param {Roo.EventObject} e
4733 * @event celldblclick
4734 * Fires when a cell is double clicked
4735 * @param {Roo.bootstrap.Table} this
4736 * @param {Roo.Element} el
4737 * @param {Number} rowIndex
4738 * @param {Number} columnIndex
4739 * @param {Roo.EventObject} e
4741 "celldblclick" : true,
4744 * Fires when a row is clicked
4745 * @param {Roo.bootstrap.Table} this
4746 * @param {Roo.Element} el
4747 * @param {Number} rowIndex
4748 * @param {Roo.EventObject} e
4752 * @event rowdblclick
4753 * Fires when a row is double clicked
4754 * @param {Roo.bootstrap.Table} this
4755 * @param {Roo.Element} el
4756 * @param {Number} rowIndex
4757 * @param {Roo.EventObject} e
4759 "rowdblclick" : true,
4762 * Fires when a mouseover occur
4763 * @param {Roo.bootstrap.Table} this
4764 * @param {Roo.Element} el
4765 * @param {Number} rowIndex
4766 * @param {Number} columnIndex
4767 * @param {Roo.EventObject} e
4772 * Fires when a mouseout occur
4773 * @param {Roo.bootstrap.Table} this
4774 * @param {Roo.Element} el
4775 * @param {Number} rowIndex
4776 * @param {Number} columnIndex
4777 * @param {Roo.EventObject} e
4782 * Fires when a row is rendered, so you can change add a style to it.
4783 * @param {Roo.bootstrap.Table} this
4784 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4791 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4815 RowSelection : false,
4816 CellSelection : false,
4819 // Roo.Element - the tbody
4822 getAutoCreate : function(){
4823 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4832 cfg.cls += ' table-striped';
4836 cfg.cls += ' table-hover';
4838 if (this.bordered) {
4839 cfg.cls += ' table-bordered';
4841 if (this.condensed) {
4842 cfg.cls += ' table-condensed';
4844 if (this.responsive) {
4845 cfg.cls += ' table-responsive';
4849 cfg.cls+= ' ' +this.cls;
4852 // this lot should be simplifed...
4855 cfg.align=this.align;
4858 cfg.bgcolor=this.bgcolor;
4861 cfg.border=this.border;
4863 if (this.cellpadding) {
4864 cfg.cellpadding=this.cellpadding;
4866 if (this.cellspacing) {
4867 cfg.cellspacing=this.cellspacing;
4870 cfg.frame=this.frame;
4873 cfg.rules=this.rules;
4875 if (this.sortable) {
4876 cfg.sortable=this.sortable;
4879 cfg.summary=this.summary;
4882 cfg.width=this.width;
4885 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4888 if(this.store || this.cm){
4890 cfg.cn.push(this.renderHeader());
4893 cfg.cn.push(this.renderBody());
4896 cfg.cn.push(this.renderFooter());
4899 cfg.cls+= ' TableGrid';
4902 return { cn : [ cfg ] };
4905 initEvents : function()
4907 if(!this.store || !this.cm){
4911 //Roo.log('initEvents with ds!!!!');
4913 this.mainBody = this.el.select('tbody', true).first();
4918 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4919 e.on('click', _this.sort, _this);
4922 this.el.on("click", this.onClick, this);
4923 this.el.on("dblclick", this.onDblClick, this);
4925 this.parent().el.setStyle('position', 'relative');
4927 this.footer.parentId = this.id;
4928 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4931 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4933 this.store.on('load', this.onLoad, this);
4934 this.store.on('beforeload', this.onBeforeLoad, this);
4935 this.store.on('update', this.onUpdate, this);
4939 onMouseover : function(e, el)
4941 var cell = Roo.get(el);
4947 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4948 cell = cell.findParent('td', false, true);
4951 var row = cell.findParent('tr', false, true);
4952 var cellIndex = cell.dom.cellIndex;
4953 var rowIndex = row.dom.rowIndex - 1; // start from 0
4955 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4959 onMouseout : function(e, el)
4961 var cell = Roo.get(el);
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; // start from 0
4975 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4979 onClick : function(e, el)
4981 var cell = Roo.get(el);
4983 if(!cell || (!this.CellSelection && !this.RowSelection)){
4988 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4989 cell = cell.findParent('td', false, true);
4992 var row = cell.findParent('tr', false, true);
4993 var cellIndex = cell.dom.cellIndex;
4994 var rowIndex = row.dom.rowIndex - 1;
4996 if(this.CellSelection){
4997 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5000 if(this.RowSelection){
5001 this.fireEvent('rowclick', this, row, rowIndex, e);
5007 onDblClick : function(e,el)
5009 var cell = Roo.get(el);
5011 if(!cell || (!this.CellSelection && !this.RowSelection)){
5015 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5016 cell = cell.findParent('td', false, true);
5019 var row = cell.findParent('tr', false, true);
5020 var cellIndex = cell.dom.cellIndex;
5021 var rowIndex = row.dom.rowIndex - 1;
5023 if(this.CellSelection){
5024 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5027 if(this.RowSelection){
5028 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5032 sort : function(e,el)
5034 var col = Roo.get(el)
5036 if(!col.hasClass('sortable')){
5040 var sort = col.attr('sort');
5043 if(col.hasClass('glyphicon-arrow-up')){
5047 this.store.sortInfo = {field : sort, direction : dir};
5050 Roo.log("calling footer first");
5051 this.footer.onClick('first');
5054 this.store.load({ params : { start : 0 } });
5058 renderHeader : function()
5067 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5069 var config = cm.config[i];
5074 html: cm.getColumnHeader(i)
5077 if(typeof(config.hidden) != 'undefined' && config.hidden){
5078 c.style += ' display:none;';
5081 if(typeof(config.dataIndex) != 'undefined'){
5082 c.sort = config.dataIndex;
5085 if(typeof(config.sortable) != 'undefined' && config.sortable){
5089 if(typeof(config.align) != 'undefined' && config.align.length){
5090 c.style += ' text-align:' + config.align + ';';
5093 if(typeof(config.width) != 'undefined'){
5094 c.style += ' width:' + config.width + 'px;';
5103 renderBody : function()
5113 colspan : this.cm.getColumnCount()
5123 renderFooter : function()
5133 colspan : this.cm.getColumnCount()
5147 Roo.log('ds onload');
5152 var ds = this.store;
5154 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5155 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5157 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5158 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5161 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5162 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5166 var tbody = this.mainBody;
5168 if(ds.getCount() > 0){
5169 ds.data.each(function(d,rowIndex){
5170 var row = this.renderRow(cm, ds, rowIndex);
5172 tbody.createChild(row);
5176 if(row.cellObjects.length){
5177 Roo.each(row.cellObjects, function(r){
5178 _this.renderCellObject(r);
5185 Roo.each(this.el.select('tbody td', true).elements, function(e){
5186 e.on('mouseover', _this.onMouseover, _this);
5189 Roo.each(this.el.select('tbody td', true).elements, function(e){
5190 e.on('mouseout', _this.onMouseout, _this);
5193 //if(this.loadMask){
5194 // this.maskEl.hide();
5199 onUpdate : function(ds,record)
5201 this.refreshRow(record);
5203 onRemove : function(ds, record, index, isUpdate){
5204 if(isUpdate !== true){
5205 this.fireEvent("beforerowremoved", this, index, record);
5207 var bt = this.mainBody.dom;
5209 bt.removeChild(bt.rows[index]);
5212 if(isUpdate !== true){
5213 //this.stripeRows(index);
5214 //this.syncRowHeights(index, index);
5216 this.fireEvent("rowremoved", this, index, record);
5221 refreshRow : function(record){
5222 var ds = this.store, index;
5223 if(typeof record == 'number'){
5225 record = ds.getAt(index);
5227 index = ds.indexOf(record);
5229 this.insertRow(ds, index, true);
5230 this.onRemove(ds, record, index+1, true);
5231 //this.syncRowHeights(index, index);
5233 this.fireEvent("rowupdated", this, index, record);
5236 insertRow : function(dm, rowIndex, isUpdate){
5239 this.fireEvent("beforerowsinserted", this, rowIndex);
5241 //var s = this.getScrollState();
5242 var row = this.renderRow(this.cm, this.store, rowIndex);
5243 // insert before rowIndex..
5244 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5248 if(row.cellObjects.length){
5249 Roo.each(row.cellObjects, function(r){
5250 _this.renderCellObject(r);
5255 this.fireEvent("rowsinserted", this, rowIndex);
5256 //this.syncRowHeights(firstRow, lastRow);
5257 //this.stripeRows(firstRow);
5264 getRowDom : function(rowIndex)
5266 // not sure if I need to check this.. but let's do it anyway..
5267 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5268 this.mainBody.dom.rows[rowIndex] : false
5270 // returns the object tree for a tr..
5273 renderRow : function(cm, ds, rowIndex) {
5275 var d = ds.getAt(rowIndex);
5282 var cellObjects = [];
5284 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5285 var config = cm.config[i];
5287 var renderer = cm.getRenderer(i);
5291 if(typeof(renderer) !== 'undefined'){
5292 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5294 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5295 // and are rendered into the cells after the row is rendered - using the id for the element.
5297 if(typeof(value) === 'object'){
5307 rowIndex : rowIndex,
5312 this.fireEvent('rowclass', this, rowcfg);
5316 cls : rowcfg.rowClass,
5318 html: (typeof(value) === 'object') ? '' : value
5325 if(typeof(config.hidden) != 'undefined' && config.hidden){
5326 td.style += ' display:none;';
5329 if(typeof(config.align) != 'undefined' && config.align.length){
5330 td.style += ' text-align:' + config.align + ';';
5333 if(typeof(config.width) != 'undefined'){
5334 td.style += ' width:' + config.width + 'px;';
5341 row.cellObjects = cellObjects;
5349 onBeforeLoad : function()
5351 //Roo.log('ds onBeforeLoad');
5355 //if(this.loadMask){
5356 // this.maskEl.show();
5362 this.el.select('tbody', true).first().dom.innerHTML = '';
5365 getSelectionModel : function(){
5367 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5369 return this.selModel;
5372 * Render the Roo.bootstrap object from renderder
5374 renderCellObject : function(r)
5378 var t = r.cfg.render(r.container);
5381 Roo.each(r.cfg.cn, function(c){
5383 container: t.getChildContainer(),
5386 _this.renderCellObject(child);
5403 * @class Roo.bootstrap.TableCell
5404 * @extends Roo.bootstrap.Component
5405 * Bootstrap TableCell class
5406 * @cfg {String} html cell contain text
5407 * @cfg {String} cls cell class
5408 * @cfg {String} tag cell tag (td|th) default td
5409 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5410 * @cfg {String} align Aligns the content in a cell
5411 * @cfg {String} axis Categorizes cells
5412 * @cfg {String} bgcolor Specifies the background color of a cell
5413 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5414 * @cfg {Number} colspan Specifies the number of columns a cell should span
5415 * @cfg {String} headers Specifies one or more header cells a cell is related to
5416 * @cfg {Number} height Sets the height of a cell
5417 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5418 * @cfg {Number} rowspan Sets the number of rows a cell should span
5419 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5420 * @cfg {String} valign Vertical aligns the content in a cell
5421 * @cfg {Number} width Specifies the width of a cell
5424 * Create a new TableCell
5425 * @param {Object} config The config object
5428 Roo.bootstrap.TableCell = function(config){
5429 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5432 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5452 getAutoCreate : function(){
5453 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5473 cfg.align=this.align
5479 cfg.bgcolor=this.bgcolor
5482 cfg.charoff=this.charoff
5485 cfg.colspan=this.colspan
5488 cfg.headers=this.headers
5491 cfg.height=this.height
5494 cfg.nowrap=this.nowrap
5497 cfg.rowspan=this.rowspan
5500 cfg.scope=this.scope
5503 cfg.valign=this.valign
5506 cfg.width=this.width
5525 * @class Roo.bootstrap.TableRow
5526 * @extends Roo.bootstrap.Component
5527 * Bootstrap TableRow class
5528 * @cfg {String} cls row class
5529 * @cfg {String} align Aligns the content in a table row
5530 * @cfg {String} bgcolor Specifies a background color for a table row
5531 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5532 * @cfg {String} valign Vertical aligns the content in a table row
5535 * Create a new TableRow
5536 * @param {Object} config The config object
5539 Roo.bootstrap.TableRow = function(config){
5540 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5543 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5551 getAutoCreate : function(){
5552 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5562 cfg.align = this.align;
5565 cfg.bgcolor = this.bgcolor;
5568 cfg.charoff = this.charoff;
5571 cfg.valign = this.valign;
5589 * @class Roo.bootstrap.TableBody
5590 * @extends Roo.bootstrap.Component
5591 * Bootstrap TableBody class
5592 * @cfg {String} cls element class
5593 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5594 * @cfg {String} align Aligns the content inside the element
5595 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5596 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5599 * Create a new TableBody
5600 * @param {Object} config The config object
5603 Roo.bootstrap.TableBody = function(config){
5604 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5607 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5615 getAutoCreate : function(){
5616 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5630 cfg.align = this.align;
5633 cfg.charoff = this.charoff;
5636 cfg.valign = this.valign;
5643 // initEvents : function()
5650 // this.store = Roo.factory(this.store, Roo.data);
5651 // this.store.on('load', this.onLoad, this);
5653 // this.store.load();
5657 // onLoad: function ()
5659 // this.fireEvent('load', this);
5669 * Ext JS Library 1.1.1
5670 * Copyright(c) 2006-2007, Ext JS, LLC.
5672 * Originally Released Under LGPL - original licence link has changed is not relivant.
5675 * <script type="text/javascript">
5678 // as we use this in bootstrap.
5679 Roo.namespace('Roo.form');
5681 * @class Roo.form.Action
5682 * Internal Class used to handle form actions
5684 * @param {Roo.form.BasicForm} el The form element or its id
5685 * @param {Object} config Configuration options
5690 // define the action interface
5691 Roo.form.Action = function(form, options){
5693 this.options = options || {};
5696 * Client Validation Failed
5699 Roo.form.Action.CLIENT_INVALID = 'client';
5701 * Server Validation Failed
5704 Roo.form.Action.SERVER_INVALID = 'server';
5706 * Connect to Server Failed
5709 Roo.form.Action.CONNECT_FAILURE = 'connect';
5711 * Reading Data from Server Failed
5714 Roo.form.Action.LOAD_FAILURE = 'load';
5716 Roo.form.Action.prototype = {
5718 failureType : undefined,
5719 response : undefined,
5723 run : function(options){
5728 success : function(response){
5733 handleResponse : function(response){
5737 // default connection failure
5738 failure : function(response){
5740 this.response = response;
5741 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5742 this.form.afterAction(this, false);
5745 processResponse : function(response){
5746 this.response = response;
5747 if(!response.responseText){
5750 this.result = this.handleResponse(response);
5754 // utility functions used internally
5755 getUrl : function(appendParams){
5756 var url = this.options.url || this.form.url || this.form.el.dom.action;
5758 var p = this.getParams();
5760 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5766 getMethod : function(){
5767 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5770 getParams : function(){
5771 var bp = this.form.baseParams;
5772 var p = this.options.params;
5774 if(typeof p == "object"){
5775 p = Roo.urlEncode(Roo.applyIf(p, bp));
5776 }else if(typeof p == 'string' && bp){
5777 p += '&' + Roo.urlEncode(bp);
5780 p = Roo.urlEncode(bp);
5785 createCallback : function(){
5787 success: this.success,
5788 failure: this.failure,
5790 timeout: (this.form.timeout*1000),
5791 upload: this.form.fileUpload ? this.success : undefined
5796 Roo.form.Action.Submit = function(form, options){
5797 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5800 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5803 haveProgress : false,
5804 uploadComplete : false,
5806 // uploadProgress indicator.
5807 uploadProgress : function()
5809 if (!this.form.progressUrl) {
5813 if (!this.haveProgress) {
5814 Roo.MessageBox.progress("Uploading", "Uploading");
5816 if (this.uploadComplete) {
5817 Roo.MessageBox.hide();
5821 this.haveProgress = true;
5823 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5825 var c = new Roo.data.Connection();
5827 url : this.form.progressUrl,
5832 success : function(req){
5833 //console.log(data);
5837 rdata = Roo.decode(req.responseText)
5839 Roo.log("Invalid data from server..");
5843 if (!rdata || !rdata.success) {
5845 Roo.MessageBox.alert(Roo.encode(rdata));
5848 var data = rdata.data;
5850 if (this.uploadComplete) {
5851 Roo.MessageBox.hide();
5856 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5857 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5860 this.uploadProgress.defer(2000,this);
5863 failure: function(data) {
5864 Roo.log('progress url failed ');
5875 // run get Values on the form, so it syncs any secondary forms.
5876 this.form.getValues();
5878 var o = this.options;
5879 var method = this.getMethod();
5880 var isPost = method == 'POST';
5881 if(o.clientValidation === false || this.form.isValid()){
5883 if (this.form.progressUrl) {
5884 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5885 (new Date() * 1) + '' + Math.random());
5890 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5891 form:this.form.el.dom,
5892 url:this.getUrl(!isPost),
5894 params:isPost ? this.getParams() : null,
5895 isUpload: this.form.fileUpload
5898 this.uploadProgress();
5900 }else if (o.clientValidation !== false){ // client validation failed
5901 this.failureType = Roo.form.Action.CLIENT_INVALID;
5902 this.form.afterAction(this, false);
5906 success : function(response)
5908 this.uploadComplete= true;
5909 if (this.haveProgress) {
5910 Roo.MessageBox.hide();
5914 var result = this.processResponse(response);
5915 if(result === true || result.success){
5916 this.form.afterAction(this, true);
5920 this.form.markInvalid(result.errors);
5921 this.failureType = Roo.form.Action.SERVER_INVALID;
5923 this.form.afterAction(this, false);
5925 failure : function(response)
5927 this.uploadComplete= true;
5928 if (this.haveProgress) {
5929 Roo.MessageBox.hide();
5932 this.response = response;
5933 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5934 this.form.afterAction(this, false);
5937 handleResponse : function(response){
5938 if(this.form.errorReader){
5939 var rs = this.form.errorReader.read(response);
5942 for(var i = 0, len = rs.records.length; i < len; i++) {
5943 var r = rs.records[i];
5947 if(errors.length < 1){
5951 success : rs.success,
5957 ret = Roo.decode(response.responseText);
5961 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5971 Roo.form.Action.Load = function(form, options){
5972 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5973 this.reader = this.form.reader;
5976 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5981 Roo.Ajax.request(Roo.apply(
5982 this.createCallback(), {
5983 method:this.getMethod(),
5984 url:this.getUrl(false),
5985 params:this.getParams()
5989 success : function(response){
5991 var result = this.processResponse(response);
5992 if(result === true || !result.success || !result.data){
5993 this.failureType = Roo.form.Action.LOAD_FAILURE;
5994 this.form.afterAction(this, false);
5997 this.form.clearInvalid();
5998 this.form.setValues(result.data);
5999 this.form.afterAction(this, true);
6002 handleResponse : function(response){
6003 if(this.form.reader){
6004 var rs = this.form.reader.read(response);
6005 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6007 success : rs.success,
6011 return Roo.decode(response.responseText);
6015 Roo.form.Action.ACTION_TYPES = {
6016 'load' : Roo.form.Action.Load,
6017 'submit' : Roo.form.Action.Submit
6026 * @class Roo.bootstrap.Form
6027 * @extends Roo.bootstrap.Component
6028 * Bootstrap Form class
6029 * @cfg {String} method GET | POST (default POST)
6030 * @cfg {String} labelAlign top | left (default top)
6031 * @cfg {String} align left | right - for navbars
6036 * @param {Object} config The config object
6040 Roo.bootstrap.Form = function(config){
6041 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6044 * @event clientvalidation
6045 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6046 * @param {Form} this
6047 * @param {Boolean} valid true if the form has passed client-side validation
6049 clientvalidation: true,
6051 * @event beforeaction
6052 * Fires before any action is performed. Return false to cancel the action.
6053 * @param {Form} this
6054 * @param {Action} action The action to be performed
6058 * @event actionfailed
6059 * Fires when an action fails.
6060 * @param {Form} this
6061 * @param {Action} action The action that failed
6063 actionfailed : true,
6065 * @event actioncomplete
6066 * Fires when an action is completed.
6067 * @param {Form} this
6068 * @param {Action} action The action that completed
6070 actioncomplete : true
6075 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6078 * @cfg {String} method
6079 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6084 * The URL to use for form actions if one isn't supplied in the action options.
6087 * @cfg {Boolean} fileUpload
6088 * Set to true if this form is a file upload.
6092 * @cfg {Object} baseParams
6093 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6097 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6101 * @cfg {Sting} align (left|right) for navbar forms
6106 activeAction : null,
6109 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6110 * element by passing it or its id or mask the form itself by passing in true.
6113 waitMsgTarget : false,
6118 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6119 * element by passing it or its id or mask the form itself by passing in true.
6123 getAutoCreate : function(){
6127 method : this.method || 'POST',
6128 id : this.id || Roo.id(),
6131 if (this.parent().xtype.match(/^Nav/)) {
6132 cfg.cls = 'navbar-form navbar-' + this.align;
6136 if (this.labelAlign == 'left' ) {
6137 cfg.cls += ' form-horizontal';
6143 initEvents : function()
6145 this.el.on('submit', this.onSubmit, this);
6146 // this was added as random key presses on the form where triggering form submit.
6147 this.el.on('keypress', function(e) {
6148 if (e.getCharCode() != 13) {
6151 // we might need to allow it for textareas.. and some other items.
6152 // check e.getTarget().
6154 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6158 Roo.log("keypress blocked");
6166 onSubmit : function(e){
6171 * Returns true if client-side validation on the form is successful.
6174 isValid : function(){
6175 var items = this.getItems();
6177 items.each(function(f){
6186 * Returns true if any fields in this form have changed since their original load.
6189 isDirty : function(){
6191 var items = this.getItems();
6192 items.each(function(f){
6202 * Performs a predefined action (submit or load) or custom actions you define on this form.
6203 * @param {String} actionName The name of the action type
6204 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6205 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6206 * accept other config options):
6208 Property Type Description
6209 ---------------- --------------- ----------------------------------------------------------------------------------
6210 url String The url for the action (defaults to the form's url)
6211 method String The form method to use (defaults to the form's method, or POST if not defined)
6212 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6213 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6214 validate the form on the client (defaults to false)
6216 * @return {BasicForm} this
6218 doAction : function(action, options){
6219 if(typeof action == 'string'){
6220 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6222 if(this.fireEvent('beforeaction', this, action) !== false){
6223 this.beforeAction(action);
6224 action.run.defer(100, action);
6230 beforeAction : function(action){
6231 var o = action.options;
6233 // not really supported yet.. ??
6235 //if(this.waitMsgTarget === true){
6236 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6237 //}else if(this.waitMsgTarget){
6238 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6239 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6241 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6247 afterAction : function(action, success){
6248 this.activeAction = null;
6249 var o = action.options;
6251 //if(this.waitMsgTarget === true){
6253 //}else if(this.waitMsgTarget){
6254 // this.waitMsgTarget.unmask();
6256 // Roo.MessageBox.updateProgress(1);
6257 // Roo.MessageBox.hide();
6264 Roo.callback(o.success, o.scope, [this, action]);
6265 this.fireEvent('actioncomplete', this, action);
6269 // failure condition..
6270 // we have a scenario where updates need confirming.
6271 // eg. if a locking scenario exists..
6272 // we look for { errors : { needs_confirm : true }} in the response.
6274 (typeof(action.result) != 'undefined') &&
6275 (typeof(action.result.errors) != 'undefined') &&
6276 (typeof(action.result.errors.needs_confirm) != 'undefined')
6279 Roo.log("not supported yet");
6282 Roo.MessageBox.confirm(
6283 "Change requires confirmation",
6284 action.result.errorMsg,
6289 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6299 Roo.callback(o.failure, o.scope, [this, action]);
6300 // show an error message if no failed handler is set..
6301 if (!this.hasListener('actionfailed')) {
6302 Roo.log("need to add dialog support");
6304 Roo.MessageBox.alert("Error",
6305 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6306 action.result.errorMsg :
6307 "Saving Failed, please check your entries or try again"
6312 this.fireEvent('actionfailed', this, action);
6317 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6318 * @param {String} id The value to search for
6321 findField : function(id){
6322 var items = this.getItems();
6323 var field = items.get(id);
6325 items.each(function(f){
6326 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6333 return field || null;
6336 * Mark fields in this form invalid in bulk.
6337 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6338 * @return {BasicForm} this
6340 markInvalid : function(errors){
6341 if(errors instanceof Array){
6342 for(var i = 0, len = errors.length; i < len; i++){
6343 var fieldError = errors[i];
6344 var f = this.findField(fieldError.id);
6346 f.markInvalid(fieldError.msg);
6352 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6353 field.markInvalid(errors[id]);
6357 //Roo.each(this.childForms || [], function (f) {
6358 // f.markInvalid(errors);
6365 * Set values for fields in this form in bulk.
6366 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6367 * @return {BasicForm} this
6369 setValues : function(values){
6370 if(values instanceof Array){ // array of objects
6371 for(var i = 0, len = values.length; i < len; i++){
6373 var f = this.findField(v.id);
6375 f.setValue(v.value);
6376 if(this.trackResetOnLoad){
6377 f.originalValue = f.getValue();
6381 }else{ // object hash
6384 if(typeof values[id] != 'function' && (field = this.findField(id))){
6386 if (field.setFromData &&
6388 field.displayField &&
6389 // combos' with local stores can
6390 // be queried via setValue()
6391 // to set their value..
6392 (field.store && !field.store.isLocal)
6396 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6397 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6398 field.setFromData(sd);
6401 field.setValue(values[id]);
6405 if(this.trackResetOnLoad){
6406 field.originalValue = field.getValue();
6412 //Roo.each(this.childForms || [], function (f) {
6413 // f.setValues(values);
6420 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6421 * they are returned as an array.
6422 * @param {Boolean} asString
6425 getValues : function(asString){
6426 //if (this.childForms) {
6427 // copy values from the child forms
6428 // Roo.each(this.childForms, function (f) {
6429 // this.setValues(f.getValues());
6435 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6436 if(asString === true){
6439 return Roo.urlDecode(fs);
6443 * Returns the fields in this form as an object with key/value pairs.
6444 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6447 getFieldValues : function(with_hidden)
6449 var items = this.getItems();
6451 items.each(function(f){
6455 var v = f.getValue();
6456 if (f.inputType =='radio') {
6457 if (typeof(ret[f.getName()]) == 'undefined') {
6458 ret[f.getName()] = ''; // empty..
6461 if (!f.el.dom.checked) {
6469 // not sure if this supported any more..
6470 if ((typeof(v) == 'object') && f.getRawValue) {
6471 v = f.getRawValue() ; // dates..
6473 // combo boxes where name != hiddenName...
6474 if (f.name != f.getName()) {
6475 ret[f.name] = f.getRawValue();
6477 ret[f.getName()] = v;
6484 * Clears all invalid messages in this form.
6485 * @return {BasicForm} this
6487 clearInvalid : function(){
6488 var items = this.getItems();
6490 items.each(function(f){
6501 * @return {BasicForm} this
6504 var items = this.getItems();
6505 items.each(function(f){
6509 Roo.each(this.childForms || [], function (f) {
6516 getItems : function()
6518 var r=new Roo.util.MixedCollection(false, function(o){
6519 return o.id || (o.id = Roo.id());
6521 var iter = function(el) {
6528 Roo.each(el.items,function(e) {
6547 * Ext JS Library 1.1.1
6548 * Copyright(c) 2006-2007, Ext JS, LLC.
6550 * Originally Released Under LGPL - original licence link has changed is not relivant.
6553 * <script type="text/javascript">
6556 * @class Roo.form.VTypes
6557 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6560 Roo.form.VTypes = function(){
6561 // closure these in so they are only created once.
6562 var alpha = /^[a-zA-Z_]+$/;
6563 var alphanum = /^[a-zA-Z0-9_]+$/;
6564 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6565 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6567 // All these messages and functions are configurable
6570 * The function used to validate email addresses
6571 * @param {String} value The email address
6573 'email' : function(v){
6574 return email.test(v);
6577 * The error text to display when the email validation function returns false
6580 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6582 * The keystroke filter mask to be applied on email input
6585 'emailMask' : /[a-z0-9_\.\-@]/i,
6588 * The function used to validate URLs
6589 * @param {String} value The URL
6591 'url' : function(v){
6595 * The error text to display when the url validation function returns false
6598 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6601 * The function used to validate alpha values
6602 * @param {String} value The value
6604 'alpha' : function(v){
6605 return alpha.test(v);
6608 * The error text to display when the alpha validation function returns false
6611 'alphaText' : 'This field should only contain letters and _',
6613 * The keystroke filter mask to be applied on alpha input
6616 'alphaMask' : /[a-z_]/i,
6619 * The function used to validate alphanumeric values
6620 * @param {String} value The value
6622 'alphanum' : function(v){
6623 return alphanum.test(v);
6626 * The error text to display when the alphanumeric validation function returns false
6629 'alphanumText' : 'This field should only contain letters, numbers and _',
6631 * The keystroke filter mask to be applied on alphanumeric input
6634 'alphanumMask' : /[a-z0-9_]/i
6644 * @class Roo.bootstrap.Input
6645 * @extends Roo.bootstrap.Component
6646 * Bootstrap Input class
6647 * @cfg {Boolean} disabled is it disabled
6648 * @cfg {String} fieldLabel - the label associated
6649 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6650 * @cfg {String} name name of the input
6651 * @cfg {string} fieldLabel - the label associated
6652 * @cfg {string} inputType - input / file submit ...
6653 * @cfg {string} placeholder - placeholder to put in text.
6654 * @cfg {string} before - input group add on before
6655 * @cfg {string} after - input group add on after
6656 * @cfg {string} size - (lg|sm) or leave empty..
6657 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6658 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6659 * @cfg {Number} md colspan out of 12 for computer-sized screens
6660 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6661 * @cfg {string} value default value of the input
6662 * @cfg {Number} labelWidth set the width of label (0-12)
6663 * @cfg {String} labelAlign (top|left)
6664 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6665 * @cfg {String} align (left|center|right) Default left
6669 * Create a new Input
6670 * @param {Object} config The config object
6673 Roo.bootstrap.Input = function(config){
6674 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6679 * Fires when this field receives input focus.
6680 * @param {Roo.form.Field} this
6685 * Fires when this field loses input focus.
6686 * @param {Roo.form.Field} this
6691 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6692 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6693 * @param {Roo.form.Field} this
6694 * @param {Roo.EventObject} e The event object
6699 * Fires just before the field blurs if the field value has changed.
6700 * @param {Roo.form.Field} this
6701 * @param {Mixed} newValue The new value
6702 * @param {Mixed} oldValue The original value
6707 * Fires after the field has been marked as invalid.
6708 * @param {Roo.form.Field} this
6709 * @param {String} msg The validation message
6714 * Fires after the field has been validated with no errors.
6715 * @param {Roo.form.Field} this
6720 * Fires after the key up
6721 * @param {Roo.form.Field} this
6722 * @param {Roo.EventObject} e The event Object
6728 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6730 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6731 automatic validation (defaults to "keyup").
6733 validationEvent : "keyup",
6735 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6737 validateOnBlur : true,
6739 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6741 validationDelay : 250,
6743 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6745 focusClass : "x-form-focus", // not needed???
6749 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6751 invalidClass : "has-error",
6754 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6756 selectOnFocus : false,
6759 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6763 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6768 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6770 disableKeyFilter : false,
6773 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6777 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6781 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6783 blankText : "This field is required",
6786 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6790 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6792 maxLength : Number.MAX_VALUE,
6794 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6796 minLengthText : "The minimum length for this field is {0}",
6798 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6800 maxLengthText : "The maximum length for this field is {0}",
6804 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6805 * If available, this function will be called only after the basic validators all return true, and will be passed the
6806 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6810 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6811 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6812 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6816 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6839 formatedValue : false,
6841 parentLabelAlign : function()
6844 while (parent.parent()) {
6845 parent = parent.parent();
6846 if (typeof(parent.labelAlign) !='undefined') {
6847 return parent.labelAlign;
6854 getAutoCreate : function(){
6856 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6862 if(this.inputType != 'hidden'){
6863 cfg.cls = 'form-group' //input-group
6869 type : this.inputType,
6871 cls : 'form-control',
6872 placeholder : this.placeholder || ''
6877 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6880 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6881 input.maxLength = this.maxLength;
6884 if (this.disabled) {
6885 input.disabled=true;
6888 if (this.readOnly) {
6889 input.readonly=true;
6893 input.name = this.name;
6896 input.cls += ' input-' + this.size;
6899 ['xs','sm','md','lg'].map(function(size){
6900 if (settings[size]) {
6901 cfg.cls += ' col-' + size + '-' + settings[size];
6905 var inputblock = input;
6907 if (this.before || this.after) {
6910 cls : 'input-group',
6913 if (this.before && typeof(this.before) == 'string') {
6915 inputblock.cn.push({
6917 cls : 'roo-input-before input-group-addon',
6921 if (this.before && typeof(this.before) == 'object') {
6922 this.before = Roo.factory(this.before);
6923 Roo.log(this.before);
6924 inputblock.cn.push({
6926 cls : 'roo-input-before input-group-' +
6927 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6931 inputblock.cn.push(input);
6933 if (this.after && typeof(this.after) == 'string') {
6934 inputblock.cn.push({
6936 cls : 'roo-input-after input-group-addon',
6940 if (this.after && typeof(this.after) == 'object') {
6941 this.after = Roo.factory(this.after);
6942 Roo.log(this.after);
6943 inputblock.cn.push({
6945 cls : 'roo-input-after input-group-' +
6946 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6951 if (align ==='left' && this.fieldLabel.length) {
6952 Roo.log("left and has label");
6958 cls : 'control-label col-sm-' + this.labelWidth,
6959 html : this.fieldLabel
6963 cls : "col-sm-" + (12 - this.labelWidth),
6970 } else if ( this.fieldLabel.length) {
6976 //cls : 'input-group-addon',
6977 html : this.fieldLabel
6987 Roo.log(" no label && no align");
6996 Roo.log('input-parentType: ' + this.parentType);
6998 if (this.parentType === 'Navbar' && this.parent().bar) {
6999 cfg.cls += ' navbar-form';
7007 * return the real input element.
7009 inputEl: function ()
7011 return this.el.select('input.form-control',true).first();
7013 setDisabled : function(v)
7015 var i = this.inputEl().dom;
7017 i.removeAttribute('disabled');
7021 i.setAttribute('disabled','true');
7023 initEvents : function()
7026 this.inputEl().on("keydown" , this.fireKey, this);
7027 this.inputEl().on("focus", this.onFocus, this);
7028 this.inputEl().on("blur", this.onBlur, this);
7030 this.inputEl().relayEvent('keyup', this);
7032 // reference to original value for reset
7033 this.originalValue = this.getValue();
7034 //Roo.form.TextField.superclass.initEvents.call(this);
7035 if(this.validationEvent == 'keyup'){
7036 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7037 this.inputEl().on('keyup', this.filterValidation, this);
7039 else if(this.validationEvent !== false){
7040 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7043 if(this.selectOnFocus){
7044 this.on("focus", this.preFocus, this);
7047 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7048 this.inputEl().on("keypress", this.filterKeys, this);
7051 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7052 this.el.on("click", this.autoSize, this);
7055 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7056 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7059 if (typeof(this.before) == 'object') {
7060 this.before.render(this.el.select('.roo-input-before',true).first());
7062 if (typeof(this.after) == 'object') {
7063 this.after.render(this.el.select('.roo-input-after',true).first());
7068 filterValidation : function(e){
7069 if(!e.isNavKeyPress()){
7070 this.validationTask.delay(this.validationDelay);
7074 * Validates the field value
7075 * @return {Boolean} True if the value is valid, else false
7077 validate : function(){
7078 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7079 if(this.disabled || this.validateValue(this.getRawValue())){
7080 this.clearInvalid();
7088 * Validates a value according to the field's validation rules and marks the field as invalid
7089 * if the validation fails
7090 * @param {Mixed} value The value to validate
7091 * @return {Boolean} True if the value is valid, else false
7093 validateValue : function(value){
7094 if(value.length < 1) { // if it's blank
7095 if(this.allowBlank){
7096 this.clearInvalid();
7099 this.markInvalid(this.blankText);
7103 if(value.length < this.minLength){
7104 this.markInvalid(String.format(this.minLengthText, this.minLength));
7107 if(value.length > this.maxLength){
7108 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7112 var vt = Roo.form.VTypes;
7113 if(!vt[this.vtype](value, this)){
7114 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7118 if(typeof this.validator == "function"){
7119 var msg = this.validator(value);
7121 this.markInvalid(msg);
7125 if(this.regex && !this.regex.test(value)){
7126 this.markInvalid(this.regexText);
7135 fireKey : function(e){
7136 //Roo.log('field ' + e.getKey());
7137 if(e.isNavKeyPress()){
7138 this.fireEvent("specialkey", this, e);
7141 focus : function (selectText){
7143 this.inputEl().focus();
7144 if(selectText === true){
7145 this.inputEl().dom.select();
7151 onFocus : function(){
7152 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7153 // this.el.addClass(this.focusClass);
7156 this.hasFocus = true;
7157 this.startValue = this.getValue();
7158 this.fireEvent("focus", this);
7162 beforeBlur : Roo.emptyFn,
7166 onBlur : function(){
7168 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7169 //this.el.removeClass(this.focusClass);
7171 this.hasFocus = false;
7172 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7175 var v = this.getValue();
7176 if(String(v) !== String(this.startValue)){
7177 this.fireEvent('change', this, v, this.startValue);
7179 this.fireEvent("blur", this);
7183 * Resets the current field value to the originally loaded value and clears any validation messages
7186 this.setValue(this.originalValue);
7187 this.clearInvalid();
7190 * Returns the name of the field
7191 * @return {Mixed} name The name field
7193 getName: function(){
7197 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7198 * @return {Mixed} value The field value
7200 getValue : function(){
7202 var v = this.inputEl().getValue();
7207 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7208 * @return {Mixed} value The field value
7210 getRawValue : function(){
7211 var v = this.inputEl().getValue();
7217 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7218 * @param {Mixed} value The value to set
7220 setRawValue : function(v){
7221 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7224 selectText : function(start, end){
7225 var v = this.getRawValue();
7227 start = start === undefined ? 0 : start;
7228 end = end === undefined ? v.length : end;
7229 var d = this.inputEl().dom;
7230 if(d.setSelectionRange){
7231 d.setSelectionRange(start, end);
7232 }else if(d.createTextRange){
7233 var range = d.createTextRange();
7234 range.moveStart("character", start);
7235 range.moveEnd("character", v.length-end);
7242 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7243 * @param {Mixed} value The value to set
7245 setValue : function(v){
7248 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7254 processValue : function(value){
7255 if(this.stripCharsRe){
7256 var newValue = value.replace(this.stripCharsRe, '');
7257 if(newValue !== value){
7258 this.setRawValue(newValue);
7265 preFocus : function(){
7267 if(this.selectOnFocus){
7268 this.inputEl().dom.select();
7271 filterKeys : function(e){
7273 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7276 var c = e.getCharCode(), cc = String.fromCharCode(c);
7277 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7280 if(!this.maskRe.test(cc)){
7285 * Clear any invalid styles/messages for this field
7287 clearInvalid : function(){
7289 if(!this.el || this.preventMark){ // not rendered
7292 this.el.removeClass(this.invalidClass);
7294 switch(this.msgTarget){
7296 this.el.dom.qtip = '';
7299 this.el.dom.title = '';
7303 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7308 this.errorIcon.dom.qtip = '';
7309 this.errorIcon.hide();
7310 this.un('resize', this.alignErrorIcon, this);
7314 var t = Roo.getDom(this.msgTarget);
7316 t.style.display = 'none';
7320 this.fireEvent('valid', this);
7323 * Mark this field as invalid
7324 * @param {String} msg The validation message
7326 markInvalid : function(msg){
7327 if(!this.el || this.preventMark){ // not rendered
7330 this.el.addClass(this.invalidClass);
7332 msg = msg || this.invalidText;
7333 switch(this.msgTarget){
7335 this.el.dom.qtip = msg;
7336 this.el.dom.qclass = 'x-form-invalid-tip';
7337 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7338 Roo.QuickTips.enable();
7342 this.el.dom.title = msg;
7346 var elp = this.el.findParent('.x-form-element', 5, true);
7347 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7348 this.errorEl.setWidth(elp.getWidth(true)-20);
7350 this.errorEl.update(msg);
7351 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7354 if(!this.errorIcon){
7355 var elp = this.el.findParent('.x-form-element', 5, true);
7356 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7358 this.alignErrorIcon();
7359 this.errorIcon.dom.qtip = msg;
7360 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7361 this.errorIcon.show();
7362 this.on('resize', this.alignErrorIcon, this);
7365 var t = Roo.getDom(this.msgTarget);
7367 t.style.display = this.msgDisplay;
7371 this.fireEvent('invalid', this, msg);
7374 SafariOnKeyDown : function(event)
7376 // this is a workaround for a password hang bug on chrome/ webkit.
7378 var isSelectAll = false;
7380 if(this.inputEl().dom.selectionEnd > 0){
7381 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7383 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7384 event.preventDefault();
7389 if(isSelectAll){ // backspace and delete key
7391 event.preventDefault();
7392 // this is very hacky as keydown always get's upper case.
7394 var cc = String.fromCharCode(event.getCharCode());
7395 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7399 adjustWidth : function(tag, w){
7400 tag = tag.toLowerCase();
7401 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7402 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7406 if(tag == 'textarea'){
7409 }else if(Roo.isOpera){
7413 if(tag == 'textarea'){
7432 * @class Roo.bootstrap.TextArea
7433 * @extends Roo.bootstrap.Input
7434 * Bootstrap TextArea class
7435 * @cfg {Number} cols Specifies the visible width of a text area
7436 * @cfg {Number} rows Specifies the visible number of lines in a text area
7437 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7438 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7439 * @cfg {string} html text
7442 * Create a new TextArea
7443 * @param {Object} config The config object
7446 Roo.bootstrap.TextArea = function(config){
7447 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7451 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7461 getAutoCreate : function(){
7463 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7474 value : this.value || '',
7475 html: this.html || '',
7476 cls : 'form-control',
7477 placeholder : this.placeholder || ''
7481 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7482 input.maxLength = this.maxLength;
7486 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7490 input.cols = this.cols;
7493 if (this.readOnly) {
7494 input.readonly = true;
7498 input.name = this.name;
7502 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7506 ['xs','sm','md','lg'].map(function(size){
7507 if (settings[size]) {
7508 cfg.cls += ' col-' + size + '-' + settings[size];
7512 var inputblock = input;
7514 if (this.before || this.after) {
7517 cls : 'input-group',
7521 inputblock.cn.push({
7523 cls : 'input-group-addon',
7527 inputblock.cn.push(input);
7529 inputblock.cn.push({
7531 cls : 'input-group-addon',
7538 if (align ==='left' && this.fieldLabel.length) {
7539 Roo.log("left and has label");
7545 cls : 'control-label col-sm-' + this.labelWidth,
7546 html : this.fieldLabel
7550 cls : "col-sm-" + (12 - this.labelWidth),
7557 } else if ( this.fieldLabel.length) {
7563 //cls : 'input-group-addon',
7564 html : this.fieldLabel
7574 Roo.log(" no label && no align");
7584 if (this.disabled) {
7585 input.disabled=true;
7592 * return the real textarea element.
7594 inputEl: function ()
7596 return this.el.select('textarea.form-control',true).first();
7604 * trigger field - base class for combo..
7609 * @class Roo.bootstrap.TriggerField
7610 * @extends Roo.bootstrap.Input
7611 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7612 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7613 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7614 * for which you can provide a custom implementation. For example:
7616 var trigger = new Roo.bootstrap.TriggerField();
7617 trigger.onTriggerClick = myTriggerFn;
7618 trigger.applyTo('my-field');
7621 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7622 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7623 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7624 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7626 * Create a new TriggerField.
7627 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7628 * to the base TextField)
7630 Roo.bootstrap.TriggerField = function(config){
7631 this.mimicing = false;
7632 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7635 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7637 * @cfg {String} triggerClass A CSS class to apply to the trigger
7640 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7644 /** @cfg {Boolean} grow @hide */
7645 /** @cfg {Number} growMin @hide */
7646 /** @cfg {Number} growMax @hide */
7652 autoSize: Roo.emptyFn,
7659 actionMode : 'wrap',
7663 getAutoCreate : function(){
7665 var align = this.labelAlign || this.parentLabelAlign();
7670 cls: 'form-group' //input-group
7677 type : this.inputType,
7678 cls : 'form-control',
7679 autocomplete: 'off',
7680 placeholder : this.placeholder || ''
7684 input.name = this.name;
7687 input.cls += ' input-' + this.size;
7690 if (this.disabled) {
7691 input.disabled=true;
7694 var inputblock = input;
7696 if (this.before || this.after) {
7699 cls : 'input-group',
7703 inputblock.cn.push({
7705 cls : 'input-group-addon',
7709 inputblock.cn.push(input);
7711 inputblock.cn.push({
7713 cls : 'input-group-addon',
7726 cls: 'form-hidden-field'
7734 Roo.log('multiple');
7742 cls: 'form-hidden-field'
7746 cls: 'select2-choices',
7750 cls: 'select2-search-field',
7763 cls: 'select2-container input-group',
7768 // cls: 'typeahead typeahead-long dropdown-menu',
7769 // style: 'display:none'
7777 cls : 'input-group-addon btn dropdown-toggle',
7785 cls: 'combobox-clear',
7799 combobox.cls += ' select2-container-multi';
7802 if (align ==='left' && this.fieldLabel.length) {
7804 Roo.log("left and has label");
7810 cls : 'control-label col-sm-' + this.labelWidth,
7811 html : this.fieldLabel
7815 cls : "col-sm-" + (12 - this.labelWidth),
7822 } else if ( this.fieldLabel.length) {
7828 //cls : 'input-group-addon',
7829 html : this.fieldLabel
7839 Roo.log(" no label && no align");
7846 ['xs','sm','md','lg'].map(function(size){
7847 if (settings[size]) {
7848 cfg.cls += ' col-' + size + '-' + settings[size];
7859 onResize : function(w, h){
7860 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7861 // if(typeof w == 'number'){
7862 // var x = w - this.trigger.getWidth();
7863 // this.inputEl().setWidth(this.adjustWidth('input', x));
7864 // this.trigger.setStyle('left', x+'px');
7869 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7872 getResizeEl : function(){
7873 return this.inputEl();
7877 getPositionEl : function(){
7878 return this.inputEl();
7882 alignErrorIcon : function(){
7883 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7887 initEvents : function(){
7891 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7892 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7894 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7895 if(this.hideTrigger){
7896 this.trigger.setDisplayed(false);
7898 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7902 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7905 //this.trigger.addClassOnOver('x-form-trigger-over');
7906 //this.trigger.addClassOnClick('x-form-trigger-click');
7909 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7913 createList : function()
7915 this.list = Roo.get(document.body).createChild({
7917 cls: 'typeahead typeahead-long dropdown-menu',
7918 style: 'display:none'
7921 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
7926 initTrigger : function(){
7931 onDestroy : function(){
7933 this.trigger.removeAllListeners();
7934 // this.trigger.remove();
7937 // this.wrap.remove();
7939 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7943 onFocus : function(){
7944 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7947 this.wrap.addClass('x-trigger-wrap-focus');
7948 this.mimicing = true;
7949 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7950 if(this.monitorTab){
7951 this.el.on("keydown", this.checkTab, this);
7958 checkTab : function(e){
7959 if(e.getKey() == e.TAB){
7965 onBlur : function(){
7970 mimicBlur : function(e, t){
7972 if(!this.wrap.contains(t) && this.validateBlur()){
7979 triggerBlur : function(){
7980 this.mimicing = false;
7981 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7982 if(this.monitorTab){
7983 this.el.un("keydown", this.checkTab, this);
7985 //this.wrap.removeClass('x-trigger-wrap-focus');
7986 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7990 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7991 validateBlur : function(e, t){
7996 onDisable : function(){
7997 this.inputEl().dom.disabled = true;
7998 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8000 // this.wrap.addClass('x-item-disabled');
8005 onEnable : function(){
8006 this.inputEl().dom.disabled = false;
8007 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8009 // this.el.removeClass('x-item-disabled');
8014 onShow : function(){
8015 var ae = this.getActionEl();
8018 ae.dom.style.display = '';
8019 ae.dom.style.visibility = 'visible';
8025 onHide : function(){
8026 var ae = this.getActionEl();
8027 ae.dom.style.display = 'none';
8031 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8032 * by an implementing function.
8034 * @param {EventObject} e
8036 onTriggerClick : Roo.emptyFn
8040 * Ext JS Library 1.1.1
8041 * Copyright(c) 2006-2007, Ext JS, LLC.
8043 * Originally Released Under LGPL - original licence link has changed is not relivant.
8046 * <script type="text/javascript">
8051 * @class Roo.data.SortTypes
8053 * Defines the default sorting (casting?) comparison functions used when sorting data.
8055 Roo.data.SortTypes = {
8057 * Default sort that does nothing
8058 * @param {Mixed} s The value being converted
8059 * @return {Mixed} The comparison value
8066 * The regular expression used to strip tags
8070 stripTagsRE : /<\/?[^>]+>/gi,
8073 * Strips all HTML tags to sort on text only
8074 * @param {Mixed} s The value being converted
8075 * @return {String} The comparison value
8077 asText : function(s){
8078 return String(s).replace(this.stripTagsRE, "");
8082 * Strips all HTML tags to sort on text only - Case insensitive
8083 * @param {Mixed} s The value being converted
8084 * @return {String} The comparison value
8086 asUCText : function(s){
8087 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8091 * Case insensitive string
8092 * @param {Mixed} s The value being converted
8093 * @return {String} The comparison value
8095 asUCString : function(s) {
8096 return String(s).toUpperCase();
8101 * @param {Mixed} s The value being converted
8102 * @return {Number} The comparison value
8104 asDate : function(s) {
8108 if(s instanceof Date){
8111 return Date.parse(String(s));
8116 * @param {Mixed} s The value being converted
8117 * @return {Float} The comparison value
8119 asFloat : function(s) {
8120 var val = parseFloat(String(s).replace(/,/g, ""));
8121 if(isNaN(val)) val = 0;
8127 * @param {Mixed} s The value being converted
8128 * @return {Number} The comparison value
8130 asInt : function(s) {
8131 var val = parseInt(String(s).replace(/,/g, ""));
8132 if(isNaN(val)) val = 0;
8137 * Ext JS Library 1.1.1
8138 * Copyright(c) 2006-2007, Ext JS, LLC.
8140 * Originally Released Under LGPL - original licence link has changed is not relivant.
8143 * <script type="text/javascript">
8147 * @class Roo.data.Record
8148 * Instances of this class encapsulate both record <em>definition</em> information, and record
8149 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8150 * to access Records cached in an {@link Roo.data.Store} object.<br>
8152 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8153 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8156 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8158 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8159 * {@link #create}. The parameters are the same.
8160 * @param {Array} data An associative Array of data values keyed by the field name.
8161 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8162 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8163 * not specified an integer id is generated.
8165 Roo.data.Record = function(data, id){
8166 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8171 * Generate a constructor for a specific record layout.
8172 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8173 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8174 * Each field definition object may contain the following properties: <ul>
8175 * <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,
8176 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8177 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8178 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8179 * is being used, then this is a string containing the javascript expression to reference the data relative to
8180 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8181 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8182 * this may be omitted.</p></li>
8183 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8184 * <ul><li>auto (Default, implies no conversion)</li>
8189 * <li>date</li></ul></p></li>
8190 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8191 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8192 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8193 * by the Reader into an object that will be stored in the Record. It is passed the
8194 * following parameters:<ul>
8195 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8197 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8199 * <br>usage:<br><pre><code>
8200 var TopicRecord = Roo.data.Record.create(
8201 {name: 'title', mapping: 'topic_title'},
8202 {name: 'author', mapping: 'username'},
8203 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8204 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8205 {name: 'lastPoster', mapping: 'user2'},
8206 {name: 'excerpt', mapping: 'post_text'}
8209 var myNewRecord = new TopicRecord({
8210 title: 'Do my job please',
8213 lastPost: new Date(),
8214 lastPoster: 'Animal',
8215 excerpt: 'No way dude!'
8217 myStore.add(myNewRecord);
8222 Roo.data.Record.create = function(o){
8224 f.superclass.constructor.apply(this, arguments);
8226 Roo.extend(f, Roo.data.Record);
8227 var p = f.prototype;
8228 p.fields = new Roo.util.MixedCollection(false, function(field){
8231 for(var i = 0, len = o.length; i < len; i++){
8232 p.fields.add(new Roo.data.Field(o[i]));
8234 f.getField = function(name){
8235 return p.fields.get(name);
8240 Roo.data.Record.AUTO_ID = 1000;
8241 Roo.data.Record.EDIT = 'edit';
8242 Roo.data.Record.REJECT = 'reject';
8243 Roo.data.Record.COMMIT = 'commit';
8245 Roo.data.Record.prototype = {
8247 * Readonly flag - true if this record has been modified.
8256 join : function(store){
8261 * Set the named field to the specified value.
8262 * @param {String} name The name of the field to set.
8263 * @param {Object} value The value to set the field to.
8265 set : function(name, value){
8266 if(this.data[name] == value){
8273 if(typeof this.modified[name] == 'undefined'){
8274 this.modified[name] = this.data[name];
8276 this.data[name] = value;
8277 if(!this.editing && this.store){
8278 this.store.afterEdit(this);
8283 * Get the value of the named field.
8284 * @param {String} name The name of the field to get the value of.
8285 * @return {Object} The value of the field.
8287 get : function(name){
8288 return this.data[name];
8292 beginEdit : function(){
8293 this.editing = true;
8298 cancelEdit : function(){
8299 this.editing = false;
8300 delete this.modified;
8304 endEdit : function(){
8305 this.editing = false;
8306 if(this.dirty && this.store){
8307 this.store.afterEdit(this);
8312 * Usually called by the {@link Roo.data.Store} which owns the Record.
8313 * Rejects all changes made to the Record since either creation, or the last commit operation.
8314 * Modified fields are reverted to their original values.
8316 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8317 * of reject operations.
8319 reject : function(){
8320 var m = this.modified;
8322 if(typeof m[n] != "function"){
8323 this.data[n] = m[n];
8327 delete this.modified;
8328 this.editing = false;
8330 this.store.afterReject(this);
8335 * Usually called by the {@link Roo.data.Store} which owns the Record.
8336 * Commits all changes made to the Record since either creation, or the last commit operation.
8338 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8339 * of commit operations.
8341 commit : function(){
8343 delete this.modified;
8344 this.editing = false;
8346 this.store.afterCommit(this);
8351 hasError : function(){
8352 return this.error != null;
8356 clearError : function(){
8361 * Creates a copy of this record.
8362 * @param {String} id (optional) A new record id if you don't want to use this record's id
8365 copy : function(newId) {
8366 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8370 * Ext JS Library 1.1.1
8371 * Copyright(c) 2006-2007, Ext JS, LLC.
8373 * Originally Released Under LGPL - original licence link has changed is not relivant.
8376 * <script type="text/javascript">
8382 * @class Roo.data.Store
8383 * @extends Roo.util.Observable
8384 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8385 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8387 * 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
8388 * has no knowledge of the format of the data returned by the Proxy.<br>
8390 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8391 * instances from the data object. These records are cached and made available through accessor functions.
8393 * Creates a new Store.
8394 * @param {Object} config A config object containing the objects needed for the Store to access data,
8395 * and read the data into Records.
8397 Roo.data.Store = function(config){
8398 this.data = new Roo.util.MixedCollection(false);
8399 this.data.getKey = function(o){
8402 this.baseParams = {};
8409 "multisort" : "_multisort"
8412 if(config && config.data){
8413 this.inlineData = config.data;
8417 Roo.apply(this, config);
8419 if(this.reader){ // reader passed
8420 this.reader = Roo.factory(this.reader, Roo.data);
8421 this.reader.xmodule = this.xmodule || false;
8422 if(!this.recordType){
8423 this.recordType = this.reader.recordType;
8425 if(this.reader.onMetaChange){
8426 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8430 if(this.recordType){
8431 this.fields = this.recordType.prototype.fields;
8437 * @event datachanged
8438 * Fires when the data cache has changed, and a widget which is using this Store
8439 * as a Record cache should refresh its view.
8440 * @param {Store} this
8445 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8446 * @param {Store} this
8447 * @param {Object} meta The JSON metadata
8452 * Fires when Records have been added to the Store
8453 * @param {Store} this
8454 * @param {Roo.data.Record[]} records The array of Records added
8455 * @param {Number} index The index at which the record(s) were added
8460 * Fires when a Record has been removed from the Store
8461 * @param {Store} this
8462 * @param {Roo.data.Record} record The Record that was removed
8463 * @param {Number} index The index at which the record was removed
8468 * Fires when a Record has been updated
8469 * @param {Store} this
8470 * @param {Roo.data.Record} record The Record that was updated
8471 * @param {String} operation The update operation being performed. Value may be one of:
8473 Roo.data.Record.EDIT
8474 Roo.data.Record.REJECT
8475 Roo.data.Record.COMMIT
8481 * Fires when the data cache has been cleared.
8482 * @param {Store} this
8487 * Fires before a request is made for a new data object. If the beforeload handler returns false
8488 * the load action will be canceled.
8489 * @param {Store} this
8490 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8494 * @event beforeloadadd
8495 * Fires after a new set of Records has been loaded.
8496 * @param {Store} this
8497 * @param {Roo.data.Record[]} records The Records that were loaded
8498 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8500 beforeloadadd : true,
8503 * Fires after a new set of Records has been loaded, before they are added to the store.
8504 * @param {Store} this
8505 * @param {Roo.data.Record[]} records The Records that were loaded
8506 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8507 * @params {Object} return from reader
8511 * @event loadexception
8512 * Fires if an exception occurs in the Proxy during loading.
8513 * Called with the signature of the Proxy's "loadexception" event.
8514 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8517 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8518 * @param {Object} load options
8519 * @param {Object} jsonData from your request (normally this contains the Exception)
8521 loadexception : true
8525 this.proxy = Roo.factory(this.proxy, Roo.data);
8526 this.proxy.xmodule = this.xmodule || false;
8527 this.relayEvents(this.proxy, ["loadexception"]);
8529 this.sortToggle = {};
8530 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8532 Roo.data.Store.superclass.constructor.call(this);
8534 if(this.inlineData){
8535 this.loadData(this.inlineData);
8536 delete this.inlineData;
8540 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8542 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8543 * without a remote query - used by combo/forms at present.
8547 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8550 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8553 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8554 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8557 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8558 * on any HTTP request
8561 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8564 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8568 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8569 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8574 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8575 * loaded or when a record is removed. (defaults to false).
8577 pruneModifiedRecords : false,
8583 * Add Records to the Store and fires the add event.
8584 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8586 add : function(records){
8587 records = [].concat(records);
8588 for(var i = 0, len = records.length; i < len; i++){
8589 records[i].join(this);
8591 var index = this.data.length;
8592 this.data.addAll(records);
8593 this.fireEvent("add", this, records, index);
8597 * Remove a Record from the Store and fires the remove event.
8598 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8600 remove : function(record){
8601 var index = this.data.indexOf(record);
8602 this.data.removeAt(index);
8603 if(this.pruneModifiedRecords){
8604 this.modified.remove(record);
8606 this.fireEvent("remove", this, record, index);
8610 * Remove all Records from the Store and fires the clear event.
8612 removeAll : function(){
8614 if(this.pruneModifiedRecords){
8617 this.fireEvent("clear", this);
8621 * Inserts Records to the Store at the given index and fires the add event.
8622 * @param {Number} index The start index at which to insert the passed Records.
8623 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8625 insert : function(index, records){
8626 records = [].concat(records);
8627 for(var i = 0, len = records.length; i < len; i++){
8628 this.data.insert(index, records[i]);
8629 records[i].join(this);
8631 this.fireEvent("add", this, records, index);
8635 * Get the index within the cache of the passed Record.
8636 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8637 * @return {Number} The index of the passed Record. Returns -1 if not found.
8639 indexOf : function(record){
8640 return this.data.indexOf(record);
8644 * Get the index within the cache of the Record with the passed id.
8645 * @param {String} id The id of the Record to find.
8646 * @return {Number} The index of the Record. Returns -1 if not found.
8648 indexOfId : function(id){
8649 return this.data.indexOfKey(id);
8653 * Get the Record with the specified id.
8654 * @param {String} id The id of the Record to find.
8655 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8657 getById : function(id){
8658 return this.data.key(id);
8662 * Get the Record at the specified index.
8663 * @param {Number} index The index of the Record to find.
8664 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8666 getAt : function(index){
8667 return this.data.itemAt(index);
8671 * Returns a range of Records between specified indices.
8672 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8673 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8674 * @return {Roo.data.Record[]} An array of Records
8676 getRange : function(start, end){
8677 return this.data.getRange(start, end);
8681 storeOptions : function(o){
8682 o = Roo.apply({}, o);
8685 this.lastOptions = o;
8689 * Loads the Record cache from the configured Proxy using the configured Reader.
8691 * If using remote paging, then the first load call must specify the <em>start</em>
8692 * and <em>limit</em> properties in the options.params property to establish the initial
8693 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8695 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8696 * and this call will return before the new data has been loaded. Perform any post-processing
8697 * in a callback function, or in a "load" event handler.</strong>
8699 * @param {Object} options An object containing properties which control loading options:<ul>
8700 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8701 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8702 * passed the following arguments:<ul>
8703 * <li>r : Roo.data.Record[]</li>
8704 * <li>options: Options object from the load call</li>
8705 * <li>success: Boolean success indicator</li></ul></li>
8706 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8707 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8710 load : function(options){
8711 options = options || {};
8712 if(this.fireEvent("beforeload", this, options) !== false){
8713 this.storeOptions(options);
8714 var p = Roo.apply(options.params || {}, this.baseParams);
8715 // if meta was not loaded from remote source.. try requesting it.
8716 if (!this.reader.metaFromRemote) {
8719 if(this.sortInfo && this.remoteSort){
8720 var pn = this.paramNames;
8721 p[pn["sort"]] = this.sortInfo.field;
8722 p[pn["dir"]] = this.sortInfo.direction;
8724 if (this.multiSort) {
8725 var pn = this.paramNames;
8726 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8729 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8734 * Reloads the Record cache from the configured Proxy using the configured Reader and
8735 * the options from the last load operation performed.
8736 * @param {Object} options (optional) An object containing properties which may override the options
8737 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8738 * the most recently used options are reused).
8740 reload : function(options){
8741 this.load(Roo.applyIf(options||{}, this.lastOptions));
8745 // Called as a callback by the Reader during a load operation.
8746 loadRecords : function(o, options, success){
8747 if(!o || success === false){
8748 if(success !== false){
8749 this.fireEvent("load", this, [], options, o);
8751 if(options.callback){
8752 options.callback.call(options.scope || this, [], options, false);
8756 // if data returned failure - throw an exception.
8757 if (o.success === false) {
8758 // show a message if no listener is registered.
8759 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8760 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8762 // loadmask wil be hooked into this..
8763 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8766 var r = o.records, t = o.totalRecords || r.length;
8768 this.fireEvent("beforeloadadd", this, r, options, o);
8770 if(!options || options.add !== true){
8771 if(this.pruneModifiedRecords){
8774 for(var i = 0, len = r.length; i < len; i++){
8778 this.data = this.snapshot;
8779 delete this.snapshot;
8782 this.data.addAll(r);
8783 this.totalLength = t;
8785 this.fireEvent("datachanged", this);
8787 this.totalLength = Math.max(t, this.data.length+r.length);
8790 this.fireEvent("load", this, r, options, o);
8791 if(options.callback){
8792 options.callback.call(options.scope || this, r, options, true);
8798 * Loads data from a passed data block. A Reader which understands the format of the data
8799 * must have been configured in the constructor.
8800 * @param {Object} data The data block from which to read the Records. The format of the data expected
8801 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8802 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8804 loadData : function(o, append){
8805 var r = this.reader.readRecords(o);
8806 this.loadRecords(r, {add: append}, true);
8810 * Gets the number of cached records.
8812 * <em>If using paging, this may not be the total size of the dataset. If the data object
8813 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8814 * the data set size</em>
8816 getCount : function(){
8817 return this.data.length || 0;
8821 * Gets the total number of records in the dataset as returned by the server.
8823 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8824 * the dataset size</em>
8826 getTotalCount : function(){
8827 return this.totalLength || 0;
8831 * Returns the sort state of the Store as an object with two properties:
8833 field {String} The name of the field by which the Records are sorted
8834 direction {String} The sort order, "ASC" or "DESC"
8837 getSortState : function(){
8838 return this.sortInfo;
8842 applySort : function(){
8843 if(this.sortInfo && !this.remoteSort){
8844 var s = this.sortInfo, f = s.field;
8845 var st = this.fields.get(f).sortType;
8846 var fn = function(r1, r2){
8847 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8848 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8850 this.data.sort(s.direction, fn);
8851 if(this.snapshot && this.snapshot != this.data){
8852 this.snapshot.sort(s.direction, fn);
8858 * Sets the default sort column and order to be used by the next load operation.
8859 * @param {String} fieldName The name of the field to sort by.
8860 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8862 setDefaultSort : function(field, dir){
8863 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8868 * If remote sorting is used, the sort is performed on the server, and the cache is
8869 * reloaded. If local sorting is used, the cache is sorted internally.
8870 * @param {String} fieldName The name of the field to sort by.
8871 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8873 sort : function(fieldName, dir){
8874 var f = this.fields.get(fieldName);
8876 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8878 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8879 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8884 this.sortToggle[f.name] = dir;
8885 this.sortInfo = {field: f.name, direction: dir};
8886 if(!this.remoteSort){
8888 this.fireEvent("datachanged", this);
8890 this.load(this.lastOptions);
8895 * Calls the specified function for each of the Records in the cache.
8896 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8897 * Returning <em>false</em> aborts and exits the iteration.
8898 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8900 each : function(fn, scope){
8901 this.data.each(fn, scope);
8905 * Gets all records modified since the last commit. Modified records are persisted across load operations
8906 * (e.g., during paging).
8907 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8909 getModifiedRecords : function(){
8910 return this.modified;
8914 createFilterFn : function(property, value, anyMatch){
8915 if(!value.exec){ // not a regex
8916 value = String(value);
8917 if(value.length == 0){
8920 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8923 return value.test(r.data[property]);
8928 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8929 * @param {String} property A field on your records
8930 * @param {Number} start The record index to start at (defaults to 0)
8931 * @param {Number} end The last record index to include (defaults to length - 1)
8932 * @return {Number} The sum
8934 sum : function(property, start, end){
8935 var rs = this.data.items, v = 0;
8937 end = (end || end === 0) ? end : rs.length-1;
8939 for(var i = start; i <= end; i++){
8940 v += (rs[i].data[property] || 0);
8946 * Filter the records by a specified property.
8947 * @param {String} field A field on your records
8948 * @param {String/RegExp} value Either a string that the field
8949 * should start with or a RegExp to test against the field
8950 * @param {Boolean} anyMatch True to match any part not just the beginning
8952 filter : function(property, value, anyMatch){
8953 var fn = this.createFilterFn(property, value, anyMatch);
8954 return fn ? this.filterBy(fn) : this.clearFilter();
8958 * Filter by a function. The specified function will be called with each
8959 * record in this data source. If the function returns true the record is included,
8960 * otherwise it is filtered.
8961 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8962 * @param {Object} scope (optional) The scope of the function (defaults to this)
8964 filterBy : function(fn, scope){
8965 this.snapshot = this.snapshot || this.data;
8966 this.data = this.queryBy(fn, scope||this);
8967 this.fireEvent("datachanged", this);
8971 * Query the records by a specified property.
8972 * @param {String} field A field on your records
8973 * @param {String/RegExp} value Either a string that the field
8974 * should start with or a RegExp to test against the field
8975 * @param {Boolean} anyMatch True to match any part not just the beginning
8976 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8978 query : function(property, value, anyMatch){
8979 var fn = this.createFilterFn(property, value, anyMatch);
8980 return fn ? this.queryBy(fn) : this.data.clone();
8984 * Query by a function. The specified function will be called with each
8985 * record in this data source. If the function returns true the record is included
8987 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8988 * @param {Object} scope (optional) The scope of the function (defaults to this)
8989 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8991 queryBy : function(fn, scope){
8992 var data = this.snapshot || this.data;
8993 return data.filterBy(fn, scope||this);
8997 * Collects unique values for a particular dataIndex from this store.
8998 * @param {String} dataIndex The property to collect
8999 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9000 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9001 * @return {Array} An array of the unique values
9003 collect : function(dataIndex, allowNull, bypassFilter){
9004 var d = (bypassFilter === true && this.snapshot) ?
9005 this.snapshot.items : this.data.items;
9006 var v, sv, r = [], l = {};
9007 for(var i = 0, len = d.length; i < len; i++){
9008 v = d[i].data[dataIndex];
9010 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9019 * Revert to a view of the Record cache with no filtering applied.
9020 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9022 clearFilter : function(suppressEvent){
9023 if(this.snapshot && this.snapshot != this.data){
9024 this.data = this.snapshot;
9025 delete this.snapshot;
9026 if(suppressEvent !== true){
9027 this.fireEvent("datachanged", this);
9033 afterEdit : function(record){
9034 if(this.modified.indexOf(record) == -1){
9035 this.modified.push(record);
9037 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9041 afterReject : function(record){
9042 this.modified.remove(record);
9043 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9047 afterCommit : function(record){
9048 this.modified.remove(record);
9049 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9053 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9054 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9056 commitChanges : function(){
9057 var m = this.modified.slice(0);
9059 for(var i = 0, len = m.length; i < len; i++){
9065 * Cancel outstanding changes on all changed records.
9067 rejectChanges : function(){
9068 var m = this.modified.slice(0);
9070 for(var i = 0, len = m.length; i < len; i++){
9075 onMetaChange : function(meta, rtype, o){
9076 this.recordType = rtype;
9077 this.fields = rtype.prototype.fields;
9078 delete this.snapshot;
9079 this.sortInfo = meta.sortInfo || this.sortInfo;
9081 this.fireEvent('metachange', this, this.reader.meta);
9084 moveIndex : function(data, type)
9086 var index = this.indexOf(data);
9088 var newIndex = index + type;
9092 this.insert(newIndex, data);
9097 * Ext JS Library 1.1.1
9098 * Copyright(c) 2006-2007, Ext JS, LLC.
9100 * Originally Released Under LGPL - original licence link has changed is not relivant.
9103 * <script type="text/javascript">
9107 * @class Roo.data.SimpleStore
9108 * @extends Roo.data.Store
9109 * Small helper class to make creating Stores from Array data easier.
9110 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9111 * @cfg {Array} fields An array of field definition objects, or field name strings.
9112 * @cfg {Array} data The multi-dimensional array of data
9114 * @param {Object} config
9116 Roo.data.SimpleStore = function(config){
9117 Roo.data.SimpleStore.superclass.constructor.call(this, {
9119 reader: new Roo.data.ArrayReader({
9122 Roo.data.Record.create(config.fields)
9124 proxy : new Roo.data.MemoryProxy(config.data)
9128 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9130 * Ext JS Library 1.1.1
9131 * Copyright(c) 2006-2007, Ext JS, LLC.
9133 * Originally Released Under LGPL - original licence link has changed is not relivant.
9136 * <script type="text/javascript">
9141 * @extends Roo.data.Store
9142 * @class Roo.data.JsonStore
9143 * Small helper class to make creating Stores for JSON data easier. <br/>
9145 var store = new Roo.data.JsonStore({
9146 url: 'get-images.php',
9148 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9151 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9152 * JsonReader and HttpProxy (unless inline data is provided).</b>
9153 * @cfg {Array} fields An array of field definition objects, or field name strings.
9155 * @param {Object} config
9157 Roo.data.JsonStore = function(c){
9158 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9159 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9160 reader: new Roo.data.JsonReader(c, c.fields)
9163 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9165 * Ext JS Library 1.1.1
9166 * Copyright(c) 2006-2007, Ext JS, LLC.
9168 * Originally Released Under LGPL - original licence link has changed is not relivant.
9171 * <script type="text/javascript">
9175 Roo.data.Field = function(config){
9176 if(typeof config == "string"){
9177 config = {name: config};
9179 Roo.apply(this, config);
9185 var st = Roo.data.SortTypes;
9186 // named sortTypes are supported, here we look them up
9187 if(typeof this.sortType == "string"){
9188 this.sortType = st[this.sortType];
9191 // set default sortType for strings and dates
9195 this.sortType = st.asUCString;
9198 this.sortType = st.asDate;
9201 this.sortType = st.none;
9206 var stripRe = /[\$,%]/g;
9208 // prebuilt conversion function for this field, instead of
9209 // switching every time we're reading a value
9211 var cv, dateFormat = this.dateFormat;
9216 cv = function(v){ return v; };
9219 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9223 return v !== undefined && v !== null && v !== '' ?
9224 parseInt(String(v).replace(stripRe, ""), 10) : '';
9229 return v !== undefined && v !== null && v !== '' ?
9230 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9235 cv = function(v){ return v === true || v === "true" || v == 1; };
9242 if(v instanceof Date){
9246 if(dateFormat == "timestamp"){
9247 return new Date(v*1000);
9249 return Date.parseDate(v, dateFormat);
9251 var parsed = Date.parse(v);
9252 return parsed ? new Date(parsed) : null;
9261 Roo.data.Field.prototype = {
9269 * Ext JS Library 1.1.1
9270 * Copyright(c) 2006-2007, Ext JS, LLC.
9272 * Originally Released Under LGPL - original licence link has changed is not relivant.
9275 * <script type="text/javascript">
9278 // Base class for reading structured data from a data source. This class is intended to be
9279 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9282 * @class Roo.data.DataReader
9283 * Base class for reading structured data from a data source. This class is intended to be
9284 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9287 Roo.data.DataReader = function(meta, recordType){
9291 this.recordType = recordType instanceof Array ?
9292 Roo.data.Record.create(recordType) : recordType;
9295 Roo.data.DataReader.prototype = {
9297 * Create an empty record
9298 * @param {Object} data (optional) - overlay some values
9299 * @return {Roo.data.Record} record created.
9301 newRow : function(d) {
9303 this.recordType.prototype.fields.each(function(c) {
9305 case 'int' : da[c.name] = 0; break;
9306 case 'date' : da[c.name] = new Date(); break;
9307 case 'float' : da[c.name] = 0.0; break;
9308 case 'boolean' : da[c.name] = false; break;
9309 default : da[c.name] = ""; break;
9313 return new this.recordType(Roo.apply(da, d));
9318 * Ext JS Library 1.1.1
9319 * Copyright(c) 2006-2007, Ext JS, LLC.
9321 * Originally Released Under LGPL - original licence link has changed is not relivant.
9324 * <script type="text/javascript">
9328 * @class Roo.data.DataProxy
9329 * @extends Roo.data.Observable
9330 * This class is an abstract base class for implementations which provide retrieval of
9331 * unformatted data objects.<br>
9333 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9334 * (of the appropriate type which knows how to parse the data object) to provide a block of
9335 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9337 * Custom implementations must implement the load method as described in
9338 * {@link Roo.data.HttpProxy#load}.
9340 Roo.data.DataProxy = function(){
9344 * Fires before a network request is made to retrieve a data object.
9345 * @param {Object} This DataProxy object.
9346 * @param {Object} params The params parameter to the load function.
9351 * Fires before the load method's callback is called.
9352 * @param {Object} This DataProxy object.
9353 * @param {Object} o The data object.
9354 * @param {Object} arg The callback argument object passed to the load function.
9358 * @event loadexception
9359 * Fires if an Exception occurs during data retrieval.
9360 * @param {Object} This DataProxy object.
9361 * @param {Object} o The data object.
9362 * @param {Object} arg The callback argument object passed to the load function.
9363 * @param {Object} e The Exception.
9365 loadexception : true
9367 Roo.data.DataProxy.superclass.constructor.call(this);
9370 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9373 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9377 * Ext JS Library 1.1.1
9378 * Copyright(c) 2006-2007, Ext JS, LLC.
9380 * Originally Released Under LGPL - original licence link has changed is not relivant.
9383 * <script type="text/javascript">
9386 * @class Roo.data.MemoryProxy
9387 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9388 * to the Reader when its load method is called.
9390 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9392 Roo.data.MemoryProxy = function(data){
9396 Roo.data.MemoryProxy.superclass.constructor.call(this);
9400 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9402 * Load data from the requested source (in this case an in-memory
9403 * data object passed to the constructor), read the data object into
9404 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9405 * process that block using the passed callback.
9406 * @param {Object} params This parameter is not used by the MemoryProxy class.
9407 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9408 * object into a block of Roo.data.Records.
9409 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9410 * The function must be passed <ul>
9411 * <li>The Record block object</li>
9412 * <li>The "arg" argument from the load function</li>
9413 * <li>A boolean success indicator</li>
9415 * @param {Object} scope The scope in which to call the callback
9416 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9418 load : function(params, reader, callback, scope, arg){
9419 params = params || {};
9422 result = reader.readRecords(this.data);
9424 this.fireEvent("loadexception", this, arg, null, e);
9425 callback.call(scope, null, arg, false);
9428 callback.call(scope, result, arg, true);
9432 update : function(params, records){
9437 * Ext JS Library 1.1.1
9438 * Copyright(c) 2006-2007, Ext JS, LLC.
9440 * Originally Released Under LGPL - original licence link has changed is not relivant.
9443 * <script type="text/javascript">
9446 * @class Roo.data.HttpProxy
9447 * @extends Roo.data.DataProxy
9448 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9449 * configured to reference a certain URL.<br><br>
9451 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9452 * from which the running page was served.<br><br>
9454 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9456 * Be aware that to enable the browser to parse an XML document, the server must set
9457 * the Content-Type header in the HTTP response to "text/xml".
9459 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9460 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9461 * will be used to make the request.
9463 Roo.data.HttpProxy = function(conn){
9464 Roo.data.HttpProxy.superclass.constructor.call(this);
9465 // is conn a conn config or a real conn?
9467 this.useAjax = !conn || !conn.events;
9471 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9472 // thse are take from connection...
9475 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9478 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9479 * extra parameters to each request made by this object. (defaults to undefined)
9482 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9483 * to each request made by this object. (defaults to undefined)
9486 * @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)
9489 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9492 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9498 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9502 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9503 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9504 * a finer-grained basis than the DataProxy events.
9506 getConnection : function(){
9507 return this.useAjax ? Roo.Ajax : this.conn;
9511 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9512 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9513 * process that block using the passed callback.
9514 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9515 * for the request to the remote server.
9516 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9517 * object into a block of Roo.data.Records.
9518 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9519 * The function must be passed <ul>
9520 * <li>The Record block object</li>
9521 * <li>The "arg" argument from the load function</li>
9522 * <li>A boolean success indicator</li>
9524 * @param {Object} scope The scope in which to call the callback
9525 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9527 load : function(params, reader, callback, scope, arg){
9528 if(this.fireEvent("beforeload", this, params) !== false){
9530 params : params || {},
9532 callback : callback,
9537 callback : this.loadResponse,
9541 Roo.applyIf(o, this.conn);
9542 if(this.activeRequest){
9543 Roo.Ajax.abort(this.activeRequest);
9545 this.activeRequest = Roo.Ajax.request(o);
9547 this.conn.request(o);
9550 callback.call(scope||this, null, arg, false);
9555 loadResponse : function(o, success, response){
9556 delete this.activeRequest;
9558 this.fireEvent("loadexception", this, o, response);
9559 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9564 result = o.reader.read(response);
9566 this.fireEvent("loadexception", this, o, response, e);
9567 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9571 this.fireEvent("load", this, o, o.request.arg);
9572 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9576 update : function(dataSet){
9581 updateResponse : function(dataSet){
9586 * Ext JS Library 1.1.1
9587 * Copyright(c) 2006-2007, Ext JS, LLC.
9589 * Originally Released Under LGPL - original licence link has changed is not relivant.
9592 * <script type="text/javascript">
9596 * @class Roo.data.ScriptTagProxy
9597 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9598 * other than the originating domain of the running page.<br><br>
9600 * <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
9601 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9603 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9604 * source code that is used as the source inside a <script> tag.<br><br>
9606 * In order for the browser to process the returned data, the server must wrap the data object
9607 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9608 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9609 * depending on whether the callback name was passed:
9612 boolean scriptTag = false;
9613 String cb = request.getParameter("callback");
9616 response.setContentType("text/javascript");
9618 response.setContentType("application/x-json");
9620 Writer out = response.getWriter();
9622 out.write(cb + "(");
9624 out.print(dataBlock.toJsonString());
9631 * @param {Object} config A configuration object.
9633 Roo.data.ScriptTagProxy = function(config){
9634 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9635 Roo.apply(this, config);
9636 this.head = document.getElementsByTagName("head")[0];
9639 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9641 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9643 * @cfg {String} url The URL from which to request the data object.
9646 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9650 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9651 * the server the name of the callback function set up by the load call to process the returned data object.
9652 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9653 * javascript output which calls this named function passing the data object as its only parameter.
9655 callbackParam : "callback",
9657 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9658 * name to the request.
9663 * Load data from the configured URL, read the data object into
9664 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9665 * process that block using the passed callback.
9666 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9667 * for the request to the remote server.
9668 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9669 * object into a block of Roo.data.Records.
9670 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9671 * The function must be passed <ul>
9672 * <li>The Record block object</li>
9673 * <li>The "arg" argument from the load function</li>
9674 * <li>A boolean success indicator</li>
9676 * @param {Object} scope The scope in which to call the callback
9677 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9679 load : function(params, reader, callback, scope, arg){
9680 if(this.fireEvent("beforeload", this, params) !== false){
9682 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9685 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9687 url += "&_dc=" + (new Date().getTime());
9689 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9692 cb : "stcCallback"+transId,
9693 scriptId : "stcScript"+transId,
9697 callback : callback,
9703 window[trans.cb] = function(o){
9704 conn.handleResponse(o, trans);
9707 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9709 if(this.autoAbort !== false){
9713 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9715 var script = document.createElement("script");
9716 script.setAttribute("src", url);
9717 script.setAttribute("type", "text/javascript");
9718 script.setAttribute("id", trans.scriptId);
9719 this.head.appendChild(script);
9723 callback.call(scope||this, null, arg, false);
9728 isLoading : function(){
9729 return this.trans ? true : false;
9733 * Abort the current server request.
9736 if(this.isLoading()){
9737 this.destroyTrans(this.trans);
9742 destroyTrans : function(trans, isLoaded){
9743 this.head.removeChild(document.getElementById(trans.scriptId));
9744 clearTimeout(trans.timeoutId);
9746 window[trans.cb] = undefined;
9748 delete window[trans.cb];
9751 // if hasn't been loaded, wait for load to remove it to prevent script error
9752 window[trans.cb] = function(){
9753 window[trans.cb] = undefined;
9755 delete window[trans.cb];
9762 handleResponse : function(o, trans){
9764 this.destroyTrans(trans, true);
9767 result = trans.reader.readRecords(o);
9769 this.fireEvent("loadexception", this, o, trans.arg, e);
9770 trans.callback.call(trans.scope||window, null, trans.arg, false);
9773 this.fireEvent("load", this, o, trans.arg);
9774 trans.callback.call(trans.scope||window, result, trans.arg, true);
9778 handleFailure : function(trans){
9780 this.destroyTrans(trans, false);
9781 this.fireEvent("loadexception", this, null, trans.arg);
9782 trans.callback.call(trans.scope||window, null, trans.arg, false);
9786 * Ext JS Library 1.1.1
9787 * Copyright(c) 2006-2007, Ext JS, LLC.
9789 * Originally Released Under LGPL - original licence link has changed is not relivant.
9792 * <script type="text/javascript">
9796 * @class Roo.data.JsonReader
9797 * @extends Roo.data.DataReader
9798 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9799 * based on mappings in a provided Roo.data.Record constructor.
9801 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9802 * in the reply previously.
9807 var RecordDef = Roo.data.Record.create([
9808 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9809 {name: 'occupation'} // This field will use "occupation" as the mapping.
9811 var myReader = new Roo.data.JsonReader({
9812 totalProperty: "results", // The property which contains the total dataset size (optional)
9813 root: "rows", // The property which contains an Array of row objects
9814 id: "id" // The property within each row object that provides an ID for the record (optional)
9818 * This would consume a JSON file like this:
9820 { 'results': 2, 'rows': [
9821 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9822 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9825 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9826 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9827 * paged from the remote server.
9828 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9829 * @cfg {String} root name of the property which contains the Array of row objects.
9830 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9832 * Create a new JsonReader
9833 * @param {Object} meta Metadata configuration options
9834 * @param {Object} recordType Either an Array of field definition objects,
9835 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9837 Roo.data.JsonReader = function(meta, recordType){
9840 // set some defaults:
9842 totalProperty: 'total',
9843 successProperty : 'success',
9848 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9850 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9853 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9854 * Used by Store query builder to append _requestMeta to params.
9857 metaFromRemote : false,
9859 * This method is only used by a DataProxy which has retrieved data from a remote server.
9860 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9861 * @return {Object} data A data block which is used by an Roo.data.Store object as
9862 * a cache of Roo.data.Records.
9864 read : function(response){
9865 var json = response.responseText;
9867 var o = /* eval:var:o */ eval("("+json+")");
9869 throw {message: "JsonReader.read: Json object not found"};
9875 this.metaFromRemote = true;
9876 this.meta = o.metaData;
9877 this.recordType = Roo.data.Record.create(o.metaData.fields);
9878 this.onMetaChange(this.meta, this.recordType, o);
9880 return this.readRecords(o);
9883 // private function a store will implement
9884 onMetaChange : function(meta, recordType, o){
9891 simpleAccess: function(obj, subsc) {
9898 getJsonAccessor: function(){
9900 return function(expr) {
9902 return(re.test(expr))
9903 ? new Function("obj", "return obj." + expr)
9913 * Create a data block containing Roo.data.Records from an XML document.
9914 * @param {Object} o An object which contains an Array of row objects in the property specified
9915 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9916 * which contains the total size of the dataset.
9917 * @return {Object} data A data block which is used by an Roo.data.Store object as
9918 * a cache of Roo.data.Records.
9920 readRecords : function(o){
9922 * After any data loads, the raw JSON data is available for further custom processing.
9926 var s = this.meta, Record = this.recordType,
9927 f = Record.prototype.fields, fi = f.items, fl = f.length;
9929 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9931 if(s.totalProperty) {
9932 this.getTotal = this.getJsonAccessor(s.totalProperty);
9934 if(s.successProperty) {
9935 this.getSuccess = this.getJsonAccessor(s.successProperty);
9937 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9939 var g = this.getJsonAccessor(s.id);
9940 this.getId = function(rec) {
9942 return (r === undefined || r === "") ? null : r;
9945 this.getId = function(){return null;};
9948 for(var jj = 0; jj < fl; jj++){
9950 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9951 this.ef[jj] = this.getJsonAccessor(map);
9955 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9956 if(s.totalProperty){
9957 var vt = parseInt(this.getTotal(o), 10);
9962 if(s.successProperty){
9963 var vs = this.getSuccess(o);
9964 if(vs === false || vs === 'false'){
9969 for(var i = 0; i < c; i++){
9972 var id = this.getId(n);
9973 for(var j = 0; j < fl; j++){
9975 var v = this.ef[j](n);
9977 Roo.log('missing convert for ' + f.name);
9981 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9983 var record = new Record(values, id);
9985 records[i] = record;
9991 totalRecords : totalRecords
9996 * Ext JS Library 1.1.1
9997 * Copyright(c) 2006-2007, Ext JS, LLC.
9999 * Originally Released Under LGPL - original licence link has changed is not relivant.
10002 * <script type="text/javascript">
10006 * @class Roo.data.ArrayReader
10007 * @extends Roo.data.DataReader
10008 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10009 * Each element of that Array represents a row of data fields. The
10010 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10011 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10015 var RecordDef = Roo.data.Record.create([
10016 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10017 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10019 var myReader = new Roo.data.ArrayReader({
10020 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10024 * This would consume an Array like this:
10026 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10028 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10030 * Create a new JsonReader
10031 * @param {Object} meta Metadata configuration options.
10032 * @param {Object} recordType Either an Array of field definition objects
10033 * as specified to {@link Roo.data.Record#create},
10034 * or an {@link Roo.data.Record} object
10035 * created using {@link Roo.data.Record#create}.
10037 Roo.data.ArrayReader = function(meta, recordType){
10038 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10041 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10043 * Create a data block containing Roo.data.Records from an XML document.
10044 * @param {Object} o An Array of row objects which represents the dataset.
10045 * @return {Object} data A data block which is used by an Roo.data.Store object as
10046 * a cache of Roo.data.Records.
10048 readRecords : function(o){
10049 var sid = this.meta ? this.meta.id : null;
10050 var recordType = this.recordType, fields = recordType.prototype.fields;
10053 for(var i = 0; i < root.length; i++){
10056 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10057 for(var j = 0, jlen = fields.length; j < jlen; j++){
10058 var f = fields.items[j];
10059 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10060 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10062 values[f.name] = v;
10064 var record = new recordType(values, id);
10066 records[records.length] = record;
10070 totalRecords : records.length
10079 * @class Roo.bootstrap.ComboBox
10080 * @extends Roo.bootstrap.TriggerField
10081 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10082 * @cfg {Boolean} append (true|false) default false
10083 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10084 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10085 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10086 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10088 * Create a new ComboBox.
10089 * @param {Object} config Configuration options
10091 Roo.bootstrap.ComboBox = function(config){
10092 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10096 * Fires when the dropdown list is expanded
10097 * @param {Roo.bootstrap.ComboBox} combo This combo box
10102 * Fires when the dropdown list is collapsed
10103 * @param {Roo.bootstrap.ComboBox} combo This combo box
10107 * @event beforeselect
10108 * Fires before a list item is selected. Return false to cancel the selection.
10109 * @param {Roo.bootstrap.ComboBox} combo This combo box
10110 * @param {Roo.data.Record} record The data record returned from the underlying store
10111 * @param {Number} index The index of the selected item in the dropdown list
10113 'beforeselect' : true,
10116 * Fires when a list item is selected
10117 * @param {Roo.bootstrap.ComboBox} combo This combo box
10118 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10119 * @param {Number} index The index of the selected item in the dropdown list
10123 * @event beforequery
10124 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10125 * The event object passed has these properties:
10126 * @param {Roo.bootstrap.ComboBox} combo This combo box
10127 * @param {String} query The query
10128 * @param {Boolean} forceAll true to force "all" query
10129 * @param {Boolean} cancel true to cancel the query
10130 * @param {Object} e The query event object
10132 'beforequery': true,
10135 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10136 * @param {Roo.bootstrap.ComboBox} combo This combo box
10141 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10142 * @param {Roo.bootstrap.ComboBox} combo This combo box
10143 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10148 * Fires when the remove value from the combobox array
10149 * @param {Roo.bootstrap.ComboBox} combo This combo box
10156 this.tickItems = [];
10158 this.selectedIndex = -1;
10159 if(this.mode == 'local'){
10160 if(config.queryDelay === undefined){
10161 this.queryDelay = 10;
10163 if(config.minChars === undefined){
10169 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10172 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10173 * rendering into an Roo.Editor, defaults to false)
10176 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10177 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10180 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10183 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10184 * the dropdown list (defaults to undefined, with no header element)
10188 * @cfg {String/Roo.Template} tpl The template to use to render the output
10192 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10194 listWidth: undefined,
10196 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10197 * mode = 'remote' or 'text' if mode = 'local')
10199 displayField: undefined,
10201 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10202 * mode = 'remote' or 'value' if mode = 'local').
10203 * Note: use of a valueField requires the user make a selection
10204 * in order for a value to be mapped.
10206 valueField: undefined,
10210 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10211 * field's data value (defaults to the underlying DOM element's name)
10213 hiddenName: undefined,
10215 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10219 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10221 selectedClass: 'active',
10224 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10228 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10229 * anchor positions (defaults to 'tl-bl')
10231 listAlign: 'tl-bl?',
10233 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10237 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10238 * query specified by the allQuery config option (defaults to 'query')
10240 triggerAction: 'query',
10242 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10243 * (defaults to 4, does not apply if editable = false)
10247 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10248 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10252 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10253 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10257 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10258 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10262 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10263 * when editable = true (defaults to false)
10265 selectOnFocus:false,
10267 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10269 queryParam: 'query',
10271 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10272 * when mode = 'remote' (defaults to 'Loading...')
10274 loadingText: 'Loading...',
10276 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10280 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10284 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10285 * traditional select (defaults to true)
10289 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10293 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10297 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10298 * listWidth has a higher value)
10302 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10303 * allow the user to set arbitrary text into the field (defaults to false)
10305 forceSelection:false,
10307 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10308 * if typeAhead = true (defaults to 250)
10310 typeAheadDelay : 250,
10312 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10313 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10315 valueNotFoundText : undefined,
10317 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10319 blockFocus : false,
10322 * @cfg {Boolean} disableClear Disable showing of clear button.
10324 disableClear : false,
10326 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10328 alwaysQuery : false,
10331 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10345 btnPosition : 'right',
10346 triggerList : true,
10347 // element that contains real text value.. (when hidden is used..)
10349 getAutoCreate : function()
10356 if(!this.tickable){
10357 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10362 * ComboBox with tickable selections
10365 var align = this.labelAlign || this.parentLabelAlign();
10368 cls : 'form-group roo-combobox-tickable' //input-group
10374 cls : 'tickable-buttons',
10379 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10386 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10393 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10400 Roo.each(buttons.cn, function(c){
10402 c.cls += ' btn-' + _this.size;
10405 if (_this.disabled) {
10416 cls: 'form-hidden-field'
10420 cls: 'select2-choices',
10424 cls: 'select2-search-field',
10436 cls: 'select2-container input-group select2-container-multi',
10441 // cls: 'typeahead typeahead-long dropdown-menu',
10442 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10447 if (align ==='left' && this.fieldLabel.length) {
10449 Roo.log("left and has label");
10455 cls : 'control-label col-sm-' + this.labelWidth,
10456 html : this.fieldLabel
10460 cls : "col-sm-" + (12 - this.labelWidth),
10467 } else if ( this.fieldLabel.length) {
10473 //cls : 'input-group-addon',
10474 html : this.fieldLabel
10484 Roo.log(" no label && no align");
10491 ['xs','sm','md','lg'].map(function(size){
10492 if (settings[size]) {
10493 cfg.cls += ' col-' + size + '-' + settings[size];
10502 initEvents: function()
10506 throw "can not find store for combo";
10508 this.store = Roo.factory(this.store, Roo.data);
10511 this.initTickableEvents();
10515 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10517 if(this.hiddenName){
10519 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10521 this.hiddenField.dom.value =
10522 this.hiddenValue !== undefined ? this.hiddenValue :
10523 this.value !== undefined ? this.value : '';
10525 // prevent input submission
10526 this.el.dom.removeAttribute('name');
10527 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10532 // this.el.dom.setAttribute('autocomplete', 'off');
10535 var cls = 'x-combo-list';
10537 //this.list = new Roo.Layer({
10538 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10544 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10545 _this.list.setWidth(lw);
10548 this.list.on('mouseover', this.onViewOver, this);
10549 this.list.on('mousemove', this.onViewMove, this);
10551 this.list.on('scroll', this.onViewScroll, this);
10554 this.list.swallowEvent('mousewheel');
10555 this.assetHeight = 0;
10558 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10559 this.assetHeight += this.header.getHeight();
10562 this.innerList = this.list.createChild({cls:cls+'-inner'});
10563 this.innerList.on('mouseover', this.onViewOver, this);
10564 this.innerList.on('mousemove', this.onViewMove, this);
10565 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10567 if(this.allowBlank && !this.pageSize && !this.disableClear){
10568 this.footer = this.list.createChild({cls:cls+'-ft'});
10569 this.pageTb = new Roo.Toolbar(this.footer);
10573 this.footer = this.list.createChild({cls:cls+'-ft'});
10574 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10575 {pageSize: this.pageSize});
10579 if (this.pageTb && this.allowBlank && !this.disableClear) {
10581 this.pageTb.add(new Roo.Toolbar.Fill(), {
10582 cls: 'x-btn-icon x-btn-clear',
10584 handler: function()
10587 _this.clearValue();
10588 _this.onSelect(false, -1);
10593 this.assetHeight += this.footer.getHeight();
10598 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10601 this.view = new Roo.View(this.list, this.tpl, {
10602 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10604 //this.view.wrapEl.setDisplayed(false);
10605 this.view.on('click', this.onViewClick, this);
10609 this.store.on('beforeload', this.onBeforeLoad, this);
10610 this.store.on('load', this.onLoad, this);
10611 this.store.on('loadexception', this.onLoadException, this);
10613 if(this.resizable){
10614 this.resizer = new Roo.Resizable(this.list, {
10615 pinned:true, handles:'se'
10617 this.resizer.on('resize', function(r, w, h){
10618 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10619 this.listWidth = w;
10620 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10621 this.restrictHeight();
10623 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10626 if(!this.editable){
10627 this.editable = true;
10628 this.setEditable(false);
10633 if (typeof(this.events.add.listeners) != 'undefined') {
10635 this.addicon = this.wrap.createChild(
10636 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10638 this.addicon.on('click', function(e) {
10639 this.fireEvent('add', this);
10642 if (typeof(this.events.edit.listeners) != 'undefined') {
10644 this.editicon = this.wrap.createChild(
10645 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10646 if (this.addicon) {
10647 this.editicon.setStyle('margin-left', '40px');
10649 this.editicon.on('click', function(e) {
10651 // we fire even if inothing is selected..
10652 this.fireEvent('edit', this, this.lastData );
10658 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10659 "up" : function(e){
10660 this.inKeyMode = true;
10664 "down" : function(e){
10665 if(!this.isExpanded()){
10666 this.onTriggerClick();
10668 this.inKeyMode = true;
10673 "enter" : function(e){
10674 // this.onViewClick();
10678 if(this.fireEvent("specialkey", this, e)){
10679 this.onViewClick(false);
10685 "esc" : function(e){
10689 "tab" : function(e){
10692 if(this.fireEvent("specialkey", this, e)){
10693 this.onViewClick(false);
10701 doRelay : function(foo, bar, hname){
10702 if(hname == 'down' || this.scope.isExpanded()){
10703 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10712 this.queryDelay = Math.max(this.queryDelay || 10,
10713 this.mode == 'local' ? 10 : 250);
10716 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10718 if(this.typeAhead){
10719 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10721 if(this.editable !== false){
10722 this.inputEl().on("keyup", this.onKeyUp, this);
10724 if(this.forceSelection){
10725 this.inputEl().on('blur', this.doForce, this);
10729 this.choices = this.el.select('ul.select2-choices', true).first();
10730 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10734 initTickableEvents: function()
10738 if(this.hiddenName){
10740 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10742 this.hiddenField.dom.value =
10743 this.hiddenValue !== undefined ? this.hiddenValue :
10744 this.value !== undefined ? this.value : '';
10746 // prevent input submission
10747 this.el.dom.removeAttribute('name');
10748 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10753 // this.list = this.el.select('ul.dropdown-menu',true).first();
10755 this.choices = this.el.select('ul.select2-choices', true).first();
10756 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10757 if(this.triggerList){
10758 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10761 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10762 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10764 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10765 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10767 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10768 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10770 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10771 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10772 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10775 this.cancelBtn.hide();
10780 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10781 _this.list.setWidth(lw);
10784 this.list.on('mouseover', this.onViewOver, this);
10785 this.list.on('mousemove', this.onViewMove, this);
10787 this.list.on('scroll', this.onViewScroll, this);
10790 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>';
10793 this.view = new Roo.View(this.list, this.tpl, {
10794 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10797 //this.view.wrapEl.setDisplayed(false);
10798 this.view.on('click', this.onViewClick, this);
10802 this.store.on('beforeload', this.onBeforeLoad, this);
10803 this.store.on('load', this.onLoad, this);
10804 this.store.on('loadexception', this.onLoadException, this);
10806 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10807 // "up" : function(e){
10808 // this.inKeyMode = true;
10809 // this.selectPrev();
10812 // "down" : function(e){
10813 // if(!this.isExpanded()){
10814 // this.onTriggerClick();
10816 // this.inKeyMode = true;
10817 // this.selectNext();
10821 // "enter" : function(e){
10822 //// this.onViewClick();
10824 // this.collapse();
10826 // if(this.fireEvent("specialkey", this, e)){
10827 // this.onViewClick(false);
10833 // "esc" : function(e){
10834 // this.collapse();
10837 // "tab" : function(e){
10838 // this.collapse();
10840 // if(this.fireEvent("specialkey", this, e)){
10841 // this.onViewClick(false);
10849 // doRelay : function(foo, bar, hname){
10850 // if(hname == 'down' || this.scope.isExpanded()){
10851 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10856 // forceKeyDown: true
10860 this.queryDelay = Math.max(this.queryDelay || 10,
10861 this.mode == 'local' ? 10 : 250);
10864 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10866 if(this.typeAhead){
10867 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10871 onDestroy : function(){
10873 this.view.setStore(null);
10874 this.view.el.removeAllListeners();
10875 this.view.el.remove();
10876 this.view.purgeListeners();
10879 this.list.dom.innerHTML = '';
10883 this.store.un('beforeload', this.onBeforeLoad, this);
10884 this.store.un('load', this.onLoad, this);
10885 this.store.un('loadexception', this.onLoadException, this);
10887 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10891 fireKey : function(e){
10892 if(e.isNavKeyPress() && !this.list.isVisible()){
10893 this.fireEvent("specialkey", this, e);
10898 onResize: function(w, h){
10899 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10901 // if(typeof w != 'number'){
10902 // // we do not handle it!?!?
10905 // var tw = this.trigger.getWidth();
10906 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10907 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10909 // this.inputEl().setWidth( this.adjustWidth('input', x));
10911 // //this.trigger.setStyle('left', x+'px');
10913 // if(this.list && this.listWidth === undefined){
10914 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10915 // this.list.setWidth(lw);
10916 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10924 * Allow or prevent the user from directly editing the field text. If false is passed,
10925 * the user will only be able to select from the items defined in the dropdown list. This method
10926 * is the runtime equivalent of setting the 'editable' config option at config time.
10927 * @param {Boolean} value True to allow the user to directly edit the field text
10929 setEditable : function(value){
10930 if(value == this.editable){
10933 this.editable = value;
10935 this.inputEl().dom.setAttribute('readOnly', true);
10936 this.inputEl().on('mousedown', this.onTriggerClick, this);
10937 this.inputEl().addClass('x-combo-noedit');
10939 this.inputEl().dom.setAttribute('readOnly', false);
10940 this.inputEl().un('mousedown', this.onTriggerClick, this);
10941 this.inputEl().removeClass('x-combo-noedit');
10947 onBeforeLoad : function(combo,opts){
10948 if(!this.hasFocus){
10952 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10954 // this.restrictHeight();
10955 this.selectedIndex = -1;
10959 onLoad : function(){
10961 this.hasQuery = false;
10963 if(!this.hasFocus){
10967 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10968 this.loading.hide();
10971 if(this.store.getCount() > 0){
10973 // this.restrictHeight();
10974 if(this.lastQuery == this.allQuery){
10975 if(this.editable && !this.tickable){
10976 this.inputEl().dom.select();
10978 if(!this.selectByValue(this.value, true) && this.autoFocus){
10979 this.select(0, true);
10982 if(this.autoFocus){
10985 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10986 this.taTask.delay(this.typeAheadDelay);
10990 this.onEmptyResults();
10996 onLoadException : function()
10998 this.hasQuery = false;
11000 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11001 this.loading.hide();
11005 Roo.log(this.store.reader.jsonData);
11006 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11008 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11014 onTypeAhead : function(){
11015 if(this.store.getCount() > 0){
11016 var r = this.store.getAt(0);
11017 var newValue = r.data[this.displayField];
11018 var len = newValue.length;
11019 var selStart = this.getRawValue().length;
11021 if(selStart != len){
11022 this.setRawValue(newValue);
11023 this.selectText(selStart, newValue.length);
11029 onSelect : function(record, index){
11031 if(this.fireEvent('beforeselect', this, record, index) !== false){
11033 this.setFromData(index > -1 ? record.data : false);
11036 this.fireEvent('select', this, record, index);
11041 * Returns the currently selected field value or empty string if no value is set.
11042 * @return {String} value The selected value
11044 getValue : function(){
11047 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11050 if(this.valueField){
11051 return typeof this.value != 'undefined' ? this.value : '';
11053 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11058 * Clears any text/value currently set in the field
11060 clearValue : function(){
11061 if(this.hiddenField){
11062 this.hiddenField.dom.value = '';
11065 this.setRawValue('');
11066 this.lastSelectionText = '';
11071 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11072 * will be displayed in the field. If the value does not match the data value of an existing item,
11073 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11074 * Otherwise the field will be blank (although the value will still be set).
11075 * @param {String} value The value to match
11077 setValue : function(v){
11084 if(this.valueField){
11085 var r = this.findRecord(this.valueField, v);
11087 text = r.data[this.displayField];
11088 }else if(this.valueNotFoundText !== undefined){
11089 text = this.valueNotFoundText;
11092 this.lastSelectionText = text;
11093 if(this.hiddenField){
11094 this.hiddenField.dom.value = v;
11096 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11100 * @property {Object} the last set data for the element
11105 * Sets the value of the field based on a object which is related to the record format for the store.
11106 * @param {Object} value the value to set as. or false on reset?
11108 setFromData : function(o){
11111 if(typeof o.display_name !== 'string'){
11112 for(var i=0;i<o.display_name.length;i++){
11113 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11121 var dv = ''; // display value
11122 var vv = ''; // value value..
11124 if (this.displayField) {
11125 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11127 // this is an error condition!!!
11128 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11131 if(this.valueField){
11132 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11135 if(this.hiddenField){
11136 this.hiddenField.dom.value = vv;
11138 this.lastSelectionText = dv;
11139 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11143 // no hidden field.. - we store the value in 'value', but still display
11144 // display field!!!!
11145 this.lastSelectionText = dv;
11146 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11152 reset : function(){
11153 // overridden so that last data is reset..
11154 this.setValue(this.originalValue);
11155 this.clearInvalid();
11156 this.lastData = false;
11158 this.view.clearSelections();
11162 findRecord : function(prop, value){
11164 if(this.store.getCount() > 0){
11165 this.store.each(function(r){
11166 if(r.data[prop] == value){
11176 getName: function()
11178 // returns hidden if it's set..
11179 if (!this.rendered) {return ''};
11180 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11184 onViewMove : function(e, t){
11185 this.inKeyMode = false;
11189 onViewOver : function(e, t){
11190 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11193 var item = this.view.findItemFromChild(t);
11196 var index = this.view.indexOf(item);
11197 this.select(index, false);
11202 onViewClick : function(view, doFocus, el, e)
11204 var index = this.view.getSelectedIndexes()[0];
11206 var r = this.store.getAt(index);
11210 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11217 Roo.each(this.tickItems, function(v,k){
11219 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11220 _this.tickItems.splice(k, 1);
11230 this.tickItems.push(r.data);
11235 this.onSelect(r, index);
11237 if(doFocus !== false && !this.blockFocus){
11238 this.inputEl().focus();
11243 restrictHeight : function(){
11244 //this.innerList.dom.style.height = '';
11245 //var inner = this.innerList.dom;
11246 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11247 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11248 //this.list.beginUpdate();
11249 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11250 this.list.alignTo(this.inputEl(), this.listAlign);
11251 this.list.alignTo(this.inputEl(), this.listAlign);
11252 //this.list.endUpdate();
11256 onEmptyResults : function(){
11261 * Returns true if the dropdown list is expanded, else false.
11263 isExpanded : function(){
11264 return this.list.isVisible();
11268 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11269 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11270 * @param {String} value The data value of the item to select
11271 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11272 * selected item if it is not currently in view (defaults to true)
11273 * @return {Boolean} True if the value matched an item in the list, else false
11275 selectByValue : function(v, scrollIntoView){
11276 if(v !== undefined && v !== null){
11277 var r = this.findRecord(this.valueField || this.displayField, v);
11279 this.select(this.store.indexOf(r), scrollIntoView);
11287 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11288 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11289 * @param {Number} index The zero-based index of the list item to select
11290 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11291 * selected item if it is not currently in view (defaults to true)
11293 select : function(index, scrollIntoView){
11294 this.selectedIndex = index;
11295 this.view.select(index);
11296 if(scrollIntoView !== false){
11297 var el = this.view.getNode(index);
11298 if(el && !this.multiple && !this.tickable){
11299 this.list.scrollChildIntoView(el, false);
11305 selectNext : function(){
11306 var ct = this.store.getCount();
11308 if(this.selectedIndex == -1){
11310 }else if(this.selectedIndex < ct-1){
11311 this.select(this.selectedIndex+1);
11317 selectPrev : function(){
11318 var ct = this.store.getCount();
11320 if(this.selectedIndex == -1){
11322 }else if(this.selectedIndex != 0){
11323 this.select(this.selectedIndex-1);
11329 onKeyUp : function(e){
11330 if(this.editable !== false && !e.isSpecialKey()){
11331 this.lastKey = e.getKey();
11332 this.dqTask.delay(this.queryDelay);
11337 validateBlur : function(){
11338 return !this.list || !this.list.isVisible();
11342 initQuery : function(){
11343 this.doQuery(this.getRawValue());
11347 doForce : function(){
11348 if(this.inputEl().dom.value.length > 0){
11349 this.inputEl().dom.value =
11350 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11356 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11357 * query allowing the query action to be canceled if needed.
11358 * @param {String} query The SQL query to execute
11359 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11360 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11361 * saved in the current store (defaults to false)
11363 doQuery : function(q, forceAll){
11365 if(q === undefined || q === null){
11370 forceAll: forceAll,
11374 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11379 forceAll = qe.forceAll;
11380 if(forceAll === true || (q.length >= this.minChars)){
11382 this.hasQuery = true;
11384 if(this.lastQuery != q || this.alwaysQuery){
11385 this.lastQuery = q;
11386 if(this.mode == 'local'){
11387 this.selectedIndex = -1;
11389 this.store.clearFilter();
11391 this.store.filter(this.displayField, q);
11395 this.store.baseParams[this.queryParam] = q;
11397 var options = {params : this.getParams(q)};
11400 options.add = true;
11401 options.params.start = this.page * this.pageSize;
11404 this.store.load(options);
11406 * this code will make the page width larger, at the beginning, the list not align correctly,
11407 * we should expand the list on onLoad
11408 * so command out it
11413 this.selectedIndex = -1;
11418 this.loadNext = false;
11422 getParams : function(q){
11424 //p[this.queryParam] = q;
11428 p.limit = this.pageSize;
11434 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11436 collapse : function(){
11437 if(!this.isExpanded()){
11441 this.hasFocus = false;
11447 this.cancelBtn.hide();
11448 this.trigger.show();
11451 Roo.get(document).un('mousedown', this.collapseIf, this);
11452 Roo.get(document).un('mousewheel', this.collapseIf, this);
11453 if (!this.editable) {
11454 Roo.get(document).un('keydown', this.listKeyPress, this);
11456 this.fireEvent('collapse', this);
11460 collapseIf : function(e){
11461 var in_combo = e.within(this.el);
11462 var in_list = e.within(this.list);
11463 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11465 if (in_combo || in_list || is_list) {
11466 //e.stopPropagation();
11471 this.onTickableFooterButtonClick(e, false, false);
11479 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11481 expand : function(){
11483 if(this.isExpanded() || !this.hasFocus){
11490 this.restrictHeight();
11494 this.tickItems = Roo.apply([], this.item);
11497 this.cancelBtn.show();
11498 this.trigger.hide();
11502 Roo.get(document).on('mousedown', this.collapseIf, this);
11503 Roo.get(document).on('mousewheel', this.collapseIf, this);
11504 if (!this.editable) {
11505 Roo.get(document).on('keydown', this.listKeyPress, this);
11508 this.fireEvent('expand', this);
11512 // Implements the default empty TriggerField.onTriggerClick function
11513 onTriggerClick : function(e)
11515 Roo.log('trigger click');
11517 if(this.disabled || !this.triggerList){
11522 this.loadNext = false;
11524 if(this.isExpanded()){
11526 if (!this.blockFocus) {
11527 this.inputEl().focus();
11531 this.hasFocus = true;
11532 if(this.triggerAction == 'all') {
11533 this.doQuery(this.allQuery, true);
11535 this.doQuery(this.getRawValue());
11537 if (!this.blockFocus) {
11538 this.inputEl().focus();
11543 onTickableTriggerClick : function(e)
11550 this.loadNext = false;
11551 this.hasFocus = true;
11553 if(this.triggerAction == 'all') {
11554 this.doQuery(this.allQuery, true);
11556 this.doQuery(this.getRawValue());
11560 onSearchFieldClick : function(e)
11562 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11567 this.loadNext = false;
11568 this.hasFocus = true;
11570 if(this.triggerAction == 'all') {
11571 this.doQuery(this.allQuery, true);
11573 this.doQuery(this.getRawValue());
11577 listKeyPress : function(e)
11579 //Roo.log('listkeypress');
11580 // scroll to first matching element based on key pres..
11581 if (e.isSpecialKey()) {
11584 var k = String.fromCharCode(e.getKey()).toUpperCase();
11587 var csel = this.view.getSelectedNodes();
11588 var cselitem = false;
11590 var ix = this.view.indexOf(csel[0]);
11591 cselitem = this.store.getAt(ix);
11592 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11598 this.store.each(function(v) {
11600 // start at existing selection.
11601 if (cselitem.id == v.id) {
11607 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11608 match = this.store.indexOf(v);
11614 if (match === false) {
11615 return true; // no more action?
11618 this.view.select(match);
11619 var sn = Roo.get(this.view.getSelectedNodes()[0])
11620 //sn.scrollIntoView(sn.dom.parentNode, false);
11623 onViewScroll : function(e, t){
11625 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11629 this.hasQuery = true;
11631 this.loading = this.list.select('.loading', true).first();
11633 if(this.loading === null){
11634 this.list.createChild({
11636 cls: 'loading select2-more-results select2-active',
11637 html: 'Loading more results...'
11640 this.loading = this.list.select('.loading', true).first();
11642 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11644 this.loading.hide();
11647 this.loading.show();
11652 this.loadNext = true;
11654 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11659 addItem : function(o)
11661 var dv = ''; // display value
11663 if (this.displayField) {
11664 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11666 // this is an error condition!!!
11667 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11674 var choice = this.choices.createChild({
11676 cls: 'select2-search-choice',
11685 cls: 'select2-search-choice-close',
11690 }, this.searchField);
11692 var close = choice.select('a.select2-search-choice-close', true).first()
11694 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11702 this.inputEl().dom.value = '';
11706 onRemoveItem : function(e, _self, o)
11708 e.preventDefault();
11709 var index = this.item.indexOf(o.data) * 1;
11712 Roo.log('not this item?!');
11716 this.item.splice(index, 1);
11721 this.fireEvent('remove', this, e);
11725 syncValue : function()
11727 if(!this.item.length){
11734 Roo.each(this.item, function(i){
11735 if(_this.valueField){
11736 value.push(i[_this.valueField]);
11743 this.value = value.join(',');
11745 if(this.hiddenField){
11746 this.hiddenField.dom.value = this.value;
11750 clearItem : function()
11752 if(!this.multiple){
11758 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11765 inputEl: function ()
11768 return this.searchField;
11770 return this.el.select('input.form-control',true).first();
11774 onTickableFooterButtonClick : function(e, btn, el)
11776 e.preventDefault();
11778 if(btn && btn.name == 'cancel'){
11779 this.tickItems = Roo.apply([], this.item);
11788 Roo.each(this.tickItems, function(o){
11799 * @cfg {Boolean} grow
11803 * @cfg {Number} growMin
11807 * @cfg {Number} growMax
11817 * Ext JS Library 1.1.1
11818 * Copyright(c) 2006-2007, Ext JS, LLC.
11820 * Originally Released Under LGPL - original licence link has changed is not relivant.
11823 * <script type="text/javascript">
11828 * @extends Roo.util.Observable
11829 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11830 * This class also supports single and multi selection modes. <br>
11831 * Create a data model bound view:
11833 var store = new Roo.data.Store(...);
11835 var view = new Roo.View({
11837 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11839 singleSelect: true,
11840 selectedClass: "ydataview-selected",
11844 // listen for node click?
11845 view.on("click", function(vw, index, node, e){
11846 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11850 dataModel.load("foobar.xml");
11852 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11854 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11855 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11857 * Note: old style constructor is still suported (container, template, config)
11860 * Create a new View
11861 * @param {Object} config The config object
11864 Roo.View = function(config, depreciated_tpl, depreciated_config){
11866 this.parent = false;
11868 if (typeof(depreciated_tpl) == 'undefined') {
11869 // new way.. - universal constructor.
11870 Roo.apply(this, config);
11871 this.el = Roo.get(this.el);
11874 this.el = Roo.get(config);
11875 this.tpl = depreciated_tpl;
11876 Roo.apply(this, depreciated_config);
11878 this.wrapEl = this.el.wrap().wrap();
11879 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11882 if(typeof(this.tpl) == "string"){
11883 this.tpl = new Roo.Template(this.tpl);
11885 // support xtype ctors..
11886 this.tpl = new Roo.factory(this.tpl, Roo);
11890 this.tpl.compile();
11895 * @event beforeclick
11896 * Fires before a click is processed. Returns false to cancel the default action.
11897 * @param {Roo.View} this
11898 * @param {Number} index The index of the target node
11899 * @param {HTMLElement} node The target node
11900 * @param {Roo.EventObject} e The raw event object
11902 "beforeclick" : true,
11905 * Fires when a template node is clicked.
11906 * @param {Roo.View} this
11907 * @param {Number} index The index of the target node
11908 * @param {HTMLElement} node The target node
11909 * @param {Roo.EventObject} e The raw event object
11914 * Fires when a template node is double clicked.
11915 * @param {Roo.View} this
11916 * @param {Number} index The index of the target node
11917 * @param {HTMLElement} node The target node
11918 * @param {Roo.EventObject} e The raw event object
11922 * @event contextmenu
11923 * Fires when a template node is right clicked.
11924 * @param {Roo.View} this
11925 * @param {Number} index The index of the target node
11926 * @param {HTMLElement} node The target node
11927 * @param {Roo.EventObject} e The raw event object
11929 "contextmenu" : true,
11931 * @event selectionchange
11932 * Fires when the selected nodes change.
11933 * @param {Roo.View} this
11934 * @param {Array} selections Array of the selected nodes
11936 "selectionchange" : true,
11939 * @event beforeselect
11940 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11941 * @param {Roo.View} this
11942 * @param {HTMLElement} node The node to be selected
11943 * @param {Array} selections Array of currently selected nodes
11945 "beforeselect" : true,
11947 * @event preparedata
11948 * Fires on every row to render, to allow you to change the data.
11949 * @param {Roo.View} this
11950 * @param {Object} data to be rendered (change this)
11952 "preparedata" : true
11960 "click": this.onClick,
11961 "dblclick": this.onDblClick,
11962 "contextmenu": this.onContextMenu,
11966 this.selections = [];
11968 this.cmp = new Roo.CompositeElementLite([]);
11970 this.store = Roo.factory(this.store, Roo.data);
11971 this.setStore(this.store, true);
11974 if ( this.footer && this.footer.xtype) {
11976 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11978 this.footer.dataSource = this.store
11979 this.footer.container = fctr;
11980 this.footer = Roo.factory(this.footer, Roo);
11981 fctr.insertFirst(this.el);
11983 // this is a bit insane - as the paging toolbar seems to detach the el..
11984 // dom.parentNode.parentNode.parentNode
11985 // they get detached?
11989 Roo.View.superclass.constructor.call(this);
11994 Roo.extend(Roo.View, Roo.util.Observable, {
11997 * @cfg {Roo.data.Store} store Data store to load data from.
12002 * @cfg {String|Roo.Element} el The container element.
12007 * @cfg {String|Roo.Template} tpl The template used by this View
12011 * @cfg {String} dataName the named area of the template to use as the data area
12012 * Works with domtemplates roo-name="name"
12016 * @cfg {String} selectedClass The css class to add to selected nodes
12018 selectedClass : "x-view-selected",
12020 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12025 * @cfg {String} text to display on mask (default Loading)
12029 * @cfg {Boolean} multiSelect Allow multiple selection
12031 multiSelect : false,
12033 * @cfg {Boolean} singleSelect Allow single selection
12035 singleSelect: false,
12038 * @cfg {Boolean} toggleSelect - selecting
12040 toggleSelect : false,
12043 * @cfg {Boolean} tickable - selecting
12048 * Returns the element this view is bound to.
12049 * @return {Roo.Element}
12051 getEl : function(){
12052 return this.wrapEl;
12058 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12060 refresh : function(){
12061 Roo.log('refresh');
12064 // if we are using something like 'domtemplate', then
12065 // the what gets used is:
12066 // t.applySubtemplate(NAME, data, wrapping data..)
12067 // the outer template then get' applied with
12068 // the store 'extra data'
12069 // and the body get's added to the
12070 // roo-name="data" node?
12071 // <span class='roo-tpl-{name}'></span> ?????
12075 this.clearSelections();
12076 this.el.update("");
12078 var records = this.store.getRange();
12079 if(records.length < 1) {
12081 // is this valid?? = should it render a template??
12083 this.el.update(this.emptyText);
12087 if (this.dataName) {
12088 this.el.update(t.apply(this.store.meta)); //????
12089 el = this.el.child('.roo-tpl-' + this.dataName);
12092 for(var i = 0, len = records.length; i < len; i++){
12093 var data = this.prepareData(records[i].data, i, records[i]);
12094 this.fireEvent("preparedata", this, data, i, records[i]);
12096 var d = Roo.apply({}, data);
12099 Roo.apply(d, {'roo-id' : Roo.id()});
12103 Roo.each(this.parent.item, function(item){
12104 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12107 Roo.apply(d, {'roo-data-checked' : 'checked'});
12111 html[html.length] = Roo.util.Format.trim(
12113 t.applySubtemplate(this.dataName, d, this.store.meta) :
12120 el.update(html.join(""));
12121 this.nodes = el.dom.childNodes;
12122 this.updateIndexes(0);
12127 * Function to override to reformat the data that is sent to
12128 * the template for each node.
12129 * DEPRICATED - use the preparedata event handler.
12130 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12131 * a JSON object for an UpdateManager bound view).
12133 prepareData : function(data, index, record)
12135 this.fireEvent("preparedata", this, data, index, record);
12139 onUpdate : function(ds, record){
12140 Roo.log('on update');
12141 this.clearSelections();
12142 var index = this.store.indexOf(record);
12143 var n = this.nodes[index];
12144 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12145 n.parentNode.removeChild(n);
12146 this.updateIndexes(index, index);
12152 onAdd : function(ds, records, index)
12154 Roo.log(['on Add', ds, records, index] );
12155 this.clearSelections();
12156 if(this.nodes.length == 0){
12160 var n = this.nodes[index];
12161 for(var i = 0, len = records.length; i < len; i++){
12162 var d = this.prepareData(records[i].data, i, records[i]);
12164 this.tpl.insertBefore(n, d);
12167 this.tpl.append(this.el, d);
12170 this.updateIndexes(index);
12173 onRemove : function(ds, record, index){
12174 Roo.log('onRemove');
12175 this.clearSelections();
12176 var el = this.dataName ?
12177 this.el.child('.roo-tpl-' + this.dataName) :
12180 el.dom.removeChild(this.nodes[index]);
12181 this.updateIndexes(index);
12185 * Refresh an individual node.
12186 * @param {Number} index
12188 refreshNode : function(index){
12189 this.onUpdate(this.store, this.store.getAt(index));
12192 updateIndexes : function(startIndex, endIndex){
12193 var ns = this.nodes;
12194 startIndex = startIndex || 0;
12195 endIndex = endIndex || ns.length - 1;
12196 for(var i = startIndex; i <= endIndex; i++){
12197 ns[i].nodeIndex = i;
12202 * Changes the data store this view uses and refresh the view.
12203 * @param {Store} store
12205 setStore : function(store, initial){
12206 if(!initial && this.store){
12207 this.store.un("datachanged", this.refresh);
12208 this.store.un("add", this.onAdd);
12209 this.store.un("remove", this.onRemove);
12210 this.store.un("update", this.onUpdate);
12211 this.store.un("clear", this.refresh);
12212 this.store.un("beforeload", this.onBeforeLoad);
12213 this.store.un("load", this.onLoad);
12214 this.store.un("loadexception", this.onLoad);
12218 store.on("datachanged", this.refresh, this);
12219 store.on("add", this.onAdd, this);
12220 store.on("remove", this.onRemove, this);
12221 store.on("update", this.onUpdate, this);
12222 store.on("clear", this.refresh, this);
12223 store.on("beforeload", this.onBeforeLoad, this);
12224 store.on("load", this.onLoad, this);
12225 store.on("loadexception", this.onLoad, this);
12233 * onbeforeLoad - masks the loading area.
12236 onBeforeLoad : function(store,opts)
12238 Roo.log('onBeforeLoad');
12240 this.el.update("");
12242 this.el.mask(this.mask ? this.mask : "Loading" );
12244 onLoad : function ()
12251 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12252 * @param {HTMLElement} node
12253 * @return {HTMLElement} The template node
12255 findItemFromChild : function(node){
12256 var el = this.dataName ?
12257 this.el.child('.roo-tpl-' + this.dataName,true) :
12260 if(!node || node.parentNode == el){
12263 var p = node.parentNode;
12264 while(p && p != el){
12265 if(p.parentNode == el){
12274 onClick : function(e){
12275 var item = this.findItemFromChild(e.getTarget());
12277 var index = this.indexOf(item);
12278 if(this.onItemClick(item, index, e) !== false){
12279 this.fireEvent("click", this, index, item, e);
12282 this.clearSelections();
12287 onContextMenu : function(e){
12288 var item = this.findItemFromChild(e.getTarget());
12290 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12295 onDblClick : function(e){
12296 var item = this.findItemFromChild(e.getTarget());
12298 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12302 onItemClick : function(item, index, e)
12304 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12307 if (this.toggleSelect) {
12308 var m = this.isSelected(item) ? 'unselect' : 'select';
12311 _t[m](item, true, false);
12314 if(this.multiSelect || this.singleSelect){
12315 if(this.multiSelect && e.shiftKey && this.lastSelection){
12316 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12318 this.select(item, this.multiSelect && e.ctrlKey);
12319 this.lastSelection = item;
12322 if(!this.tickable){
12323 e.preventDefault();
12331 * Get the number of selected nodes.
12334 getSelectionCount : function(){
12335 return this.selections.length;
12339 * Get the currently selected nodes.
12340 * @return {Array} An array of HTMLElements
12342 getSelectedNodes : function(){
12343 return this.selections;
12347 * Get the indexes of the selected nodes.
12350 getSelectedIndexes : function(){
12351 var indexes = [], s = this.selections;
12352 for(var i = 0, len = s.length; i < len; i++){
12353 indexes.push(s[i].nodeIndex);
12359 * Clear all selections
12360 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12362 clearSelections : function(suppressEvent){
12363 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12364 this.cmp.elements = this.selections;
12365 this.cmp.removeClass(this.selectedClass);
12366 this.selections = [];
12367 if(!suppressEvent){
12368 this.fireEvent("selectionchange", this, this.selections);
12374 * Returns true if the passed node is selected
12375 * @param {HTMLElement/Number} node The node or node index
12376 * @return {Boolean}
12378 isSelected : function(node){
12379 var s = this.selections;
12383 node = this.getNode(node);
12384 return s.indexOf(node) !== -1;
12389 * @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
12390 * @param {Boolean} keepExisting (optional) true to keep existing selections
12391 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12393 select : function(nodeInfo, keepExisting, suppressEvent){
12394 if(nodeInfo instanceof Array){
12396 this.clearSelections(true);
12398 for(var i = 0, len = nodeInfo.length; i < len; i++){
12399 this.select(nodeInfo[i], true, true);
12403 var node = this.getNode(nodeInfo);
12404 if(!node || this.isSelected(node)){
12405 return; // already selected.
12408 this.clearSelections(true);
12410 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12411 Roo.fly(node).addClass(this.selectedClass);
12412 this.selections.push(node);
12413 if(!suppressEvent){
12414 this.fireEvent("selectionchange", this, this.selections);
12422 * @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
12423 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12424 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12426 unselect : function(nodeInfo, keepExisting, suppressEvent)
12428 if(nodeInfo instanceof Array){
12429 Roo.each(this.selections, function(s) {
12430 this.unselect(s, nodeInfo);
12434 var node = this.getNode(nodeInfo);
12435 if(!node || !this.isSelected(node)){
12436 Roo.log("not selected");
12437 return; // not selected.
12441 Roo.each(this.selections, function(s) {
12443 Roo.fly(node).removeClass(this.selectedClass);
12450 this.selections= ns;
12451 this.fireEvent("selectionchange", this, this.selections);
12455 * Gets a template node.
12456 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12457 * @return {HTMLElement} The node or null if it wasn't found
12459 getNode : function(nodeInfo){
12460 if(typeof nodeInfo == "string"){
12461 return document.getElementById(nodeInfo);
12462 }else if(typeof nodeInfo == "number"){
12463 return this.nodes[nodeInfo];
12469 * Gets a range template nodes.
12470 * @param {Number} startIndex
12471 * @param {Number} endIndex
12472 * @return {Array} An array of nodes
12474 getNodes : function(start, end){
12475 var ns = this.nodes;
12476 start = start || 0;
12477 end = typeof end == "undefined" ? ns.length - 1 : end;
12480 for(var i = start; i <= end; i++){
12484 for(var i = start; i >= end; i--){
12492 * Finds the index of the passed node
12493 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12494 * @return {Number} The index of the node or -1
12496 indexOf : function(node){
12497 node = this.getNode(node);
12498 if(typeof node.nodeIndex == "number"){
12499 return node.nodeIndex;
12501 var ns = this.nodes;
12502 for(var i = 0, len = ns.length; i < len; i++){
12513 * based on jquery fullcalendar
12517 Roo.bootstrap = Roo.bootstrap || {};
12519 * @class Roo.bootstrap.Calendar
12520 * @extends Roo.bootstrap.Component
12521 * Bootstrap Calendar class
12522 * @cfg {Boolean} loadMask (true|false) default false
12523 * @cfg {Object} header generate the user specific header of the calendar, default false
12526 * Create a new Container
12527 * @param {Object} config The config object
12532 Roo.bootstrap.Calendar = function(config){
12533 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12537 * Fires when a date is selected
12538 * @param {DatePicker} this
12539 * @param {Date} date The selected date
12543 * @event monthchange
12544 * Fires when the displayed month changes
12545 * @param {DatePicker} this
12546 * @param {Date} date The selected month
12548 'monthchange': true,
12550 * @event evententer
12551 * Fires when mouse over an event
12552 * @param {Calendar} this
12553 * @param {event} Event
12555 'evententer': true,
12557 * @event eventleave
12558 * Fires when the mouse leaves an
12559 * @param {Calendar} this
12562 'eventleave': true,
12564 * @event eventclick
12565 * Fires when the mouse click an
12566 * @param {Calendar} this
12575 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12578 * @cfg {Number} startDay
12579 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12587 getAutoCreate : function(){
12590 var fc_button = function(name, corner, style, content ) {
12591 return Roo.apply({},{
12593 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12595 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12598 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12609 style : 'width:100%',
12616 cls : 'fc-header-left',
12618 fc_button('prev', 'left', 'arrow', '‹' ),
12619 fc_button('next', 'right', 'arrow', '›' ),
12620 { tag: 'span', cls: 'fc-header-space' },
12621 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12629 cls : 'fc-header-center',
12633 cls: 'fc-header-title',
12636 html : 'month / year'
12644 cls : 'fc-header-right',
12646 /* fc_button('month', 'left', '', 'month' ),
12647 fc_button('week', '', '', 'week' ),
12648 fc_button('day', 'right', '', 'day' )
12660 header = this.header;
12663 var cal_heads = function() {
12665 // fixme - handle this.
12667 for (var i =0; i < Date.dayNames.length; i++) {
12668 var d = Date.dayNames[i];
12671 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12672 html : d.substring(0,3)
12676 ret[0].cls += ' fc-first';
12677 ret[6].cls += ' fc-last';
12680 var cal_cell = function(n) {
12683 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12688 cls: 'fc-day-number',
12692 cls: 'fc-day-content',
12696 style: 'position: relative;' // height: 17px;
12708 var cal_rows = function() {
12711 for (var r = 0; r < 6; r++) {
12718 for (var i =0; i < Date.dayNames.length; i++) {
12719 var d = Date.dayNames[i];
12720 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12723 row.cn[0].cls+=' fc-first';
12724 row.cn[0].cn[0].style = 'min-height:90px';
12725 row.cn[6].cls+=' fc-last';
12729 ret[0].cls += ' fc-first';
12730 ret[4].cls += ' fc-prev-last';
12731 ret[5].cls += ' fc-last';
12738 cls: 'fc-border-separate',
12739 style : 'width:100%',
12747 cls : 'fc-first fc-last',
12765 cls : 'fc-content',
12766 style : "position: relative;",
12769 cls : 'fc-view fc-view-month fc-grid',
12770 style : 'position: relative',
12771 unselectable : 'on',
12774 cls : 'fc-event-container',
12775 style : 'position:absolute;z-index:8;top:0;left:0;'
12793 initEvents : function()
12796 throw "can not find store for calendar";
12802 style: "text-align:center",
12806 style: "background-color:white;width:50%;margin:250 auto",
12810 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12821 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12823 var size = this.el.select('.fc-content', true).first().getSize();
12824 this.maskEl.setSize(size.width, size.height);
12825 this.maskEl.enableDisplayMode("block");
12826 if(!this.loadMask){
12827 this.maskEl.hide();
12830 this.store = Roo.factory(this.store, Roo.data);
12831 this.store.on('load', this.onLoad, this);
12832 this.store.on('beforeload', this.onBeforeLoad, this);
12836 this.cells = this.el.select('.fc-day',true);
12837 //Roo.log(this.cells);
12838 this.textNodes = this.el.query('.fc-day-number');
12839 this.cells.addClassOnOver('fc-state-hover');
12841 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12842 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12843 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12844 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12846 this.on('monthchange', this.onMonthChange, this);
12848 this.update(new Date().clearTime());
12851 resize : function() {
12852 var sz = this.el.getSize();
12854 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12855 this.el.select('.fc-day-content div',true).setHeight(34);
12860 showPrevMonth : function(e){
12861 this.update(this.activeDate.add("mo", -1));
12863 showToday : function(e){
12864 this.update(new Date().clearTime());
12867 showNextMonth : function(e){
12868 this.update(this.activeDate.add("mo", 1));
12872 showPrevYear : function(){
12873 this.update(this.activeDate.add("y", -1));
12877 showNextYear : function(){
12878 this.update(this.activeDate.add("y", 1));
12883 update : function(date)
12885 var vd = this.activeDate;
12886 this.activeDate = date;
12887 // if(vd && this.el){
12888 // var t = date.getTime();
12889 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12890 // Roo.log('using add remove');
12892 // this.fireEvent('monthchange', this, date);
12894 // this.cells.removeClass("fc-state-highlight");
12895 // this.cells.each(function(c){
12896 // if(c.dateValue == t){
12897 // c.addClass("fc-state-highlight");
12898 // setTimeout(function(){
12899 // try{c.dom.firstChild.focus();}catch(e){}
12909 var days = date.getDaysInMonth();
12911 var firstOfMonth = date.getFirstDateOfMonth();
12912 var startingPos = firstOfMonth.getDay()-this.startDay;
12914 if(startingPos < this.startDay){
12918 var pm = date.add(Date.MONTH, -1);
12919 var prevStart = pm.getDaysInMonth()-startingPos;
12921 this.cells = this.el.select('.fc-day',true);
12922 this.textNodes = this.el.query('.fc-day-number');
12923 this.cells.addClassOnOver('fc-state-hover');
12925 var cells = this.cells.elements;
12926 var textEls = this.textNodes;
12928 Roo.each(cells, function(cell){
12929 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12932 days += startingPos;
12934 // convert everything to numbers so it's fast
12935 var day = 86400000;
12936 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12939 //Roo.log(prevStart);
12941 var today = new Date().clearTime().getTime();
12942 var sel = date.clearTime().getTime();
12943 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12944 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12945 var ddMatch = this.disabledDatesRE;
12946 var ddText = this.disabledDatesText;
12947 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12948 var ddaysText = this.disabledDaysText;
12949 var format = this.format;
12951 var setCellClass = function(cal, cell){
12955 //Roo.log('set Cell Class');
12957 var t = d.getTime();
12961 cell.dateValue = t;
12963 cell.className += " fc-today";
12964 cell.className += " fc-state-highlight";
12965 cell.title = cal.todayText;
12968 // disable highlight in other month..
12969 //cell.className += " fc-state-highlight";
12974 cell.className = " fc-state-disabled";
12975 cell.title = cal.minText;
12979 cell.className = " fc-state-disabled";
12980 cell.title = cal.maxText;
12984 if(ddays.indexOf(d.getDay()) != -1){
12985 cell.title = ddaysText;
12986 cell.className = " fc-state-disabled";
12989 if(ddMatch && format){
12990 var fvalue = d.dateFormat(format);
12991 if(ddMatch.test(fvalue)){
12992 cell.title = ddText.replace("%0", fvalue);
12993 cell.className = " fc-state-disabled";
12997 if (!cell.initialClassName) {
12998 cell.initialClassName = cell.dom.className;
13001 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13006 for(; i < startingPos; i++) {
13007 textEls[i].innerHTML = (++prevStart);
13008 d.setDate(d.getDate()+1);
13010 cells[i].className = "fc-past fc-other-month";
13011 setCellClass(this, cells[i]);
13016 for(; i < days; i++){
13017 intDay = i - startingPos + 1;
13018 textEls[i].innerHTML = (intDay);
13019 d.setDate(d.getDate()+1);
13021 cells[i].className = ''; // "x-date-active";
13022 setCellClass(this, cells[i]);
13026 for(; i < 42; i++) {
13027 textEls[i].innerHTML = (++extraDays);
13028 d.setDate(d.getDate()+1);
13030 cells[i].className = "fc-future fc-other-month";
13031 setCellClass(this, cells[i]);
13034 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13036 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13038 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13039 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13041 if(totalRows != 6){
13042 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13043 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13046 this.fireEvent('monthchange', this, date);
13050 if(!this.internalRender){
13051 var main = this.el.dom.firstChild;
13052 var w = main.offsetWidth;
13053 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13054 Roo.fly(main).setWidth(w);
13055 this.internalRender = true;
13056 // opera does not respect the auto grow header center column
13057 // then, after it gets a width opera refuses to recalculate
13058 // without a second pass
13059 if(Roo.isOpera && !this.secondPass){
13060 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13061 this.secondPass = true;
13062 this.update.defer(10, this, [date]);
13069 findCell : function(dt) {
13070 dt = dt.clearTime().getTime();
13072 this.cells.each(function(c){
13073 //Roo.log("check " +c.dateValue + '?=' + dt);
13074 if(c.dateValue == dt){
13084 findCells : function(ev) {
13085 var s = ev.start.clone().clearTime().getTime();
13087 var e= ev.end.clone().clearTime().getTime();
13090 this.cells.each(function(c){
13091 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13093 if(c.dateValue > e){
13096 if(c.dateValue < s){
13105 // findBestRow: function(cells)
13109 // for (var i =0 ; i < cells.length;i++) {
13110 // ret = Math.max(cells[i].rows || 0,ret);
13117 addItem : function(ev)
13119 // look for vertical location slot in
13120 var cells = this.findCells(ev);
13122 // ev.row = this.findBestRow(cells);
13124 // work out the location.
13128 for(var i =0; i < cells.length; i++) {
13130 cells[i].row = cells[0].row;
13133 cells[i].row = cells[i].row + 1;
13143 if (crow.start.getY() == cells[i].getY()) {
13145 crow.end = cells[i];
13162 cells[0].events.push(ev);
13164 this.calevents.push(ev);
13167 clearEvents: function() {
13169 if(!this.calevents){
13173 Roo.each(this.cells.elements, function(c){
13179 Roo.each(this.calevents, function(e) {
13180 Roo.each(e.els, function(el) {
13181 el.un('mouseenter' ,this.onEventEnter, this);
13182 el.un('mouseleave' ,this.onEventLeave, this);
13187 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13193 renderEvents: function()
13197 this.cells.each(function(c) {
13206 if(c.row != c.events.length){
13207 r = 4 - (4 - (c.row - c.events.length));
13210 c.events = ev.slice(0, r);
13211 c.more = ev.slice(r);
13213 if(c.more.length && c.more.length == 1){
13214 c.events.push(c.more.pop());
13217 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13221 this.cells.each(function(c) {
13223 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13226 for (var e = 0; e < c.events.length; e++){
13227 var ev = c.events[e];
13228 var rows = ev.rows;
13230 for(var i = 0; i < rows.length; i++) {
13232 // how many rows should it span..
13235 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13236 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13238 unselectable : "on",
13241 cls: 'fc-event-inner',
13245 // cls: 'fc-event-time',
13246 // html : cells.length > 1 ? '' : ev.time
13250 cls: 'fc-event-title',
13251 html : String.format('{0}', ev.title)
13258 cls: 'ui-resizable-handle ui-resizable-e',
13259 html : '  '
13266 cfg.cls += ' fc-event-start';
13268 if ((i+1) == rows.length) {
13269 cfg.cls += ' fc-event-end';
13272 var ctr = _this.el.select('.fc-event-container',true).first();
13273 var cg = ctr.createChild(cfg);
13275 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13276 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13278 var r = (c.more.length) ? 1 : 0;
13279 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13280 cg.setWidth(ebox.right - sbox.x -2);
13282 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13283 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13284 cg.on('click', _this.onEventClick, _this, ev);
13295 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13296 style : 'position: absolute',
13297 unselectable : "on",
13300 cls: 'fc-event-inner',
13304 cls: 'fc-event-title',
13312 cls: 'ui-resizable-handle ui-resizable-e',
13313 html : '  '
13319 var ctr = _this.el.select('.fc-event-container',true).first();
13320 var cg = ctr.createChild(cfg);
13322 var sbox = c.select('.fc-day-content',true).first().getBox();
13323 var ebox = c.select('.fc-day-content',true).first().getBox();
13325 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13326 cg.setWidth(ebox.right - sbox.x -2);
13328 cg.on('click', _this.onMoreEventClick, _this, c.more);
13338 onEventEnter: function (e, el,event,d) {
13339 this.fireEvent('evententer', this, el, event);
13342 onEventLeave: function (e, el,event,d) {
13343 this.fireEvent('eventleave', this, el, event);
13346 onEventClick: function (e, el,event,d) {
13347 this.fireEvent('eventclick', this, el, event);
13350 onMonthChange: function () {
13354 onMoreEventClick: function(e, el, more)
13358 this.calpopover.placement = 'right';
13359 this.calpopover.setTitle('More');
13361 this.calpopover.setContent('');
13363 var ctr = this.calpopover.el.select('.popover-content', true).first();
13365 Roo.each(more, function(m){
13367 cls : 'fc-event-hori fc-event-draggable',
13370 var cg = ctr.createChild(cfg);
13372 cg.on('click', _this.onEventClick, _this, m);
13375 this.calpopover.show(el);
13380 onLoad: function ()
13382 this.calevents = [];
13385 if(this.store.getCount() > 0){
13386 this.store.data.each(function(d){
13389 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13390 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13391 time : d.data.start_time,
13392 title : d.data.title,
13393 description : d.data.description,
13394 venue : d.data.venue
13399 this.renderEvents();
13401 if(this.calevents.length && this.loadMask){
13402 this.maskEl.hide();
13406 onBeforeLoad: function()
13408 this.clearEvents();
13410 this.maskEl.show();
13424 * @class Roo.bootstrap.Popover
13425 * @extends Roo.bootstrap.Component
13426 * Bootstrap Popover class
13427 * @cfg {String} html contents of the popover (or false to use children..)
13428 * @cfg {String} title of popover (or false to hide)
13429 * @cfg {String} placement how it is placed
13430 * @cfg {String} trigger click || hover (or false to trigger manually)
13431 * @cfg {String} over what (parent or false to trigger manually.)
13434 * Create a new Popover
13435 * @param {Object} config The config object
13438 Roo.bootstrap.Popover = function(config){
13439 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13442 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13444 title: 'Fill in a title',
13447 placement : 'right',
13448 trigger : 'hover', // hover
13452 can_build_overlaid : false,
13454 getChildContainer : function()
13456 return this.el.select('.popover-content',true).first();
13459 getAutoCreate : function(){
13460 Roo.log('make popover?');
13462 cls : 'popover roo-dynamic',
13463 style: 'display:block',
13469 cls : 'popover-inner',
13473 cls: 'popover-title',
13477 cls : 'popover-content',
13488 setTitle: function(str)
13490 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13492 setContent: function(str)
13494 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13496 // as it get's added to the bottom of the page.
13497 onRender : function(ct, position)
13499 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13501 var cfg = Roo.apply({}, this.getAutoCreate());
13505 cfg.cls += ' ' + this.cls;
13508 cfg.style = this.style;
13510 Roo.log("adding to ")
13511 this.el = Roo.get(document.body).createChild(cfg, position);
13517 initEvents : function()
13519 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13520 this.el.enableDisplayMode('block');
13522 if (this.over === false) {
13525 if (this.triggers === false) {
13528 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13529 var triggers = this.trigger ? this.trigger.split(' ') : [];
13530 Roo.each(triggers, function(trigger) {
13532 if (trigger == 'click') {
13533 on_el.on('click', this.toggle, this);
13534 } else if (trigger != 'manual') {
13535 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13536 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13538 on_el.on(eventIn ,this.enter, this);
13539 on_el.on(eventOut, this.leave, this);
13550 toggle : function () {
13551 this.hoverState == 'in' ? this.leave() : this.enter();
13554 enter : function () {
13557 clearTimeout(this.timeout);
13559 this.hoverState = 'in'
13561 if (!this.delay || !this.delay.show) {
13566 this.timeout = setTimeout(function () {
13567 if (_t.hoverState == 'in') {
13570 }, this.delay.show)
13572 leave : function() {
13573 clearTimeout(this.timeout);
13575 this.hoverState = 'out'
13577 if (!this.delay || !this.delay.hide) {
13582 this.timeout = setTimeout(function () {
13583 if (_t.hoverState == 'out') {
13586 }, this.delay.hide)
13589 show : function (on_el)
13592 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13595 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13596 if (this.html !== false) {
13597 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13599 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13600 if (!this.title.length) {
13601 this.el.select('.popover-title',true).hide();
13604 var placement = typeof this.placement == 'function' ?
13605 this.placement.call(this, this.el, on_el) :
13608 var autoToken = /\s?auto?\s?/i;
13609 var autoPlace = autoToken.test(placement);
13611 placement = placement.replace(autoToken, '') || 'top';
13615 //this.el.setXY([0,0]);
13617 this.el.dom.style.display='block';
13618 this.el.addClass(placement);
13620 //this.el.appendTo(on_el);
13622 var p = this.getPosition();
13623 var box = this.el.getBox();
13628 var align = Roo.bootstrap.Popover.alignment[placement]
13629 this.el.alignTo(on_el, align[0],align[1]);
13630 //var arrow = this.el.select('.arrow',true).first();
13631 //arrow.set(align[2],
13633 this.el.addClass('in');
13634 this.hoverState = null;
13636 if (this.el.hasClass('fade')) {
13643 this.el.setXY([0,0]);
13644 this.el.removeClass('in');
13651 Roo.bootstrap.Popover.alignment = {
13652 'left' : ['r-l', [-10,0], 'right'],
13653 'right' : ['l-r', [10,0], 'left'],
13654 'bottom' : ['t-b', [0,10], 'top'],
13655 'top' : [ 'b-t', [0,-10], 'bottom']
13666 * @class Roo.bootstrap.Progress
13667 * @extends Roo.bootstrap.Component
13668 * Bootstrap Progress class
13669 * @cfg {Boolean} striped striped of the progress bar
13670 * @cfg {Boolean} active animated of the progress bar
13674 * Create a new Progress
13675 * @param {Object} config The config object
13678 Roo.bootstrap.Progress = function(config){
13679 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13682 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13687 getAutoCreate : function(){
13695 cfg.cls += ' progress-striped';
13699 cfg.cls += ' active';
13718 * @class Roo.bootstrap.ProgressBar
13719 * @extends Roo.bootstrap.Component
13720 * Bootstrap ProgressBar class
13721 * @cfg {Number} aria_valuenow aria-value now
13722 * @cfg {Number} aria_valuemin aria-value min
13723 * @cfg {Number} aria_valuemax aria-value max
13724 * @cfg {String} label label for the progress bar
13725 * @cfg {String} panel (success | info | warning | danger )
13726 * @cfg {String} role role of the progress bar
13727 * @cfg {String} sr_only text
13731 * Create a new ProgressBar
13732 * @param {Object} config The config object
13735 Roo.bootstrap.ProgressBar = function(config){
13736 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13739 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13743 aria_valuemax : 100,
13749 getAutoCreate : function()
13754 cls: 'progress-bar',
13755 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13767 cfg.role = this.role;
13770 if(this.aria_valuenow){
13771 cfg['aria-valuenow'] = this.aria_valuenow;
13774 if(this.aria_valuemin){
13775 cfg['aria-valuemin'] = this.aria_valuemin;
13778 if(this.aria_valuemax){
13779 cfg['aria-valuemax'] = this.aria_valuemax;
13782 if(this.label && !this.sr_only){
13783 cfg.html = this.label;
13787 cfg.cls += ' progress-bar-' + this.panel;
13793 update : function(aria_valuenow)
13795 this.aria_valuenow = aria_valuenow;
13797 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13812 * @class Roo.bootstrap.TabGroup
13813 * @extends Roo.bootstrap.Column
13814 * Bootstrap Column class
13815 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13816 * @cfg {Boolean} carousel true to make the group behave like a carousel
13819 * Create a new TabGroup
13820 * @param {Object} config The config object
13823 Roo.bootstrap.TabGroup = function(config){
13824 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13826 this.navId = Roo.id();
13829 Roo.bootstrap.TabGroup.register(this);
13833 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13836 transition : false,
13838 getAutoCreate : function()
13840 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13842 cfg.cls += ' tab-content';
13844 if (this.carousel) {
13845 cfg.cls += ' carousel slide';
13847 cls : 'carousel-inner'
13854 getChildContainer : function()
13856 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13860 * register a Navigation item
13861 * @param {Roo.bootstrap.NavItem} the navitem to add
13863 register : function(item)
13865 this.tabs.push( item);
13866 item.navId = this.navId; // not really needed..
13870 getActivePanel : function()
13873 Roo.each(this.tabs, function(t) {
13883 getPanelByName : function(n)
13886 Roo.each(this.tabs, function(t) {
13887 if (t.tabId == n) {
13895 indexOfPanel : function(p)
13898 Roo.each(this.tabs, function(t,i) {
13899 if (t.tabId == p.tabId) {
13908 * show a specific panel
13909 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13910 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13912 showPanel : function (pan)
13915 if (typeof(pan) == 'number') {
13916 pan = this.tabs[pan];
13918 if (typeof(pan) == 'string') {
13919 pan = this.getPanelByName(pan);
13921 if (pan.tabId == this.getActivePanel().tabId) {
13924 var cur = this.getActivePanel();
13926 if (false === cur.fireEvent('beforedeactivate')) {
13930 if (this.carousel) {
13931 this.transition = true;
13932 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13933 var lr = dir == 'next' ? 'left' : 'right';
13934 pan.el.addClass(dir); // or prev
13935 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13936 cur.el.addClass(lr); // or right
13937 pan.el.addClass(lr);
13940 cur.el.on('transitionend', function() {
13941 Roo.log("trans end?");
13943 pan.el.removeClass([lr,dir]);
13944 pan.setActive(true);
13946 cur.el.removeClass([lr]);
13947 cur.setActive(false);
13949 _this.transition = false;
13951 }, this, { single: true } );
13955 cur.setActive(false);
13956 pan.setActive(true);
13960 showPanelNext : function()
13962 var i = this.indexOfPanel(this.getActivePanel());
13963 if (i > this.tabs.length) {
13966 this.showPanel(this.tabs[i+1]);
13968 showPanelPrev : function()
13970 var i = this.indexOfPanel(this.getActivePanel());
13974 this.showPanel(this.tabs[i-1]);
13985 Roo.apply(Roo.bootstrap.TabGroup, {
13989 * register a Navigation Group
13990 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13992 register : function(navgrp)
13994 this.groups[navgrp.navId] = navgrp;
13998 * fetch a Navigation Group based on the navigation ID
13999 * if one does not exist , it will get created.
14000 * @param {string} the navgroup to add
14001 * @returns {Roo.bootstrap.NavGroup} the navgroup
14003 get: function(navId) {
14004 if (typeof(this.groups[navId]) == 'undefined') {
14005 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14007 return this.groups[navId] ;
14022 * @class Roo.bootstrap.TabPanel
14023 * @extends Roo.bootstrap.Component
14024 * Bootstrap TabPanel class
14025 * @cfg {Boolean} active panel active
14026 * @cfg {String} html panel content
14027 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14028 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14032 * Create a new TabPanel
14033 * @param {Object} config The config object
14036 Roo.bootstrap.TabPanel = function(config){
14037 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14041 * Fires when the active status changes
14042 * @param {Roo.bootstrap.TabPanel} this
14043 * @param {Boolean} state the new state
14048 * @event beforedeactivate
14049 * Fires before a tab is de-activated - can be used to do validation on a form.
14050 * @param {Roo.bootstrap.TabPanel} this
14051 * @return {Boolean} false if there is an error
14054 'beforedeactivate': true
14057 this.tabId = this.tabId || Roo.id();
14061 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14068 getAutoCreate : function(){
14071 // item is needed for carousel - not sure if it has any effect otherwise
14072 cls: 'tab-pane item',
14073 html: this.html || ''
14077 cfg.cls += ' active';
14081 cfg.tabId = this.tabId;
14088 initEvents: function()
14090 Roo.log('-------- init events on tab panel ---------');
14092 var p = this.parent();
14093 this.navId = this.navId || p.navId;
14095 if (typeof(this.navId) != 'undefined') {
14096 // not really needed.. but just in case.. parent should be a NavGroup.
14097 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14098 Roo.log(['register', tg, this]);
14104 onRender : function(ct, position)
14106 // Roo.log("Call onRender: " + this.xtype);
14108 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14116 setActive: function(state)
14118 Roo.log("panel - set active " + this.tabId + "=" + state);
14120 this.active = state;
14122 this.el.removeClass('active');
14124 } else if (!this.el.hasClass('active')) {
14125 this.el.addClass('active');
14127 this.fireEvent('changed', this, state);
14144 * @class Roo.bootstrap.DateField
14145 * @extends Roo.bootstrap.Input
14146 * Bootstrap DateField class
14147 * @cfg {Number} weekStart default 0
14148 * @cfg {Number} weekStart default 0
14149 * @cfg {Number} viewMode default empty, (months|years)
14150 * @cfg {Number} minViewMode default empty, (months|years)
14151 * @cfg {Number} startDate default -Infinity
14152 * @cfg {Number} endDate default Infinity
14153 * @cfg {Boolean} todayHighlight default false
14154 * @cfg {Boolean} todayBtn default false
14155 * @cfg {Boolean} calendarWeeks default false
14156 * @cfg {Object} daysOfWeekDisabled default empty
14158 * @cfg {Boolean} keyboardNavigation default true
14159 * @cfg {String} language default en
14162 * Create a new DateField
14163 * @param {Object} config The config object
14166 Roo.bootstrap.DateField = function(config){
14167 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14171 * Fires when this field show.
14172 * @param {Roo.bootstrap.DateField} this
14173 * @param {Mixed} date The date value
14178 * Fires when this field hide.
14179 * @param {Roo.bootstrap.DateField} this
14180 * @param {Mixed} date The date value
14185 * Fires when select a date.
14186 * @param {Roo.bootstrap.DateField} this
14187 * @param {Mixed} date The date value
14193 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14196 * @cfg {String} format
14197 * The default date format string which can be overriden for localization support. The format must be
14198 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14202 * @cfg {String} altFormats
14203 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14204 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14206 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14214 todayHighlight : false,
14220 keyboardNavigation: true,
14222 calendarWeeks: false,
14224 startDate: -Infinity,
14228 daysOfWeekDisabled: [],
14232 UTCDate: function()
14234 return new Date(Date.UTC.apply(Date, arguments));
14237 UTCToday: function()
14239 var today = new Date();
14240 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14243 getDate: function() {
14244 var d = this.getUTCDate();
14245 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14248 getUTCDate: function() {
14252 setDate: function(d) {
14253 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14256 setUTCDate: function(d) {
14258 this.setValue(this.formatDate(this.date));
14261 onRender: function(ct, position)
14264 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14266 this.language = this.language || 'en';
14267 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14268 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14270 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14271 this.format = this.format || 'm/d/y';
14272 this.isInline = false;
14273 this.isInput = true;
14274 this.component = this.el.select('.add-on', true).first() || false;
14275 this.component = (this.component && this.component.length === 0) ? false : this.component;
14276 this.hasInput = this.component && this.inputEL().length;
14278 if (typeof(this.minViewMode === 'string')) {
14279 switch (this.minViewMode) {
14281 this.minViewMode = 1;
14284 this.minViewMode = 2;
14287 this.minViewMode = 0;
14292 if (typeof(this.viewMode === 'string')) {
14293 switch (this.viewMode) {
14306 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14308 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14310 this.picker().on('mousedown', this.onMousedown, this);
14311 this.picker().on('click', this.onClick, this);
14313 this.picker().addClass('datepicker-dropdown');
14315 this.startViewMode = this.viewMode;
14318 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14319 if(!this.calendarWeeks){
14324 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14325 v.attr('colspan', function(i, val){
14326 return parseInt(val) + 1;
14331 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14333 this.setStartDate(this.startDate);
14334 this.setEndDate(this.endDate);
14336 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14343 if(this.isInline) {
14348 picker : function()
14350 return this.el.select('.datepicker', true).first();
14353 fillDow: function()
14355 var dowCnt = this.weekStart;
14364 if(this.calendarWeeks){
14372 while (dowCnt < this.weekStart + 7) {
14376 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14380 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14383 fillMonths: function()
14386 var months = this.picker().select('>.datepicker-months td', true).first();
14388 months.dom.innerHTML = '';
14394 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14397 months.createChild(month);
14405 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14407 if (this.date < this.startDate) {
14408 this.viewDate = new Date(this.startDate);
14409 } else if (this.date > this.endDate) {
14410 this.viewDate = new Date(this.endDate);
14412 this.viewDate = new Date(this.date);
14420 var d = new Date(this.viewDate),
14421 year = d.getUTCFullYear(),
14422 month = d.getUTCMonth(),
14423 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14424 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14425 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14426 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14427 currentDate = this.date && this.date.valueOf(),
14428 today = this.UTCToday();
14430 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14432 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14434 // this.picker.select('>tfoot th.today').
14435 // .text(dates[this.language].today)
14436 // .toggle(this.todayBtn !== false);
14438 this.updateNavArrows();
14441 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14443 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14445 prevMonth.setUTCDate(day);
14447 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14449 var nextMonth = new Date(prevMonth);
14451 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14453 nextMonth = nextMonth.valueOf();
14455 var fillMonths = false;
14457 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14459 while(prevMonth.valueOf() < nextMonth) {
14462 if (prevMonth.getUTCDay() === this.weekStart) {
14464 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14472 if(this.calendarWeeks){
14473 // ISO 8601: First week contains first thursday.
14474 // ISO also states week starts on Monday, but we can be more abstract here.
14476 // Start of current week: based on weekstart/current date
14477 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14478 // Thursday of this week
14479 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14480 // First Thursday of year, year from thursday
14481 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14482 // Calendar week: ms between thursdays, div ms per day, div 7 days
14483 calWeek = (th - yth) / 864e5 / 7 + 1;
14485 fillMonths.cn.push({
14493 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14495 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14498 if (this.todayHighlight &&
14499 prevMonth.getUTCFullYear() == today.getFullYear() &&
14500 prevMonth.getUTCMonth() == today.getMonth() &&
14501 prevMonth.getUTCDate() == today.getDate()) {
14502 clsName += ' today';
14505 if (currentDate && prevMonth.valueOf() === currentDate) {
14506 clsName += ' active';
14509 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14510 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14511 clsName += ' disabled';
14514 fillMonths.cn.push({
14516 cls: 'day ' + clsName,
14517 html: prevMonth.getDate()
14520 prevMonth.setDate(prevMonth.getDate()+1);
14523 var currentYear = this.date && this.date.getUTCFullYear();
14524 var currentMonth = this.date && this.date.getUTCMonth();
14526 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14528 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14529 v.removeClass('active');
14531 if(currentYear === year && k === currentMonth){
14532 v.addClass('active');
14535 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14536 v.addClass('disabled');
14542 year = parseInt(year/10, 10) * 10;
14544 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14546 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14549 for (var i = -1; i < 11; i++) {
14550 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14552 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14560 showMode: function(dir)
14563 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14565 Roo.each(this.picker().select('>div',true).elements, function(v){
14566 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14569 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14574 if(this.isInline) return;
14576 this.picker().removeClass(['bottom', 'top']);
14578 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14580 * place to the top of element!
14584 this.picker().addClass('top');
14585 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14590 this.picker().addClass('bottom');
14592 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14595 parseDate : function(value)
14597 if(!value || value instanceof Date){
14600 var v = Date.parseDate(value, this.format);
14601 if (!v && this.useIso) {
14602 v = Date.parseDate(value, 'Y-m-d');
14604 if(!v && this.altFormats){
14605 if(!this.altFormatsArray){
14606 this.altFormatsArray = this.altFormats.split("|");
14608 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14609 v = Date.parseDate(value, this.altFormatsArray[i]);
14615 formatDate : function(date, fmt)
14617 return (!date || !(date instanceof Date)) ?
14618 date : date.dateFormat(fmt || this.format);
14621 onFocus : function()
14623 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14627 onBlur : function()
14629 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14631 var d = this.inputEl().getValue();
14642 this.picker().show();
14646 this.fireEvent('show', this, this.date);
14651 if(this.isInline) return;
14652 this.picker().hide();
14653 this.viewMode = this.startViewMode;
14656 this.fireEvent('hide', this, this.date);
14660 onMousedown: function(e)
14662 e.stopPropagation();
14663 e.preventDefault();
14668 Roo.bootstrap.DateField.superclass.keyup.call(this);
14672 setValue: function(v)
14674 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14676 var d = new Date(v);
14678 if(isNaN(d.getTime())){
14682 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14686 this.fireEvent('select', this, this.date);
14690 getValue: function()
14692 return this.formatDate(this.date);
14695 fireKey: function(e)
14697 if (!this.picker().isVisible()){
14698 if (e.keyCode == 27) // allow escape to hide and re-show picker
14703 var dateChanged = false,
14705 newDate, newViewDate;
14710 e.preventDefault();
14714 if (!this.keyboardNavigation) break;
14715 dir = e.keyCode == 37 ? -1 : 1;
14718 newDate = this.moveYear(this.date, dir);
14719 newViewDate = this.moveYear(this.viewDate, dir);
14720 } else if (e.shiftKey){
14721 newDate = this.moveMonth(this.date, dir);
14722 newViewDate = this.moveMonth(this.viewDate, dir);
14724 newDate = new Date(this.date);
14725 newDate.setUTCDate(this.date.getUTCDate() + dir);
14726 newViewDate = new Date(this.viewDate);
14727 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14729 if (this.dateWithinRange(newDate)){
14730 this.date = newDate;
14731 this.viewDate = newViewDate;
14732 this.setValue(this.formatDate(this.date));
14734 e.preventDefault();
14735 dateChanged = true;
14740 if (!this.keyboardNavigation) break;
14741 dir = e.keyCode == 38 ? -1 : 1;
14743 newDate = this.moveYear(this.date, dir);
14744 newViewDate = this.moveYear(this.viewDate, dir);
14745 } else if (e.shiftKey){
14746 newDate = this.moveMonth(this.date, dir);
14747 newViewDate = this.moveMonth(this.viewDate, dir);
14749 newDate = new Date(this.date);
14750 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14751 newViewDate = new Date(this.viewDate);
14752 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14754 if (this.dateWithinRange(newDate)){
14755 this.date = newDate;
14756 this.viewDate = newViewDate;
14757 this.setValue(this.formatDate(this.date));
14759 e.preventDefault();
14760 dateChanged = true;
14764 this.setValue(this.formatDate(this.date));
14766 e.preventDefault();
14769 this.setValue(this.formatDate(this.date));
14783 onClick: function(e)
14785 e.stopPropagation();
14786 e.preventDefault();
14788 var target = e.getTarget();
14790 if(target.nodeName.toLowerCase() === 'i'){
14791 target = Roo.get(target).dom.parentNode;
14794 var nodeName = target.nodeName;
14795 var className = target.className;
14796 var html = target.innerHTML;
14798 switch(nodeName.toLowerCase()) {
14800 switch(className) {
14806 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14807 switch(this.viewMode){
14809 this.viewDate = this.moveMonth(this.viewDate, dir);
14813 this.viewDate = this.moveYear(this.viewDate, dir);
14819 var date = new Date();
14820 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14822 this.setValue(this.formatDate(this.date));
14829 if (className.indexOf('disabled') === -1) {
14830 this.viewDate.setUTCDate(1);
14831 if (className.indexOf('month') !== -1) {
14832 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14834 var year = parseInt(html, 10) || 0;
14835 this.viewDate.setUTCFullYear(year);
14844 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14845 var day = parseInt(html, 10) || 1;
14846 var year = this.viewDate.getUTCFullYear(),
14847 month = this.viewDate.getUTCMonth();
14849 if (className.indexOf('old') !== -1) {
14856 } else if (className.indexOf('new') !== -1) {
14864 this.date = this.UTCDate(year, month, day,0,0,0,0);
14865 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14867 this.setValue(this.formatDate(this.date));
14874 setStartDate: function(startDate)
14876 this.startDate = startDate || -Infinity;
14877 if (this.startDate !== -Infinity) {
14878 this.startDate = this.parseDate(this.startDate);
14881 this.updateNavArrows();
14884 setEndDate: function(endDate)
14886 this.endDate = endDate || Infinity;
14887 if (this.endDate !== Infinity) {
14888 this.endDate = this.parseDate(this.endDate);
14891 this.updateNavArrows();
14894 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14896 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14897 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14898 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14900 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14901 return parseInt(d, 10);
14904 this.updateNavArrows();
14907 updateNavArrows: function()
14909 var d = new Date(this.viewDate),
14910 year = d.getUTCFullYear(),
14911 month = d.getUTCMonth();
14913 Roo.each(this.picker().select('.prev', true).elements, function(v){
14915 switch (this.viewMode) {
14918 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14924 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14931 Roo.each(this.picker().select('.next', true).elements, function(v){
14933 switch (this.viewMode) {
14936 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14942 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14950 moveMonth: function(date, dir)
14952 if (!dir) return date;
14953 var new_date = new Date(date.valueOf()),
14954 day = new_date.getUTCDate(),
14955 month = new_date.getUTCMonth(),
14956 mag = Math.abs(dir),
14958 dir = dir > 0 ? 1 : -1;
14961 // If going back one month, make sure month is not current month
14962 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14964 return new_date.getUTCMonth() == month;
14966 // If going forward one month, make sure month is as expected
14967 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14969 return new_date.getUTCMonth() != new_month;
14971 new_month = month + dir;
14972 new_date.setUTCMonth(new_month);
14973 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14974 if (new_month < 0 || new_month > 11)
14975 new_month = (new_month + 12) % 12;
14977 // For magnitudes >1, move one month at a time...
14978 for (var i=0; i<mag; i++)
14979 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14980 new_date = this.moveMonth(new_date, dir);
14981 // ...then reset the day, keeping it in the new month
14982 new_month = new_date.getUTCMonth();
14983 new_date.setUTCDate(day);
14985 return new_month != new_date.getUTCMonth();
14988 // Common date-resetting loop -- if date is beyond end of month, make it
14991 new_date.setUTCDate(--day);
14992 new_date.setUTCMonth(new_month);
14997 moveYear: function(date, dir)
14999 return this.moveMonth(date, dir*12);
15002 dateWithinRange: function(date)
15004 return date >= this.startDate && date <= this.endDate;
15010 this.picker().remove();
15015 Roo.apply(Roo.bootstrap.DateField, {
15026 html: '<i class="fa fa-arrow-left"/>'
15036 html: '<i class="fa fa-arrow-right"/>'
15078 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15079 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15080 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15081 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15082 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15095 navFnc: 'FullYear',
15100 navFnc: 'FullYear',
15105 Roo.apply(Roo.bootstrap.DateField, {
15109 cls: 'datepicker dropdown-menu',
15113 cls: 'datepicker-days',
15117 cls: 'table-condensed',
15119 Roo.bootstrap.DateField.head,
15123 Roo.bootstrap.DateField.footer
15130 cls: 'datepicker-months',
15134 cls: 'table-condensed',
15136 Roo.bootstrap.DateField.head,
15137 Roo.bootstrap.DateField.content,
15138 Roo.bootstrap.DateField.footer
15145 cls: 'datepicker-years',
15149 cls: 'table-condensed',
15151 Roo.bootstrap.DateField.head,
15152 Roo.bootstrap.DateField.content,
15153 Roo.bootstrap.DateField.footer
15172 * @class Roo.bootstrap.TimeField
15173 * @extends Roo.bootstrap.Input
15174 * Bootstrap DateField class
15178 * Create a new TimeField
15179 * @param {Object} config The config object
15182 Roo.bootstrap.TimeField = function(config){
15183 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15187 * Fires when this field show.
15188 * @param {Roo.bootstrap.DateField} this
15189 * @param {Mixed} date The date value
15194 * Fires when this field hide.
15195 * @param {Roo.bootstrap.DateField} this
15196 * @param {Mixed} date The date value
15201 * Fires when select a date.
15202 * @param {Roo.bootstrap.DateField} this
15203 * @param {Mixed} date The date value
15209 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15212 * @cfg {String} format
15213 * The default time format string which can be overriden for localization support. The format must be
15214 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15218 onRender: function(ct, position)
15221 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15223 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15225 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15227 this.pop = this.picker().select('>.datepicker-time',true).first();
15228 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15230 this.picker().on('mousedown', this.onMousedown, this);
15231 this.picker().on('click', this.onClick, this);
15233 this.picker().addClass('datepicker-dropdown');
15238 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15239 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15240 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15241 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15242 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15243 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15247 fireKey: function(e){
15248 if (!this.picker().isVisible()){
15249 if (e.keyCode == 27) // allow escape to hide and re-show picker
15254 e.preventDefault();
15262 this.onTogglePeriod();
15265 this.onIncrementMinutes();
15268 this.onDecrementMinutes();
15277 onClick: function(e) {
15278 e.stopPropagation();
15279 e.preventDefault();
15282 picker : function()
15284 return this.el.select('.datepicker', true).first();
15287 fillTime: function()
15289 var time = this.pop.select('tbody', true).first();
15291 time.dom.innerHTML = '';
15306 cls: 'hours-up glyphicon glyphicon-chevron-up'
15326 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15347 cls: 'timepicker-hour',
15362 cls: 'timepicker-minute',
15377 cls: 'btn btn-primary period',
15399 cls: 'hours-down glyphicon glyphicon-chevron-down'
15419 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15437 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15444 var hours = this.time.getHours();
15445 var minutes = this.time.getMinutes();
15458 hours = hours - 12;
15462 hours = '0' + hours;
15466 minutes = '0' + minutes;
15469 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15470 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15471 this.pop.select('button', true).first().dom.innerHTML = period;
15477 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15479 var cls = ['bottom'];
15481 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15488 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15493 this.picker().addClass(cls.join('-'));
15497 Roo.each(cls, function(c){
15499 _this.picker().setTop(_this.inputEl().getHeight());
15503 _this.picker().setTop(0 - _this.picker().getHeight());
15508 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15512 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15519 onFocus : function()
15521 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15525 onBlur : function()
15527 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15533 this.picker().show();
15538 this.fireEvent('show', this, this.date);
15543 this.picker().hide();
15546 this.fireEvent('hide', this, this.date);
15549 setTime : function()
15552 this.setValue(this.time.format(this.format));
15554 this.fireEvent('select', this, this.date);
15559 onMousedown: function(e){
15560 e.stopPropagation();
15561 e.preventDefault();
15564 onIncrementHours: function()
15566 Roo.log('onIncrementHours');
15567 this.time = this.time.add(Date.HOUR, 1);
15572 onDecrementHours: function()
15574 Roo.log('onDecrementHours');
15575 this.time = this.time.add(Date.HOUR, -1);
15579 onIncrementMinutes: function()
15581 Roo.log('onIncrementMinutes');
15582 this.time = this.time.add(Date.MINUTE, 1);
15586 onDecrementMinutes: function()
15588 Roo.log('onDecrementMinutes');
15589 this.time = this.time.add(Date.MINUTE, -1);
15593 onTogglePeriod: function()
15595 Roo.log('onTogglePeriod');
15596 this.time = this.time.add(Date.HOUR, 12);
15603 Roo.apply(Roo.bootstrap.TimeField, {
15633 cls: 'btn btn-info ok',
15645 Roo.apply(Roo.bootstrap.TimeField, {
15649 cls: 'datepicker dropdown-menu',
15653 cls: 'datepicker-time',
15657 cls: 'table-condensed',
15659 Roo.bootstrap.TimeField.content,
15660 Roo.bootstrap.TimeField.footer
15679 * @class Roo.bootstrap.CheckBox
15680 * @extends Roo.bootstrap.Input
15681 * Bootstrap CheckBox class
15683 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15684 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15685 * @cfg {String} boxLabel The text that appears beside the checkbox
15686 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15687 * @cfg {Boolean} checked initnal the element
15691 * Create a new CheckBox
15692 * @param {Object} config The config object
15695 Roo.bootstrap.CheckBox = function(config){
15696 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15701 * Fires when the element is checked or unchecked.
15702 * @param {Roo.bootstrap.CheckBox} this This input
15703 * @param {Boolean} checked The new checked value
15709 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15711 inputType: 'checkbox',
15718 getAutoCreate : function()
15720 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15726 cfg.cls = 'form-group checkbox' //input-group
15734 type : this.inputType,
15735 value : (!this.checked) ? this.valueOff : this.inputValue,
15736 cls : 'roo-checkbox', //'form-box',
15737 placeholder : this.placeholder || ''
15741 if (this.weight) { // Validity check?
15742 cfg.cls += " checkbox-" + this.weight;
15745 if (this.disabled) {
15746 input.disabled=true;
15750 input.checked = this.checked;
15754 input.name = this.name;
15758 input.cls += ' input-' + this.size;
15762 ['xs','sm','md','lg'].map(function(size){
15763 if (settings[size]) {
15764 cfg.cls += ' col-' + size + '-' + settings[size];
15770 var inputblock = input;
15775 if (this.before || this.after) {
15778 cls : 'input-group',
15782 inputblock.cn.push({
15784 cls : 'input-group-addon',
15788 inputblock.cn.push(input);
15790 inputblock.cn.push({
15792 cls : 'input-group-addon',
15799 if (align ==='left' && this.fieldLabel.length) {
15800 Roo.log("left and has label");
15806 cls : 'control-label col-md-' + this.labelWidth,
15807 html : this.fieldLabel
15811 cls : "col-md-" + (12 - this.labelWidth),
15818 } else if ( this.fieldLabel.length) {
15823 tag: this.boxLabel ? 'span' : 'label',
15825 cls: 'control-label box-input-label',
15826 //cls : 'input-group-addon',
15827 html : this.fieldLabel
15837 Roo.log(" no label && no align");
15838 cfg.cn = [ inputblock ] ;
15847 html: this.boxLabel
15859 * return the real input element.
15861 inputEl: function ()
15863 return this.el.select('input.roo-checkbox',true).first();
15868 return this.el.select('label.control-label',true).first();
15871 initEvents : function()
15873 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15875 this.inputEl().on('click', this.onClick, this);
15879 onClick : function()
15881 this.setChecked(!this.checked);
15884 setChecked : function(state,suppressEvent)
15886 this.checked = state;
15888 this.inputEl().dom.checked = state;
15890 if(suppressEvent !== true){
15891 this.fireEvent('check', this, state);
15894 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15898 setValue : function(v,suppressEvent)
15900 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15914 * @class Roo.bootstrap.Radio
15915 * @extends Roo.bootstrap.CheckBox
15916 * Bootstrap Radio class
15919 * Create a new Radio
15920 * @param {Object} config The config object
15923 Roo.bootstrap.Radio = function(config){
15924 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15928 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15930 inputType: 'radio',
15934 getAutoCreate : function()
15936 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15942 cfg.cls = 'form-group radio' //input-group
15947 type : this.inputType,
15948 value : (!this.checked) ? this.valueOff : this.inputValue,
15950 placeholder : this.placeholder || ''
15953 if (this.weight) { // Validity check?
15954 cfg.cls += " radio-" + this.weight;
15956 if (this.disabled) {
15957 input.disabled=true;
15961 input.checked = this.checked;
15965 input.name = this.name;
15969 input.cls += ' input-' + this.size;
15973 ['xs','sm','md','lg'].map(function(size){
15974 if (settings[size]) {
15975 cfg.cls += ' col-' + size + '-' + settings[size];
15979 var inputblock = input;
15981 if (this.before || this.after) {
15984 cls : 'input-group',
15988 inputblock.cn.push({
15990 cls : 'input-group-addon',
15994 inputblock.cn.push(input);
15996 inputblock.cn.push({
15998 cls : 'input-group-addon',
16005 if (align ==='left' && this.fieldLabel.length) {
16006 Roo.log("left and has label");
16012 cls : 'control-label col-md-' + this.labelWidth,
16013 html : this.fieldLabel
16017 cls : "col-md-" + (12 - this.labelWidth),
16024 } else if ( this.fieldLabel.length) {
16031 cls: 'control-label box-input-label',
16032 //cls : 'input-group-addon',
16033 html : this.fieldLabel
16043 Roo.log(" no label && no align");
16058 html: this.boxLabel
16065 inputEl: function ()
16067 return this.el.select('input.roo-radio',true).first();
16069 onClick : function()
16071 this.setChecked(true);
16074 setChecked : function(state,suppressEvent)
16077 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16078 v.dom.checked = false;
16082 this.checked = state;
16083 this.inputEl().dom.checked = state;
16085 if(suppressEvent !== true){
16086 this.fireEvent('check', this, state);
16089 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16093 getGroupValue : function()
16096 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16097 if(v.dom.checked == true){
16098 value = v.dom.value;
16106 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16107 * @return {Mixed} value The field value
16109 getValue : function(){
16110 return this.getGroupValue();
16116 //<script type="text/javascript">
16119 * Based Ext JS Library 1.1.1
16120 * Copyright(c) 2006-2007, Ext JS, LLC.
16126 * @class Roo.HtmlEditorCore
16127 * @extends Roo.Component
16128 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16130 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16133 Roo.HtmlEditorCore = function(config){
16136 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16139 * @event initialize
16140 * Fires when the editor is fully initialized (including the iframe)
16141 * @param {Roo.HtmlEditorCore} this
16146 * Fires when the editor is first receives the focus. Any insertion must wait
16147 * until after this event.
16148 * @param {Roo.HtmlEditorCore} this
16152 * @event beforesync
16153 * Fires before the textarea is updated with content from the editor iframe. Return false
16154 * to cancel the sync.
16155 * @param {Roo.HtmlEditorCore} this
16156 * @param {String} html
16160 * @event beforepush
16161 * Fires before the iframe editor is updated with content from the textarea. Return false
16162 * to cancel the push.
16163 * @param {Roo.HtmlEditorCore} this
16164 * @param {String} html
16169 * Fires when the textarea is updated with content from the editor iframe.
16170 * @param {Roo.HtmlEditorCore} this
16171 * @param {String} html
16176 * Fires when the iframe editor is updated with content from the textarea.
16177 * @param {Roo.HtmlEditorCore} this
16178 * @param {String} html
16183 * @event editorevent
16184 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16185 * @param {Roo.HtmlEditorCore} this
16193 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16197 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16203 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16208 * @cfg {Number} height (in pixels)
16212 * @cfg {Number} width (in pixels)
16217 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16220 stylesheets: false,
16225 // private properties
16226 validationEvent : false,
16228 initialized : false,
16230 sourceEditMode : false,
16231 onFocus : Roo.emptyFn,
16233 hideMode:'offsets',
16241 * Protected method that will not generally be called directly. It
16242 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16243 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16245 getDocMarkup : function(){
16248 Roo.log(this.stylesheets);
16250 // inherit styels from page...??
16251 if (this.stylesheets === false) {
16253 Roo.get(document.head).select('style').each(function(node) {
16254 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16257 Roo.get(document.head).select('link').each(function(node) {
16258 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16261 } else if (!this.stylesheets.length) {
16263 st = '<style type="text/css">' +
16264 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16267 Roo.each(this.stylesheets, function(s) {
16268 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16273 st += '<style type="text/css">' +
16274 'IMG { cursor: pointer } ' +
16278 return '<html><head>' + st +
16279 //<style type="text/css">' +
16280 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16282 ' </head><body class="roo-htmleditor-body"></body></html>';
16286 onRender : function(ct, position)
16289 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16290 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16293 this.el.dom.style.border = '0 none';
16294 this.el.dom.setAttribute('tabIndex', -1);
16295 this.el.addClass('x-hidden hide');
16299 if(Roo.isIE){ // fix IE 1px bogus margin
16300 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16304 this.frameId = Roo.id();
16308 var iframe = this.owner.wrap.createChild({
16310 cls: 'form-control', // bootstrap..
16312 name: this.frameId,
16313 frameBorder : 'no',
16314 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16319 this.iframe = iframe.dom;
16321 this.assignDocWin();
16323 this.doc.designMode = 'on';
16326 this.doc.write(this.getDocMarkup());
16330 var task = { // must defer to wait for browser to be ready
16332 //console.log("run task?" + this.doc.readyState);
16333 this.assignDocWin();
16334 if(this.doc.body || this.doc.readyState == 'complete'){
16336 this.doc.designMode="on";
16340 Roo.TaskMgr.stop(task);
16341 this.initEditor.defer(10, this);
16348 Roo.TaskMgr.start(task);
16355 onResize : function(w, h)
16357 Roo.log('resize: ' +w + ',' + h );
16358 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16362 if(typeof w == 'number'){
16364 this.iframe.style.width = w + 'px';
16366 if(typeof h == 'number'){
16368 this.iframe.style.height = h + 'px';
16370 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16377 * Toggles the editor between standard and source edit mode.
16378 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16380 toggleSourceEdit : function(sourceEditMode){
16382 this.sourceEditMode = sourceEditMode === true;
16384 if(this.sourceEditMode){
16386 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16389 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16390 //this.iframe.className = '';
16393 //this.setSize(this.owner.wrap.getSize());
16394 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16401 * Protected method that will not generally be called directly. If you need/want
16402 * custom HTML cleanup, this is the method you should override.
16403 * @param {String} html The HTML to be cleaned
16404 * return {String} The cleaned HTML
16406 cleanHtml : function(html){
16407 html = String(html);
16408 if(html.length > 5){
16409 if(Roo.isSafari){ // strip safari nonsense
16410 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16413 if(html == ' '){
16420 * HTML Editor -> Textarea
16421 * Protected method that will not generally be called directly. Syncs the contents
16422 * of the editor iframe with the textarea.
16424 syncValue : function(){
16425 if(this.initialized){
16426 var bd = (this.doc.body || this.doc.documentElement);
16427 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16428 var html = bd.innerHTML;
16430 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16431 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16433 html = '<div style="'+m[0]+'">' + html + '</div>';
16436 html = this.cleanHtml(html);
16437 // fix up the special chars.. normaly like back quotes in word...
16438 // however we do not want to do this with chinese..
16439 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16440 var cc = b.charCodeAt();
16442 (cc >= 0x4E00 && cc < 0xA000 ) ||
16443 (cc >= 0x3400 && cc < 0x4E00 ) ||
16444 (cc >= 0xf900 && cc < 0xfb00 )
16450 if(this.owner.fireEvent('beforesync', this, html) !== false){
16451 this.el.dom.value = html;
16452 this.owner.fireEvent('sync', this, html);
16458 * Protected method that will not generally be called directly. Pushes the value of the textarea
16459 * into the iframe editor.
16461 pushValue : function(){
16462 if(this.initialized){
16463 var v = this.el.dom.value.trim();
16465 // if(v.length < 1){
16469 if(this.owner.fireEvent('beforepush', this, v) !== false){
16470 var d = (this.doc.body || this.doc.documentElement);
16472 this.cleanUpPaste();
16473 this.el.dom.value = d.innerHTML;
16474 this.owner.fireEvent('push', this, v);
16480 deferFocus : function(){
16481 this.focus.defer(10, this);
16485 focus : function(){
16486 if(this.win && !this.sourceEditMode){
16493 assignDocWin: function()
16495 var iframe = this.iframe;
16498 this.doc = iframe.contentWindow.document;
16499 this.win = iframe.contentWindow;
16501 if (!Roo.get(this.frameId)) {
16504 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16505 this.win = Roo.get(this.frameId).dom.contentWindow;
16510 initEditor : function(){
16511 //console.log("INIT EDITOR");
16512 this.assignDocWin();
16516 this.doc.designMode="on";
16518 this.doc.write(this.getDocMarkup());
16521 var dbody = (this.doc.body || this.doc.documentElement);
16522 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16523 // this copies styles from the containing element into thsi one..
16524 // not sure why we need all of this..
16525 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16527 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16528 //ss['background-attachment'] = 'fixed'; // w3c
16529 dbody.bgProperties = 'fixed'; // ie
16530 //Roo.DomHelper.applyStyles(dbody, ss);
16531 Roo.EventManager.on(this.doc, {
16532 //'mousedown': this.onEditorEvent,
16533 'mouseup': this.onEditorEvent,
16534 'dblclick': this.onEditorEvent,
16535 'click': this.onEditorEvent,
16536 'keyup': this.onEditorEvent,
16541 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16543 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16544 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16546 this.initialized = true;
16548 this.owner.fireEvent('initialize', this);
16553 onDestroy : function(){
16559 //for (var i =0; i < this.toolbars.length;i++) {
16560 // // fixme - ask toolbars for heights?
16561 // this.toolbars[i].onDestroy();
16564 //this.wrap.dom.innerHTML = '';
16565 //this.wrap.remove();
16570 onFirstFocus : function(){
16572 this.assignDocWin();
16575 this.activated = true;
16578 if(Roo.isGecko){ // prevent silly gecko errors
16580 var s = this.win.getSelection();
16581 if(!s.focusNode || s.focusNode.nodeType != 3){
16582 var r = s.getRangeAt(0);
16583 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16588 this.execCmd('useCSS', true);
16589 this.execCmd('styleWithCSS', false);
16592 this.owner.fireEvent('activate', this);
16596 adjustFont: function(btn){
16597 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16598 //if(Roo.isSafari){ // safari
16601 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16602 if(Roo.isSafari){ // safari
16603 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16604 v = (v < 10) ? 10 : v;
16605 v = (v > 48) ? 48 : v;
16606 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16611 v = Math.max(1, v+adjust);
16613 this.execCmd('FontSize', v );
16616 onEditorEvent : function(e){
16617 this.owner.fireEvent('editorevent', this, e);
16618 // this.updateToolbar();
16619 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16622 insertTag : function(tg)
16624 // could be a bit smarter... -> wrap the current selected tRoo..
16625 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16627 range = this.createRange(this.getSelection());
16628 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16629 wrappingNode.appendChild(range.extractContents());
16630 range.insertNode(wrappingNode);
16637 this.execCmd("formatblock", tg);
16641 insertText : function(txt)
16645 var range = this.createRange();
16646 range.deleteContents();
16647 //alert(Sender.getAttribute('label'));
16649 range.insertNode(this.doc.createTextNode(txt));
16655 * Executes a Midas editor command on the editor document and performs necessary focus and
16656 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16657 * @param {String} cmd The Midas command
16658 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16660 relayCmd : function(cmd, value){
16662 this.execCmd(cmd, value);
16663 this.owner.fireEvent('editorevent', this);
16664 //this.updateToolbar();
16665 this.owner.deferFocus();
16669 * Executes a Midas editor command directly on the editor document.
16670 * For visual commands, you should use {@link #relayCmd} instead.
16671 * <b>This should only be called after the editor is initialized.</b>
16672 * @param {String} cmd The Midas command
16673 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16675 execCmd : function(cmd, value){
16676 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16683 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16685 * @param {String} text | dom node..
16687 insertAtCursor : function(text)
16692 if(!this.activated){
16698 var r = this.doc.selection.createRange();
16709 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16713 // from jquery ui (MIT licenced)
16715 var win = this.win;
16717 if (win.getSelection && win.getSelection().getRangeAt) {
16718 range = win.getSelection().getRangeAt(0);
16719 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16720 range.insertNode(node);
16721 } else if (win.document.selection && win.document.selection.createRange) {
16722 // no firefox support
16723 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16724 win.document.selection.createRange().pasteHTML(txt);
16726 // no firefox support
16727 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16728 this.execCmd('InsertHTML', txt);
16737 mozKeyPress : function(e){
16739 var c = e.getCharCode(), cmd;
16742 c = String.fromCharCode(c).toLowerCase();
16756 this.cleanUpPaste.defer(100, this);
16764 e.preventDefault();
16772 fixKeys : function(){ // load time branching for fastest keydown performance
16774 return function(e){
16775 var k = e.getKey(), r;
16778 r = this.doc.selection.createRange();
16781 r.pasteHTML('    ');
16788 r = this.doc.selection.createRange();
16790 var target = r.parentElement();
16791 if(!target || target.tagName.toLowerCase() != 'li'){
16793 r.pasteHTML('<br />');
16799 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16800 this.cleanUpPaste.defer(100, this);
16806 }else if(Roo.isOpera){
16807 return function(e){
16808 var k = e.getKey();
16812 this.execCmd('InsertHTML','    ');
16815 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16816 this.cleanUpPaste.defer(100, this);
16821 }else if(Roo.isSafari){
16822 return function(e){
16823 var k = e.getKey();
16827 this.execCmd('InsertText','\t');
16831 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16832 this.cleanUpPaste.defer(100, this);
16840 getAllAncestors: function()
16842 var p = this.getSelectedNode();
16845 a.push(p); // push blank onto stack..
16846 p = this.getParentElement();
16850 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16854 a.push(this.doc.body);
16858 lastSelNode : false,
16861 getSelection : function()
16863 this.assignDocWin();
16864 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16867 getSelectedNode: function()
16869 // this may only work on Gecko!!!
16871 // should we cache this!!!!
16876 var range = this.createRange(this.getSelection()).cloneRange();
16879 var parent = range.parentElement();
16881 var testRange = range.duplicate();
16882 testRange.moveToElementText(parent);
16883 if (testRange.inRange(range)) {
16886 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16889 parent = parent.parentElement;
16894 // is ancestor a text element.
16895 var ac = range.commonAncestorContainer;
16896 if (ac.nodeType == 3) {
16897 ac = ac.parentNode;
16900 var ar = ac.childNodes;
16903 var other_nodes = [];
16904 var has_other_nodes = false;
16905 for (var i=0;i<ar.length;i++) {
16906 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16909 // fullly contained node.
16911 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16916 // probably selected..
16917 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16918 other_nodes.push(ar[i]);
16922 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16927 has_other_nodes = true;
16929 if (!nodes.length && other_nodes.length) {
16930 nodes= other_nodes;
16932 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16938 createRange: function(sel)
16940 // this has strange effects when using with
16941 // top toolbar - not sure if it's a great idea.
16942 //this.editor.contentWindow.focus();
16943 if (typeof sel != "undefined") {
16945 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16947 return this.doc.createRange();
16950 return this.doc.createRange();
16953 getParentElement: function()
16956 this.assignDocWin();
16957 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16959 var range = this.createRange(sel);
16962 var p = range.commonAncestorContainer;
16963 while (p.nodeType == 3) { // text node
16974 * Range intersection.. the hard stuff...
16978 * [ -- selected range --- ]
16982 * if end is before start or hits it. fail.
16983 * if start is after end or hits it fail.
16985 * if either hits (but other is outside. - then it's not
16991 // @see http://www.thismuchiknow.co.uk/?p=64.
16992 rangeIntersectsNode : function(range, node)
16994 var nodeRange = node.ownerDocument.createRange();
16996 nodeRange.selectNode(node);
16998 nodeRange.selectNodeContents(node);
17001 var rangeStartRange = range.cloneRange();
17002 rangeStartRange.collapse(true);
17004 var rangeEndRange = range.cloneRange();
17005 rangeEndRange.collapse(false);
17007 var nodeStartRange = nodeRange.cloneRange();
17008 nodeStartRange.collapse(true);
17010 var nodeEndRange = nodeRange.cloneRange();
17011 nodeEndRange.collapse(false);
17013 return rangeStartRange.compareBoundaryPoints(
17014 Range.START_TO_START, nodeEndRange) == -1 &&
17015 rangeEndRange.compareBoundaryPoints(
17016 Range.START_TO_START, nodeStartRange) == 1;
17020 rangeCompareNode : function(range, node)
17022 var nodeRange = node.ownerDocument.createRange();
17024 nodeRange.selectNode(node);
17026 nodeRange.selectNodeContents(node);
17030 range.collapse(true);
17032 nodeRange.collapse(true);
17034 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17035 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17037 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17039 var nodeIsBefore = ss == 1;
17040 var nodeIsAfter = ee == -1;
17042 if (nodeIsBefore && nodeIsAfter)
17044 if (!nodeIsBefore && nodeIsAfter)
17045 return 1; //right trailed.
17047 if (nodeIsBefore && !nodeIsAfter)
17048 return 2; // left trailed.
17053 // private? - in a new class?
17054 cleanUpPaste : function()
17056 // cleans up the whole document..
17057 Roo.log('cleanuppaste');
17059 this.cleanUpChildren(this.doc.body);
17060 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17061 if (clean != this.doc.body.innerHTML) {
17062 this.doc.body.innerHTML = clean;
17067 cleanWordChars : function(input) {// change the chars to hex code
17068 var he = Roo.HtmlEditorCore;
17070 var output = input;
17071 Roo.each(he.swapCodes, function(sw) {
17072 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17074 output = output.replace(swapper, sw[1]);
17081 cleanUpChildren : function (n)
17083 if (!n.childNodes.length) {
17086 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17087 this.cleanUpChild(n.childNodes[i]);
17094 cleanUpChild : function (node)
17097 //console.log(node);
17098 if (node.nodeName == "#text") {
17099 // clean up silly Windows -- stuff?
17102 if (node.nodeName == "#comment") {
17103 node.parentNode.removeChild(node);
17104 // clean up silly Windows -- stuff?
17108 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17110 node.parentNode.removeChild(node);
17115 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17117 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17118 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17120 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17121 // remove_keep_children = true;
17124 if (remove_keep_children) {
17125 this.cleanUpChildren(node);
17126 // inserts everything just before this node...
17127 while (node.childNodes.length) {
17128 var cn = node.childNodes[0];
17129 node.removeChild(cn);
17130 node.parentNode.insertBefore(cn, node);
17132 node.parentNode.removeChild(node);
17136 if (!node.attributes || !node.attributes.length) {
17137 this.cleanUpChildren(node);
17141 function cleanAttr(n,v)
17144 if (v.match(/^\./) || v.match(/^\//)) {
17147 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17150 if (v.match(/^#/)) {
17153 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17154 node.removeAttribute(n);
17158 function cleanStyle(n,v)
17160 if (v.match(/expression/)) { //XSS?? should we even bother..
17161 node.removeAttribute(n);
17164 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17165 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17168 var parts = v.split(/;/);
17171 Roo.each(parts, function(p) {
17172 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17176 var l = p.split(':').shift().replace(/\s+/g,'');
17177 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17179 if ( cblack.indexOf(l) > -1) {
17180 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17181 //node.removeAttribute(n);
17185 // only allow 'c whitelisted system attributes'
17186 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17187 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17188 //node.removeAttribute(n);
17198 if (clean.length) {
17199 node.setAttribute(n, clean.join(';'));
17201 node.removeAttribute(n);
17207 for (var i = node.attributes.length-1; i > -1 ; i--) {
17208 var a = node.attributes[i];
17211 if (a.name.toLowerCase().substr(0,2)=='on') {
17212 node.removeAttribute(a.name);
17215 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17216 node.removeAttribute(a.name);
17219 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17220 cleanAttr(a.name,a.value); // fixme..
17223 if (a.name == 'style') {
17224 cleanStyle(a.name,a.value);
17227 /// clean up MS crap..
17228 // tecnically this should be a list of valid class'es..
17231 if (a.name == 'class') {
17232 if (a.value.match(/^Mso/)) {
17233 node.className = '';
17236 if (a.value.match(/body/)) {
17237 node.className = '';
17248 this.cleanUpChildren(node);
17253 * Clean up MS wordisms...
17255 cleanWord : function(node)
17258 var cleanWordChildren = function()
17260 if (!node.childNodes.length) {
17263 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17264 _t.cleanWord(node.childNodes[i]);
17270 this.cleanWord(this.doc.body);
17273 if (node.nodeName == "#text") {
17274 // clean up silly Windows -- stuff?
17277 if (node.nodeName == "#comment") {
17278 node.parentNode.removeChild(node);
17279 // clean up silly Windows -- stuff?
17283 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17284 node.parentNode.removeChild(node);
17288 // remove - but keep children..
17289 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17290 while (node.childNodes.length) {
17291 var cn = node.childNodes[0];
17292 node.removeChild(cn);
17293 node.parentNode.insertBefore(cn, node);
17295 node.parentNode.removeChild(node);
17296 cleanWordChildren();
17300 if (node.className.length) {
17302 var cn = node.className.split(/\W+/);
17304 Roo.each(cn, function(cls) {
17305 if (cls.match(/Mso[a-zA-Z]+/)) {
17310 node.className = cna.length ? cna.join(' ') : '';
17312 node.removeAttribute("class");
17316 if (node.hasAttribute("lang")) {
17317 node.removeAttribute("lang");
17320 if (node.hasAttribute("style")) {
17322 var styles = node.getAttribute("style").split(";");
17324 Roo.each(styles, function(s) {
17325 if (!s.match(/:/)) {
17328 var kv = s.split(":");
17329 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17332 // what ever is left... we allow.
17335 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17336 if (!nstyle.length) {
17337 node.removeAttribute('style');
17341 cleanWordChildren();
17345 domToHTML : function(currentElement, depth, nopadtext) {
17347 depth = depth || 0;
17348 nopadtext = nopadtext || false;
17350 if (!currentElement) {
17351 return this.domToHTML(this.doc.body);
17354 //Roo.log(currentElement);
17356 var allText = false;
17357 var nodeName = currentElement.nodeName;
17358 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17360 if (nodeName == '#text') {
17361 return currentElement.nodeValue;
17366 if (nodeName != 'BODY') {
17369 // Prints the node tagName, such as <A>, <IMG>, etc
17372 for(i = 0; i < currentElement.attributes.length;i++) {
17374 var aname = currentElement.attributes.item(i).name;
17375 if (!currentElement.attributes.item(i).value.length) {
17378 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17381 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17390 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17393 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17398 // Traverse the tree
17400 var currentElementChild = currentElement.childNodes.item(i);
17401 var allText = true;
17402 var innerHTML = '';
17404 while (currentElementChild) {
17405 // Formatting code (indent the tree so it looks nice on the screen)
17406 var nopad = nopadtext;
17407 if (lastnode == 'SPAN') {
17411 if (currentElementChild.nodeName == '#text') {
17412 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17413 if (!nopad && toadd.length > 80) {
17414 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17416 innerHTML += toadd;
17419 currentElementChild = currentElement.childNodes.item(i);
17425 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17427 // Recursively traverse the tree structure of the child node
17428 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17429 lastnode = currentElementChild.nodeName;
17431 currentElementChild=currentElement.childNodes.item(i);
17437 // The remaining code is mostly for formatting the tree
17438 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17443 ret+= "</"+tagName+">";
17449 // hide stuff that is not compatible
17463 * @event specialkey
17467 * @cfg {String} fieldClass @hide
17470 * @cfg {String} focusClass @hide
17473 * @cfg {String} autoCreate @hide
17476 * @cfg {String} inputType @hide
17479 * @cfg {String} invalidClass @hide
17482 * @cfg {String} invalidText @hide
17485 * @cfg {String} msgFx @hide
17488 * @cfg {String} validateOnBlur @hide
17492 Roo.HtmlEditorCore.white = [
17493 'area', 'br', 'img', 'input', 'hr', 'wbr',
17495 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17496 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17497 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17498 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17499 'table', 'ul', 'xmp',
17501 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17504 'dir', 'menu', 'ol', 'ul', 'dl',
17510 Roo.HtmlEditorCore.black = [
17511 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17513 'base', 'basefont', 'bgsound', 'blink', 'body',
17514 'frame', 'frameset', 'head', 'html', 'ilayer',
17515 'iframe', 'layer', 'link', 'meta', 'object',
17516 'script', 'style' ,'title', 'xml' // clean later..
17518 Roo.HtmlEditorCore.clean = [
17519 'script', 'style', 'title', 'xml'
17521 Roo.HtmlEditorCore.remove = [
17526 Roo.HtmlEditorCore.ablack = [
17530 Roo.HtmlEditorCore.aclean = [
17531 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17535 Roo.HtmlEditorCore.pwhite= [
17536 'http', 'https', 'mailto'
17539 // white listed style attributes.
17540 Roo.HtmlEditorCore.cwhite= [
17541 // 'text-align', /// default is to allow most things..
17547 // black listed style attributes.
17548 Roo.HtmlEditorCore.cblack= [
17549 // 'font-size' -- this can be set by the project
17553 Roo.HtmlEditorCore.swapCodes =[
17572 * @class Roo.bootstrap.HtmlEditor
17573 * @extends Roo.bootstrap.TextArea
17574 * Bootstrap HtmlEditor class
17577 * Create a new HtmlEditor
17578 * @param {Object} config The config object
17581 Roo.bootstrap.HtmlEditor = function(config){
17582 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17583 if (!this.toolbars) {
17584 this.toolbars = [];
17586 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17589 * @event initialize
17590 * Fires when the editor is fully initialized (including the iframe)
17591 * @param {HtmlEditor} this
17596 * Fires when the editor is first receives the focus. Any insertion must wait
17597 * until after this event.
17598 * @param {HtmlEditor} this
17602 * @event beforesync
17603 * Fires before the textarea is updated with content from the editor iframe. Return false
17604 * to cancel the sync.
17605 * @param {HtmlEditor} this
17606 * @param {String} html
17610 * @event beforepush
17611 * Fires before the iframe editor is updated with content from the textarea. Return false
17612 * to cancel the push.
17613 * @param {HtmlEditor} this
17614 * @param {String} html
17619 * Fires when the textarea is updated with content from the editor iframe.
17620 * @param {HtmlEditor} this
17621 * @param {String} html
17626 * Fires when the iframe editor is updated with content from the textarea.
17627 * @param {HtmlEditor} this
17628 * @param {String} html
17632 * @event editmodechange
17633 * Fires when the editor switches edit modes
17634 * @param {HtmlEditor} this
17635 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17637 editmodechange: true,
17639 * @event editorevent
17640 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17641 * @param {HtmlEditor} this
17645 * @event firstfocus
17646 * Fires when on first focus - needed by toolbars..
17647 * @param {HtmlEditor} this
17652 * Auto save the htmlEditor value as a file into Events
17653 * @param {HtmlEditor} this
17657 * @event savedpreview
17658 * preview the saved version of htmlEditor
17659 * @param {HtmlEditor} this
17666 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17670 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17675 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17680 * @cfg {Number} height (in pixels)
17684 * @cfg {Number} width (in pixels)
17689 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17692 stylesheets: false,
17697 // private properties
17698 validationEvent : false,
17700 initialized : false,
17703 onFocus : Roo.emptyFn,
17705 hideMode:'offsets',
17708 tbContainer : false,
17710 toolbarContainer :function() {
17711 return this.wrap.select('.x-html-editor-tb',true).first();
17715 * Protected method that will not generally be called directly. It
17716 * is called when the editor creates its toolbar. Override this method if you need to
17717 * add custom toolbar buttons.
17718 * @param {HtmlEditor} editor
17720 createToolbar : function(){
17722 Roo.log("create toolbars");
17724 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17725 this.toolbars[0].render(this.toolbarContainer());
17729 // if (!editor.toolbars || !editor.toolbars.length) {
17730 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17733 // for (var i =0 ; i < editor.toolbars.length;i++) {
17734 // editor.toolbars[i] = Roo.factory(
17735 // typeof(editor.toolbars[i]) == 'string' ?
17736 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17737 // Roo.bootstrap.HtmlEditor);
17738 // editor.toolbars[i].init(editor);
17744 onRender : function(ct, position)
17746 // Roo.log("Call onRender: " + this.xtype);
17748 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17750 this.wrap = this.inputEl().wrap({
17751 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17754 this.editorcore.onRender(ct, position);
17756 if (this.resizable) {
17757 this.resizeEl = new Roo.Resizable(this.wrap, {
17761 minHeight : this.height,
17762 height: this.height,
17763 handles : this.resizable,
17766 resize : function(r, w, h) {
17767 _t.onResize(w,h); // -something
17773 this.createToolbar(this);
17776 if(!this.width && this.resizable){
17777 this.setSize(this.wrap.getSize());
17779 if (this.resizeEl) {
17780 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17781 // should trigger onReize..
17787 onResize : function(w, h)
17789 Roo.log('resize: ' +w + ',' + h );
17790 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17794 if(this.inputEl() ){
17795 if(typeof w == 'number'){
17796 var aw = w - this.wrap.getFrameWidth('lr');
17797 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17800 if(typeof h == 'number'){
17801 var tbh = -11; // fixme it needs to tool bar size!
17802 for (var i =0; i < this.toolbars.length;i++) {
17803 // fixme - ask toolbars for heights?
17804 tbh += this.toolbars[i].el.getHeight();
17805 //if (this.toolbars[i].footer) {
17806 // tbh += this.toolbars[i].footer.el.getHeight();
17814 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17815 ah -= 5; // knock a few pixes off for look..
17816 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17820 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17821 this.editorcore.onResize(ew,eh);
17826 * Toggles the editor between standard and source edit mode.
17827 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17829 toggleSourceEdit : function(sourceEditMode)
17831 this.editorcore.toggleSourceEdit(sourceEditMode);
17833 if(this.editorcore.sourceEditMode){
17834 Roo.log('editor - showing textarea');
17837 // Roo.log(this.syncValue());
17839 this.inputEl().removeClass(['hide', 'x-hidden']);
17840 this.inputEl().dom.removeAttribute('tabIndex');
17841 this.inputEl().focus();
17843 Roo.log('editor - hiding textarea');
17845 // Roo.log(this.pushValue());
17848 this.inputEl().addClass(['hide', 'x-hidden']);
17849 this.inputEl().dom.setAttribute('tabIndex', -1);
17850 //this.deferFocus();
17853 if(this.resizable){
17854 this.setSize(this.wrap.getSize());
17857 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17860 // private (for BoxComponent)
17861 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17863 // private (for BoxComponent)
17864 getResizeEl : function(){
17868 // private (for BoxComponent)
17869 getPositionEl : function(){
17874 initEvents : function(){
17875 this.originalValue = this.getValue();
17879 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17882 // markInvalid : Roo.emptyFn,
17884 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17887 // clearInvalid : Roo.emptyFn,
17889 setValue : function(v){
17890 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17891 this.editorcore.pushValue();
17896 deferFocus : function(){
17897 this.focus.defer(10, this);
17901 focus : function(){
17902 this.editorcore.focus();
17908 onDestroy : function(){
17914 for (var i =0; i < this.toolbars.length;i++) {
17915 // fixme - ask toolbars for heights?
17916 this.toolbars[i].onDestroy();
17919 this.wrap.dom.innerHTML = '';
17920 this.wrap.remove();
17925 onFirstFocus : function(){
17926 //Roo.log("onFirstFocus");
17927 this.editorcore.onFirstFocus();
17928 for (var i =0; i < this.toolbars.length;i++) {
17929 this.toolbars[i].onFirstFocus();
17935 syncValue : function()
17937 this.editorcore.syncValue();
17940 pushValue : function()
17942 this.editorcore.pushValue();
17946 // hide stuff that is not compatible
17960 * @event specialkey
17964 * @cfg {String} fieldClass @hide
17967 * @cfg {String} focusClass @hide
17970 * @cfg {String} autoCreate @hide
17973 * @cfg {String} inputType @hide
17976 * @cfg {String} invalidClass @hide
17979 * @cfg {String} invalidText @hide
17982 * @cfg {String} msgFx @hide
17985 * @cfg {String} validateOnBlur @hide
17994 Roo.namespace('Roo.bootstrap.htmleditor');
17996 * @class Roo.bootstrap.HtmlEditorToolbar1
18001 new Roo.bootstrap.HtmlEditor({
18004 new Roo.bootstrap.HtmlEditorToolbar1({
18005 disable : { fonts: 1 , format: 1, ..., ... , ...],
18011 * @cfg {Object} disable List of elements to disable..
18012 * @cfg {Array} btns List of additional buttons.
18016 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18019 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18022 Roo.apply(this, config);
18024 // default disabled, based on 'good practice'..
18025 this.disable = this.disable || {};
18026 Roo.applyIf(this.disable, {
18029 specialElements : true
18031 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18033 this.editor = config.editor;
18034 this.editorcore = config.editor.editorcore;
18036 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18038 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18039 // dont call parent... till later.
18041 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18046 editorcore : false,
18051 "h1","h2","h3","h4","h5","h6",
18053 "abbr", "acronym", "address", "cite", "samp", "var",
18057 onRender : function(ct, position)
18059 // Roo.log("Call onRender: " + this.xtype);
18061 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18063 this.el.dom.style.marginBottom = '0';
18065 var editorcore = this.editorcore;
18066 var editor= this.editor;
18069 var btn = function(id,cmd , toggle, handler){
18071 var event = toggle ? 'toggle' : 'click';
18076 xns: Roo.bootstrap,
18079 enableToggle:toggle !== false,
18081 pressed : toggle ? false : null,
18084 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18085 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18094 xns: Roo.bootstrap,
18095 glyphicon : 'font',
18099 xns: Roo.bootstrap,
18103 Roo.each(this.formats, function(f) {
18104 style.menu.items.push({
18106 xns: Roo.bootstrap,
18107 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18112 editorcore.insertTag(this.tagname);
18119 children.push(style);
18122 btn('bold',false,true);
18123 btn('italic',false,true);
18124 btn('align-left', 'justifyleft',true);
18125 btn('align-center', 'justifycenter',true);
18126 btn('align-right' , 'justifyright',true);
18127 btn('link', false, false, function(btn) {
18128 //Roo.log("create link?");
18129 var url = prompt(this.createLinkText, this.defaultLinkValue);
18130 if(url && url != 'http:/'+'/'){
18131 this.editorcore.relayCmd('createlink', url);
18134 btn('list','insertunorderedlist',true);
18135 btn('pencil', false,true, function(btn){
18138 this.toggleSourceEdit(btn.pressed);
18144 xns: Roo.bootstrap,
18149 xns: Roo.bootstrap,
18154 cog.menu.items.push({
18156 xns: Roo.bootstrap,
18157 html : Clean styles,
18162 editorcore.insertTag(this.tagname);
18171 this.xtype = 'NavSimplebar';
18173 for(var i=0;i< children.length;i++) {
18175 this.buttons.add(this.addxtypeChild(children[i]));
18179 editor.on('editorevent', this.updateToolbar, this);
18181 onBtnClick : function(id)
18183 this.editorcore.relayCmd(id);
18184 this.editorcore.focus();
18188 * Protected method that will not generally be called directly. It triggers
18189 * a toolbar update by reading the markup state of the current selection in the editor.
18191 updateToolbar: function(){
18193 if(!this.editorcore.activated){
18194 this.editor.onFirstFocus(); // is this neeed?
18198 var btns = this.buttons;
18199 var doc = this.editorcore.doc;
18200 btns.get('bold').setActive(doc.queryCommandState('bold'));
18201 btns.get('italic').setActive(doc.queryCommandState('italic'));
18202 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18204 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18205 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18206 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18208 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18209 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18212 var ans = this.editorcore.getAllAncestors();
18213 if (this.formatCombo) {
18216 var store = this.formatCombo.store;
18217 this.formatCombo.setValue("");
18218 for (var i =0; i < ans.length;i++) {
18219 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18221 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18229 // hides menus... - so this cant be on a menu...
18230 Roo.bootstrap.MenuMgr.hideAll();
18232 Roo.bootstrap.MenuMgr.hideAll();
18233 //this.editorsyncValue();
18235 onFirstFocus: function() {
18236 this.buttons.each(function(item){
18240 toggleSourceEdit : function(sourceEditMode){
18243 if(sourceEditMode){
18244 Roo.log("disabling buttons");
18245 this.buttons.each( function(item){
18246 if(item.cmd != 'pencil'){
18252 Roo.log("enabling buttons");
18253 if(this.editorcore.initialized){
18254 this.buttons.each( function(item){
18260 Roo.log("calling toggole on editor");
18261 // tell the editor that it's been pressed..
18262 this.editor.toggleSourceEdit(sourceEditMode);
18272 * @class Roo.bootstrap.Table.AbstractSelectionModel
18273 * @extends Roo.util.Observable
18274 * Abstract base class for grid SelectionModels. It provides the interface that should be
18275 * implemented by descendant classes. This class should not be directly instantiated.
18278 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18279 this.locked = false;
18280 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18284 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18285 /** @ignore Called by the grid automatically. Do not call directly. */
18286 init : function(grid){
18292 * Locks the selections.
18295 this.locked = true;
18299 * Unlocks the selections.
18301 unlock : function(){
18302 this.locked = false;
18306 * Returns true if the selections are locked.
18307 * @return {Boolean}
18309 isLocked : function(){
18310 return this.locked;
18314 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18315 * @class Roo.bootstrap.Table.RowSelectionModel
18316 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18317 * It supports multiple selections and keyboard selection/navigation.
18319 * @param {Object} config
18322 Roo.bootstrap.Table.RowSelectionModel = function(config){
18323 Roo.apply(this, config);
18324 this.selections = new Roo.util.MixedCollection(false, function(o){
18329 this.lastActive = false;
18333 * @event selectionchange
18334 * Fires when the selection changes
18335 * @param {SelectionModel} this
18337 "selectionchange" : true,
18339 * @event afterselectionchange
18340 * Fires after the selection changes (eg. by key press or clicking)
18341 * @param {SelectionModel} this
18343 "afterselectionchange" : true,
18345 * @event beforerowselect
18346 * Fires when a row is selected being selected, return false to cancel.
18347 * @param {SelectionModel} this
18348 * @param {Number} rowIndex The selected index
18349 * @param {Boolean} keepExisting False if other selections will be cleared
18351 "beforerowselect" : true,
18354 * Fires when a row is selected.
18355 * @param {SelectionModel} this
18356 * @param {Number} rowIndex The selected index
18357 * @param {Roo.data.Record} r The record
18359 "rowselect" : true,
18361 * @event rowdeselect
18362 * Fires when a row is deselected.
18363 * @param {SelectionModel} this
18364 * @param {Number} rowIndex The selected index
18366 "rowdeselect" : true
18368 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18369 this.locked = false;
18372 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18374 * @cfg {Boolean} singleSelect
18375 * True to allow selection of only one row at a time (defaults to false)
18377 singleSelect : false,
18380 initEvents : function(){
18382 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18383 this.grid.on("mousedown", this.handleMouseDown, this);
18384 }else{ // allow click to work like normal
18385 this.grid.on("rowclick", this.handleDragableRowClick, this);
18388 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18389 "up" : function(e){
18391 this.selectPrevious(e.shiftKey);
18392 }else if(this.last !== false && this.lastActive !== false){
18393 var last = this.last;
18394 this.selectRange(this.last, this.lastActive-1);
18395 this.grid.getView().focusRow(this.lastActive);
18396 if(last !== false){
18400 this.selectFirstRow();
18402 this.fireEvent("afterselectionchange", this);
18404 "down" : function(e){
18406 this.selectNext(e.shiftKey);
18407 }else if(this.last !== false && this.lastActive !== false){
18408 var last = this.last;
18409 this.selectRange(this.last, this.lastActive+1);
18410 this.grid.getView().focusRow(this.lastActive);
18411 if(last !== false){
18415 this.selectFirstRow();
18417 this.fireEvent("afterselectionchange", this);
18422 var view = this.grid.view;
18423 view.on("refresh", this.onRefresh, this);
18424 view.on("rowupdated", this.onRowUpdated, this);
18425 view.on("rowremoved", this.onRemove, this);
18429 onRefresh : function(){
18430 var ds = this.grid.dataSource, i, v = this.grid.view;
18431 var s = this.selections;
18432 s.each(function(r){
18433 if((i = ds.indexOfId(r.id)) != -1){
18442 onRemove : function(v, index, r){
18443 this.selections.remove(r);
18447 onRowUpdated : function(v, index, r){
18448 if(this.isSelected(r)){
18449 v.onRowSelect(index);
18455 * @param {Array} records The records to select
18456 * @param {Boolean} keepExisting (optional) True to keep existing selections
18458 selectRecords : function(records, keepExisting){
18460 this.clearSelections();
18462 var ds = this.grid.dataSource;
18463 for(var i = 0, len = records.length; i < len; i++){
18464 this.selectRow(ds.indexOf(records[i]), true);
18469 * Gets the number of selected rows.
18472 getCount : function(){
18473 return this.selections.length;
18477 * Selects the first row in the grid.
18479 selectFirstRow : function(){
18484 * Select the last row.
18485 * @param {Boolean} keepExisting (optional) True to keep existing selections
18487 selectLastRow : function(keepExisting){
18488 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18492 * Selects the row immediately following the last selected row.
18493 * @param {Boolean} keepExisting (optional) True to keep existing selections
18495 selectNext : function(keepExisting){
18496 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18497 this.selectRow(this.last+1, keepExisting);
18498 this.grid.getView().focusRow(this.last);
18503 * Selects the row that precedes the last selected row.
18504 * @param {Boolean} keepExisting (optional) True to keep existing selections
18506 selectPrevious : function(keepExisting){
18508 this.selectRow(this.last-1, keepExisting);
18509 this.grid.getView().focusRow(this.last);
18514 * Returns the selected records
18515 * @return {Array} Array of selected records
18517 getSelections : function(){
18518 return [].concat(this.selections.items);
18522 * Returns the first selected record.
18525 getSelected : function(){
18526 return this.selections.itemAt(0);
18531 * Clears all selections.
18533 clearSelections : function(fast){
18534 if(this.locked) return;
18536 var ds = this.grid.dataSource;
18537 var s = this.selections;
18538 s.each(function(r){
18539 this.deselectRow(ds.indexOfId(r.id));
18543 this.selections.clear();
18550 * Selects all rows.
18552 selectAll : function(){
18553 if(this.locked) return;
18554 this.selections.clear();
18555 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18556 this.selectRow(i, true);
18561 * Returns True if there is a selection.
18562 * @return {Boolean}
18564 hasSelection : function(){
18565 return this.selections.length > 0;
18569 * Returns True if the specified row is selected.
18570 * @param {Number/Record} record The record or index of the record to check
18571 * @return {Boolean}
18573 isSelected : function(index){
18574 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18575 return (r && this.selections.key(r.id) ? true : false);
18579 * Returns True if the specified record id is selected.
18580 * @param {String} id The id of record to check
18581 * @return {Boolean}
18583 isIdSelected : function(id){
18584 return (this.selections.key(id) ? true : false);
18588 handleMouseDown : function(e, t){
18589 var view = this.grid.getView(), rowIndex;
18590 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18593 if(e.shiftKey && this.last !== false){
18594 var last = this.last;
18595 this.selectRange(last, rowIndex, e.ctrlKey);
18596 this.last = last; // reset the last
18597 view.focusRow(rowIndex);
18599 var isSelected = this.isSelected(rowIndex);
18600 if(e.button !== 0 && isSelected){
18601 view.focusRow(rowIndex);
18602 }else if(e.ctrlKey && isSelected){
18603 this.deselectRow(rowIndex);
18604 }else if(!isSelected){
18605 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18606 view.focusRow(rowIndex);
18609 this.fireEvent("afterselectionchange", this);
18612 handleDragableRowClick : function(grid, rowIndex, e)
18614 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18615 this.selectRow(rowIndex, false);
18616 grid.view.focusRow(rowIndex);
18617 this.fireEvent("afterselectionchange", this);
18622 * Selects multiple rows.
18623 * @param {Array} rows Array of the indexes of the row to select
18624 * @param {Boolean} keepExisting (optional) True to keep existing selections
18626 selectRows : function(rows, keepExisting){
18628 this.clearSelections();
18630 for(var i = 0, len = rows.length; i < len; i++){
18631 this.selectRow(rows[i], true);
18636 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18637 * @param {Number} startRow The index of the first row in the range
18638 * @param {Number} endRow The index of the last row in the range
18639 * @param {Boolean} keepExisting (optional) True to retain existing selections
18641 selectRange : function(startRow, endRow, keepExisting){
18642 if(this.locked) return;
18644 this.clearSelections();
18646 if(startRow <= endRow){
18647 for(var i = startRow; i <= endRow; i++){
18648 this.selectRow(i, true);
18651 for(var i = startRow; i >= endRow; i--){
18652 this.selectRow(i, true);
18658 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18659 * @param {Number} startRow The index of the first row in the range
18660 * @param {Number} endRow The index of the last row in the range
18662 deselectRange : function(startRow, endRow, preventViewNotify){
18663 if(this.locked) return;
18664 for(var i = startRow; i <= endRow; i++){
18665 this.deselectRow(i, preventViewNotify);
18671 * @param {Number} row The index of the row to select
18672 * @param {Boolean} keepExisting (optional) True to keep existing selections
18674 selectRow : function(index, keepExisting, preventViewNotify){
18675 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18676 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18677 if(!keepExisting || this.singleSelect){
18678 this.clearSelections();
18680 var r = this.grid.dataSource.getAt(index);
18681 this.selections.add(r);
18682 this.last = this.lastActive = index;
18683 if(!preventViewNotify){
18684 this.grid.getView().onRowSelect(index);
18686 this.fireEvent("rowselect", this, index, r);
18687 this.fireEvent("selectionchange", this);
18693 * @param {Number} row The index of the row to deselect
18695 deselectRow : function(index, preventViewNotify){
18696 if(this.locked) return;
18697 if(this.last == index){
18700 if(this.lastActive == index){
18701 this.lastActive = false;
18703 var r = this.grid.dataSource.getAt(index);
18704 this.selections.remove(r);
18705 if(!preventViewNotify){
18706 this.grid.getView().onRowDeselect(index);
18708 this.fireEvent("rowdeselect", this, index);
18709 this.fireEvent("selectionchange", this);
18713 restoreLast : function(){
18715 this.last = this._last;
18720 acceptsNav : function(row, col, cm){
18721 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18725 onEditorKey : function(field, e){
18726 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18731 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18733 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18735 }else if(k == e.ENTER && !e.ctrlKey){
18739 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18741 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18743 }else if(k == e.ESC){
18747 g.startEditing(newCell[0], newCell[1]);
18752 * Ext JS Library 1.1.1
18753 * Copyright(c) 2006-2007, Ext JS, LLC.
18755 * Originally Released Under LGPL - original licence link has changed is not relivant.
18758 * <script type="text/javascript">
18762 * @class Roo.bootstrap.PagingToolbar
18764 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18766 * Create a new PagingToolbar
18767 * @param {Object} config The config object
18769 Roo.bootstrap.PagingToolbar = function(config)
18771 // old args format still supported... - xtype is prefered..
18772 // created from xtype...
18773 var ds = config.dataSource;
18774 this.toolbarItems = [];
18775 if (config.items) {
18776 this.toolbarItems = config.items;
18777 // config.items = [];
18780 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18787 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18791 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18793 * @cfg {Roo.data.Store} dataSource
18794 * The underlying data store providing the paged data
18797 * @cfg {String/HTMLElement/Element} container
18798 * container The id or element that will contain the toolbar
18801 * @cfg {Boolean} displayInfo
18802 * True to display the displayMsg (defaults to false)
18805 * @cfg {Number} pageSize
18806 * The number of records to display per page (defaults to 20)
18810 * @cfg {String} displayMsg
18811 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18813 displayMsg : 'Displaying {0} - {1} of {2}',
18815 * @cfg {String} emptyMsg
18816 * The message to display when no records are found (defaults to "No data to display")
18818 emptyMsg : 'No data to display',
18820 * Customizable piece of the default paging text (defaults to "Page")
18823 beforePageText : "Page",
18825 * Customizable piece of the default paging text (defaults to "of %0")
18828 afterPageText : "of {0}",
18830 * Customizable piece of the default paging text (defaults to "First Page")
18833 firstText : "First Page",
18835 * Customizable piece of the default paging text (defaults to "Previous Page")
18838 prevText : "Previous Page",
18840 * Customizable piece of the default paging text (defaults to "Next Page")
18843 nextText : "Next Page",
18845 * Customizable piece of the default paging text (defaults to "Last Page")
18848 lastText : "Last Page",
18850 * Customizable piece of the default paging text (defaults to "Refresh")
18853 refreshText : "Refresh",
18857 onRender : function(ct, position)
18859 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18860 this.navgroup.parentId = this.id;
18861 this.navgroup.onRender(this.el, null);
18862 // add the buttons to the navgroup
18864 if(this.displayInfo){
18865 Roo.log(this.el.select('ul.navbar-nav',true).first());
18866 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18867 this.displayEl = this.el.select('.x-paging-info', true).first();
18868 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18869 // this.displayEl = navel.el.select('span',true).first();
18875 Roo.each(_this.buttons, function(e){
18876 Roo.factory(e).onRender(_this.el, null);
18880 Roo.each(_this.toolbarItems, function(e) {
18881 _this.navgroup.addItem(e);
18884 this.first = this.navgroup.addItem({
18885 tooltip: this.firstText,
18887 icon : 'fa fa-backward',
18889 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18892 this.prev = this.navgroup.addItem({
18893 tooltip: this.prevText,
18895 icon : 'fa fa-step-backward',
18897 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18899 //this.addSeparator();
18902 var field = this.navgroup.addItem( {
18904 cls : 'x-paging-position',
18906 html : this.beforePageText +
18907 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18908 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18911 this.field = field.el.select('input', true).first();
18912 this.field.on("keydown", this.onPagingKeydown, this);
18913 this.field.on("focus", function(){this.dom.select();});
18916 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18917 //this.field.setHeight(18);
18918 //this.addSeparator();
18919 this.next = this.navgroup.addItem({
18920 tooltip: this.nextText,
18922 html : ' <i class="fa fa-step-forward">',
18924 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18926 this.last = this.navgroup.addItem({
18927 tooltip: this.lastText,
18928 icon : 'fa fa-forward',
18931 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18933 //this.addSeparator();
18934 this.loading = this.navgroup.addItem({
18935 tooltip: this.refreshText,
18936 icon: 'fa fa-refresh',
18938 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18944 updateInfo : function(){
18945 if(this.displayEl){
18946 var count = this.ds.getCount();
18947 var msg = count == 0 ?
18951 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18953 this.displayEl.update(msg);
18958 onLoad : function(ds, r, o){
18959 this.cursor = o.params ? o.params.start : 0;
18960 var d = this.getPageData(),
18964 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18965 this.field.dom.value = ap;
18966 this.first.setDisabled(ap == 1);
18967 this.prev.setDisabled(ap == 1);
18968 this.next.setDisabled(ap == ps);
18969 this.last.setDisabled(ap == ps);
18970 this.loading.enable();
18975 getPageData : function(){
18976 var total = this.ds.getTotalCount();
18979 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18980 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18985 onLoadError : function(){
18986 this.loading.enable();
18990 onPagingKeydown : function(e){
18991 var k = e.getKey();
18992 var d = this.getPageData();
18994 var v = this.field.dom.value, pageNum;
18995 if(!v || isNaN(pageNum = parseInt(v, 10))){
18996 this.field.dom.value = d.activePage;
18999 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19000 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19003 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))
19005 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19006 this.field.dom.value = pageNum;
19007 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19010 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19012 var v = this.field.dom.value, pageNum;
19013 var increment = (e.shiftKey) ? 10 : 1;
19014 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19016 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19017 this.field.dom.value = d.activePage;
19020 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19022 this.field.dom.value = parseInt(v, 10) + increment;
19023 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19024 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19031 beforeLoad : function(){
19033 this.loading.disable();
19038 onClick : function(which){
19045 ds.load({params:{start: 0, limit: this.pageSize}});
19048 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19051 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19054 var total = ds.getTotalCount();
19055 var extra = total % this.pageSize;
19056 var lastStart = extra ? (total - extra) : total-this.pageSize;
19057 ds.load({params:{start: lastStart, limit: this.pageSize}});
19060 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19066 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19067 * @param {Roo.data.Store} store The data store to unbind
19069 unbind : function(ds){
19070 ds.un("beforeload", this.beforeLoad, this);
19071 ds.un("load", this.onLoad, this);
19072 ds.un("loadexception", this.onLoadError, this);
19073 ds.un("remove", this.updateInfo, this);
19074 ds.un("add", this.updateInfo, this);
19075 this.ds = undefined;
19079 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19080 * @param {Roo.data.Store} store The data store to bind
19082 bind : function(ds){
19083 ds.on("beforeload", this.beforeLoad, this);
19084 ds.on("load", this.onLoad, this);
19085 ds.on("loadexception", this.onLoadError, this);
19086 ds.on("remove", this.updateInfo, this);
19087 ds.on("add", this.updateInfo, this);
19098 * @class Roo.bootstrap.MessageBar
19099 * @extends Roo.bootstrap.Component
19100 * Bootstrap MessageBar class
19101 * @cfg {String} html contents of the MessageBar
19102 * @cfg {String} weight (info | success | warning | danger) default info
19103 * @cfg {String} beforeClass insert the bar before the given class
19104 * @cfg {Boolean} closable (true | false) default false
19105 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19108 * Create a new Element
19109 * @param {Object} config The config object
19112 Roo.bootstrap.MessageBar = function(config){
19113 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19116 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19122 beforeClass: 'bootstrap-sticky-wrap',
19124 getAutoCreate : function(){
19128 cls: 'alert alert-dismissable alert-' + this.weight,
19133 html: this.html || ''
19139 cfg.cls += ' alert-messages-fixed';
19153 onRender : function(ct, position)
19155 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19158 var cfg = Roo.apply({}, this.getAutoCreate());
19162 cfg.cls += ' ' + this.cls;
19165 cfg.style = this.style;
19167 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19169 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19172 this.el.select('>button.close').on('click', this.hide, this);
19178 if (!this.rendered) {
19184 this.fireEvent('show', this);
19190 if (!this.rendered) {
19196 this.fireEvent('hide', this);
19199 update : function()
19201 // var e = this.el.dom.firstChild;
19203 // if(this.closable){
19204 // e = e.nextSibling;
19207 // e.data = this.html || '';
19209 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19225 * @class Roo.bootstrap.Graph
19226 * @extends Roo.bootstrap.Component
19227 * Bootstrap Graph class
19231 @cfg {String} graphtype bar | vbar | pie
19232 @cfg {number} g_x coodinator | centre x (pie)
19233 @cfg {number} g_y coodinator | centre y (pie)
19234 @cfg {number} g_r radius (pie)
19235 @cfg {number} g_height height of the chart (respected by all elements in the set)
19236 @cfg {number} g_width width of the chart (respected by all elements in the set)
19237 @cfg {Object} title The title of the chart
19240 -opts (object) options for the chart
19242 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19243 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19245 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.
19246 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19248 o stretch (boolean)
19250 -opts (object) options for the pie
19253 o startAngle (number)
19254 o endAngle (number)
19258 * Create a new Input
19259 * @param {Object} config The config object
19262 Roo.bootstrap.Graph = function(config){
19263 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19269 * The img click event for the img.
19270 * @param {Roo.EventObject} e
19276 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19287 //g_colors: this.colors,
19294 getAutoCreate : function(){
19305 onRender : function(ct,position){
19306 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19307 this.raphael = Raphael(this.el.dom);
19309 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19310 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19311 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19312 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19314 r.text(160, 10, "Single Series Chart").attr(txtattr);
19315 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19316 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19317 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19319 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19320 r.barchart(330, 10, 300, 220, data1);
19321 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19322 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19325 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19326 // r.barchart(30, 30, 560, 250, xdata, {
19327 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19328 // axis : "0 0 1 1",
19329 // axisxlabels : xdata
19330 // //yvalues : cols,
19333 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19335 // this.load(null,xdata,{
19336 // axis : "0 0 1 1",
19337 // axisxlabels : xdata
19342 load : function(graphtype,xdata,opts){
19343 this.raphael.clear();
19345 graphtype = this.graphtype;
19350 var r = this.raphael,
19351 fin = function () {
19352 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19354 fout = function () {
19355 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19357 pfin = function() {
19358 this.sector.stop();
19359 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19362 this.label[0].stop();
19363 this.label[0].attr({ r: 7.5 });
19364 this.label[1].attr({ "font-weight": 800 });
19367 pfout = function() {
19368 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19371 this.label[0].animate({ r: 5 }, 500, "bounce");
19372 this.label[1].attr({ "font-weight": 400 });
19378 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19381 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19384 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19385 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19387 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19394 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19399 setTitle: function(o)
19404 initEvents: function() {
19407 this.el.on('click', this.onClick, this);
19411 onClick : function(e)
19413 Roo.log('img onclick');
19414 this.fireEvent('click', this, e);
19426 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19429 * @class Roo.bootstrap.dash.NumberBox
19430 * @extends Roo.bootstrap.Component
19431 * Bootstrap NumberBox class
19432 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19433 * @cfg {String} headline Box headline
19434 * @cfg {String} content Box content
19435 * @cfg {String} icon Box icon
19436 * @cfg {String} footer Footer text
19437 * @cfg {String} fhref Footer href
19440 * Create a new NumberBox
19441 * @param {Object} config The config object
19445 Roo.bootstrap.dash.NumberBox = function(config){
19446 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19450 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19460 getAutoCreate : function(){
19464 cls : 'small-box bg-' + this.bgcolor,
19472 cls : 'roo-headline',
19473 html : this.headline
19477 cls : 'roo-content',
19478 html : this.content
19492 cls : 'ion ' + this.icon
19501 cls : 'small-box-footer',
19502 href : this.fhref || '#',
19506 cfg.cn.push(footer);
19513 onRender : function(ct,position){
19514 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19521 setHeadline: function (value)
19523 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19526 setFooter: function (value, href)
19528 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19531 this.el.select('a.small-box-footer',true).first().attr('href', href);
19536 setContent: function (value)
19538 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19541 initEvents: function()
19555 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19558 * @class Roo.bootstrap.dash.TabBox
19559 * @extends Roo.bootstrap.Component
19560 * Bootstrap TabBox class
19561 * @cfg {String} title Title of the TabBox
19562 * @cfg {String} icon Icon of the TabBox
19563 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19566 * Create a new TabBox
19567 * @param {Object} config The config object
19571 Roo.bootstrap.dash.TabBox = function(config){
19572 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19577 * When a pane is added
19578 * @param {Roo.bootstrap.dash.TabPane} pane
19585 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19591 getChildContainer : function()
19593 return this.el.select('.tab-content', true).first();
19596 getAutoCreate : function(){
19600 cls: 'pull-left header',
19608 cls: 'fa ' + this.icon
19615 cls: 'nav-tabs-custom',
19619 cls: 'nav nav-tabs pull-right',
19626 cls: 'tab-content no-padding',
19634 initEvents : function()
19636 //Roo.log('add add pane handler');
19637 this.on('addpane', this.onAddPane, this);
19640 * Updates the box title
19641 * @param {String} html to set the title to.
19643 setTitle : function(value)
19645 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19647 onAddPane : function(pane)
19649 //Roo.log('addpane');
19651 // tabs are rendere left to right..
19652 if(!this.showtabs){
19656 var ctr = this.el.select('.nav-tabs', true).first();
19659 var existing = ctr.select('.nav-tab',true);
19660 var qty = existing.getCount();;
19663 var tab = ctr.createChild({
19665 cls : 'nav-tab' + (qty ? '' : ' active'),
19673 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19676 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19678 pane.el.addClass('active');
19683 onTabClick : function(ev,un,ob,pane)
19685 //Roo.log('tab - prev default');
19686 ev.preventDefault();
19689 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19690 pane.tab.addClass('active');
19691 //Roo.log(pane.title);
19692 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19693 // technically we should have a deactivate event.. but maybe add later.
19694 // and it should not de-activate the selected tab...
19696 pane.el.addClass('active');
19697 pane.fireEvent('activate');
19712 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19714 * @class Roo.bootstrap.TabPane
19715 * @extends Roo.bootstrap.Component
19716 * Bootstrap TabPane class
19717 * @cfg {Boolean} active (false | true) Default false
19718 * @cfg {String} title title of panel
19722 * Create a new TabPane
19723 * @param {Object} config The config object
19726 Roo.bootstrap.dash.TabPane = function(config){
19727 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19731 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19736 // the tabBox that this is attached to.
19739 getAutoCreate : function()
19747 cfg.cls += ' active';
19752 initEvents : function()
19754 //Roo.log('trigger add pane handler');
19755 this.parent().fireEvent('addpane', this)
19759 * Updates the tab title
19760 * @param {String} html to set the title to.
19762 setTitle: function(str)
19768 this.tab.select('a', true).first().dom.innerHTML = str;
19785 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19788 * @class Roo.bootstrap.menu.Menu
19789 * @extends Roo.bootstrap.Component
19790 * Bootstrap Menu class - container for Menu
19791 * @cfg {String} html Text of the menu
19792 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19793 * @cfg {String} icon Font awesome icon
19794 * @cfg {String} pos Menu align to (top | bottom) default bottom
19798 * Create a new Menu
19799 * @param {Object} config The config object
19803 Roo.bootstrap.menu.Menu = function(config){
19804 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19808 * @event beforeshow
19809 * Fires before this menu is displayed
19810 * @param {Roo.bootstrap.menu.Menu} this
19814 * @event beforehide
19815 * Fires before this menu is hidden
19816 * @param {Roo.bootstrap.menu.Menu} this
19821 * Fires after this menu is displayed
19822 * @param {Roo.bootstrap.menu.Menu} this
19827 * Fires after this menu is hidden
19828 * @param {Roo.bootstrap.menu.Menu} this
19833 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19834 * @param {Roo.bootstrap.menu.Menu} this
19835 * @param {Roo.EventObject} e
19842 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19846 weight : 'default',
19851 getChildContainer : function() {
19852 if(this.isSubMenu){
19856 return this.el.select('ul.dropdown-menu', true).first();
19859 getAutoCreate : function()
19864 cls : 'roo-menu-text',
19872 cls : 'fa ' + this.icon
19883 cls : 'dropdown-button btn btn-' + this.weight,
19888 cls : 'dropdown-toggle btn btn-' + this.weight,
19898 cls : 'dropdown-menu'
19904 if(this.pos == 'top'){
19905 cfg.cls += ' dropup';
19908 if(this.isSubMenu){
19911 cls : 'dropdown-menu'
19918 onRender : function(ct, position)
19920 this.isSubMenu = ct.hasClass('dropdown-submenu');
19922 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19925 initEvents : function()
19927 if(this.isSubMenu){
19931 this.hidden = true;
19933 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19934 this.triggerEl.on('click', this.onTriggerPress, this);
19936 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19937 this.buttonEl.on('click', this.onClick, this);
19943 if(this.isSubMenu){
19947 return this.el.select('ul.dropdown-menu', true).first();
19950 onClick : function(e)
19952 this.fireEvent("click", this, e);
19955 onTriggerPress : function(e)
19957 if (this.isVisible()) {
19964 isVisible : function(){
19965 return !this.hidden;
19970 this.fireEvent("beforeshow", this);
19972 this.hidden = false;
19973 this.el.addClass('open');
19975 Roo.get(document).on("mouseup", this.onMouseUp, this);
19977 this.fireEvent("show", this);
19984 this.fireEvent("beforehide", this);
19986 this.hidden = true;
19987 this.el.removeClass('open');
19989 Roo.get(document).un("mouseup", this.onMouseUp);
19991 this.fireEvent("hide", this);
19994 onMouseUp : function()
20008 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20011 * @class Roo.bootstrap.menu.Item
20012 * @extends Roo.bootstrap.Component
20013 * Bootstrap MenuItem class
20014 * @cfg {Boolean} submenu (true | false) default false
20015 * @cfg {String} html text of the item
20016 * @cfg {String} href the link
20017 * @cfg {Boolean} disable (true | false) default false
20018 * @cfg {Boolean} preventDefault (true | false) default true
20019 * @cfg {String} icon Font awesome icon
20020 * @cfg {String} pos Submenu align to (left | right) default right
20024 * Create a new Item
20025 * @param {Object} config The config object
20029 Roo.bootstrap.menu.Item = function(config){
20030 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20034 * Fires when the mouse is hovering over this menu
20035 * @param {Roo.bootstrap.menu.Item} this
20036 * @param {Roo.EventObject} e
20041 * Fires when the mouse exits this menu
20042 * @param {Roo.bootstrap.menu.Item} this
20043 * @param {Roo.EventObject} e
20049 * The raw click event for the entire grid.
20050 * @param {Roo.EventObject} e
20056 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20061 preventDefault: true,
20066 getAutoCreate : function()
20071 cls : 'roo-menu-item-text',
20079 cls : 'fa ' + this.icon
20088 href : this.href || '#',
20095 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20099 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20101 if(this.pos == 'left'){
20102 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20109 initEvents : function()
20111 this.el.on('mouseover', this.onMouseOver, this);
20112 this.el.on('mouseout', this.onMouseOut, this);
20114 this.el.select('a', true).first().on('click', this.onClick, this);
20118 onClick : function(e)
20120 if(this.preventDefault){
20121 e.preventDefault();
20124 this.fireEvent("click", this, e);
20127 onMouseOver : function(e)
20129 if(this.submenu && this.pos == 'left'){
20130 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20133 this.fireEvent("mouseover", this, e);
20136 onMouseOut : function(e)
20138 this.fireEvent("mouseout", this, e);
20150 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20153 * @class Roo.bootstrap.menu.Separator
20154 * @extends Roo.bootstrap.Component
20155 * Bootstrap Separator class
20158 * Create a new Separator
20159 * @param {Object} config The config object
20163 Roo.bootstrap.menu.Separator = function(config){
20164 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20167 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20169 getAutoCreate : function(){