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 or 0 for hidden
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
775 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
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] !== false) {
808 if (!settings[size]) { // 0 = hidden
809 cfg.cls += ' hidden-' + size;
812 cfg.cls += ' col-' + size + '-' + settings[size];
815 if (this.html.length) {
816 cfg.html = this.html;
835 * @class Roo.bootstrap.Container
836 * @extends Roo.bootstrap.Component
837 * Bootstrap Container class
838 * @cfg {Boolean} jumbotron is it a jumbotron element
839 * @cfg {String} html content of element
840 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
841 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
842 * @cfg {String} header content of header (for panel)
843 * @cfg {String} footer content of footer (for panel)
844 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
845 * @cfg {String} tag (header|aside|section) type of HTML tag.
849 * Create a new Container
850 * @param {Object} config The config object
853 Roo.bootstrap.Container = function(config){
854 Roo.bootstrap.Container.superclass.constructor.call(this, config);
857 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
868 getChildContainer : function() {
874 if (this.panel.length) {
875 return this.el.select('.panel-body',true).first();
882 getAutoCreate : function(){
885 tag : this.tag || 'div',
889 if (this.jumbotron) {
890 cfg.cls = 'jumbotron';
892 // - this is applied by the parent..
894 // cfg.cls = this.cls + '';
897 if (this.sticky.length) {
899 var bd = Roo.get(document.body);
900 if (!bd.hasClass('bootstrap-sticky')) {
901 bd.addClass('bootstrap-sticky');
902 Roo.select('html',true).setStyle('height', '100%');
905 cfg.cls += 'bootstrap-sticky-' + this.sticky;
909 if (this.well.length) {
913 cfg.cls +=' well well-' +this.well;
923 if (this.panel.length) {
924 cfg.cls += ' panel panel-' + this.panel;
926 if (this.header.length) {
929 cls : 'panel-heading',
945 if (this.footer.length) {
947 cls : 'panel-footer',
956 body.html = this.html || cfg.html;
958 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
959 cfg.cls = 'container';
967 if(!this.el || !this.panel.length || !this.header.length){
971 return this.el.select('.panel-title',true).first();
974 setTitle : function(v)
976 var titleEl = this.titleEl();
982 titleEl.dom.innerHTML = v;
985 getTitle : function()
988 var titleEl = this.titleEl();
994 return titleEl.dom.innerHTML;
1008 * @class Roo.bootstrap.Img
1009 * @extends Roo.bootstrap.Component
1010 * Bootstrap Img class
1011 * @cfg {Boolean} imgResponsive false | true
1012 * @cfg {String} border rounded | circle | thumbnail
1013 * @cfg {String} src image source
1014 * @cfg {String} alt image alternative text
1015 * @cfg {String} href a tag href
1016 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1019 * Create a new Input
1020 * @param {Object} config The config object
1023 Roo.bootstrap.Img = function(config){
1024 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1030 * The img click event for the img.
1031 * @param {Roo.EventObject} e
1037 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1039 imgResponsive: true,
1045 getAutoCreate : function(){
1049 cls: (this.imgResponsive) ? 'img-responsive' : '',
1053 cfg.html = this.html || cfg.html;
1055 cfg.src = this.src || cfg.src;
1057 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1058 cfg.cls += ' img-' + this.border;
1075 a.target = this.target;
1081 return (this.href) ? a : cfg;
1084 initEvents: function() {
1087 this.el.on('click', this.onClick, this);
1091 onClick : function(e)
1093 Roo.log('img onclick');
1094 this.fireEvent('click', this, e);
1108 * @class Roo.bootstrap.Link
1109 * @extends Roo.bootstrap.Component
1110 * Bootstrap Link Class
1111 * @cfg {String} alt image alternative text
1112 * @cfg {String} href a tag href
1113 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1114 * @cfg {String} html the content of the link.
1115 * @cfg {Boolean} preventDefault (true | false) default false
1119 * Create a new Input
1120 * @param {Object} config The config object
1123 Roo.bootstrap.Link = function(config){
1124 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1130 * The img click event for the img.
1131 * @param {Roo.EventObject} e
1137 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1141 preventDefault: false,
1143 getAutoCreate : function(){
1147 html : this.html || 'html-missing'
1154 cfg.href = this.href || '#';
1156 cfg.target = this.target;
1162 initEvents: function() {
1164 if(!this.href || this.preventDefault){
1165 this.el.on('click', this.onClick, this);
1169 onClick : function(e)
1171 if(this.preventDefault){
1174 //Roo.log('img onclick');
1175 this.fireEvent('click', this, e);
1188 * @class Roo.bootstrap.Header
1189 * @extends Roo.bootstrap.Component
1190 * Bootstrap Header class
1191 * @cfg {String} html content of header
1192 * @cfg {Number} level (1|2|3|4|5|6) default 1
1195 * Create a new Header
1196 * @param {Object} config The config object
1200 Roo.bootstrap.Header = function(config){
1201 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1204 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1212 getAutoCreate : function(){
1215 tag: 'h' + (1 *this.level),
1216 html: this.html || 'fill in html'
1228 * Ext JS Library 1.1.1
1229 * Copyright(c) 2006-2007, Ext JS, LLC.
1231 * Originally Released Under LGPL - original licence link has changed is not relivant.
1234 * <script type="text/javascript">
1238 * @class Roo.bootstrap.MenuMgr
1239 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1242 Roo.bootstrap.MenuMgr = function(){
1243 var menus, active, groups = {}, attached = false, lastShow = new Date();
1245 // private - called when first menu is created
1248 active = new Roo.util.MixedCollection();
1249 Roo.get(document).addKeyListener(27, function(){
1250 if(active.length > 0){
1258 if(active && active.length > 0){
1259 var c = active.clone();
1269 if(active.length < 1){
1270 Roo.get(document).un("mouseup", onMouseDown);
1278 var last = active.last();
1279 lastShow = new Date();
1282 Roo.get(document).on("mouseup", onMouseDown);
1287 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1288 m.parentMenu.activeChild = m;
1289 }else if(last && last.isVisible()){
1290 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1295 function onBeforeHide(m){
1297 m.activeChild.hide();
1299 if(m.autoHideTimer){
1300 clearTimeout(m.autoHideTimer);
1301 delete m.autoHideTimer;
1306 function onBeforeShow(m){
1307 var pm = m.parentMenu;
1308 if(!pm && !m.allowOtherMenus){
1310 }else if(pm && pm.activeChild && active != m){
1311 pm.activeChild.hide();
1316 function onMouseDown(e){
1317 Roo.log("on MouseDown");
1318 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1326 function onBeforeCheck(mi, state){
1328 var g = groups[mi.group];
1329 for(var i = 0, l = g.length; i < l; i++){
1331 g[i].setChecked(false);
1340 * Hides all menus that are currently visible
1342 hideAll : function(){
1347 register : function(menu){
1351 menus[menu.id] = menu;
1352 menu.on("beforehide", onBeforeHide);
1353 menu.on("hide", onHide);
1354 menu.on("beforeshow", onBeforeShow);
1355 menu.on("show", onShow);
1357 if(g && menu.events["checkchange"]){
1361 groups[g].push(menu);
1362 menu.on("checkchange", onCheck);
1367 * Returns a {@link Roo.menu.Menu} object
1368 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1369 * be used to generate and return a new Menu instance.
1371 get : function(menu){
1372 if(typeof menu == "string"){ // menu id
1374 }else if(menu.events){ // menu instance
1377 /*else if(typeof menu.length == 'number'){ // array of menu items?
1378 return new Roo.bootstrap.Menu({items:menu});
1379 }else{ // otherwise, must be a config
1380 return new Roo.bootstrap.Menu(menu);
1387 unregister : function(menu){
1388 delete menus[menu.id];
1389 menu.un("beforehide", onBeforeHide);
1390 menu.un("hide", onHide);
1391 menu.un("beforeshow", onBeforeShow);
1392 menu.un("show", onShow);
1394 if(g && menu.events["checkchange"]){
1395 groups[g].remove(menu);
1396 menu.un("checkchange", onCheck);
1401 registerCheckable : function(menuItem){
1402 var g = menuItem.group;
1407 groups[g].push(menuItem);
1408 menuItem.on("beforecheckchange", onBeforeCheck);
1413 unregisterCheckable : function(menuItem){
1414 var g = menuItem.group;
1416 groups[g].remove(menuItem);
1417 menuItem.un("beforecheckchange", onBeforeCheck);
1429 * @class Roo.bootstrap.Menu
1430 * @extends Roo.bootstrap.Component
1431 * Bootstrap Menu class - container for MenuItems
1432 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1436 * @param {Object} config The config object
1440 Roo.bootstrap.Menu = function(config){
1441 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1442 if (this.registerMenu) {
1443 Roo.bootstrap.MenuMgr.register(this);
1448 * Fires before this menu is displayed
1449 * @param {Roo.menu.Menu} this
1454 * Fires before this menu is hidden
1455 * @param {Roo.menu.Menu} this
1460 * Fires after this menu is displayed
1461 * @param {Roo.menu.Menu} this
1466 * Fires after this menu is hidden
1467 * @param {Roo.menu.Menu} this
1472 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1473 * @param {Roo.menu.Menu} this
1474 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1475 * @param {Roo.EventObject} e
1480 * Fires when the mouse is hovering over this menu
1481 * @param {Roo.menu.Menu} this
1482 * @param {Roo.EventObject} e
1483 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1488 * Fires when the mouse exits this menu
1489 * @param {Roo.menu.Menu} this
1490 * @param {Roo.EventObject} e
1491 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1496 * Fires when a menu item contained in this menu is clicked
1497 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1498 * @param {Roo.EventObject} e
1502 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1505 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1509 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1512 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1514 registerMenu : true,
1516 menuItems :false, // stores the menu items..
1522 getChildContainer : function() {
1526 getAutoCreate : function(){
1528 //if (['right'].indexOf(this.align)!==-1) {
1529 // cfg.cn[1].cls += ' pull-right'
1535 cls : 'dropdown-menu' ,
1536 style : 'z-index:1000'
1540 if (this.type === 'submenu') {
1541 cfg.cls = 'submenu active';
1543 if (this.type === 'treeview') {
1544 cfg.cls = 'treeview-menu';
1549 initEvents : function() {
1551 // Roo.log("ADD event");
1552 // Roo.log(this.triggerEl.dom);
1553 this.triggerEl.on('click', this.onTriggerPress, this);
1554 this.triggerEl.addClass('dropdown-toggle');
1555 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1557 this.el.on("mouseover", this.onMouseOver, this);
1558 this.el.on("mouseout", this.onMouseOut, this);
1562 findTargetItem : function(e){
1563 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1567 //Roo.log(t); Roo.log(t.id);
1569 //Roo.log(this.menuitems);
1570 return this.menuitems.get(t.id);
1572 //return this.items.get(t.menuItemId);
1577 onClick : function(e){
1578 Roo.log("menu.onClick");
1579 var t = this.findTargetItem(e);
1585 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1586 if(t == this.activeItem && t.shouldDeactivate(e)){
1587 this.activeItem.deactivate();
1588 delete this.activeItem;
1592 this.setActiveItem(t, true);
1599 Roo.log('pass click event');
1603 this.fireEvent("click", this, t, e);
1607 onMouseOver : function(e){
1608 var t = this.findTargetItem(e);
1611 // if(t.canActivate && !t.disabled){
1612 // this.setActiveItem(t, true);
1616 this.fireEvent("mouseover", this, e, t);
1618 isVisible : function(){
1619 return !this.hidden;
1621 onMouseOut : function(e){
1622 var t = this.findTargetItem(e);
1625 // if(t == this.activeItem && t.shouldDeactivate(e)){
1626 // this.activeItem.deactivate();
1627 // delete this.activeItem;
1630 this.fireEvent("mouseout", this, e, t);
1635 * Displays this menu relative to another element
1636 * @param {String/HTMLElement/Roo.Element} element The element to align to
1637 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1638 * the element (defaults to this.defaultAlign)
1639 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1641 show : function(el, pos, parentMenu){
1642 this.parentMenu = parentMenu;
1646 this.fireEvent("beforeshow", this);
1647 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1650 * Displays this menu at a specific xy position
1651 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1652 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1654 showAt : function(xy, parentMenu, /* private: */_e){
1655 this.parentMenu = parentMenu;
1660 this.fireEvent("beforeshow", this);
1662 //xy = this.el.adjustForConstraints(xy);
1664 //this.el.setXY(xy);
1666 this.hideMenuItems();
1667 this.hidden = false;
1668 this.triggerEl.addClass('open');
1670 this.fireEvent("show", this);
1676 this.doFocus.defer(50, this);
1680 doFocus : function(){
1682 this.focusEl.focus();
1687 * Hides this menu and optionally all parent menus
1688 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1690 hide : function(deep){
1692 this.hideMenuItems();
1693 if(this.el && this.isVisible()){
1694 this.fireEvent("beforehide", this);
1695 if(this.activeItem){
1696 this.activeItem.deactivate();
1697 this.activeItem = null;
1699 this.triggerEl.removeClass('open');;
1701 this.fireEvent("hide", this);
1703 if(deep === true && this.parentMenu){
1704 this.parentMenu.hide(true);
1708 onTriggerPress : function(e)
1711 Roo.log('trigger press');
1712 //Roo.log(e.getTarget());
1713 // Roo.log(this.triggerEl.dom);
1714 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1717 if (this.isVisible()) {
1721 this.show(this.triggerEl, false, false);
1730 hideMenuItems : function()
1732 //$(backdrop).remove()
1733 Roo.select('.open',true).each(function(aa) {
1735 aa.removeClass('open');
1736 //var parent = getParent($(this))
1737 //var relatedTarget = { relatedTarget: this }
1739 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1740 //if (e.isDefaultPrevented()) return
1741 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1744 addxtypeChild : function (tree, cntr) {
1745 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1747 this.menuitems.add(comp);
1768 * @class Roo.bootstrap.MenuItem
1769 * @extends Roo.bootstrap.Component
1770 * Bootstrap MenuItem class
1771 * @cfg {String} html the menu label
1772 * @cfg {String} href the link
1773 * @cfg {Boolean} preventDefault (true | false) default true
1777 * Create a new MenuItem
1778 * @param {Object} config The config object
1782 Roo.bootstrap.MenuItem = function(config){
1783 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1788 * The raw click event for the entire grid.
1789 * @param {Roo.EventObject} e
1795 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1799 preventDefault: true,
1801 getAutoCreate : function(){
1804 cls: 'dropdown-menu-item',
1813 if (this.parent().type == 'treeview') {
1814 cfg.cls = 'treeview-menu';
1817 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1818 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1822 initEvents: function() {
1824 //this.el.select('a').on('click', this.onClick, this);
1827 onClick : function(e)
1829 Roo.log('item on click ');
1830 //if(this.preventDefault){
1831 // e.preventDefault();
1833 //this.parent().hideMenuItems();
1835 this.fireEvent('click', this, e);
1854 * @class Roo.bootstrap.MenuSeparator
1855 * @extends Roo.bootstrap.Component
1856 * Bootstrap MenuSeparator class
1859 * Create a new MenuItem
1860 * @param {Object} config The config object
1864 Roo.bootstrap.MenuSeparator = function(config){
1865 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1868 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1870 getAutoCreate : function(){
1885 <div class="modal fade">
1886 <div class="modal-dialog">
1887 <div class="modal-content">
1888 <div class="modal-header">
1889 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1890 <h4 class="modal-title">Modal title</h4>
1892 <div class="modal-body">
1893 <p>One fine body…</p>
1895 <div class="modal-footer">
1896 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1897 <button type="button" class="btn btn-primary">Save changes</button>
1899 </div><!-- /.modal-content -->
1900 </div><!-- /.modal-dialog -->
1901 </div><!-- /.modal -->
1911 * @class Roo.bootstrap.Modal
1912 * @extends Roo.bootstrap.Component
1913 * Bootstrap Modal class
1914 * @cfg {String} title Title of dialog
1915 * @cfg {Boolean} specificTitle (true|false) default false
1916 * @cfg {Array} buttons Array of buttons or standard button set..
1917 * @cfg {String} buttonPosition (left|right|center) default right
1920 * Create a new Modal Dialog
1921 * @param {Object} config The config object
1924 Roo.bootstrap.Modal = function(config){
1925 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1930 * The raw btnclick event for the button
1931 * @param {Roo.EventObject} e
1935 this.buttons = this.buttons || [];
1938 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1940 title : 'test dialog',
1947 specificTitle: false,
1949 buttonPosition: 'right',
1951 onRender : function(ct, position)
1953 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1956 var cfg = Roo.apply({}, this.getAutoCreate());
1959 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1961 //if (!cfg.name.length) {
1965 cfg.cls += ' ' + this.cls;
1968 cfg.style = this.style;
1970 this.el = Roo.get(document.body).createChild(cfg, position);
1972 //var type = this.el.dom.type;
1974 if(this.tabIndex !== undefined){
1975 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1980 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1981 this.maskEl.enableDisplayMode("block");
1983 //this.el.addClass("x-dlg-modal");
1985 if (this.buttons.length) {
1986 Roo.each(this.buttons, function(bb) {
1987 b = Roo.apply({}, bb);
1988 b.xns = b.xns || Roo.bootstrap;
1989 b.xtype = b.xtype || 'Button';
1990 if (typeof(b.listeners) == 'undefined') {
1991 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1994 var btn = Roo.factory(b);
1996 btn.onRender(this.el.select('.modal-footer div').first());
2000 // render the children.
2003 if(typeof(this.items) != 'undefined'){
2004 var items = this.items;
2007 for(var i =0;i < items.length;i++) {
2008 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2012 this.items = nitems;
2014 this.body = this.el.select('.modal-body',true).first();
2015 this.close = this.el.select('.modal-header .close', true).first();
2016 this.footer = this.el.select('.modal-footer',true).first();
2018 //this.el.addClass([this.fieldClass, this.cls]);
2021 getAutoCreate : function(){
2026 html : this.html || ''
2031 cls : 'modal-title',
2035 if(this.specificTitle){
2041 style : 'display: none',
2044 cls: "modal-dialog",
2047 cls : "modal-content",
2050 cls : 'modal-header',
2062 cls : 'modal-footer',
2066 cls: 'btn-' + this.buttonPosition
2085 getChildContainer : function() {
2087 return this.el.select('.modal-body',true).first();
2090 getButtonContainer : function() {
2091 return this.el.select('.modal-footer div',true).first();
2094 initEvents : function()
2096 this.el.select('.modal-header .close').on('click', this.hide, this);
2098 // this.addxtype(this);
2102 if (!this.rendered) {
2106 this.el.addClass('on');
2107 this.el.removeClass('fade');
2108 this.el.setStyle('display', 'block');
2109 Roo.get(document.body).addClass("x-body-masked");
2110 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2112 this.el.setStyle('zIndex', '10001');
2113 this.fireEvent('show', this);
2119 Roo.log('Modal hide?!');
2121 Roo.get(document.body).removeClass("x-body-masked");
2122 this.el.removeClass('on');
2123 this.el.addClass('fade');
2124 this.el.setStyle('display', 'none');
2125 this.fireEvent('hide', this);
2128 addButton : function(str, cb)
2132 var b = Roo.apply({}, { html : str } );
2133 b.xns = b.xns || Roo.bootstrap;
2134 b.xtype = b.xtype || 'Button';
2135 if (typeof(b.listeners) == 'undefined') {
2136 b.listeners = { click : cb.createDelegate(this) };
2139 var btn = Roo.factory(b);
2141 btn.onRender(this.el.select('.modal-footer div').first());
2147 setDefaultButton : function(btn)
2149 //this.el.select('.modal-footer').()
2151 resizeTo: function(w,h)
2155 setContentSize : function(w, h)
2159 onButtonClick: function(btn,e)
2162 this.fireEvent('btnclick', btn.name, e);
2164 setTitle: function(str) {
2165 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2171 Roo.apply(Roo.bootstrap.Modal, {
2173 * Button config that displays a single OK button
2182 * Button config that displays Yes and No buttons
2198 * Button config that displays OK and Cancel buttons
2213 * Button config that displays Yes, No and Cancel buttons
2235 * messagebox - can be used as a replace
2239 * @class Roo.MessageBox
2240 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2244 Roo.Msg.alert('Status', 'Changes saved successfully.');
2246 // Prompt for user data:
2247 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2249 // process text value...
2253 // Show a dialog using config options:
2255 title:'Save Changes?',
2256 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2257 buttons: Roo.Msg.YESNOCANCEL,
2264 Roo.bootstrap.MessageBox = function(){
2265 var dlg, opt, mask, waitTimer;
2266 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2267 var buttons, activeTextEl, bwidth;
2271 var handleButton = function(button){
2273 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2277 var handleHide = function(){
2279 dlg.el.removeClass(opt.cls);
2282 // Roo.TaskMgr.stop(waitTimer);
2283 // waitTimer = null;
2288 var updateButtons = function(b){
2291 buttons["ok"].hide();
2292 buttons["cancel"].hide();
2293 buttons["yes"].hide();
2294 buttons["no"].hide();
2295 //dlg.footer.dom.style.display = 'none';
2298 dlg.footer.dom.style.display = '';
2299 for(var k in buttons){
2300 if(typeof buttons[k] != "function"){
2303 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2304 width += buttons[k].el.getWidth()+15;
2314 var handleEsc = function(d, k, e){
2315 if(opt && opt.closable !== false){
2325 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2326 * @return {Roo.BasicDialog} The BasicDialog element
2328 getDialog : function(){
2330 dlg = new Roo.bootstrap.Modal( {
2333 //constraintoviewport:false,
2335 //collapsible : false,
2340 //buttonAlign:"center",
2341 closeClick : function(){
2342 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2345 handleButton("cancel");
2350 dlg.on("hide", handleHide);
2352 //dlg.addKeyListener(27, handleEsc);
2354 this.buttons = buttons;
2355 var bt = this.buttonText;
2356 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2357 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2358 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2359 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2361 bodyEl = dlg.body.createChild({
2363 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2364 '<textarea class="roo-mb-textarea"></textarea>' +
2365 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2367 msgEl = bodyEl.dom.firstChild;
2368 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2369 textboxEl.enableDisplayMode();
2370 textboxEl.addKeyListener([10,13], function(){
2371 if(dlg.isVisible() && opt && opt.buttons){
2374 }else if(opt.buttons.yes){
2375 handleButton("yes");
2379 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2380 textareaEl.enableDisplayMode();
2381 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2382 progressEl.enableDisplayMode();
2383 var pf = progressEl.dom.firstChild;
2385 pp = Roo.get(pf.firstChild);
2386 pp.setHeight(pf.offsetHeight);
2394 * Updates the message box body text
2395 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2396 * the XHTML-compliant non-breaking space character '&#160;')
2397 * @return {Roo.MessageBox} This message box
2399 updateText : function(text){
2400 if(!dlg.isVisible() && !opt.width){
2401 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2403 msgEl.innerHTML = text || ' ';
2405 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2406 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2408 Math.min(opt.width || cw , this.maxWidth),
2409 Math.max(opt.minWidth || this.minWidth, bwidth)
2412 activeTextEl.setWidth(w);
2414 if(dlg.isVisible()){
2415 dlg.fixedcenter = false;
2417 // to big, make it scroll. = But as usual stupid IE does not support
2420 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2421 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2422 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2424 bodyEl.dom.style.height = '';
2425 bodyEl.dom.style.overflowY = '';
2428 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2430 bodyEl.dom.style.overflowX = '';
2433 dlg.setContentSize(w, bodyEl.getHeight());
2434 if(dlg.isVisible()){
2435 dlg.fixedcenter = true;
2441 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2442 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2443 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2444 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2445 * @return {Roo.MessageBox} This message box
2447 updateProgress : function(value, text){
2449 this.updateText(text);
2451 if (pp) { // weird bug on my firefox - for some reason this is not defined
2452 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2458 * Returns true if the message box is currently displayed
2459 * @return {Boolean} True if the message box is visible, else false
2461 isVisible : function(){
2462 return dlg && dlg.isVisible();
2466 * Hides the message box if it is displayed
2469 if(this.isVisible()){
2475 * Displays a new message box, or reinitializes an existing message box, based on the config options
2476 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2477 * The following config object properties are supported:
2479 Property Type Description
2480 ---------- --------------- ------------------------------------------------------------------------------------
2481 animEl String/Element An id or Element from which the message box should animate as it opens and
2482 closes (defaults to undefined)
2483 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2484 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2485 closable Boolean False to hide the top-right close button (defaults to true). Note that
2486 progress and wait dialogs will ignore this property and always hide the
2487 close button as they can only be closed programmatically.
2488 cls String A custom CSS class to apply to the message box element
2489 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2490 displayed (defaults to 75)
2491 fn Function A callback function to execute after closing the dialog. The arguments to the
2492 function will be btn (the name of the button that was clicked, if applicable,
2493 e.g. "ok"), and text (the value of the active text field, if applicable).
2494 Progress and wait dialogs will ignore this option since they do not respond to
2495 user actions and can only be closed programmatically, so any required function
2496 should be called by the same code after it closes the dialog.
2497 icon String A CSS class that provides a background image to be used as an icon for
2498 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2499 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2500 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2501 modal Boolean False to allow user interaction with the page while the message box is
2502 displayed (defaults to true)
2503 msg String A string that will replace the existing message box body text (defaults
2504 to the XHTML-compliant non-breaking space character ' ')
2505 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2506 progress Boolean True to display a progress bar (defaults to false)
2507 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2508 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2509 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2510 title String The title text
2511 value String The string value to set into the active textbox element if displayed
2512 wait Boolean True to display a progress bar (defaults to false)
2513 width Number The width of the dialog in pixels
2520 msg: 'Please enter your address:',
2522 buttons: Roo.MessageBox.OKCANCEL,
2525 animEl: 'addAddressBtn'
2528 * @param {Object} config Configuration options
2529 * @return {Roo.MessageBox} This message box
2531 show : function(options)
2534 // this causes nightmares if you show one dialog after another
2535 // especially on callbacks..
2537 if(this.isVisible()){
2540 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2541 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2542 Roo.log("New Dialog Message:" + options.msg )
2543 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2544 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2547 var d = this.getDialog();
2549 d.setTitle(opt.title || " ");
2550 d.close.setDisplayed(opt.closable !== false);
2551 activeTextEl = textboxEl;
2552 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2557 textareaEl.setHeight(typeof opt.multiline == "number" ?
2558 opt.multiline : this.defaultTextHeight);
2559 activeTextEl = textareaEl;
2568 progressEl.setDisplayed(opt.progress === true);
2569 this.updateProgress(0);
2570 activeTextEl.dom.value = opt.value || "";
2572 dlg.setDefaultButton(activeTextEl);
2574 var bs = opt.buttons;
2578 }else if(bs && bs.yes){
2579 db = buttons["yes"];
2581 dlg.setDefaultButton(db);
2583 bwidth = updateButtons(opt.buttons);
2584 this.updateText(opt.msg);
2586 d.el.addClass(opt.cls);
2588 d.proxyDrag = opt.proxyDrag === true;
2589 d.modal = opt.modal !== false;
2590 d.mask = opt.modal !== false ? mask : false;
2592 // force it to the end of the z-index stack so it gets a cursor in FF
2593 document.body.appendChild(dlg.el.dom);
2594 d.animateTarget = null;
2595 d.show(options.animEl);
2601 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2602 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2603 * and closing the message box when the process is complete.
2604 * @param {String} title The title bar text
2605 * @param {String} msg The message box body text
2606 * @return {Roo.MessageBox} This message box
2608 progress : function(title, msg){
2615 minWidth: this.minProgressWidth,
2622 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2623 * If a callback function is passed it will be called after the user clicks the button, and the
2624 * id of the button that was clicked will be passed as the only parameter to the callback
2625 * (could also be the top-right close button).
2626 * @param {String} title The title bar text
2627 * @param {String} msg The message box body text
2628 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2629 * @param {Object} scope (optional) The scope of the callback function
2630 * @return {Roo.MessageBox} This message box
2632 alert : function(title, msg, fn, scope){
2645 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2646 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2647 * You are responsible for closing the message box when the process is complete.
2648 * @param {String} msg The message box body text
2649 * @param {String} title (optional) The title bar text
2650 * @return {Roo.MessageBox} This message box
2652 wait : function(msg, title){
2663 waitTimer = Roo.TaskMgr.start({
2665 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2673 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2674 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2675 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2676 * @param {String} title The title bar text
2677 * @param {String} msg The message box body text
2678 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2679 * @param {Object} scope (optional) The scope of the callback function
2680 * @return {Roo.MessageBox} This message box
2682 confirm : function(title, msg, fn, scope){
2686 buttons: this.YESNO,
2695 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2696 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2697 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2698 * (could also be the top-right close button) and the text that was entered will be passed as the two
2699 * parameters to the callback.
2700 * @param {String} title The title bar text
2701 * @param {String} msg The message box body text
2702 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2703 * @param {Object} scope (optional) The scope of the callback function
2704 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2705 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2706 * @return {Roo.MessageBox} This message box
2708 prompt : function(title, msg, fn, scope, multiline){
2712 buttons: this.OKCANCEL,
2717 multiline: multiline,
2724 * Button config that displays a single OK button
2729 * Button config that displays Yes and No buttons
2732 YESNO : {yes:true, no:true},
2734 * Button config that displays OK and Cancel buttons
2737 OKCANCEL : {ok:true, cancel:true},
2739 * Button config that displays Yes, No and Cancel buttons
2742 YESNOCANCEL : {yes:true, no:true, cancel:true},
2745 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2748 defaultTextHeight : 75,
2750 * The maximum width in pixels of the message box (defaults to 600)
2755 * The minimum width in pixels of the message box (defaults to 100)
2760 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2761 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2764 minProgressWidth : 250,
2766 * An object containing the default button text strings that can be overriden for localized language support.
2767 * Supported properties are: ok, cancel, yes and no.
2768 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2781 * Shorthand for {@link Roo.MessageBox}
2783 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2784 Roo.Msg = Roo.Msg || Roo.MessageBox;
2793 * @class Roo.bootstrap.Navbar
2794 * @extends Roo.bootstrap.Component
2795 * Bootstrap Navbar class
2798 * Create a new Navbar
2799 * @param {Object} config The config object
2803 Roo.bootstrap.Navbar = function(config){
2804 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2808 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2817 getAutoCreate : function(){
2820 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2824 initEvents :function ()
2826 //Roo.log(this.el.select('.navbar-toggle',true));
2827 this.el.select('.navbar-toggle',true).on('click', function() {
2828 // Roo.log('click');
2829 this.el.select('.navbar-collapse',true).toggleClass('in');
2837 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2839 var size = this.el.getSize();
2840 this.maskEl.setSize(size.width, size.height);
2841 this.maskEl.enableDisplayMode("block");
2850 getChildContainer : function()
2852 if (this.el.select('.collapse').getCount()) {
2853 return this.el.select('.collapse',true).first();
2886 * @class Roo.bootstrap.NavSimplebar
2887 * @extends Roo.bootstrap.Navbar
2888 * Bootstrap Sidebar class
2890 * @cfg {Boolean} inverse is inverted color
2892 * @cfg {String} type (nav | pills | tabs)
2893 * @cfg {Boolean} arrangement stacked | justified
2894 * @cfg {String} align (left | right) alignment
2896 * @cfg {Boolean} main (true|false) main nav bar? default false
2897 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2899 * @cfg {String} tag (header|footer|nav|div) default is nav
2905 * Create a new Sidebar
2906 * @param {Object} config The config object
2910 Roo.bootstrap.NavSimplebar = function(config){
2911 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2914 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2930 getAutoCreate : function(){
2934 tag : this.tag || 'div',
2947 this.type = this.type || 'nav';
2948 if (['tabs','pills'].indexOf(this.type)!==-1) {
2949 cfg.cn[0].cls += ' nav-' + this.type
2953 if (this.type!=='nav') {
2954 Roo.log('nav type must be nav/tabs/pills')
2956 cfg.cn[0].cls += ' navbar-nav'
2962 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2963 cfg.cn[0].cls += ' nav-' + this.arrangement;
2967 if (this.align === 'right') {
2968 cfg.cn[0].cls += ' navbar-right';
2972 cfg.cls += ' navbar-inverse';
2999 * @class Roo.bootstrap.NavHeaderbar
3000 * @extends Roo.bootstrap.NavSimplebar
3001 * Bootstrap Sidebar class
3003 * @cfg {String} brand what is brand
3004 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3005 * @cfg {String} brand_href href of the brand
3006 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3007 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3010 * Create a new Sidebar
3011 * @param {Object} config The config object
3015 Roo.bootstrap.NavHeaderbar = function(config){
3016 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3019 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3027 getAutoCreate : function(){
3030 tag: this.nav || 'nav',
3039 cls: 'navbar-header',
3044 cls: 'navbar-toggle',
3045 'data-toggle': 'collapse',
3050 html: 'Toggle navigation'
3072 cls: 'collapse navbar-collapse',
3076 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3078 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3079 cfg.cls += ' navbar-' + this.position;
3081 // tag can override this..
3083 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3086 if (this.brand !== '') {
3089 href: this.brand_href ? this.brand_href : '#',
3090 cls: 'navbar-brand',
3098 cfg.cls += ' main-nav';
3106 initEvents : function()
3108 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3110 if (this.autohide) {
3115 Roo.get(document).on('scroll',function(e) {
3116 var ns = Roo.get(document).getScroll().top;
3117 var os = prevScroll;
3121 ft.removeClass('slideDown');
3122 ft.addClass('slideUp');
3125 ft.removeClass('slideUp');
3126 ft.addClass('slideDown');
3150 * @class Roo.bootstrap.NavSidebar
3151 * @extends Roo.bootstrap.Navbar
3152 * Bootstrap Sidebar class
3155 * Create a new Sidebar
3156 * @param {Object} config The config object
3160 Roo.bootstrap.NavSidebar = function(config){
3161 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3164 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3166 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3168 getAutoCreate : function(){
3173 cls: 'sidebar sidebar-nav'
3195 * @class Roo.bootstrap.NavGroup
3196 * @extends Roo.bootstrap.Component
3197 * Bootstrap NavGroup class
3198 * @cfg {String} align left | right
3199 * @cfg {Boolean} inverse false | true
3200 * @cfg {String} type (nav|pills|tab) default nav
3201 * @cfg {String} navId - reference Id for navbar.
3205 * Create a new nav group
3206 * @param {Object} config The config object
3209 Roo.bootstrap.NavGroup = function(config){
3210 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3213 Roo.bootstrap.NavGroup.register(this);
3217 * Fires when the active item changes
3218 * @param {Roo.bootstrap.NavGroup} this
3219 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3220 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3227 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3238 getAutoCreate : function()
3240 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3247 if (['tabs','pills'].indexOf(this.type)!==-1) {
3248 cfg.cls += ' nav-' + this.type
3250 if (this.type!=='nav') {
3251 Roo.log('nav type must be nav/tabs/pills')
3253 cfg.cls += ' navbar-nav'
3256 if (this.parent().sidebar) {
3259 cls: 'dashboard-menu sidebar-menu'
3265 if (this.form === true) {
3271 if (this.align === 'right') {
3272 cfg.cls += ' navbar-right';
3274 cfg.cls += ' navbar-left';
3278 if (this.align === 'right') {
3279 cfg.cls += ' navbar-right';
3283 cfg.cls += ' navbar-inverse';
3291 * sets the active Navigation item
3292 * @param {Roo.bootstrap.NavItem} the new current navitem
3294 setActiveItem : function(item)
3297 Roo.each(this.navItems, function(v){
3302 v.setActive(false, true);
3309 item.setActive(true, true);
3310 this.fireEvent('changed', this, item, prev);
3315 * gets the active Navigation item
3316 * @return {Roo.bootstrap.NavItem} the current navitem
3318 getActive : function()
3322 Roo.each(this.navItems, function(v){
3333 indexOfNav : function()
3337 Roo.each(this.navItems, function(v,i){
3348 * adds a Navigation item
3349 * @param {Roo.bootstrap.NavItem} the navitem to add
3351 addItem : function(cfg)
3353 var cn = new Roo.bootstrap.NavItem(cfg);
3355 cn.parentId = this.id;
3356 cn.onRender(this.el, null);
3360 * register a Navigation item
3361 * @param {Roo.bootstrap.NavItem} the navitem to add
3363 register : function(item)
3365 this.navItems.push( item);
3366 item.navId = this.navId;
3371 getNavItem: function(tabId)
3374 Roo.each(this.navItems, function(e) {
3375 if (e.tabId == tabId) {
3385 setActiveNext : function()
3387 var i = this.indexOfNav(this.getActive());
3388 if (i > this.navItems.length) {
3391 this.setActiveItem(this.navItems[i+1]);
3393 setActivePrev : function()
3395 var i = this.indexOfNav(this.getActive());
3399 this.setActiveItem(this.navItems[i-1]);
3401 clearWasActive : function(except) {
3402 Roo.each(this.navItems, function(e) {
3403 if (e.tabId != except.tabId && e.was_active) {
3404 e.was_active = false;
3411 getWasActive : function ()
3414 Roo.each(this.navItems, function(e) {
3429 Roo.apply(Roo.bootstrap.NavGroup, {
3433 * register a Navigation Group
3434 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3436 register : function(navgrp)
3438 this.groups[navgrp.navId] = navgrp;
3442 * fetch a Navigation Group based on the navigation ID
3443 * @param {string} the navgroup to add
3444 * @returns {Roo.bootstrap.NavGroup} the navgroup
3446 get: function(navId) {
3447 if (typeof(this.groups[navId]) == 'undefined') {
3449 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3451 return this.groups[navId] ;
3466 * @class Roo.bootstrap.NavItem
3467 * @extends Roo.bootstrap.Component
3468 * Bootstrap Navbar.NavItem class
3469 * @cfg {String} href link to
3470 * @cfg {String} html content of button
3471 * @cfg {String} badge text inside badge
3472 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3473 * @cfg {String} glyphicon name of glyphicon
3474 * @cfg {String} icon name of font awesome icon
3475 * @cfg {Boolean} active Is item active
3476 * @cfg {Boolean} disabled Is item disabled
3478 * @cfg {Boolean} preventDefault (true | false) default false
3479 * @cfg {String} tabId the tab that this item activates.
3480 * @cfg {String} tagtype (a|span) render as a href or span?
3483 * Create a new Navbar Item
3484 * @param {Object} config The config object
3486 Roo.bootstrap.NavItem = function(config){
3487 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3492 * The raw click event for the entire grid.
3493 * @param {Roo.EventObject} e
3498 * Fires when the active item active state changes
3499 * @param {Roo.bootstrap.NavItem} this
3500 * @param {boolean} state the new state
3508 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3516 preventDefault : false,
3523 getAutoCreate : function(){
3531 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3533 if (this.disabled) {
3534 cfg.cls += ' disabled';
3537 if (this.href || this.html || this.glyphicon || this.icon) {
3541 href : this.href || "#",
3542 html: this.html || ''
3547 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3550 if(this.glyphicon) {
3551 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3556 cfg.cn[0].html += " <span class='caret'></span>";
3560 if (this.badge !== '') {
3562 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3570 initEvents: function() {
3571 // Roo.log('init events?');
3572 // Roo.log(this.el.dom);
3573 if (typeof (this.menu) != 'undefined') {
3574 this.menu.parentType = this.xtype;
3575 this.menu.triggerEl = this.el;
3576 this.addxtype(Roo.apply({}, this.menu));
3580 this.el.select('a',true).on('click', this.onClick, this);
3581 // at this point parent should be available..
3582 this.parent().register(this);
3585 onClick : function(e)
3588 if(this.preventDefault){
3591 if (this.disabled) {
3595 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3596 if (tg && tg.transition) {
3597 Roo.log("waiting for the transitionend");
3601 Roo.log("fire event clicked");
3602 if(this.fireEvent('click', this, e) === false){
3606 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3607 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3608 this.parent().setActiveItem(this);
3613 isActive: function () {
3616 setActive : function(state, fire, is_was_active)
3618 if (this.active && !state & this.navId) {
3619 this.was_active = true;
3620 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3622 nv.clearWasActive(this);
3626 this.active = state;
3629 this.el.removeClass('active');
3630 } else if (!this.el.hasClass('active')) {
3631 this.el.addClass('active');
3634 this.fireEvent('changed', this, state);
3637 // show a panel if it's registered and related..
3639 if (!this.navId || !this.tabId || !state || is_was_active) {
3643 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3647 var pan = tg.getPanelByName(this.tabId);
3651 // if we can not flip to new panel - go back to old nav highlight..
3652 if (false == tg.showPanel(pan)) {
3653 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3655 var onav = nv.getWasActive();
3657 onav.setActive(true, false, true);
3666 // this should not be here...
3667 setDisabled : function(state)
3669 this.disabled = state;
3671 this.el.removeClass('disabled');
3672 } else if (!this.el.hasClass('disabled')) {
3673 this.el.addClass('disabled');
3686 * <span> icon </span>
3687 * <span> text </span>
3688 * <span>badge </span>
3692 * @class Roo.bootstrap.NavSidebarItem
3693 * @extends Roo.bootstrap.NavItem
3694 * Bootstrap Navbar.NavSidebarItem class
3696 * Create a new Navbar Button
3697 * @param {Object} config The config object
3699 Roo.bootstrap.NavSidebarItem = function(config){
3700 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3705 * The raw click event for the entire grid.
3706 * @param {Roo.EventObject} e
3711 * Fires when the active item active state changes
3712 * @param {Roo.bootstrap.NavSidebarItem} this
3713 * @param {boolean} state the new state
3721 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3724 getAutoCreate : function(){
3729 href : this.href || '#',
3741 html : this.html || ''
3746 cfg.cls += ' active';
3750 if (this.glyphicon || this.icon) {
3751 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3752 a.cn.push({ tag : 'i', cls : c }) ;
3757 if (this.badge !== '') {
3758 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3762 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3763 a.cls += 'dropdown-toggle treeview' ;
3787 * @class Roo.bootstrap.Row
3788 * @extends Roo.bootstrap.Component
3789 * Bootstrap Row class (contains columns...)
3793 * @param {Object} config The config object
3796 Roo.bootstrap.Row = function(config){
3797 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3800 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3802 getAutoCreate : function(){
3821 * @class Roo.bootstrap.Element
3822 * @extends Roo.bootstrap.Component
3823 * Bootstrap Element class
3824 * @cfg {String} html contents of the element
3825 * @cfg {String} tag tag of the element
3826 * @cfg {String} cls class of the element
3829 * Create a new Element
3830 * @param {Object} config The config object
3833 Roo.bootstrap.Element = function(config){
3834 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3837 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3844 getAutoCreate : function(){
3869 * @class Roo.bootstrap.Pagination
3870 * @extends Roo.bootstrap.Component
3871 * Bootstrap Pagination class
3872 * @cfg {String} size xs | sm | md | lg
3873 * @cfg {Boolean} inverse false | true
3876 * Create a new Pagination
3877 * @param {Object} config The config object
3880 Roo.bootstrap.Pagination = function(config){
3881 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3884 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3890 getAutoCreate : function(){
3896 cfg.cls += ' inverse';
3902 cfg.cls += " " + this.cls;
3920 * @class Roo.bootstrap.PaginationItem
3921 * @extends Roo.bootstrap.Component
3922 * Bootstrap PaginationItem class
3923 * @cfg {String} html text
3924 * @cfg {String} href the link
3925 * @cfg {Boolean} preventDefault (true | false) default true
3926 * @cfg {Boolean} active (true | false) default false
3930 * Create a new PaginationItem
3931 * @param {Object} config The config object
3935 Roo.bootstrap.PaginationItem = function(config){
3936 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3941 * The raw click event for the entire grid.
3942 * @param {Roo.EventObject} e
3948 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3952 preventDefault: true,
3956 getAutoCreate : function(){
3962 href : this.href ? this.href : '#',
3963 html : this.html ? this.html : ''
3973 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3979 initEvents: function() {
3981 this.el.on('click', this.onClick, this);
3984 onClick : function(e)
3986 Roo.log('PaginationItem on click ');
3987 if(this.preventDefault){
3991 this.fireEvent('click', this, e);
4007 * @class Roo.bootstrap.Slider
4008 * @extends Roo.bootstrap.Component
4009 * Bootstrap Slider class
4012 * Create a new Slider
4013 * @param {Object} config The config object
4016 Roo.bootstrap.Slider = function(config){
4017 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4020 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4022 getAutoCreate : function(){
4026 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4030 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4042 * Ext JS Library 1.1.1
4043 * Copyright(c) 2006-2007, Ext JS, LLC.
4045 * Originally Released Under LGPL - original licence link has changed is not relivant.
4048 * <script type="text/javascript">
4053 * @class Roo.grid.ColumnModel
4054 * @extends Roo.util.Observable
4055 * This is the default implementation of a ColumnModel used by the Grid. It defines
4056 * the columns in the grid.
4059 var colModel = new Roo.grid.ColumnModel([
4060 {header: "Ticker", width: 60, sortable: true, locked: true},
4061 {header: "Company Name", width: 150, sortable: true},
4062 {header: "Market Cap.", width: 100, sortable: true},
4063 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4064 {header: "Employees", width: 100, sortable: true, resizable: false}
4069 * The config options listed for this class are options which may appear in each
4070 * individual column definition.
4071 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4073 * @param {Object} config An Array of column config objects. See this class's
4074 * config objects for details.
4076 Roo.grid.ColumnModel = function(config){
4078 * The config passed into the constructor
4080 this.config = config;
4083 // if no id, create one
4084 // if the column does not have a dataIndex mapping,
4085 // map it to the order it is in the config
4086 for(var i = 0, len = config.length; i < len; i++){
4088 if(typeof c.dataIndex == "undefined"){
4091 if(typeof c.renderer == "string"){
4092 c.renderer = Roo.util.Format[c.renderer];
4094 if(typeof c.id == "undefined"){
4097 if(c.editor && c.editor.xtype){
4098 c.editor = Roo.factory(c.editor, Roo.grid);
4100 if(c.editor && c.editor.isFormField){
4101 c.editor = new Roo.grid.GridEditor(c.editor);
4103 this.lookup[c.id] = c;
4107 * The width of columns which have no width specified (defaults to 100)
4110 this.defaultWidth = 100;
4113 * Default sortable of columns which have no sortable specified (defaults to false)
4116 this.defaultSortable = false;
4120 * @event widthchange
4121 * Fires when the width of a column changes.
4122 * @param {ColumnModel} this
4123 * @param {Number} columnIndex The column index
4124 * @param {Number} newWidth The new width
4126 "widthchange": true,
4128 * @event headerchange
4129 * Fires when the text of a header changes.
4130 * @param {ColumnModel} this
4131 * @param {Number} columnIndex The column index
4132 * @param {Number} newText The new header text
4134 "headerchange": true,
4136 * @event hiddenchange
4137 * Fires when a column is hidden or "unhidden".
4138 * @param {ColumnModel} this
4139 * @param {Number} columnIndex The column index
4140 * @param {Boolean} hidden true if hidden, false otherwise
4142 "hiddenchange": true,
4144 * @event columnmoved
4145 * Fires when a column is moved.
4146 * @param {ColumnModel} this
4147 * @param {Number} oldIndex
4148 * @param {Number} newIndex
4150 "columnmoved" : true,
4152 * @event columlockchange
4153 * Fires when a column's locked state is changed
4154 * @param {ColumnModel} this
4155 * @param {Number} colIndex
4156 * @param {Boolean} locked true if locked
4158 "columnlockchange" : true
4160 Roo.grid.ColumnModel.superclass.constructor.call(this);
4162 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4164 * @cfg {String} header The header text to display in the Grid view.
4167 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4168 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4169 * specified, the column's index is used as an index into the Record's data Array.
4172 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4173 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4176 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4177 * Defaults to the value of the {@link #defaultSortable} property.
4178 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4181 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4184 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4187 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4190 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4193 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4194 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4195 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4196 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4199 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4202 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4206 * Returns the id of the column at the specified index.
4207 * @param {Number} index The column index
4208 * @return {String} the id
4210 getColumnId : function(index){
4211 return this.config[index].id;
4215 * Returns the column for a specified id.
4216 * @param {String} id The column id
4217 * @return {Object} the column
4219 getColumnById : function(id){
4220 return this.lookup[id];
4225 * Returns the column for a specified dataIndex.
4226 * @param {String} dataIndex The column dataIndex
4227 * @return {Object|Boolean} the column or false if not found
4229 getColumnByDataIndex: function(dataIndex){
4230 var index = this.findColumnIndex(dataIndex);
4231 return index > -1 ? this.config[index] : false;
4235 * Returns the index for a specified column id.
4236 * @param {String} id The column id
4237 * @return {Number} the index, or -1 if not found
4239 getIndexById : function(id){
4240 for(var i = 0, len = this.config.length; i < len; i++){
4241 if(this.config[i].id == id){
4249 * Returns the index for a specified column dataIndex.
4250 * @param {String} dataIndex The column dataIndex
4251 * @return {Number} the index, or -1 if not found
4254 findColumnIndex : function(dataIndex){
4255 for(var i = 0, len = this.config.length; i < len; i++){
4256 if(this.config[i].dataIndex == dataIndex){
4264 moveColumn : function(oldIndex, newIndex){
4265 var c = this.config[oldIndex];
4266 this.config.splice(oldIndex, 1);
4267 this.config.splice(newIndex, 0, c);
4268 this.dataMap = null;
4269 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4272 isLocked : function(colIndex){
4273 return this.config[colIndex].locked === true;
4276 setLocked : function(colIndex, value, suppressEvent){
4277 if(this.isLocked(colIndex) == value){
4280 this.config[colIndex].locked = value;
4282 this.fireEvent("columnlockchange", this, colIndex, value);
4286 getTotalLockedWidth : function(){
4288 for(var i = 0; i < this.config.length; i++){
4289 if(this.isLocked(i) && !this.isHidden(i)){
4290 this.totalWidth += this.getColumnWidth(i);
4296 getLockedCount : function(){
4297 for(var i = 0, len = this.config.length; i < len; i++){
4298 if(!this.isLocked(i)){
4305 * Returns the number of columns.
4308 getColumnCount : function(visibleOnly){
4309 if(visibleOnly === true){
4311 for(var i = 0, len = this.config.length; i < len; i++){
4312 if(!this.isHidden(i)){
4318 return this.config.length;
4322 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4323 * @param {Function} fn
4324 * @param {Object} scope (optional)
4325 * @return {Array} result
4327 getColumnsBy : function(fn, scope){
4329 for(var i = 0, len = this.config.length; i < len; i++){
4330 var c = this.config[i];
4331 if(fn.call(scope||this, c, i) === true){
4339 * Returns true if the specified column is sortable.
4340 * @param {Number} col The column index
4343 isSortable : function(col){
4344 if(typeof this.config[col].sortable == "undefined"){
4345 return this.defaultSortable;
4347 return this.config[col].sortable;
4351 * Returns the rendering (formatting) function defined for the column.
4352 * @param {Number} col The column index.
4353 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4355 getRenderer : function(col){
4356 if(!this.config[col].renderer){
4357 return Roo.grid.ColumnModel.defaultRenderer;
4359 return this.config[col].renderer;
4363 * Sets the rendering (formatting) function for a column.
4364 * @param {Number} col The column index
4365 * @param {Function} fn The function to use to process the cell's raw data
4366 * to return HTML markup for the grid view. The render function is called with
4367 * the following parameters:<ul>
4368 * <li>Data value.</li>
4369 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4370 * <li>css A CSS style string to apply to the table cell.</li>
4371 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4372 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4373 * <li>Row index</li>
4374 * <li>Column index</li>
4375 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4377 setRenderer : function(col, fn){
4378 this.config[col].renderer = fn;
4382 * Returns the width for the specified column.
4383 * @param {Number} col The column index
4386 getColumnWidth : function(col){
4387 return this.config[col].width * 1 || this.defaultWidth;
4391 * Sets the width for a column.
4392 * @param {Number} col The column index
4393 * @param {Number} width The new width
4395 setColumnWidth : function(col, width, suppressEvent){
4396 this.config[col].width = width;
4397 this.totalWidth = null;
4399 this.fireEvent("widthchange", this, col, width);
4404 * Returns the total width of all columns.
4405 * @param {Boolean} includeHidden True to include hidden column widths
4408 getTotalWidth : function(includeHidden){
4409 if(!this.totalWidth){
4410 this.totalWidth = 0;
4411 for(var i = 0, len = this.config.length; i < len; i++){
4412 if(includeHidden || !this.isHidden(i)){
4413 this.totalWidth += this.getColumnWidth(i);
4417 return this.totalWidth;
4421 * Returns the header for the specified column.
4422 * @param {Number} col The column index
4425 getColumnHeader : function(col){
4426 return this.config[col].header;
4430 * Sets the header for a column.
4431 * @param {Number} col The column index
4432 * @param {String} header The new header
4434 setColumnHeader : function(col, header){
4435 this.config[col].header = header;
4436 this.fireEvent("headerchange", this, col, header);
4440 * Returns the tooltip for the specified column.
4441 * @param {Number} col The column index
4444 getColumnTooltip : function(col){
4445 return this.config[col].tooltip;
4448 * Sets the tooltip for a column.
4449 * @param {Number} col The column index
4450 * @param {String} tooltip The new tooltip
4452 setColumnTooltip : function(col, tooltip){
4453 this.config[col].tooltip = tooltip;
4457 * Returns the dataIndex for the specified column.
4458 * @param {Number} col The column index
4461 getDataIndex : function(col){
4462 return this.config[col].dataIndex;
4466 * Sets the dataIndex for a column.
4467 * @param {Number} col The column index
4468 * @param {Number} dataIndex The new dataIndex
4470 setDataIndex : function(col, dataIndex){
4471 this.config[col].dataIndex = dataIndex;
4477 * Returns true if the cell is editable.
4478 * @param {Number} colIndex The column index
4479 * @param {Number} rowIndex The row index
4482 isCellEditable : function(colIndex, rowIndex){
4483 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4487 * Returns the editor defined for the cell/column.
4488 * return false or null to disable editing.
4489 * @param {Number} colIndex The column index
4490 * @param {Number} rowIndex The row index
4493 getCellEditor : function(colIndex, rowIndex){
4494 return this.config[colIndex].editor;
4498 * Sets if a column is editable.
4499 * @param {Number} col The column index
4500 * @param {Boolean} editable True if the column is editable
4502 setEditable : function(col, editable){
4503 this.config[col].editable = editable;
4508 * Returns true if the column is hidden.
4509 * @param {Number} colIndex The column index
4512 isHidden : function(colIndex){
4513 return this.config[colIndex].hidden;
4518 * Returns true if the column width cannot be changed
4520 isFixed : function(colIndex){
4521 return this.config[colIndex].fixed;
4525 * Returns true if the column can be resized
4528 isResizable : function(colIndex){
4529 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4532 * Sets if a column is hidden.
4533 * @param {Number} colIndex The column index
4534 * @param {Boolean} hidden True if the column is hidden
4536 setHidden : function(colIndex, hidden){
4537 this.config[colIndex].hidden = hidden;
4538 this.totalWidth = null;
4539 this.fireEvent("hiddenchange", this, colIndex, hidden);
4543 * Sets the editor for a column.
4544 * @param {Number} col The column index
4545 * @param {Object} editor The editor object
4547 setEditor : function(col, editor){
4548 this.config[col].editor = editor;
4552 Roo.grid.ColumnModel.defaultRenderer = function(value){
4553 if(typeof value == "string" && value.length < 1){
4559 // Alias for backwards compatibility
4560 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4563 * Ext JS Library 1.1.1
4564 * Copyright(c) 2006-2007, Ext JS, LLC.
4566 * Originally Released Under LGPL - original licence link has changed is not relivant.
4569 * <script type="text/javascript">
4573 * @class Roo.LoadMask
4574 * A simple utility class for generically masking elements while loading data. If the element being masked has
4575 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4576 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4577 * element's UpdateManager load indicator and will be destroyed after the initial load.
4579 * Create a new LoadMask
4580 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4581 * @param {Object} config The config object
4583 Roo.LoadMask = function(el, config){
4584 this.el = Roo.get(el);
4585 Roo.apply(this, config);
4587 this.store.on('beforeload', this.onBeforeLoad, this);
4588 this.store.on('load', this.onLoad, this);
4589 this.store.on('loadexception', this.onLoadException, this);
4590 this.removeMask = false;
4592 var um = this.el.getUpdateManager();
4593 um.showLoadIndicator = false; // disable the default indicator
4594 um.on('beforeupdate', this.onBeforeLoad, this);
4595 um.on('update', this.onLoad, this);
4596 um.on('failure', this.onLoad, this);
4597 this.removeMask = true;
4601 Roo.LoadMask.prototype = {
4603 * @cfg {Boolean} removeMask
4604 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4605 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4609 * The text to display in a centered loading message box (defaults to 'Loading...')
4613 * @cfg {String} msgCls
4614 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4616 msgCls : 'x-mask-loading',
4619 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4625 * Disables the mask to prevent it from being displayed
4627 disable : function(){
4628 this.disabled = true;
4632 * Enables the mask so that it can be displayed
4634 enable : function(){
4635 this.disabled = false;
4638 onLoadException : function()
4642 if (typeof(arguments[3]) != 'undefined') {
4643 Roo.MessageBox.alert("Error loading",arguments[3]);
4647 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4648 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4657 this.el.unmask(this.removeMask);
4662 this.el.unmask(this.removeMask);
4666 onBeforeLoad : function(){
4668 this.el.mask(this.msg, this.msgCls);
4673 destroy : function(){
4675 this.store.un('beforeload', this.onBeforeLoad, this);
4676 this.store.un('load', this.onLoad, this);
4677 this.store.un('loadexception', this.onLoadException, this);
4679 var um = this.el.getUpdateManager();
4680 um.un('beforeupdate', this.onBeforeLoad, this);
4681 um.un('update', this.onLoad, this);
4682 um.un('failure', this.onLoad, this);
4693 * @class Roo.bootstrap.Table
4694 * @extends Roo.bootstrap.Component
4695 * Bootstrap Table class
4696 * @cfg {String} cls table class
4697 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4698 * @cfg {String} bgcolor Specifies the background color for a table
4699 * @cfg {Number} border Specifies whether the table cells should have borders or not
4700 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4701 * @cfg {Number} cellspacing Specifies the space between cells
4702 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4703 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4704 * @cfg {String} sortable Specifies that the table should be sortable
4705 * @cfg {String} summary Specifies a summary of the content of a table
4706 * @cfg {Number} width Specifies the width of a table
4707 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4709 * @cfg {boolean} striped Should the rows be alternative striped
4710 * @cfg {boolean} bordered Add borders to the table
4711 * @cfg {boolean} hover Add hover highlighting
4712 * @cfg {boolean} condensed Format condensed
4713 * @cfg {boolean} responsive Format condensed
4714 * @cfg {Boolean} loadMask (true|false) default false
4715 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4716 * @cfg {Boolean} thead (true|false) generate thead, default true
4717 * @cfg {Boolean} RowSelection (true|false) default false
4718 * @cfg {Boolean} CellSelection (true|false) default false
4720 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4724 * Create a new Table
4725 * @param {Object} config The config object
4728 Roo.bootstrap.Table = function(config){
4729 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4732 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4733 this.sm = this.selModel;
4734 this.sm.xmodule = this.xmodule || false;
4736 if (this.cm && typeof(this.cm.config) == 'undefined') {
4737 this.colModel = new Roo.grid.ColumnModel(this.cm);
4738 this.cm = this.colModel;
4739 this.cm.xmodule = this.xmodule || false;
4742 this.store= Roo.factory(this.store, Roo.data);
4743 this.ds = this.store;
4744 this.ds.xmodule = this.xmodule || false;
4747 if (this.footer && this.store) {
4748 this.footer.dataSource = this.ds;
4749 this.footer = Roo.factory(this.footer);
4756 * Fires when a cell is clicked
4757 * @param {Roo.bootstrap.Table} this
4758 * @param {Roo.Element} el
4759 * @param {Number} rowIndex
4760 * @param {Number} columnIndex
4761 * @param {Roo.EventObject} e
4765 * @event celldblclick
4766 * Fires when a cell is double clicked
4767 * @param {Roo.bootstrap.Table} this
4768 * @param {Roo.Element} el
4769 * @param {Number} rowIndex
4770 * @param {Number} columnIndex
4771 * @param {Roo.EventObject} e
4773 "celldblclick" : true,
4776 * Fires when a row is clicked
4777 * @param {Roo.bootstrap.Table} this
4778 * @param {Roo.Element} el
4779 * @param {Number} rowIndex
4780 * @param {Roo.EventObject} e
4784 * @event rowdblclick
4785 * Fires when a row is double clicked
4786 * @param {Roo.bootstrap.Table} this
4787 * @param {Roo.Element} el
4788 * @param {Number} rowIndex
4789 * @param {Roo.EventObject} e
4791 "rowdblclick" : true,
4794 * Fires when a mouseover occur
4795 * @param {Roo.bootstrap.Table} this
4796 * @param {Roo.Element} el
4797 * @param {Number} rowIndex
4798 * @param {Number} columnIndex
4799 * @param {Roo.EventObject} e
4804 * Fires when a mouseout occur
4805 * @param {Roo.bootstrap.Table} this
4806 * @param {Roo.Element} el
4807 * @param {Number} rowIndex
4808 * @param {Number} columnIndex
4809 * @param {Roo.EventObject} e
4814 * Fires when a row is rendered, so you can change add a style to it.
4815 * @param {Roo.bootstrap.Table} this
4816 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4823 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4847 RowSelection : false,
4848 CellSelection : false,
4851 // Roo.Element - the tbody
4854 getAutoCreate : function(){
4855 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4864 cfg.cls += ' table-striped';
4868 cfg.cls += ' table-hover';
4870 if (this.bordered) {
4871 cfg.cls += ' table-bordered';
4873 if (this.condensed) {
4874 cfg.cls += ' table-condensed';
4876 if (this.responsive) {
4877 cfg.cls += ' table-responsive';
4881 cfg.cls+= ' ' +this.cls;
4884 // this lot should be simplifed...
4887 cfg.align=this.align;
4890 cfg.bgcolor=this.bgcolor;
4893 cfg.border=this.border;
4895 if (this.cellpadding) {
4896 cfg.cellpadding=this.cellpadding;
4898 if (this.cellspacing) {
4899 cfg.cellspacing=this.cellspacing;
4902 cfg.frame=this.frame;
4905 cfg.rules=this.rules;
4907 if (this.sortable) {
4908 cfg.sortable=this.sortable;
4911 cfg.summary=this.summary;
4914 cfg.width=this.width;
4917 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4920 if(this.store || this.cm){
4922 cfg.cn.push(this.renderHeader());
4925 cfg.cn.push(this.renderBody());
4928 cfg.cn.push(this.renderFooter());
4931 cfg.cls+= ' TableGrid';
4934 return { cn : [ cfg ] };
4937 initEvents : function()
4939 if(!this.store || !this.cm){
4943 //Roo.log('initEvents with ds!!!!');
4945 this.mainBody = this.el.select('tbody', true).first();
4950 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4951 e.on('click', _this.sort, _this);
4954 this.el.on("click", this.onClick, this);
4955 this.el.on("dblclick", this.onDblClick, this);
4957 this.parent().el.setStyle('position', 'relative');
4959 this.footer.parentId = this.id;
4960 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4963 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4965 this.store.on('load', this.onLoad, this);
4966 this.store.on('beforeload', this.onBeforeLoad, this);
4967 this.store.on('update', this.onUpdate, this);
4971 onMouseover : function(e, el)
4973 var cell = Roo.get(el);
4979 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4980 cell = cell.findParent('td', false, true);
4983 var row = cell.findParent('tr', false, true);
4984 var cellIndex = cell.dom.cellIndex;
4985 var rowIndex = row.dom.rowIndex - 1; // start from 0
4987 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4991 onMouseout : function(e, el)
4993 var cell = Roo.get(el);
4999 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5000 cell = cell.findParent('td', false, true);
5003 var row = cell.findParent('tr', false, true);
5004 var cellIndex = cell.dom.cellIndex;
5005 var rowIndex = row.dom.rowIndex - 1; // start from 0
5007 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5011 onClick : function(e, el)
5013 var cell = Roo.get(el);
5015 if(!cell || (!this.CellSelection && !this.RowSelection)){
5020 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5021 cell = cell.findParent('td', false, true);
5024 var row = cell.findParent('tr', false, true);
5025 var cellIndex = cell.dom.cellIndex;
5026 var rowIndex = row.dom.rowIndex - 1;
5028 if(this.CellSelection){
5029 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5032 if(this.RowSelection){
5033 this.fireEvent('rowclick', this, row, rowIndex, e);
5039 onDblClick : function(e,el)
5041 var cell = Roo.get(el);
5043 if(!cell || (!this.CellSelection && !this.RowSelection)){
5047 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5048 cell = cell.findParent('td', false, true);
5051 var row = cell.findParent('tr', false, true);
5052 var cellIndex = cell.dom.cellIndex;
5053 var rowIndex = row.dom.rowIndex - 1;
5055 if(this.CellSelection){
5056 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5059 if(this.RowSelection){
5060 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5064 sort : function(e,el)
5066 var col = Roo.get(el)
5068 if(!col.hasClass('sortable')){
5072 var sort = col.attr('sort');
5075 if(col.hasClass('glyphicon-arrow-up')){
5079 this.store.sortInfo = {field : sort, direction : dir};
5082 Roo.log("calling footer first");
5083 this.footer.onClick('first');
5086 this.store.load({ params : { start : 0 } });
5090 renderHeader : function()
5099 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5101 var config = cm.config[i];
5106 html: cm.getColumnHeader(i)
5109 if(typeof(config.hidden) != 'undefined' && config.hidden){
5110 c.style += ' display:none;';
5113 if(typeof(config.dataIndex) != 'undefined'){
5114 c.sort = config.dataIndex;
5117 if(typeof(config.sortable) != 'undefined' && config.sortable){
5121 if(typeof(config.align) != 'undefined' && config.align.length){
5122 c.style += ' text-align:' + config.align + ';';
5125 if(typeof(config.width) != 'undefined'){
5126 c.style += ' width:' + config.width + 'px;';
5135 renderBody : function()
5145 colspan : this.cm.getColumnCount()
5155 renderFooter : function()
5165 colspan : this.cm.getColumnCount()
5179 Roo.log('ds onload');
5184 var ds = this.store;
5186 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5187 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5189 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5190 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5193 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5194 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5198 var tbody = this.mainBody;
5200 if(ds.getCount() > 0){
5201 ds.data.each(function(d,rowIndex){
5202 var row = this.renderRow(cm, ds, rowIndex);
5204 tbody.createChild(row);
5208 if(row.cellObjects.length){
5209 Roo.each(row.cellObjects, function(r){
5210 _this.renderCellObject(r);
5217 Roo.each(this.el.select('tbody td', true).elements, function(e){
5218 e.on('mouseover', _this.onMouseover, _this);
5221 Roo.each(this.el.select('tbody td', true).elements, function(e){
5222 e.on('mouseout', _this.onMouseout, _this);
5225 //if(this.loadMask){
5226 // this.maskEl.hide();
5231 onUpdate : function(ds,record)
5233 this.refreshRow(record);
5235 onRemove : function(ds, record, index, isUpdate){
5236 if(isUpdate !== true){
5237 this.fireEvent("beforerowremoved", this, index, record);
5239 var bt = this.mainBody.dom;
5241 bt.removeChild(bt.rows[index]);
5244 if(isUpdate !== true){
5245 //this.stripeRows(index);
5246 //this.syncRowHeights(index, index);
5248 this.fireEvent("rowremoved", this, index, record);
5253 refreshRow : function(record){
5254 var ds = this.store, index;
5255 if(typeof record == 'number'){
5257 record = ds.getAt(index);
5259 index = ds.indexOf(record);
5261 this.insertRow(ds, index, true);
5262 this.onRemove(ds, record, index+1, true);
5263 //this.syncRowHeights(index, index);
5265 this.fireEvent("rowupdated", this, index, record);
5268 insertRow : function(dm, rowIndex, isUpdate){
5271 this.fireEvent("beforerowsinserted", this, rowIndex);
5273 //var s = this.getScrollState();
5274 var row = this.renderRow(this.cm, this.store, rowIndex);
5275 // insert before rowIndex..
5276 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5280 if(row.cellObjects.length){
5281 Roo.each(row.cellObjects, function(r){
5282 _this.renderCellObject(r);
5287 this.fireEvent("rowsinserted", this, rowIndex);
5288 //this.syncRowHeights(firstRow, lastRow);
5289 //this.stripeRows(firstRow);
5296 getRowDom : function(rowIndex)
5298 // not sure if I need to check this.. but let's do it anyway..
5299 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5300 this.mainBody.dom.rows[rowIndex] : false
5302 // returns the object tree for a tr..
5305 renderRow : function(cm, ds, rowIndex) {
5307 var d = ds.getAt(rowIndex);
5314 var cellObjects = [];
5316 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5317 var config = cm.config[i];
5319 var renderer = cm.getRenderer(i);
5323 if(typeof(renderer) !== 'undefined'){
5324 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5326 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5327 // and are rendered into the cells after the row is rendered - using the id for the element.
5329 if(typeof(value) === 'object'){
5339 rowIndex : rowIndex,
5344 this.fireEvent('rowclass', this, rowcfg);
5348 cls : rowcfg.rowClass,
5350 html: (typeof(value) === 'object') ? '' : value
5357 if(typeof(config.hidden) != 'undefined' && config.hidden){
5358 td.style += ' display:none;';
5361 if(typeof(config.align) != 'undefined' && config.align.length){
5362 td.style += ' text-align:' + config.align + ';';
5365 if(typeof(config.width) != 'undefined'){
5366 td.style += ' width:' + config.width + 'px;';
5373 row.cellObjects = cellObjects;
5381 onBeforeLoad : function()
5383 //Roo.log('ds onBeforeLoad');
5387 //if(this.loadMask){
5388 // this.maskEl.show();
5394 this.el.select('tbody', true).first().dom.innerHTML = '';
5397 getSelectionModel : function(){
5399 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5401 return this.selModel;
5404 * Render the Roo.bootstrap object from renderder
5406 renderCellObject : function(r)
5410 var t = r.cfg.render(r.container);
5413 Roo.each(r.cfg.cn, function(c){
5415 container: t.getChildContainer(),
5418 _this.renderCellObject(child);
5435 * @class Roo.bootstrap.TableCell
5436 * @extends Roo.bootstrap.Component
5437 * Bootstrap TableCell class
5438 * @cfg {String} html cell contain text
5439 * @cfg {String} cls cell class
5440 * @cfg {String} tag cell tag (td|th) default td
5441 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5442 * @cfg {String} align Aligns the content in a cell
5443 * @cfg {String} axis Categorizes cells
5444 * @cfg {String} bgcolor Specifies the background color of a cell
5445 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5446 * @cfg {Number} colspan Specifies the number of columns a cell should span
5447 * @cfg {String} headers Specifies one or more header cells a cell is related to
5448 * @cfg {Number} height Sets the height of a cell
5449 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5450 * @cfg {Number} rowspan Sets the number of rows a cell should span
5451 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5452 * @cfg {String} valign Vertical aligns the content in a cell
5453 * @cfg {Number} width Specifies the width of a cell
5456 * Create a new TableCell
5457 * @param {Object} config The config object
5460 Roo.bootstrap.TableCell = function(config){
5461 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5464 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5484 getAutoCreate : function(){
5485 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5505 cfg.align=this.align
5511 cfg.bgcolor=this.bgcolor
5514 cfg.charoff=this.charoff
5517 cfg.colspan=this.colspan
5520 cfg.headers=this.headers
5523 cfg.height=this.height
5526 cfg.nowrap=this.nowrap
5529 cfg.rowspan=this.rowspan
5532 cfg.scope=this.scope
5535 cfg.valign=this.valign
5538 cfg.width=this.width
5557 * @class Roo.bootstrap.TableRow
5558 * @extends Roo.bootstrap.Component
5559 * Bootstrap TableRow class
5560 * @cfg {String} cls row class
5561 * @cfg {String} align Aligns the content in a table row
5562 * @cfg {String} bgcolor Specifies a background color for a table row
5563 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5564 * @cfg {String} valign Vertical aligns the content in a table row
5567 * Create a new TableRow
5568 * @param {Object} config The config object
5571 Roo.bootstrap.TableRow = function(config){
5572 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5575 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5583 getAutoCreate : function(){
5584 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5594 cfg.align = this.align;
5597 cfg.bgcolor = this.bgcolor;
5600 cfg.charoff = this.charoff;
5603 cfg.valign = this.valign;
5621 * @class Roo.bootstrap.TableBody
5622 * @extends Roo.bootstrap.Component
5623 * Bootstrap TableBody class
5624 * @cfg {String} cls element class
5625 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5626 * @cfg {String} align Aligns the content inside the element
5627 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5628 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5631 * Create a new TableBody
5632 * @param {Object} config The config object
5635 Roo.bootstrap.TableBody = function(config){
5636 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5639 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5647 getAutoCreate : function(){
5648 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5662 cfg.align = this.align;
5665 cfg.charoff = this.charoff;
5668 cfg.valign = this.valign;
5675 // initEvents : function()
5682 // this.store = Roo.factory(this.store, Roo.data);
5683 // this.store.on('load', this.onLoad, this);
5685 // this.store.load();
5689 // onLoad: function ()
5691 // this.fireEvent('load', this);
5701 * Ext JS Library 1.1.1
5702 * Copyright(c) 2006-2007, Ext JS, LLC.
5704 * Originally Released Under LGPL - original licence link has changed is not relivant.
5707 * <script type="text/javascript">
5710 // as we use this in bootstrap.
5711 Roo.namespace('Roo.form');
5713 * @class Roo.form.Action
5714 * Internal Class used to handle form actions
5716 * @param {Roo.form.BasicForm} el The form element or its id
5717 * @param {Object} config Configuration options
5722 // define the action interface
5723 Roo.form.Action = function(form, options){
5725 this.options = options || {};
5728 * Client Validation Failed
5731 Roo.form.Action.CLIENT_INVALID = 'client';
5733 * Server Validation Failed
5736 Roo.form.Action.SERVER_INVALID = 'server';
5738 * Connect to Server Failed
5741 Roo.form.Action.CONNECT_FAILURE = 'connect';
5743 * Reading Data from Server Failed
5746 Roo.form.Action.LOAD_FAILURE = 'load';
5748 Roo.form.Action.prototype = {
5750 failureType : undefined,
5751 response : undefined,
5755 run : function(options){
5760 success : function(response){
5765 handleResponse : function(response){
5769 // default connection failure
5770 failure : function(response){
5772 this.response = response;
5773 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5774 this.form.afterAction(this, false);
5777 processResponse : function(response){
5778 this.response = response;
5779 if(!response.responseText){
5782 this.result = this.handleResponse(response);
5786 // utility functions used internally
5787 getUrl : function(appendParams){
5788 var url = this.options.url || this.form.url || this.form.el.dom.action;
5790 var p = this.getParams();
5792 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5798 getMethod : function(){
5799 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5802 getParams : function(){
5803 var bp = this.form.baseParams;
5804 var p = this.options.params;
5806 if(typeof p == "object"){
5807 p = Roo.urlEncode(Roo.applyIf(p, bp));
5808 }else if(typeof p == 'string' && bp){
5809 p += '&' + Roo.urlEncode(bp);
5812 p = Roo.urlEncode(bp);
5817 createCallback : function(){
5819 success: this.success,
5820 failure: this.failure,
5822 timeout: (this.form.timeout*1000),
5823 upload: this.form.fileUpload ? this.success : undefined
5828 Roo.form.Action.Submit = function(form, options){
5829 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5832 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5835 haveProgress : false,
5836 uploadComplete : false,
5838 // uploadProgress indicator.
5839 uploadProgress : function()
5841 if (!this.form.progressUrl) {
5845 if (!this.haveProgress) {
5846 Roo.MessageBox.progress("Uploading", "Uploading");
5848 if (this.uploadComplete) {
5849 Roo.MessageBox.hide();
5853 this.haveProgress = true;
5855 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5857 var c = new Roo.data.Connection();
5859 url : this.form.progressUrl,
5864 success : function(req){
5865 //console.log(data);
5869 rdata = Roo.decode(req.responseText)
5871 Roo.log("Invalid data from server..");
5875 if (!rdata || !rdata.success) {
5877 Roo.MessageBox.alert(Roo.encode(rdata));
5880 var data = rdata.data;
5882 if (this.uploadComplete) {
5883 Roo.MessageBox.hide();
5888 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5889 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5892 this.uploadProgress.defer(2000,this);
5895 failure: function(data) {
5896 Roo.log('progress url failed ');
5907 // run get Values on the form, so it syncs any secondary forms.
5908 this.form.getValues();
5910 var o = this.options;
5911 var method = this.getMethod();
5912 var isPost = method == 'POST';
5913 if(o.clientValidation === false || this.form.isValid()){
5915 if (this.form.progressUrl) {
5916 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5917 (new Date() * 1) + '' + Math.random());
5922 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5923 form:this.form.el.dom,
5924 url:this.getUrl(!isPost),
5926 params:isPost ? this.getParams() : null,
5927 isUpload: this.form.fileUpload
5930 this.uploadProgress();
5932 }else if (o.clientValidation !== false){ // client validation failed
5933 this.failureType = Roo.form.Action.CLIENT_INVALID;
5934 this.form.afterAction(this, false);
5938 success : function(response)
5940 this.uploadComplete= true;
5941 if (this.haveProgress) {
5942 Roo.MessageBox.hide();
5946 var result = this.processResponse(response);
5947 if(result === true || result.success){
5948 this.form.afterAction(this, true);
5952 this.form.markInvalid(result.errors);
5953 this.failureType = Roo.form.Action.SERVER_INVALID;
5955 this.form.afterAction(this, false);
5957 failure : function(response)
5959 this.uploadComplete= true;
5960 if (this.haveProgress) {
5961 Roo.MessageBox.hide();
5964 this.response = response;
5965 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5966 this.form.afterAction(this, false);
5969 handleResponse : function(response){
5970 if(this.form.errorReader){
5971 var rs = this.form.errorReader.read(response);
5974 for(var i = 0, len = rs.records.length; i < len; i++) {
5975 var r = rs.records[i];
5979 if(errors.length < 1){
5983 success : rs.success,
5989 ret = Roo.decode(response.responseText);
5993 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6003 Roo.form.Action.Load = function(form, options){
6004 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6005 this.reader = this.form.reader;
6008 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6013 Roo.Ajax.request(Roo.apply(
6014 this.createCallback(), {
6015 method:this.getMethod(),
6016 url:this.getUrl(false),
6017 params:this.getParams()
6021 success : function(response){
6023 var result = this.processResponse(response);
6024 if(result === true || !result.success || !result.data){
6025 this.failureType = Roo.form.Action.LOAD_FAILURE;
6026 this.form.afterAction(this, false);
6029 this.form.clearInvalid();
6030 this.form.setValues(result.data);
6031 this.form.afterAction(this, true);
6034 handleResponse : function(response){
6035 if(this.form.reader){
6036 var rs = this.form.reader.read(response);
6037 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6039 success : rs.success,
6043 return Roo.decode(response.responseText);
6047 Roo.form.Action.ACTION_TYPES = {
6048 'load' : Roo.form.Action.Load,
6049 'submit' : Roo.form.Action.Submit
6058 * @class Roo.bootstrap.Form
6059 * @extends Roo.bootstrap.Component
6060 * Bootstrap Form class
6061 * @cfg {String} method GET | POST (default POST)
6062 * @cfg {String} labelAlign top | left (default top)
6063 * @cfg {String} align left | right - for navbars
6068 * @param {Object} config The config object
6072 Roo.bootstrap.Form = function(config){
6073 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6076 * @event clientvalidation
6077 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6078 * @param {Form} this
6079 * @param {Boolean} valid true if the form has passed client-side validation
6081 clientvalidation: true,
6083 * @event beforeaction
6084 * Fires before any action is performed. Return false to cancel the action.
6085 * @param {Form} this
6086 * @param {Action} action The action to be performed
6090 * @event actionfailed
6091 * Fires when an action fails.
6092 * @param {Form} this
6093 * @param {Action} action The action that failed
6095 actionfailed : true,
6097 * @event actioncomplete
6098 * Fires when an action is completed.
6099 * @param {Form} this
6100 * @param {Action} action The action that completed
6102 actioncomplete : true
6107 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6110 * @cfg {String} method
6111 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6116 * The URL to use for form actions if one isn't supplied in the action options.
6119 * @cfg {Boolean} fileUpload
6120 * Set to true if this form is a file upload.
6124 * @cfg {Object} baseParams
6125 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6129 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6133 * @cfg {Sting} align (left|right) for navbar forms
6138 activeAction : null,
6141 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6142 * element by passing it or its id or mask the form itself by passing in true.
6145 waitMsgTarget : false,
6150 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6151 * element by passing it or its id or mask the form itself by passing in true.
6155 getAutoCreate : function(){
6159 method : this.method || 'POST',
6160 id : this.id || Roo.id(),
6163 if (this.parent().xtype.match(/^Nav/)) {
6164 cfg.cls = 'navbar-form navbar-' + this.align;
6168 if (this.labelAlign == 'left' ) {
6169 cfg.cls += ' form-horizontal';
6175 initEvents : function()
6177 this.el.on('submit', this.onSubmit, this);
6178 // this was added as random key presses on the form where triggering form submit.
6179 this.el.on('keypress', function(e) {
6180 if (e.getCharCode() != 13) {
6183 // we might need to allow it for textareas.. and some other items.
6184 // check e.getTarget().
6186 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6190 Roo.log("keypress blocked");
6198 onSubmit : function(e){
6203 * Returns true if client-side validation on the form is successful.
6206 isValid : function(){
6207 var items = this.getItems();
6209 items.each(function(f){
6218 * Returns true if any fields in this form have changed since their original load.
6221 isDirty : function(){
6223 var items = this.getItems();
6224 items.each(function(f){
6234 * Performs a predefined action (submit or load) or custom actions you define on this form.
6235 * @param {String} actionName The name of the action type
6236 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6237 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6238 * accept other config options):
6240 Property Type Description
6241 ---------------- --------------- ----------------------------------------------------------------------------------
6242 url String The url for the action (defaults to the form's url)
6243 method String The form method to use (defaults to the form's method, or POST if not defined)
6244 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6245 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6246 validate the form on the client (defaults to false)
6248 * @return {BasicForm} this
6250 doAction : function(action, options){
6251 if(typeof action == 'string'){
6252 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6254 if(this.fireEvent('beforeaction', this, action) !== false){
6255 this.beforeAction(action);
6256 action.run.defer(100, action);
6262 beforeAction : function(action){
6263 var o = action.options;
6265 // not really supported yet.. ??
6267 //if(this.waitMsgTarget === true){
6268 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6269 //}else if(this.waitMsgTarget){
6270 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6271 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6273 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6279 afterAction : function(action, success){
6280 this.activeAction = null;
6281 var o = action.options;
6283 //if(this.waitMsgTarget === true){
6285 //}else if(this.waitMsgTarget){
6286 // this.waitMsgTarget.unmask();
6288 // Roo.MessageBox.updateProgress(1);
6289 // Roo.MessageBox.hide();
6296 Roo.callback(o.success, o.scope, [this, action]);
6297 this.fireEvent('actioncomplete', this, action);
6301 // failure condition..
6302 // we have a scenario where updates need confirming.
6303 // eg. if a locking scenario exists..
6304 // we look for { errors : { needs_confirm : true }} in the response.
6306 (typeof(action.result) != 'undefined') &&
6307 (typeof(action.result.errors) != 'undefined') &&
6308 (typeof(action.result.errors.needs_confirm) != 'undefined')
6311 Roo.log("not supported yet");
6314 Roo.MessageBox.confirm(
6315 "Change requires confirmation",
6316 action.result.errorMsg,
6321 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6331 Roo.callback(o.failure, o.scope, [this, action]);
6332 // show an error message if no failed handler is set..
6333 if (!this.hasListener('actionfailed')) {
6334 Roo.log("need to add dialog support");
6336 Roo.MessageBox.alert("Error",
6337 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6338 action.result.errorMsg :
6339 "Saving Failed, please check your entries or try again"
6344 this.fireEvent('actionfailed', this, action);
6349 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6350 * @param {String} id The value to search for
6353 findField : function(id){
6354 var items = this.getItems();
6355 var field = items.get(id);
6357 items.each(function(f){
6358 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6365 return field || null;
6368 * Mark fields in this form invalid in bulk.
6369 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6370 * @return {BasicForm} this
6372 markInvalid : function(errors){
6373 if(errors instanceof Array){
6374 for(var i = 0, len = errors.length; i < len; i++){
6375 var fieldError = errors[i];
6376 var f = this.findField(fieldError.id);
6378 f.markInvalid(fieldError.msg);
6384 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6385 field.markInvalid(errors[id]);
6389 //Roo.each(this.childForms || [], function (f) {
6390 // f.markInvalid(errors);
6397 * Set values for fields in this form in bulk.
6398 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6399 * @return {BasicForm} this
6401 setValues : function(values){
6402 if(values instanceof Array){ // array of objects
6403 for(var i = 0, len = values.length; i < len; i++){
6405 var f = this.findField(v.id);
6407 f.setValue(v.value);
6408 if(this.trackResetOnLoad){
6409 f.originalValue = f.getValue();
6413 }else{ // object hash
6416 if(typeof values[id] != 'function' && (field = this.findField(id))){
6418 if (field.setFromData &&
6420 field.displayField &&
6421 // combos' with local stores can
6422 // be queried via setValue()
6423 // to set their value..
6424 (field.store && !field.store.isLocal)
6428 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6429 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6430 field.setFromData(sd);
6433 field.setValue(values[id]);
6437 if(this.trackResetOnLoad){
6438 field.originalValue = field.getValue();
6444 //Roo.each(this.childForms || [], function (f) {
6445 // f.setValues(values);
6452 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6453 * they are returned as an array.
6454 * @param {Boolean} asString
6457 getValues : function(asString){
6458 //if (this.childForms) {
6459 // copy values from the child forms
6460 // Roo.each(this.childForms, function (f) {
6461 // this.setValues(f.getValues());
6467 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6468 if(asString === true){
6471 return Roo.urlDecode(fs);
6475 * Returns the fields in this form as an object with key/value pairs.
6476 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6479 getFieldValues : function(with_hidden)
6481 var items = this.getItems();
6483 items.each(function(f){
6487 var v = f.getValue();
6488 if (f.inputType =='radio') {
6489 if (typeof(ret[f.getName()]) == 'undefined') {
6490 ret[f.getName()] = ''; // empty..
6493 if (!f.el.dom.checked) {
6501 // not sure if this supported any more..
6502 if ((typeof(v) == 'object') && f.getRawValue) {
6503 v = f.getRawValue() ; // dates..
6505 // combo boxes where name != hiddenName...
6506 if (f.name != f.getName()) {
6507 ret[f.name] = f.getRawValue();
6509 ret[f.getName()] = v;
6516 * Clears all invalid messages in this form.
6517 * @return {BasicForm} this
6519 clearInvalid : function(){
6520 var items = this.getItems();
6522 items.each(function(f){
6533 * @return {BasicForm} this
6536 var items = this.getItems();
6537 items.each(function(f){
6541 Roo.each(this.childForms || [], function (f) {
6548 getItems : function()
6550 var r=new Roo.util.MixedCollection(false, function(o){
6551 return o.id || (o.id = Roo.id());
6553 var iter = function(el) {
6560 Roo.each(el.items,function(e) {
6579 * Ext JS Library 1.1.1
6580 * Copyright(c) 2006-2007, Ext JS, LLC.
6582 * Originally Released Under LGPL - original licence link has changed is not relivant.
6585 * <script type="text/javascript">
6588 * @class Roo.form.VTypes
6589 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6592 Roo.form.VTypes = function(){
6593 // closure these in so they are only created once.
6594 var alpha = /^[a-zA-Z_]+$/;
6595 var alphanum = /^[a-zA-Z0-9_]+$/;
6596 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6597 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6599 // All these messages and functions are configurable
6602 * The function used to validate email addresses
6603 * @param {String} value The email address
6605 'email' : function(v){
6606 return email.test(v);
6609 * The error text to display when the email validation function returns false
6612 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6614 * The keystroke filter mask to be applied on email input
6617 'emailMask' : /[a-z0-9_\.\-@]/i,
6620 * The function used to validate URLs
6621 * @param {String} value The URL
6623 'url' : function(v){
6627 * The error text to display when the url validation function returns false
6630 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6633 * The function used to validate alpha values
6634 * @param {String} value The value
6636 'alpha' : function(v){
6637 return alpha.test(v);
6640 * The error text to display when the alpha validation function returns false
6643 'alphaText' : 'This field should only contain letters and _',
6645 * The keystroke filter mask to be applied on alpha input
6648 'alphaMask' : /[a-z_]/i,
6651 * The function used to validate alphanumeric values
6652 * @param {String} value The value
6654 'alphanum' : function(v){
6655 return alphanum.test(v);
6658 * The error text to display when the alphanumeric validation function returns false
6661 'alphanumText' : 'This field should only contain letters, numbers and _',
6663 * The keystroke filter mask to be applied on alphanumeric input
6666 'alphanumMask' : /[a-z0-9_]/i
6676 * @class Roo.bootstrap.Input
6677 * @extends Roo.bootstrap.Component
6678 * Bootstrap Input class
6679 * @cfg {Boolean} disabled is it disabled
6680 * @cfg {String} fieldLabel - the label associated
6681 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6682 * @cfg {String} name name of the input
6683 * @cfg {string} fieldLabel - the label associated
6684 * @cfg {string} inputType - input / file submit ...
6685 * @cfg {string} placeholder - placeholder to put in text.
6686 * @cfg {string} before - input group add on before
6687 * @cfg {string} after - input group add on after
6688 * @cfg {string} size - (lg|sm) or leave empty..
6689 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6690 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6691 * @cfg {Number} md colspan out of 12 for computer-sized screens
6692 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6693 * @cfg {string} value default value of the input
6694 * @cfg {Number} labelWidth set the width of label (0-12)
6695 * @cfg {String} labelAlign (top|left)
6696 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6697 * @cfg {String} align (left|center|right) Default left
6701 * Create a new Input
6702 * @param {Object} config The config object
6705 Roo.bootstrap.Input = function(config){
6706 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6711 * Fires when this field receives input focus.
6712 * @param {Roo.form.Field} this
6717 * Fires when this field loses input focus.
6718 * @param {Roo.form.Field} this
6723 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6724 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6725 * @param {Roo.form.Field} this
6726 * @param {Roo.EventObject} e The event object
6731 * Fires just before the field blurs if the field value has changed.
6732 * @param {Roo.form.Field} this
6733 * @param {Mixed} newValue The new value
6734 * @param {Mixed} oldValue The original value
6739 * Fires after the field has been marked as invalid.
6740 * @param {Roo.form.Field} this
6741 * @param {String} msg The validation message
6746 * Fires after the field has been validated with no errors.
6747 * @param {Roo.form.Field} this
6752 * Fires after the key up
6753 * @param {Roo.form.Field} this
6754 * @param {Roo.EventObject} e The event Object
6760 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6762 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6763 automatic validation (defaults to "keyup").
6765 validationEvent : "keyup",
6767 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6769 validateOnBlur : true,
6771 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6773 validationDelay : 250,
6775 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6777 focusClass : "x-form-focus", // not needed???
6781 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6783 invalidClass : "has-error",
6786 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6788 selectOnFocus : false,
6791 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6795 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6800 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6802 disableKeyFilter : false,
6805 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6809 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6813 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6815 blankText : "This field is required",
6818 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6822 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6824 maxLength : Number.MAX_VALUE,
6826 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6828 minLengthText : "The minimum length for this field is {0}",
6830 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6832 maxLengthText : "The maximum length for this field is {0}",
6836 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6837 * If available, this function will be called only after the basic validators all return true, and will be passed the
6838 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6842 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6843 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6844 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6848 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6871 formatedValue : false,
6873 parentLabelAlign : function()
6876 while (parent.parent()) {
6877 parent = parent.parent();
6878 if (typeof(parent.labelAlign) !='undefined') {
6879 return parent.labelAlign;
6886 getAutoCreate : function(){
6888 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6894 if(this.inputType != 'hidden'){
6895 cfg.cls = 'form-group' //input-group
6901 type : this.inputType,
6903 cls : 'form-control',
6904 placeholder : this.placeholder || ''
6909 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6912 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6913 input.maxLength = this.maxLength;
6916 if (this.disabled) {
6917 input.disabled=true;
6920 if (this.readOnly) {
6921 input.readonly=true;
6925 input.name = this.name;
6928 input.cls += ' input-' + this.size;
6931 ['xs','sm','md','lg'].map(function(size){
6932 if (settings[size]) {
6933 cfg.cls += ' col-' + size + '-' + settings[size];
6937 var inputblock = input;
6939 if (this.before || this.after) {
6942 cls : 'input-group',
6945 if (this.before && typeof(this.before) == 'string') {
6947 inputblock.cn.push({
6949 cls : 'roo-input-before input-group-addon',
6953 if (this.before && typeof(this.before) == 'object') {
6954 this.before = Roo.factory(this.before);
6955 Roo.log(this.before);
6956 inputblock.cn.push({
6958 cls : 'roo-input-before input-group-' +
6959 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6963 inputblock.cn.push(input);
6965 if (this.after && typeof(this.after) == 'string') {
6966 inputblock.cn.push({
6968 cls : 'roo-input-after input-group-addon',
6972 if (this.after && typeof(this.after) == 'object') {
6973 this.after = Roo.factory(this.after);
6974 Roo.log(this.after);
6975 inputblock.cn.push({
6977 cls : 'roo-input-after input-group-' +
6978 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6983 if (align ==='left' && this.fieldLabel.length) {
6984 Roo.log("left and has label");
6990 cls : 'control-label col-sm-' + this.labelWidth,
6991 html : this.fieldLabel
6995 cls : "col-sm-" + (12 - this.labelWidth),
7002 } else if ( this.fieldLabel.length) {
7008 //cls : 'input-group-addon',
7009 html : this.fieldLabel
7019 Roo.log(" no label && no align");
7028 Roo.log('input-parentType: ' + this.parentType);
7030 if (this.parentType === 'Navbar' && this.parent().bar) {
7031 cfg.cls += ' navbar-form';
7039 * return the real input element.
7041 inputEl: function ()
7043 return this.el.select('input.form-control',true).first();
7045 setDisabled : function(v)
7047 var i = this.inputEl().dom;
7049 i.removeAttribute('disabled');
7053 i.setAttribute('disabled','true');
7055 initEvents : function()
7058 this.inputEl().on("keydown" , this.fireKey, this);
7059 this.inputEl().on("focus", this.onFocus, this);
7060 this.inputEl().on("blur", this.onBlur, this);
7062 this.inputEl().relayEvent('keyup', this);
7064 // reference to original value for reset
7065 this.originalValue = this.getValue();
7066 //Roo.form.TextField.superclass.initEvents.call(this);
7067 if(this.validationEvent == 'keyup'){
7068 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7069 this.inputEl().on('keyup', this.filterValidation, this);
7071 else if(this.validationEvent !== false){
7072 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7075 if(this.selectOnFocus){
7076 this.on("focus", this.preFocus, this);
7079 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7080 this.inputEl().on("keypress", this.filterKeys, this);
7083 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7084 this.el.on("click", this.autoSize, this);
7087 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7088 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7091 if (typeof(this.before) == 'object') {
7092 this.before.render(this.el.select('.roo-input-before',true).first());
7094 if (typeof(this.after) == 'object') {
7095 this.after.render(this.el.select('.roo-input-after',true).first());
7100 filterValidation : function(e){
7101 if(!e.isNavKeyPress()){
7102 this.validationTask.delay(this.validationDelay);
7106 * Validates the field value
7107 * @return {Boolean} True if the value is valid, else false
7109 validate : function(){
7110 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7111 if(this.disabled || this.validateValue(this.getRawValue())){
7112 this.clearInvalid();
7120 * Validates a value according to the field's validation rules and marks the field as invalid
7121 * if the validation fails
7122 * @param {Mixed} value The value to validate
7123 * @return {Boolean} True if the value is valid, else false
7125 validateValue : function(value){
7126 if(value.length < 1) { // if it's blank
7127 if(this.allowBlank){
7128 this.clearInvalid();
7131 this.markInvalid(this.blankText);
7135 if(value.length < this.minLength){
7136 this.markInvalid(String.format(this.minLengthText, this.minLength));
7139 if(value.length > this.maxLength){
7140 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7144 var vt = Roo.form.VTypes;
7145 if(!vt[this.vtype](value, this)){
7146 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7150 if(typeof this.validator == "function"){
7151 var msg = this.validator(value);
7153 this.markInvalid(msg);
7157 if(this.regex && !this.regex.test(value)){
7158 this.markInvalid(this.regexText);
7167 fireKey : function(e){
7168 //Roo.log('field ' + e.getKey());
7169 if(e.isNavKeyPress()){
7170 this.fireEvent("specialkey", this, e);
7173 focus : function (selectText){
7175 this.inputEl().focus();
7176 if(selectText === true){
7177 this.inputEl().dom.select();
7183 onFocus : function(){
7184 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7185 // this.el.addClass(this.focusClass);
7188 this.hasFocus = true;
7189 this.startValue = this.getValue();
7190 this.fireEvent("focus", this);
7194 beforeBlur : Roo.emptyFn,
7198 onBlur : function(){
7200 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7201 //this.el.removeClass(this.focusClass);
7203 this.hasFocus = false;
7204 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7207 var v = this.getValue();
7208 if(String(v) !== String(this.startValue)){
7209 this.fireEvent('change', this, v, this.startValue);
7211 this.fireEvent("blur", this);
7215 * Resets the current field value to the originally loaded value and clears any validation messages
7218 this.setValue(this.originalValue);
7219 this.clearInvalid();
7222 * Returns the name of the field
7223 * @return {Mixed} name The name field
7225 getName: function(){
7229 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7230 * @return {Mixed} value The field value
7232 getValue : function(){
7234 var v = this.inputEl().getValue();
7239 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7240 * @return {Mixed} value The field value
7242 getRawValue : function(){
7243 var v = this.inputEl().getValue();
7249 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7250 * @param {Mixed} value The value to set
7252 setRawValue : function(v){
7253 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7256 selectText : function(start, end){
7257 var v = this.getRawValue();
7259 start = start === undefined ? 0 : start;
7260 end = end === undefined ? v.length : end;
7261 var d = this.inputEl().dom;
7262 if(d.setSelectionRange){
7263 d.setSelectionRange(start, end);
7264 }else if(d.createTextRange){
7265 var range = d.createTextRange();
7266 range.moveStart("character", start);
7267 range.moveEnd("character", v.length-end);
7274 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7275 * @param {Mixed} value The value to set
7277 setValue : function(v){
7280 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7286 processValue : function(value){
7287 if(this.stripCharsRe){
7288 var newValue = value.replace(this.stripCharsRe, '');
7289 if(newValue !== value){
7290 this.setRawValue(newValue);
7297 preFocus : function(){
7299 if(this.selectOnFocus){
7300 this.inputEl().dom.select();
7303 filterKeys : function(e){
7305 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7308 var c = e.getCharCode(), cc = String.fromCharCode(c);
7309 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7312 if(!this.maskRe.test(cc)){
7317 * Clear any invalid styles/messages for this field
7319 clearInvalid : function(){
7321 if(!this.el || this.preventMark){ // not rendered
7324 this.el.removeClass(this.invalidClass);
7326 switch(this.msgTarget){
7328 this.el.dom.qtip = '';
7331 this.el.dom.title = '';
7335 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7340 this.errorIcon.dom.qtip = '';
7341 this.errorIcon.hide();
7342 this.un('resize', this.alignErrorIcon, this);
7346 var t = Roo.getDom(this.msgTarget);
7348 t.style.display = 'none';
7352 this.fireEvent('valid', this);
7355 * Mark this field as invalid
7356 * @param {String} msg The validation message
7358 markInvalid : function(msg){
7359 if(!this.el || this.preventMark){ // not rendered
7362 this.el.addClass(this.invalidClass);
7364 msg = msg || this.invalidText;
7365 switch(this.msgTarget){
7367 this.el.dom.qtip = msg;
7368 this.el.dom.qclass = 'x-form-invalid-tip';
7369 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7370 Roo.QuickTips.enable();
7374 this.el.dom.title = msg;
7378 var elp = this.el.findParent('.x-form-element', 5, true);
7379 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7380 this.errorEl.setWidth(elp.getWidth(true)-20);
7382 this.errorEl.update(msg);
7383 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7386 if(!this.errorIcon){
7387 var elp = this.el.findParent('.x-form-element', 5, true);
7388 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7390 this.alignErrorIcon();
7391 this.errorIcon.dom.qtip = msg;
7392 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7393 this.errorIcon.show();
7394 this.on('resize', this.alignErrorIcon, this);
7397 var t = Roo.getDom(this.msgTarget);
7399 t.style.display = this.msgDisplay;
7403 this.fireEvent('invalid', this, msg);
7406 SafariOnKeyDown : function(event)
7408 // this is a workaround for a password hang bug on chrome/ webkit.
7410 var isSelectAll = false;
7412 if(this.inputEl().dom.selectionEnd > 0){
7413 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7415 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7416 event.preventDefault();
7421 if(isSelectAll){ // backspace and delete key
7423 event.preventDefault();
7424 // this is very hacky as keydown always get's upper case.
7426 var cc = String.fromCharCode(event.getCharCode());
7427 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7431 adjustWidth : function(tag, w){
7432 tag = tag.toLowerCase();
7433 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7434 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7438 if(tag == 'textarea'){
7441 }else if(Roo.isOpera){
7445 if(tag == 'textarea'){
7464 * @class Roo.bootstrap.TextArea
7465 * @extends Roo.bootstrap.Input
7466 * Bootstrap TextArea class
7467 * @cfg {Number} cols Specifies the visible width of a text area
7468 * @cfg {Number} rows Specifies the visible number of lines in a text area
7469 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7470 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7471 * @cfg {string} html text
7474 * Create a new TextArea
7475 * @param {Object} config The config object
7478 Roo.bootstrap.TextArea = function(config){
7479 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7483 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7493 getAutoCreate : function(){
7495 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7506 value : this.value || '',
7507 html: this.html || '',
7508 cls : 'form-control',
7509 placeholder : this.placeholder || ''
7513 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7514 input.maxLength = this.maxLength;
7518 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7522 input.cols = this.cols;
7525 if (this.readOnly) {
7526 input.readonly = true;
7530 input.name = this.name;
7534 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7538 ['xs','sm','md','lg'].map(function(size){
7539 if (settings[size]) {
7540 cfg.cls += ' col-' + size + '-' + settings[size];
7544 var inputblock = input;
7546 if (this.before || this.after) {
7549 cls : 'input-group',
7553 inputblock.cn.push({
7555 cls : 'input-group-addon',
7559 inputblock.cn.push(input);
7561 inputblock.cn.push({
7563 cls : 'input-group-addon',
7570 if (align ==='left' && this.fieldLabel.length) {
7571 Roo.log("left and has label");
7577 cls : 'control-label col-sm-' + this.labelWidth,
7578 html : this.fieldLabel
7582 cls : "col-sm-" + (12 - this.labelWidth),
7589 } else if ( this.fieldLabel.length) {
7595 //cls : 'input-group-addon',
7596 html : this.fieldLabel
7606 Roo.log(" no label && no align");
7616 if (this.disabled) {
7617 input.disabled=true;
7624 * return the real textarea element.
7626 inputEl: function ()
7628 return this.el.select('textarea.form-control',true).first();
7636 * trigger field - base class for combo..
7641 * @class Roo.bootstrap.TriggerField
7642 * @extends Roo.bootstrap.Input
7643 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7644 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7645 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7646 * for which you can provide a custom implementation. For example:
7648 var trigger = new Roo.bootstrap.TriggerField();
7649 trigger.onTriggerClick = myTriggerFn;
7650 trigger.applyTo('my-field');
7653 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7654 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7655 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7656 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7658 * Create a new TriggerField.
7659 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7660 * to the base TextField)
7662 Roo.bootstrap.TriggerField = function(config){
7663 this.mimicing = false;
7664 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7667 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7669 * @cfg {String} triggerClass A CSS class to apply to the trigger
7672 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7676 /** @cfg {Boolean} grow @hide */
7677 /** @cfg {Number} growMin @hide */
7678 /** @cfg {Number} growMax @hide */
7684 autoSize: Roo.emptyFn,
7691 actionMode : 'wrap',
7695 getAutoCreate : function(){
7697 var align = this.labelAlign || this.parentLabelAlign();
7702 cls: 'form-group' //input-group
7709 type : this.inputType,
7710 cls : 'form-control',
7711 autocomplete: 'off',
7712 placeholder : this.placeholder || ''
7716 input.name = this.name;
7719 input.cls += ' input-' + this.size;
7722 if (this.disabled) {
7723 input.disabled=true;
7726 var inputblock = input;
7728 if (this.before || this.after) {
7731 cls : 'input-group',
7735 inputblock.cn.push({
7737 cls : 'input-group-addon',
7741 inputblock.cn.push(input);
7743 inputblock.cn.push({
7745 cls : 'input-group-addon',
7758 cls: 'form-hidden-field'
7766 Roo.log('multiple');
7774 cls: 'form-hidden-field'
7778 cls: 'select2-choices',
7782 cls: 'select2-search-field',
7795 cls: 'select2-container input-group',
7800 // cls: 'typeahead typeahead-long dropdown-menu',
7801 // style: 'display:none'
7806 if(!this.multiple && this.showToggleBtn){
7809 cls : 'input-group-addon btn dropdown-toggle',
7817 cls: 'combobox-clear',
7831 combobox.cls += ' select2-container-multi';
7834 if (align ==='left' && this.fieldLabel.length) {
7836 Roo.log("left and has label");
7842 cls : 'control-label col-sm-' + this.labelWidth,
7843 html : this.fieldLabel
7847 cls : "col-sm-" + (12 - this.labelWidth),
7854 } else if ( this.fieldLabel.length) {
7860 //cls : 'input-group-addon',
7861 html : this.fieldLabel
7871 Roo.log(" no label && no align");
7878 ['xs','sm','md','lg'].map(function(size){
7879 if (settings[size]) {
7880 cfg.cls += ' col-' + size + '-' + settings[size];
7891 onResize : function(w, h){
7892 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7893 // if(typeof w == 'number'){
7894 // var x = w - this.trigger.getWidth();
7895 // this.inputEl().setWidth(this.adjustWidth('input', x));
7896 // this.trigger.setStyle('left', x+'px');
7901 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7904 getResizeEl : function(){
7905 return this.inputEl();
7909 getPositionEl : function(){
7910 return this.inputEl();
7914 alignErrorIcon : function(){
7915 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7919 initEvents : function(){
7923 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7924 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7925 if(!this.multiple && this.showToggleBtn){
7926 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7927 if(this.hideTrigger){
7928 this.trigger.setDisplayed(false);
7930 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7934 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7937 //this.trigger.addClassOnOver('x-form-trigger-over');
7938 //this.trigger.addClassOnClick('x-form-trigger-click');
7941 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7945 createList : function()
7947 this.list = Roo.get(document.body).createChild({
7949 cls: 'typeahead typeahead-long dropdown-menu',
7950 style: 'display:none'
7953 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
7958 initTrigger : function(){
7963 onDestroy : function(){
7965 this.trigger.removeAllListeners();
7966 // this.trigger.remove();
7969 // this.wrap.remove();
7971 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7975 onFocus : function(){
7976 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7979 this.wrap.addClass('x-trigger-wrap-focus');
7980 this.mimicing = true;
7981 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7982 if(this.monitorTab){
7983 this.el.on("keydown", this.checkTab, this);
7990 checkTab : function(e){
7991 if(e.getKey() == e.TAB){
7997 onBlur : function(){
8002 mimicBlur : function(e, t){
8004 if(!this.wrap.contains(t) && this.validateBlur()){
8011 triggerBlur : function(){
8012 this.mimicing = false;
8013 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8014 if(this.monitorTab){
8015 this.el.un("keydown", this.checkTab, this);
8017 //this.wrap.removeClass('x-trigger-wrap-focus');
8018 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8022 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8023 validateBlur : function(e, t){
8028 onDisable : function(){
8029 this.inputEl().dom.disabled = true;
8030 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8032 // this.wrap.addClass('x-item-disabled');
8037 onEnable : function(){
8038 this.inputEl().dom.disabled = false;
8039 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8041 // this.el.removeClass('x-item-disabled');
8046 onShow : function(){
8047 var ae = this.getActionEl();
8050 ae.dom.style.display = '';
8051 ae.dom.style.visibility = 'visible';
8057 onHide : function(){
8058 var ae = this.getActionEl();
8059 ae.dom.style.display = 'none';
8063 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8064 * by an implementing function.
8066 * @param {EventObject} e
8068 onTriggerClick : Roo.emptyFn
8072 * Ext JS Library 1.1.1
8073 * Copyright(c) 2006-2007, Ext JS, LLC.
8075 * Originally Released Under LGPL - original licence link has changed is not relivant.
8078 * <script type="text/javascript">
8083 * @class Roo.data.SortTypes
8085 * Defines the default sorting (casting?) comparison functions used when sorting data.
8087 Roo.data.SortTypes = {
8089 * Default sort that does nothing
8090 * @param {Mixed} s The value being converted
8091 * @return {Mixed} The comparison value
8098 * The regular expression used to strip tags
8102 stripTagsRE : /<\/?[^>]+>/gi,
8105 * Strips all HTML tags to sort on text only
8106 * @param {Mixed} s The value being converted
8107 * @return {String} The comparison value
8109 asText : function(s){
8110 return String(s).replace(this.stripTagsRE, "");
8114 * Strips all HTML tags to sort on text only - Case insensitive
8115 * @param {Mixed} s The value being converted
8116 * @return {String} The comparison value
8118 asUCText : function(s){
8119 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8123 * Case insensitive string
8124 * @param {Mixed} s The value being converted
8125 * @return {String} The comparison value
8127 asUCString : function(s) {
8128 return String(s).toUpperCase();
8133 * @param {Mixed} s The value being converted
8134 * @return {Number} The comparison value
8136 asDate : function(s) {
8140 if(s instanceof Date){
8143 return Date.parse(String(s));
8148 * @param {Mixed} s The value being converted
8149 * @return {Float} The comparison value
8151 asFloat : function(s) {
8152 var val = parseFloat(String(s).replace(/,/g, ""));
8153 if(isNaN(val)) val = 0;
8159 * @param {Mixed} s The value being converted
8160 * @return {Number} The comparison value
8162 asInt : function(s) {
8163 var val = parseInt(String(s).replace(/,/g, ""));
8164 if(isNaN(val)) val = 0;
8169 * Ext JS Library 1.1.1
8170 * Copyright(c) 2006-2007, Ext JS, LLC.
8172 * Originally Released Under LGPL - original licence link has changed is not relivant.
8175 * <script type="text/javascript">
8179 * @class Roo.data.Record
8180 * Instances of this class encapsulate both record <em>definition</em> information, and record
8181 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8182 * to access Records cached in an {@link Roo.data.Store} object.<br>
8184 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8185 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8188 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8190 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8191 * {@link #create}. The parameters are the same.
8192 * @param {Array} data An associative Array of data values keyed by the field name.
8193 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8194 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8195 * not specified an integer id is generated.
8197 Roo.data.Record = function(data, id){
8198 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8203 * Generate a constructor for a specific record layout.
8204 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8205 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8206 * Each field definition object may contain the following properties: <ul>
8207 * <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,
8208 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8209 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8210 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8211 * is being used, then this is a string containing the javascript expression to reference the data relative to
8212 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8213 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8214 * this may be omitted.</p></li>
8215 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8216 * <ul><li>auto (Default, implies no conversion)</li>
8221 * <li>date</li></ul></p></li>
8222 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8223 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8224 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8225 * by the Reader into an object that will be stored in the Record. It is passed the
8226 * following parameters:<ul>
8227 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8229 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8231 * <br>usage:<br><pre><code>
8232 var TopicRecord = Roo.data.Record.create(
8233 {name: 'title', mapping: 'topic_title'},
8234 {name: 'author', mapping: 'username'},
8235 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8236 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8237 {name: 'lastPoster', mapping: 'user2'},
8238 {name: 'excerpt', mapping: 'post_text'}
8241 var myNewRecord = new TopicRecord({
8242 title: 'Do my job please',
8245 lastPost: new Date(),
8246 lastPoster: 'Animal',
8247 excerpt: 'No way dude!'
8249 myStore.add(myNewRecord);
8254 Roo.data.Record.create = function(o){
8256 f.superclass.constructor.apply(this, arguments);
8258 Roo.extend(f, Roo.data.Record);
8259 var p = f.prototype;
8260 p.fields = new Roo.util.MixedCollection(false, function(field){
8263 for(var i = 0, len = o.length; i < len; i++){
8264 p.fields.add(new Roo.data.Field(o[i]));
8266 f.getField = function(name){
8267 return p.fields.get(name);
8272 Roo.data.Record.AUTO_ID = 1000;
8273 Roo.data.Record.EDIT = 'edit';
8274 Roo.data.Record.REJECT = 'reject';
8275 Roo.data.Record.COMMIT = 'commit';
8277 Roo.data.Record.prototype = {
8279 * Readonly flag - true if this record has been modified.
8288 join : function(store){
8293 * Set the named field to the specified value.
8294 * @param {String} name The name of the field to set.
8295 * @param {Object} value The value to set the field to.
8297 set : function(name, value){
8298 if(this.data[name] == value){
8305 if(typeof this.modified[name] == 'undefined'){
8306 this.modified[name] = this.data[name];
8308 this.data[name] = value;
8309 if(!this.editing && this.store){
8310 this.store.afterEdit(this);
8315 * Get the value of the named field.
8316 * @param {String} name The name of the field to get the value of.
8317 * @return {Object} The value of the field.
8319 get : function(name){
8320 return this.data[name];
8324 beginEdit : function(){
8325 this.editing = true;
8330 cancelEdit : function(){
8331 this.editing = false;
8332 delete this.modified;
8336 endEdit : function(){
8337 this.editing = false;
8338 if(this.dirty && this.store){
8339 this.store.afterEdit(this);
8344 * Usually called by the {@link Roo.data.Store} which owns the Record.
8345 * Rejects all changes made to the Record since either creation, or the last commit operation.
8346 * Modified fields are reverted to their original values.
8348 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8349 * of reject operations.
8351 reject : function(){
8352 var m = this.modified;
8354 if(typeof m[n] != "function"){
8355 this.data[n] = m[n];
8359 delete this.modified;
8360 this.editing = false;
8362 this.store.afterReject(this);
8367 * Usually called by the {@link Roo.data.Store} which owns the Record.
8368 * Commits all changes made to the Record since either creation, or the last commit operation.
8370 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8371 * of commit operations.
8373 commit : function(){
8375 delete this.modified;
8376 this.editing = false;
8378 this.store.afterCommit(this);
8383 hasError : function(){
8384 return this.error != null;
8388 clearError : function(){
8393 * Creates a copy of this record.
8394 * @param {String} id (optional) A new record id if you don't want to use this record's id
8397 copy : function(newId) {
8398 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8402 * Ext JS Library 1.1.1
8403 * Copyright(c) 2006-2007, Ext JS, LLC.
8405 * Originally Released Under LGPL - original licence link has changed is not relivant.
8408 * <script type="text/javascript">
8414 * @class Roo.data.Store
8415 * @extends Roo.util.Observable
8416 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8417 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8419 * 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
8420 * has no knowledge of the format of the data returned by the Proxy.<br>
8422 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8423 * instances from the data object. These records are cached and made available through accessor functions.
8425 * Creates a new Store.
8426 * @param {Object} config A config object containing the objects needed for the Store to access data,
8427 * and read the data into Records.
8429 Roo.data.Store = function(config){
8430 this.data = new Roo.util.MixedCollection(false);
8431 this.data.getKey = function(o){
8434 this.baseParams = {};
8441 "multisort" : "_multisort"
8444 if(config && config.data){
8445 this.inlineData = config.data;
8449 Roo.apply(this, config);
8451 if(this.reader){ // reader passed
8452 this.reader = Roo.factory(this.reader, Roo.data);
8453 this.reader.xmodule = this.xmodule || false;
8454 if(!this.recordType){
8455 this.recordType = this.reader.recordType;
8457 if(this.reader.onMetaChange){
8458 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8462 if(this.recordType){
8463 this.fields = this.recordType.prototype.fields;
8469 * @event datachanged
8470 * Fires when the data cache has changed, and a widget which is using this Store
8471 * as a Record cache should refresh its view.
8472 * @param {Store} this
8477 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8478 * @param {Store} this
8479 * @param {Object} meta The JSON metadata
8484 * Fires when Records have been added to the Store
8485 * @param {Store} this
8486 * @param {Roo.data.Record[]} records The array of Records added
8487 * @param {Number} index The index at which the record(s) were added
8492 * Fires when a Record has been removed from the Store
8493 * @param {Store} this
8494 * @param {Roo.data.Record} record The Record that was removed
8495 * @param {Number} index The index at which the record was removed
8500 * Fires when a Record has been updated
8501 * @param {Store} this
8502 * @param {Roo.data.Record} record The Record that was updated
8503 * @param {String} operation The update operation being performed. Value may be one of:
8505 Roo.data.Record.EDIT
8506 Roo.data.Record.REJECT
8507 Roo.data.Record.COMMIT
8513 * Fires when the data cache has been cleared.
8514 * @param {Store} this
8519 * Fires before a request is made for a new data object. If the beforeload handler returns false
8520 * the load action will be canceled.
8521 * @param {Store} this
8522 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8526 * @event beforeloadadd
8527 * Fires after a new set of Records has been loaded.
8528 * @param {Store} this
8529 * @param {Roo.data.Record[]} records The Records that were loaded
8530 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8532 beforeloadadd : true,
8535 * Fires after a new set of Records has been loaded, before they are added to the store.
8536 * @param {Store} this
8537 * @param {Roo.data.Record[]} records The Records that were loaded
8538 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8539 * @params {Object} return from reader
8543 * @event loadexception
8544 * Fires if an exception occurs in the Proxy during loading.
8545 * Called with the signature of the Proxy's "loadexception" event.
8546 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8549 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8550 * @param {Object} load options
8551 * @param {Object} jsonData from your request (normally this contains the Exception)
8553 loadexception : true
8557 this.proxy = Roo.factory(this.proxy, Roo.data);
8558 this.proxy.xmodule = this.xmodule || false;
8559 this.relayEvents(this.proxy, ["loadexception"]);
8561 this.sortToggle = {};
8562 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8564 Roo.data.Store.superclass.constructor.call(this);
8566 if(this.inlineData){
8567 this.loadData(this.inlineData);
8568 delete this.inlineData;
8572 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8574 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8575 * without a remote query - used by combo/forms at present.
8579 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8582 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8585 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8586 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8589 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8590 * on any HTTP request
8593 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8596 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8600 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8601 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8606 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8607 * loaded or when a record is removed. (defaults to false).
8609 pruneModifiedRecords : false,
8615 * Add Records to the Store and fires the add event.
8616 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8618 add : function(records){
8619 records = [].concat(records);
8620 for(var i = 0, len = records.length; i < len; i++){
8621 records[i].join(this);
8623 var index = this.data.length;
8624 this.data.addAll(records);
8625 this.fireEvent("add", this, records, index);
8629 * Remove a Record from the Store and fires the remove event.
8630 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8632 remove : function(record){
8633 var index = this.data.indexOf(record);
8634 this.data.removeAt(index);
8635 if(this.pruneModifiedRecords){
8636 this.modified.remove(record);
8638 this.fireEvent("remove", this, record, index);
8642 * Remove all Records from the Store and fires the clear event.
8644 removeAll : function(){
8646 if(this.pruneModifiedRecords){
8649 this.fireEvent("clear", this);
8653 * Inserts Records to the Store at the given index and fires the add event.
8654 * @param {Number} index The start index at which to insert the passed Records.
8655 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8657 insert : function(index, records){
8658 records = [].concat(records);
8659 for(var i = 0, len = records.length; i < len; i++){
8660 this.data.insert(index, records[i]);
8661 records[i].join(this);
8663 this.fireEvent("add", this, records, index);
8667 * Get the index within the cache of the passed Record.
8668 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8669 * @return {Number} The index of the passed Record. Returns -1 if not found.
8671 indexOf : function(record){
8672 return this.data.indexOf(record);
8676 * Get the index within the cache of the Record with the passed id.
8677 * @param {String} id The id of the Record to find.
8678 * @return {Number} The index of the Record. Returns -1 if not found.
8680 indexOfId : function(id){
8681 return this.data.indexOfKey(id);
8685 * Get the Record with the specified id.
8686 * @param {String} id The id of the Record to find.
8687 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8689 getById : function(id){
8690 return this.data.key(id);
8694 * Get the Record at the specified index.
8695 * @param {Number} index The index of the Record to find.
8696 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8698 getAt : function(index){
8699 return this.data.itemAt(index);
8703 * Returns a range of Records between specified indices.
8704 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8705 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8706 * @return {Roo.data.Record[]} An array of Records
8708 getRange : function(start, end){
8709 return this.data.getRange(start, end);
8713 storeOptions : function(o){
8714 o = Roo.apply({}, o);
8717 this.lastOptions = o;
8721 * Loads the Record cache from the configured Proxy using the configured Reader.
8723 * If using remote paging, then the first load call must specify the <em>start</em>
8724 * and <em>limit</em> properties in the options.params property to establish the initial
8725 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8727 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8728 * and this call will return before the new data has been loaded. Perform any post-processing
8729 * in a callback function, or in a "load" event handler.</strong>
8731 * @param {Object} options An object containing properties which control loading options:<ul>
8732 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8733 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8734 * passed the following arguments:<ul>
8735 * <li>r : Roo.data.Record[]</li>
8736 * <li>options: Options object from the load call</li>
8737 * <li>success: Boolean success indicator</li></ul></li>
8738 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8739 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8742 load : function(options){
8743 options = options || {};
8744 if(this.fireEvent("beforeload", this, options) !== false){
8745 this.storeOptions(options);
8746 var p = Roo.apply(options.params || {}, this.baseParams);
8747 // if meta was not loaded from remote source.. try requesting it.
8748 if (!this.reader.metaFromRemote) {
8751 if(this.sortInfo && this.remoteSort){
8752 var pn = this.paramNames;
8753 p[pn["sort"]] = this.sortInfo.field;
8754 p[pn["dir"]] = this.sortInfo.direction;
8756 if (this.multiSort) {
8757 var pn = this.paramNames;
8758 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8761 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8766 * Reloads the Record cache from the configured Proxy using the configured Reader and
8767 * the options from the last load operation performed.
8768 * @param {Object} options (optional) An object containing properties which may override the options
8769 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8770 * the most recently used options are reused).
8772 reload : function(options){
8773 this.load(Roo.applyIf(options||{}, this.lastOptions));
8777 // Called as a callback by the Reader during a load operation.
8778 loadRecords : function(o, options, success){
8779 if(!o || success === false){
8780 if(success !== false){
8781 this.fireEvent("load", this, [], options, o);
8783 if(options.callback){
8784 options.callback.call(options.scope || this, [], options, false);
8788 // if data returned failure - throw an exception.
8789 if (o.success === false) {
8790 // show a message if no listener is registered.
8791 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8792 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8794 // loadmask wil be hooked into this..
8795 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8798 var r = o.records, t = o.totalRecords || r.length;
8800 this.fireEvent("beforeloadadd", this, r, options, o);
8802 if(!options || options.add !== true){
8803 if(this.pruneModifiedRecords){
8806 for(var i = 0, len = r.length; i < len; i++){
8810 this.data = this.snapshot;
8811 delete this.snapshot;
8814 this.data.addAll(r);
8815 this.totalLength = t;
8817 this.fireEvent("datachanged", this);
8819 this.totalLength = Math.max(t, this.data.length+r.length);
8822 this.fireEvent("load", this, r, options, o);
8823 if(options.callback){
8824 options.callback.call(options.scope || this, r, options, true);
8830 * Loads data from a passed data block. A Reader which understands the format of the data
8831 * must have been configured in the constructor.
8832 * @param {Object} data The data block from which to read the Records. The format of the data expected
8833 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8834 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8836 loadData : function(o, append){
8837 var r = this.reader.readRecords(o);
8838 this.loadRecords(r, {add: append}, true);
8842 * Gets the number of cached records.
8844 * <em>If using paging, this may not be the total size of the dataset. If the data object
8845 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8846 * the data set size</em>
8848 getCount : function(){
8849 return this.data.length || 0;
8853 * Gets the total number of records in the dataset as returned by the server.
8855 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8856 * the dataset size</em>
8858 getTotalCount : function(){
8859 return this.totalLength || 0;
8863 * Returns the sort state of the Store as an object with two properties:
8865 field {String} The name of the field by which the Records are sorted
8866 direction {String} The sort order, "ASC" or "DESC"
8869 getSortState : function(){
8870 return this.sortInfo;
8874 applySort : function(){
8875 if(this.sortInfo && !this.remoteSort){
8876 var s = this.sortInfo, f = s.field;
8877 var st = this.fields.get(f).sortType;
8878 var fn = function(r1, r2){
8879 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8880 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8882 this.data.sort(s.direction, fn);
8883 if(this.snapshot && this.snapshot != this.data){
8884 this.snapshot.sort(s.direction, fn);
8890 * Sets the default sort column and order to be used by the next load operation.
8891 * @param {String} fieldName The name of the field to sort by.
8892 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8894 setDefaultSort : function(field, dir){
8895 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8900 * If remote sorting is used, the sort is performed on the server, and the cache is
8901 * reloaded. If local sorting is used, the cache is sorted internally.
8902 * @param {String} fieldName The name of the field to sort by.
8903 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8905 sort : function(fieldName, dir){
8906 var f = this.fields.get(fieldName);
8908 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8910 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8911 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8916 this.sortToggle[f.name] = dir;
8917 this.sortInfo = {field: f.name, direction: dir};
8918 if(!this.remoteSort){
8920 this.fireEvent("datachanged", this);
8922 this.load(this.lastOptions);
8927 * Calls the specified function for each of the Records in the cache.
8928 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8929 * Returning <em>false</em> aborts and exits the iteration.
8930 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8932 each : function(fn, scope){
8933 this.data.each(fn, scope);
8937 * Gets all records modified since the last commit. Modified records are persisted across load operations
8938 * (e.g., during paging).
8939 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8941 getModifiedRecords : function(){
8942 return this.modified;
8946 createFilterFn : function(property, value, anyMatch){
8947 if(!value.exec){ // not a regex
8948 value = String(value);
8949 if(value.length == 0){
8952 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8955 return value.test(r.data[property]);
8960 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8961 * @param {String} property A field on your records
8962 * @param {Number} start The record index to start at (defaults to 0)
8963 * @param {Number} end The last record index to include (defaults to length - 1)
8964 * @return {Number} The sum
8966 sum : function(property, start, end){
8967 var rs = this.data.items, v = 0;
8969 end = (end || end === 0) ? end : rs.length-1;
8971 for(var i = start; i <= end; i++){
8972 v += (rs[i].data[property] || 0);
8978 * Filter the records by a specified property.
8979 * @param {String} field A field on your records
8980 * @param {String/RegExp} value Either a string that the field
8981 * should start with or a RegExp to test against the field
8982 * @param {Boolean} anyMatch True to match any part not just the beginning
8984 filter : function(property, value, anyMatch){
8985 var fn = this.createFilterFn(property, value, anyMatch);
8986 return fn ? this.filterBy(fn) : this.clearFilter();
8990 * Filter by a function. The specified function will be called with each
8991 * record in this data source. If the function returns true the record is included,
8992 * otherwise it is filtered.
8993 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8994 * @param {Object} scope (optional) The scope of the function (defaults to this)
8996 filterBy : function(fn, scope){
8997 this.snapshot = this.snapshot || this.data;
8998 this.data = this.queryBy(fn, scope||this);
8999 this.fireEvent("datachanged", this);
9003 * Query the records by a specified property.
9004 * @param {String} field A field on your records
9005 * @param {String/RegExp} value Either a string that the field
9006 * should start with or a RegExp to test against the field
9007 * @param {Boolean} anyMatch True to match any part not just the beginning
9008 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9010 query : function(property, value, anyMatch){
9011 var fn = this.createFilterFn(property, value, anyMatch);
9012 return fn ? this.queryBy(fn) : this.data.clone();
9016 * Query by a function. The specified function will be called with each
9017 * record in this data source. If the function returns true the record is included
9019 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9020 * @param {Object} scope (optional) The scope of the function (defaults to this)
9021 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9023 queryBy : function(fn, scope){
9024 var data = this.snapshot || this.data;
9025 return data.filterBy(fn, scope||this);
9029 * Collects unique values for a particular dataIndex from this store.
9030 * @param {String} dataIndex The property to collect
9031 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9032 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9033 * @return {Array} An array of the unique values
9035 collect : function(dataIndex, allowNull, bypassFilter){
9036 var d = (bypassFilter === true && this.snapshot) ?
9037 this.snapshot.items : this.data.items;
9038 var v, sv, r = [], l = {};
9039 for(var i = 0, len = d.length; i < len; i++){
9040 v = d[i].data[dataIndex];
9042 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9051 * Revert to a view of the Record cache with no filtering applied.
9052 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9054 clearFilter : function(suppressEvent){
9055 if(this.snapshot && this.snapshot != this.data){
9056 this.data = this.snapshot;
9057 delete this.snapshot;
9058 if(suppressEvent !== true){
9059 this.fireEvent("datachanged", this);
9065 afterEdit : function(record){
9066 if(this.modified.indexOf(record) == -1){
9067 this.modified.push(record);
9069 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9073 afterReject : function(record){
9074 this.modified.remove(record);
9075 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9079 afterCommit : function(record){
9080 this.modified.remove(record);
9081 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9085 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9086 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9088 commitChanges : function(){
9089 var m = this.modified.slice(0);
9091 for(var i = 0, len = m.length; i < len; i++){
9097 * Cancel outstanding changes on all changed records.
9099 rejectChanges : function(){
9100 var m = this.modified.slice(0);
9102 for(var i = 0, len = m.length; i < len; i++){
9107 onMetaChange : function(meta, rtype, o){
9108 this.recordType = rtype;
9109 this.fields = rtype.prototype.fields;
9110 delete this.snapshot;
9111 this.sortInfo = meta.sortInfo || this.sortInfo;
9113 this.fireEvent('metachange', this, this.reader.meta);
9116 moveIndex : function(data, type)
9118 var index = this.indexOf(data);
9120 var newIndex = index + type;
9124 this.insert(newIndex, data);
9129 * Ext JS Library 1.1.1
9130 * Copyright(c) 2006-2007, Ext JS, LLC.
9132 * Originally Released Under LGPL - original licence link has changed is not relivant.
9135 * <script type="text/javascript">
9139 * @class Roo.data.SimpleStore
9140 * @extends Roo.data.Store
9141 * Small helper class to make creating Stores from Array data easier.
9142 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9143 * @cfg {Array} fields An array of field definition objects, or field name strings.
9144 * @cfg {Array} data The multi-dimensional array of data
9146 * @param {Object} config
9148 Roo.data.SimpleStore = function(config){
9149 Roo.data.SimpleStore.superclass.constructor.call(this, {
9151 reader: new Roo.data.ArrayReader({
9154 Roo.data.Record.create(config.fields)
9156 proxy : new Roo.data.MemoryProxy(config.data)
9160 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9162 * Ext JS Library 1.1.1
9163 * Copyright(c) 2006-2007, Ext JS, LLC.
9165 * Originally Released Under LGPL - original licence link has changed is not relivant.
9168 * <script type="text/javascript">
9173 * @extends Roo.data.Store
9174 * @class Roo.data.JsonStore
9175 * Small helper class to make creating Stores for JSON data easier. <br/>
9177 var store = new Roo.data.JsonStore({
9178 url: 'get-images.php',
9180 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9183 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9184 * JsonReader and HttpProxy (unless inline data is provided).</b>
9185 * @cfg {Array} fields An array of field definition objects, or field name strings.
9187 * @param {Object} config
9189 Roo.data.JsonStore = function(c){
9190 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9191 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9192 reader: new Roo.data.JsonReader(c, c.fields)
9195 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9197 * Ext JS Library 1.1.1
9198 * Copyright(c) 2006-2007, Ext JS, LLC.
9200 * Originally Released Under LGPL - original licence link has changed is not relivant.
9203 * <script type="text/javascript">
9207 Roo.data.Field = function(config){
9208 if(typeof config == "string"){
9209 config = {name: config};
9211 Roo.apply(this, config);
9217 var st = Roo.data.SortTypes;
9218 // named sortTypes are supported, here we look them up
9219 if(typeof this.sortType == "string"){
9220 this.sortType = st[this.sortType];
9223 // set default sortType for strings and dates
9227 this.sortType = st.asUCString;
9230 this.sortType = st.asDate;
9233 this.sortType = st.none;
9238 var stripRe = /[\$,%]/g;
9240 // prebuilt conversion function for this field, instead of
9241 // switching every time we're reading a value
9243 var cv, dateFormat = this.dateFormat;
9248 cv = function(v){ return v; };
9251 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9255 return v !== undefined && v !== null && v !== '' ?
9256 parseInt(String(v).replace(stripRe, ""), 10) : '';
9261 return v !== undefined && v !== null && v !== '' ?
9262 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9267 cv = function(v){ return v === true || v === "true" || v == 1; };
9274 if(v instanceof Date){
9278 if(dateFormat == "timestamp"){
9279 return new Date(v*1000);
9281 return Date.parseDate(v, dateFormat);
9283 var parsed = Date.parse(v);
9284 return parsed ? new Date(parsed) : null;
9293 Roo.data.Field.prototype = {
9301 * Ext JS Library 1.1.1
9302 * Copyright(c) 2006-2007, Ext JS, LLC.
9304 * Originally Released Under LGPL - original licence link has changed is not relivant.
9307 * <script type="text/javascript">
9310 // Base class for reading structured data from a data source. This class is intended to be
9311 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9314 * @class Roo.data.DataReader
9315 * Base class for reading structured data from a data source. This class is intended to be
9316 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9319 Roo.data.DataReader = function(meta, recordType){
9323 this.recordType = recordType instanceof Array ?
9324 Roo.data.Record.create(recordType) : recordType;
9327 Roo.data.DataReader.prototype = {
9329 * Create an empty record
9330 * @param {Object} data (optional) - overlay some values
9331 * @return {Roo.data.Record} record created.
9333 newRow : function(d) {
9335 this.recordType.prototype.fields.each(function(c) {
9337 case 'int' : da[c.name] = 0; break;
9338 case 'date' : da[c.name] = new Date(); break;
9339 case 'float' : da[c.name] = 0.0; break;
9340 case 'boolean' : da[c.name] = false; break;
9341 default : da[c.name] = ""; break;
9345 return new this.recordType(Roo.apply(da, d));
9350 * Ext JS Library 1.1.1
9351 * Copyright(c) 2006-2007, Ext JS, LLC.
9353 * Originally Released Under LGPL - original licence link has changed is not relivant.
9356 * <script type="text/javascript">
9360 * @class Roo.data.DataProxy
9361 * @extends Roo.data.Observable
9362 * This class is an abstract base class for implementations which provide retrieval of
9363 * unformatted data objects.<br>
9365 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9366 * (of the appropriate type which knows how to parse the data object) to provide a block of
9367 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9369 * Custom implementations must implement the load method as described in
9370 * {@link Roo.data.HttpProxy#load}.
9372 Roo.data.DataProxy = function(){
9376 * Fires before a network request is made to retrieve a data object.
9377 * @param {Object} This DataProxy object.
9378 * @param {Object} params The params parameter to the load function.
9383 * Fires before the load method's callback is called.
9384 * @param {Object} This DataProxy object.
9385 * @param {Object} o The data object.
9386 * @param {Object} arg The callback argument object passed to the load function.
9390 * @event loadexception
9391 * Fires if an Exception occurs during data retrieval.
9392 * @param {Object} This DataProxy object.
9393 * @param {Object} o The data object.
9394 * @param {Object} arg The callback argument object passed to the load function.
9395 * @param {Object} e The Exception.
9397 loadexception : true
9399 Roo.data.DataProxy.superclass.constructor.call(this);
9402 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9405 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9409 * Ext JS Library 1.1.1
9410 * Copyright(c) 2006-2007, Ext JS, LLC.
9412 * Originally Released Under LGPL - original licence link has changed is not relivant.
9415 * <script type="text/javascript">
9418 * @class Roo.data.MemoryProxy
9419 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9420 * to the Reader when its load method is called.
9422 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9424 Roo.data.MemoryProxy = function(data){
9428 Roo.data.MemoryProxy.superclass.constructor.call(this);
9432 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9434 * Load data from the requested source (in this case an in-memory
9435 * data object passed to the constructor), read the data object into
9436 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9437 * process that block using the passed callback.
9438 * @param {Object} params This parameter is not used by the MemoryProxy class.
9439 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9440 * object into a block of Roo.data.Records.
9441 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9442 * The function must be passed <ul>
9443 * <li>The Record block object</li>
9444 * <li>The "arg" argument from the load function</li>
9445 * <li>A boolean success indicator</li>
9447 * @param {Object} scope The scope in which to call the callback
9448 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9450 load : function(params, reader, callback, scope, arg){
9451 params = params || {};
9454 result = reader.readRecords(this.data);
9456 this.fireEvent("loadexception", this, arg, null, e);
9457 callback.call(scope, null, arg, false);
9460 callback.call(scope, result, arg, true);
9464 update : function(params, records){
9469 * Ext JS Library 1.1.1
9470 * Copyright(c) 2006-2007, Ext JS, LLC.
9472 * Originally Released Under LGPL - original licence link has changed is not relivant.
9475 * <script type="text/javascript">
9478 * @class Roo.data.HttpProxy
9479 * @extends Roo.data.DataProxy
9480 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9481 * configured to reference a certain URL.<br><br>
9483 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9484 * from which the running page was served.<br><br>
9486 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9488 * Be aware that to enable the browser to parse an XML document, the server must set
9489 * the Content-Type header in the HTTP response to "text/xml".
9491 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9492 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9493 * will be used to make the request.
9495 Roo.data.HttpProxy = function(conn){
9496 Roo.data.HttpProxy.superclass.constructor.call(this);
9497 // is conn a conn config or a real conn?
9499 this.useAjax = !conn || !conn.events;
9503 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9504 // thse are take from connection...
9507 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9510 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9511 * extra parameters to each request made by this object. (defaults to undefined)
9514 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9515 * to each request made by this object. (defaults to undefined)
9518 * @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)
9521 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9524 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9530 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9534 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9535 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9536 * a finer-grained basis than the DataProxy events.
9538 getConnection : function(){
9539 return this.useAjax ? Roo.Ajax : this.conn;
9543 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9544 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9545 * process that block using the passed callback.
9546 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9547 * for the request to the remote server.
9548 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9549 * object into a block of Roo.data.Records.
9550 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9551 * The function must be passed <ul>
9552 * <li>The Record block object</li>
9553 * <li>The "arg" argument from the load function</li>
9554 * <li>A boolean success indicator</li>
9556 * @param {Object} scope The scope in which to call the callback
9557 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9559 load : function(params, reader, callback, scope, arg){
9560 if(this.fireEvent("beforeload", this, params) !== false){
9562 params : params || {},
9564 callback : callback,
9569 callback : this.loadResponse,
9573 Roo.applyIf(o, this.conn);
9574 if(this.activeRequest){
9575 Roo.Ajax.abort(this.activeRequest);
9577 this.activeRequest = Roo.Ajax.request(o);
9579 this.conn.request(o);
9582 callback.call(scope||this, null, arg, false);
9587 loadResponse : function(o, success, response){
9588 delete this.activeRequest;
9590 this.fireEvent("loadexception", this, o, response);
9591 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9596 result = o.reader.read(response);
9598 this.fireEvent("loadexception", this, o, response, e);
9599 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9603 this.fireEvent("load", this, o, o.request.arg);
9604 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9608 update : function(dataSet){
9613 updateResponse : function(dataSet){
9618 * Ext JS Library 1.1.1
9619 * Copyright(c) 2006-2007, Ext JS, LLC.
9621 * Originally Released Under LGPL - original licence link has changed is not relivant.
9624 * <script type="text/javascript">
9628 * @class Roo.data.ScriptTagProxy
9629 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9630 * other than the originating domain of the running page.<br><br>
9632 * <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
9633 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9635 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9636 * source code that is used as the source inside a <script> tag.<br><br>
9638 * In order for the browser to process the returned data, the server must wrap the data object
9639 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9640 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9641 * depending on whether the callback name was passed:
9644 boolean scriptTag = false;
9645 String cb = request.getParameter("callback");
9648 response.setContentType("text/javascript");
9650 response.setContentType("application/x-json");
9652 Writer out = response.getWriter();
9654 out.write(cb + "(");
9656 out.print(dataBlock.toJsonString());
9663 * @param {Object} config A configuration object.
9665 Roo.data.ScriptTagProxy = function(config){
9666 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9667 Roo.apply(this, config);
9668 this.head = document.getElementsByTagName("head")[0];
9671 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9673 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9675 * @cfg {String} url The URL from which to request the data object.
9678 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9682 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9683 * the server the name of the callback function set up by the load call to process the returned data object.
9684 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9685 * javascript output which calls this named function passing the data object as its only parameter.
9687 callbackParam : "callback",
9689 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9690 * name to the request.
9695 * Load data from the configured URL, read the data object into
9696 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9697 * process that block using the passed callback.
9698 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9699 * for the request to the remote server.
9700 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9701 * object into a block of Roo.data.Records.
9702 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9703 * The function must be passed <ul>
9704 * <li>The Record block object</li>
9705 * <li>The "arg" argument from the load function</li>
9706 * <li>A boolean success indicator</li>
9708 * @param {Object} scope The scope in which to call the callback
9709 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9711 load : function(params, reader, callback, scope, arg){
9712 if(this.fireEvent("beforeload", this, params) !== false){
9714 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9717 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9719 url += "&_dc=" + (new Date().getTime());
9721 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9724 cb : "stcCallback"+transId,
9725 scriptId : "stcScript"+transId,
9729 callback : callback,
9735 window[trans.cb] = function(o){
9736 conn.handleResponse(o, trans);
9739 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9741 if(this.autoAbort !== false){
9745 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9747 var script = document.createElement("script");
9748 script.setAttribute("src", url);
9749 script.setAttribute("type", "text/javascript");
9750 script.setAttribute("id", trans.scriptId);
9751 this.head.appendChild(script);
9755 callback.call(scope||this, null, arg, false);
9760 isLoading : function(){
9761 return this.trans ? true : false;
9765 * Abort the current server request.
9768 if(this.isLoading()){
9769 this.destroyTrans(this.trans);
9774 destroyTrans : function(trans, isLoaded){
9775 this.head.removeChild(document.getElementById(trans.scriptId));
9776 clearTimeout(trans.timeoutId);
9778 window[trans.cb] = undefined;
9780 delete window[trans.cb];
9783 // if hasn't been loaded, wait for load to remove it to prevent script error
9784 window[trans.cb] = function(){
9785 window[trans.cb] = undefined;
9787 delete window[trans.cb];
9794 handleResponse : function(o, trans){
9796 this.destroyTrans(trans, true);
9799 result = trans.reader.readRecords(o);
9801 this.fireEvent("loadexception", this, o, trans.arg, e);
9802 trans.callback.call(trans.scope||window, null, trans.arg, false);
9805 this.fireEvent("load", this, o, trans.arg);
9806 trans.callback.call(trans.scope||window, result, trans.arg, true);
9810 handleFailure : function(trans){
9812 this.destroyTrans(trans, false);
9813 this.fireEvent("loadexception", this, null, trans.arg);
9814 trans.callback.call(trans.scope||window, null, trans.arg, false);
9818 * Ext JS Library 1.1.1
9819 * Copyright(c) 2006-2007, Ext JS, LLC.
9821 * Originally Released Under LGPL - original licence link has changed is not relivant.
9824 * <script type="text/javascript">
9828 * @class Roo.data.JsonReader
9829 * @extends Roo.data.DataReader
9830 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9831 * based on mappings in a provided Roo.data.Record constructor.
9833 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9834 * in the reply previously.
9839 var RecordDef = Roo.data.Record.create([
9840 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9841 {name: 'occupation'} // This field will use "occupation" as the mapping.
9843 var myReader = new Roo.data.JsonReader({
9844 totalProperty: "results", // The property which contains the total dataset size (optional)
9845 root: "rows", // The property which contains an Array of row objects
9846 id: "id" // The property within each row object that provides an ID for the record (optional)
9850 * This would consume a JSON file like this:
9852 { 'results': 2, 'rows': [
9853 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9854 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9857 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9858 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9859 * paged from the remote server.
9860 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9861 * @cfg {String} root name of the property which contains the Array of row objects.
9862 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9864 * Create a new JsonReader
9865 * @param {Object} meta Metadata configuration options
9866 * @param {Object} recordType Either an Array of field definition objects,
9867 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9869 Roo.data.JsonReader = function(meta, recordType){
9872 // set some defaults:
9874 totalProperty: 'total',
9875 successProperty : 'success',
9880 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9882 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9885 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9886 * Used by Store query builder to append _requestMeta to params.
9889 metaFromRemote : false,
9891 * This method is only used by a DataProxy which has retrieved data from a remote server.
9892 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9893 * @return {Object} data A data block which is used by an Roo.data.Store object as
9894 * a cache of Roo.data.Records.
9896 read : function(response){
9897 var json = response.responseText;
9899 var o = /* eval:var:o */ eval("("+json+")");
9901 throw {message: "JsonReader.read: Json object not found"};
9907 this.metaFromRemote = true;
9908 this.meta = o.metaData;
9909 this.recordType = Roo.data.Record.create(o.metaData.fields);
9910 this.onMetaChange(this.meta, this.recordType, o);
9912 return this.readRecords(o);
9915 // private function a store will implement
9916 onMetaChange : function(meta, recordType, o){
9923 simpleAccess: function(obj, subsc) {
9930 getJsonAccessor: function(){
9932 return function(expr) {
9934 return(re.test(expr))
9935 ? new Function("obj", "return obj." + expr)
9945 * Create a data block containing Roo.data.Records from an XML document.
9946 * @param {Object} o An object which contains an Array of row objects in the property specified
9947 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9948 * which contains the total size of the dataset.
9949 * @return {Object} data A data block which is used by an Roo.data.Store object as
9950 * a cache of Roo.data.Records.
9952 readRecords : function(o){
9954 * After any data loads, the raw JSON data is available for further custom processing.
9958 var s = this.meta, Record = this.recordType,
9959 f = Record.prototype.fields, fi = f.items, fl = f.length;
9961 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9963 if(s.totalProperty) {
9964 this.getTotal = this.getJsonAccessor(s.totalProperty);
9966 if(s.successProperty) {
9967 this.getSuccess = this.getJsonAccessor(s.successProperty);
9969 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9971 var g = this.getJsonAccessor(s.id);
9972 this.getId = function(rec) {
9974 return (r === undefined || r === "") ? null : r;
9977 this.getId = function(){return null;};
9980 for(var jj = 0; jj < fl; jj++){
9982 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9983 this.ef[jj] = this.getJsonAccessor(map);
9987 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9988 if(s.totalProperty){
9989 var vt = parseInt(this.getTotal(o), 10);
9994 if(s.successProperty){
9995 var vs = this.getSuccess(o);
9996 if(vs === false || vs === 'false'){
10001 for(var i = 0; i < c; i++){
10004 var id = this.getId(n);
10005 for(var j = 0; j < fl; j++){
10007 var v = this.ef[j](n);
10009 Roo.log('missing convert for ' + f.name);
10013 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10015 var record = new Record(values, id);
10017 records[i] = record;
10023 totalRecords : totalRecords
10028 * Ext JS Library 1.1.1
10029 * Copyright(c) 2006-2007, Ext JS, LLC.
10031 * Originally Released Under LGPL - original licence link has changed is not relivant.
10034 * <script type="text/javascript">
10038 * @class Roo.data.ArrayReader
10039 * @extends Roo.data.DataReader
10040 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10041 * Each element of that Array represents a row of data fields. The
10042 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10043 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10047 var RecordDef = Roo.data.Record.create([
10048 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10049 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10051 var myReader = new Roo.data.ArrayReader({
10052 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10056 * This would consume an Array like this:
10058 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10060 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10062 * Create a new JsonReader
10063 * @param {Object} meta Metadata configuration options.
10064 * @param {Object} recordType Either an Array of field definition objects
10065 * as specified to {@link Roo.data.Record#create},
10066 * or an {@link Roo.data.Record} object
10067 * created using {@link Roo.data.Record#create}.
10069 Roo.data.ArrayReader = function(meta, recordType){
10070 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10073 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10075 * Create a data block containing Roo.data.Records from an XML document.
10076 * @param {Object} o An Array of row objects which represents the dataset.
10077 * @return {Object} data A data block which is used by an Roo.data.Store object as
10078 * a cache of Roo.data.Records.
10080 readRecords : function(o){
10081 var sid = this.meta ? this.meta.id : null;
10082 var recordType = this.recordType, fields = recordType.prototype.fields;
10085 for(var i = 0; i < root.length; i++){
10088 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10089 for(var j = 0, jlen = fields.length; j < jlen; j++){
10090 var f = fields.items[j];
10091 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10092 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10094 values[f.name] = v;
10096 var record = new recordType(values, id);
10098 records[records.length] = record;
10102 totalRecords : records.length
10111 * @class Roo.bootstrap.ComboBox
10112 * @extends Roo.bootstrap.TriggerField
10113 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10114 * @cfg {Boolean} append (true|false) default false
10115 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10116 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10117 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10118 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10119 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10121 * Create a new ComboBox.
10122 * @param {Object} config Configuration options
10124 Roo.bootstrap.ComboBox = function(config){
10125 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10129 * Fires when the dropdown list is expanded
10130 * @param {Roo.bootstrap.ComboBox} combo This combo box
10135 * Fires when the dropdown list is collapsed
10136 * @param {Roo.bootstrap.ComboBox} combo This combo box
10140 * @event beforeselect
10141 * Fires before a list item is selected. Return false to cancel the selection.
10142 * @param {Roo.bootstrap.ComboBox} combo This combo box
10143 * @param {Roo.data.Record} record The data record returned from the underlying store
10144 * @param {Number} index The index of the selected item in the dropdown list
10146 'beforeselect' : true,
10149 * Fires when a list item is selected
10150 * @param {Roo.bootstrap.ComboBox} combo This combo box
10151 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10152 * @param {Number} index The index of the selected item in the dropdown list
10156 * @event beforequery
10157 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10158 * The event object passed has these properties:
10159 * @param {Roo.bootstrap.ComboBox} combo This combo box
10160 * @param {String} query The query
10161 * @param {Boolean} forceAll true to force "all" query
10162 * @param {Boolean} cancel true to cancel the query
10163 * @param {Object} e The query event object
10165 'beforequery': true,
10168 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10169 * @param {Roo.bootstrap.ComboBox} combo This combo box
10174 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10175 * @param {Roo.bootstrap.ComboBox} combo This combo box
10176 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10181 * Fires when the remove value from the combobox array
10182 * @param {Roo.bootstrap.ComboBox} combo This combo box
10189 this.tickItems = [];
10191 this.selectedIndex = -1;
10192 if(this.mode == 'local'){
10193 if(config.queryDelay === undefined){
10194 this.queryDelay = 10;
10196 if(config.minChars === undefined){
10202 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10205 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10206 * rendering into an Roo.Editor, defaults to false)
10209 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10210 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10213 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10216 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10217 * the dropdown list (defaults to undefined, with no header element)
10221 * @cfg {String/Roo.Template} tpl The template to use to render the output
10225 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10227 listWidth: undefined,
10229 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10230 * mode = 'remote' or 'text' if mode = 'local')
10232 displayField: undefined,
10234 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10235 * mode = 'remote' or 'value' if mode = 'local').
10236 * Note: use of a valueField requires the user make a selection
10237 * in order for a value to be mapped.
10239 valueField: undefined,
10243 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10244 * field's data value (defaults to the underlying DOM element's name)
10246 hiddenName: undefined,
10248 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10252 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10254 selectedClass: 'active',
10257 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10261 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10262 * anchor positions (defaults to 'tl-bl')
10264 listAlign: 'tl-bl?',
10266 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10270 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10271 * query specified by the allQuery config option (defaults to 'query')
10273 triggerAction: 'query',
10275 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10276 * (defaults to 4, does not apply if editable = false)
10280 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10281 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10285 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10286 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10290 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10291 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10295 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10296 * when editable = true (defaults to false)
10298 selectOnFocus:false,
10300 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10302 queryParam: 'query',
10304 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10305 * when mode = 'remote' (defaults to 'Loading...')
10307 loadingText: 'Loading...',
10309 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10313 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10317 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10318 * traditional select (defaults to true)
10322 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10326 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10330 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10331 * listWidth has a higher value)
10335 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10336 * allow the user to set arbitrary text into the field (defaults to false)
10338 forceSelection:false,
10340 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10341 * if typeAhead = true (defaults to 250)
10343 typeAheadDelay : 250,
10345 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10346 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10348 valueNotFoundText : undefined,
10350 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10352 blockFocus : false,
10355 * @cfg {Boolean} disableClear Disable showing of clear button.
10357 disableClear : false,
10359 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10361 alwaysQuery : false,
10364 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10378 btnPosition : 'right',
10379 triggerList : true,
10380 showToggleBtn : true,
10381 // element that contains real text value.. (when hidden is used..)
10383 getAutoCreate : function()
10390 if(!this.tickable){
10391 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10396 * ComboBox with tickable selections
10399 var align = this.labelAlign || this.parentLabelAlign();
10402 cls : 'form-group roo-combobox-tickable' //input-group
10408 cls : 'tickable-buttons',
10413 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10420 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10427 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10434 Roo.each(buttons.cn, function(c){
10436 c.cls += ' btn-' + _this.size;
10439 if (_this.disabled) {
10450 cls: 'form-hidden-field'
10454 cls: 'select2-choices',
10458 cls: 'select2-search-field',
10470 cls: 'select2-container input-group select2-container-multi',
10475 // cls: 'typeahead typeahead-long dropdown-menu',
10476 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10481 if (align ==='left' && this.fieldLabel.length) {
10483 Roo.log("left and has label");
10489 cls : 'control-label col-sm-' + this.labelWidth,
10490 html : this.fieldLabel
10494 cls : "col-sm-" + (12 - this.labelWidth),
10501 } else if ( this.fieldLabel.length) {
10507 //cls : 'input-group-addon',
10508 html : this.fieldLabel
10518 Roo.log(" no label && no align");
10525 ['xs','sm','md','lg'].map(function(size){
10526 if (settings[size]) {
10527 cfg.cls += ' col-' + size + '-' + settings[size];
10536 initEvents: function()
10540 throw "can not find store for combo";
10542 this.store = Roo.factory(this.store, Roo.data);
10545 this.initTickableEvents();
10549 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10551 if(this.hiddenName){
10553 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10555 this.hiddenField.dom.value =
10556 this.hiddenValue !== undefined ? this.hiddenValue :
10557 this.value !== undefined ? this.value : '';
10559 // prevent input submission
10560 this.el.dom.removeAttribute('name');
10561 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10566 // this.el.dom.setAttribute('autocomplete', 'off');
10569 var cls = 'x-combo-list';
10571 //this.list = new Roo.Layer({
10572 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10578 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10579 _this.list.setWidth(lw);
10582 this.list.on('mouseover', this.onViewOver, this);
10583 this.list.on('mousemove', this.onViewMove, this);
10585 this.list.on('scroll', this.onViewScroll, this);
10588 this.list.swallowEvent('mousewheel');
10589 this.assetHeight = 0;
10592 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10593 this.assetHeight += this.header.getHeight();
10596 this.innerList = this.list.createChild({cls:cls+'-inner'});
10597 this.innerList.on('mouseover', this.onViewOver, this);
10598 this.innerList.on('mousemove', this.onViewMove, this);
10599 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10601 if(this.allowBlank && !this.pageSize && !this.disableClear){
10602 this.footer = this.list.createChild({cls:cls+'-ft'});
10603 this.pageTb = new Roo.Toolbar(this.footer);
10607 this.footer = this.list.createChild({cls:cls+'-ft'});
10608 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10609 {pageSize: this.pageSize});
10613 if (this.pageTb && this.allowBlank && !this.disableClear) {
10615 this.pageTb.add(new Roo.Toolbar.Fill(), {
10616 cls: 'x-btn-icon x-btn-clear',
10618 handler: function()
10621 _this.clearValue();
10622 _this.onSelect(false, -1);
10627 this.assetHeight += this.footer.getHeight();
10632 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10635 this.view = new Roo.View(this.list, this.tpl, {
10636 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10638 //this.view.wrapEl.setDisplayed(false);
10639 this.view.on('click', this.onViewClick, this);
10643 this.store.on('beforeload', this.onBeforeLoad, this);
10644 this.store.on('load', this.onLoad, this);
10645 this.store.on('loadexception', this.onLoadException, this);
10647 if(this.resizable){
10648 this.resizer = new Roo.Resizable(this.list, {
10649 pinned:true, handles:'se'
10651 this.resizer.on('resize', function(r, w, h){
10652 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10653 this.listWidth = w;
10654 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10655 this.restrictHeight();
10657 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10660 if(!this.editable){
10661 this.editable = true;
10662 this.setEditable(false);
10667 if (typeof(this.events.add.listeners) != 'undefined') {
10669 this.addicon = this.wrap.createChild(
10670 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10672 this.addicon.on('click', function(e) {
10673 this.fireEvent('add', this);
10676 if (typeof(this.events.edit.listeners) != 'undefined') {
10678 this.editicon = this.wrap.createChild(
10679 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10680 if (this.addicon) {
10681 this.editicon.setStyle('margin-left', '40px');
10683 this.editicon.on('click', function(e) {
10685 // we fire even if inothing is selected..
10686 this.fireEvent('edit', this, this.lastData );
10692 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10693 "up" : function(e){
10694 this.inKeyMode = true;
10698 "down" : function(e){
10699 if(!this.isExpanded()){
10700 this.onTriggerClick();
10702 this.inKeyMode = true;
10707 "enter" : function(e){
10708 // this.onViewClick();
10712 if(this.fireEvent("specialkey", this, e)){
10713 this.onViewClick(false);
10719 "esc" : function(e){
10723 "tab" : function(e){
10726 if(this.fireEvent("specialkey", this, e)){
10727 this.onViewClick(false);
10735 doRelay : function(foo, bar, hname){
10736 if(hname == 'down' || this.scope.isExpanded()){
10737 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10746 this.queryDelay = Math.max(this.queryDelay || 10,
10747 this.mode == 'local' ? 10 : 250);
10750 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10752 if(this.typeAhead){
10753 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10755 if(this.editable !== false){
10756 this.inputEl().on("keyup", this.onKeyUp, this);
10758 if(this.forceSelection){
10759 this.inputEl().on('blur', this.doForce, this);
10763 this.choices = this.el.select('ul.select2-choices', true).first();
10764 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10768 initTickableEvents: function()
10772 if(this.hiddenName){
10774 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10776 this.hiddenField.dom.value =
10777 this.hiddenValue !== undefined ? this.hiddenValue :
10778 this.value !== undefined ? this.value : '';
10780 // prevent input submission
10781 this.el.dom.removeAttribute('name');
10782 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10787 // this.list = this.el.select('ul.dropdown-menu',true).first();
10789 this.choices = this.el.select('ul.select2-choices', true).first();
10790 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10791 if(this.triggerList){
10792 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10795 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10796 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10798 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10799 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10801 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10802 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10804 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10805 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10806 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10809 this.cancelBtn.hide();
10814 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10815 _this.list.setWidth(lw);
10818 this.list.on('mouseover', this.onViewOver, this);
10819 this.list.on('mousemove', this.onViewMove, this);
10821 this.list.on('scroll', this.onViewScroll, this);
10824 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>';
10827 this.view = new Roo.View(this.list, this.tpl, {
10828 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10831 //this.view.wrapEl.setDisplayed(false);
10832 this.view.on('click', this.onViewClick, this);
10836 this.store.on('beforeload', this.onBeforeLoad, this);
10837 this.store.on('load', this.onLoad, this);
10838 this.store.on('loadexception', this.onLoadException, this);
10840 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10841 // "up" : function(e){
10842 // this.inKeyMode = true;
10843 // this.selectPrev();
10846 // "down" : function(e){
10847 // if(!this.isExpanded()){
10848 // this.onTriggerClick();
10850 // this.inKeyMode = true;
10851 // this.selectNext();
10855 // "enter" : function(e){
10856 //// this.onViewClick();
10858 // this.collapse();
10860 // if(this.fireEvent("specialkey", this, e)){
10861 // this.onViewClick(false);
10867 // "esc" : function(e){
10868 // this.collapse();
10871 // "tab" : function(e){
10872 // this.collapse();
10874 // if(this.fireEvent("specialkey", this, e)){
10875 // this.onViewClick(false);
10883 // doRelay : function(foo, bar, hname){
10884 // if(hname == 'down' || this.scope.isExpanded()){
10885 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10890 // forceKeyDown: true
10894 this.queryDelay = Math.max(this.queryDelay || 10,
10895 this.mode == 'local' ? 10 : 250);
10898 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10900 if(this.typeAhead){
10901 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10905 onDestroy : function(){
10907 this.view.setStore(null);
10908 this.view.el.removeAllListeners();
10909 this.view.el.remove();
10910 this.view.purgeListeners();
10913 this.list.dom.innerHTML = '';
10917 this.store.un('beforeload', this.onBeforeLoad, this);
10918 this.store.un('load', this.onLoad, this);
10919 this.store.un('loadexception', this.onLoadException, this);
10921 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10925 fireKey : function(e){
10926 if(e.isNavKeyPress() && !this.list.isVisible()){
10927 this.fireEvent("specialkey", this, e);
10932 onResize: function(w, h){
10933 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10935 // if(typeof w != 'number'){
10936 // // we do not handle it!?!?
10939 // var tw = this.trigger.getWidth();
10940 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10941 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10943 // this.inputEl().setWidth( this.adjustWidth('input', x));
10945 // //this.trigger.setStyle('left', x+'px');
10947 // if(this.list && this.listWidth === undefined){
10948 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10949 // this.list.setWidth(lw);
10950 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10958 * Allow or prevent the user from directly editing the field text. If false is passed,
10959 * the user will only be able to select from the items defined in the dropdown list. This method
10960 * is the runtime equivalent of setting the 'editable' config option at config time.
10961 * @param {Boolean} value True to allow the user to directly edit the field text
10963 setEditable : function(value){
10964 if(value == this.editable){
10967 this.editable = value;
10969 this.inputEl().dom.setAttribute('readOnly', true);
10970 this.inputEl().on('mousedown', this.onTriggerClick, this);
10971 this.inputEl().addClass('x-combo-noedit');
10973 this.inputEl().dom.setAttribute('readOnly', false);
10974 this.inputEl().un('mousedown', this.onTriggerClick, this);
10975 this.inputEl().removeClass('x-combo-noedit');
10981 onBeforeLoad : function(combo,opts){
10982 if(!this.hasFocus){
10986 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10988 // this.restrictHeight();
10989 this.selectedIndex = -1;
10993 onLoad : function(){
10995 this.hasQuery = false;
10997 if(!this.hasFocus){
11001 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11002 this.loading.hide();
11005 if(this.store.getCount() > 0){
11007 // this.restrictHeight();
11008 if(this.lastQuery == this.allQuery){
11009 if(this.editable && !this.tickable){
11010 this.inputEl().dom.select();
11012 if(!this.selectByValue(this.value, true) && this.autoFocus){
11013 this.select(0, true);
11016 if(this.autoFocus){
11019 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11020 this.taTask.delay(this.typeAheadDelay);
11024 this.onEmptyResults();
11030 onLoadException : function()
11032 this.hasQuery = false;
11034 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11035 this.loading.hide();
11039 Roo.log(this.store.reader.jsonData);
11040 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11042 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11048 onTypeAhead : function(){
11049 if(this.store.getCount() > 0){
11050 var r = this.store.getAt(0);
11051 var newValue = r.data[this.displayField];
11052 var len = newValue.length;
11053 var selStart = this.getRawValue().length;
11055 if(selStart != len){
11056 this.setRawValue(newValue);
11057 this.selectText(selStart, newValue.length);
11063 onSelect : function(record, index){
11065 if(this.fireEvent('beforeselect', this, record, index) !== false){
11067 this.setFromData(index > -1 ? record.data : false);
11070 this.fireEvent('select', this, record, index);
11075 * Returns the currently selected field value or empty string if no value is set.
11076 * @return {String} value The selected value
11078 getValue : function(){
11081 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11084 if(this.valueField){
11085 return typeof this.value != 'undefined' ? this.value : '';
11087 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11092 * Clears any text/value currently set in the field
11094 clearValue : function(){
11095 if(this.hiddenField){
11096 this.hiddenField.dom.value = '';
11099 this.setRawValue('');
11100 this.lastSelectionText = '';
11105 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11106 * will be displayed in the field. If the value does not match the data value of an existing item,
11107 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11108 * Otherwise the field will be blank (although the value will still be set).
11109 * @param {String} value The value to match
11111 setValue : function(v){
11118 if(this.valueField){
11119 var r = this.findRecord(this.valueField, v);
11121 text = r.data[this.displayField];
11122 }else if(this.valueNotFoundText !== undefined){
11123 text = this.valueNotFoundText;
11126 this.lastSelectionText = text;
11127 if(this.hiddenField){
11128 this.hiddenField.dom.value = v;
11130 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11134 * @property {Object} the last set data for the element
11139 * Sets the value of the field based on a object which is related to the record format for the store.
11140 * @param {Object} value the value to set as. or false on reset?
11142 setFromData : function(o){
11145 if(typeof o.display_name !== 'string'){
11146 for(var i=0;i<o.display_name.length;i++){
11147 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11155 var dv = ''; // display value
11156 var vv = ''; // value value..
11158 if (this.displayField) {
11159 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11161 // this is an error condition!!!
11162 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11165 if(this.valueField){
11166 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11169 if(this.hiddenField){
11170 this.hiddenField.dom.value = vv;
11172 this.lastSelectionText = dv;
11173 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11177 // no hidden field.. - we store the value in 'value', but still display
11178 // display field!!!!
11179 this.lastSelectionText = dv;
11180 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11186 reset : function(){
11187 // overridden so that last data is reset..
11188 this.setValue(this.originalValue);
11189 this.clearInvalid();
11190 this.lastData = false;
11192 this.view.clearSelections();
11196 findRecord : function(prop, value){
11198 if(this.store.getCount() > 0){
11199 this.store.each(function(r){
11200 if(r.data[prop] == value){
11210 getName: function()
11212 // returns hidden if it's set..
11213 if (!this.rendered) {return ''};
11214 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11218 onViewMove : function(e, t){
11219 this.inKeyMode = false;
11223 onViewOver : function(e, t){
11224 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11227 var item = this.view.findItemFromChild(t);
11230 var index = this.view.indexOf(item);
11231 this.select(index, false);
11236 onViewClick : function(view, doFocus, el, e)
11238 var index = this.view.getSelectedIndexes()[0];
11240 var r = this.store.getAt(index);
11244 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11251 Roo.each(this.tickItems, function(v,k){
11253 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11254 _this.tickItems.splice(k, 1);
11264 this.tickItems.push(r.data);
11269 this.onSelect(r, index);
11271 if(doFocus !== false && !this.blockFocus){
11272 this.inputEl().focus();
11277 restrictHeight : function(){
11278 //this.innerList.dom.style.height = '';
11279 //var inner = this.innerList.dom;
11280 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11281 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11282 //this.list.beginUpdate();
11283 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11284 this.list.alignTo(this.inputEl(), this.listAlign);
11285 this.list.alignTo(this.inputEl(), this.listAlign);
11286 //this.list.endUpdate();
11290 onEmptyResults : function(){
11295 * Returns true if the dropdown list is expanded, else false.
11297 isExpanded : function(){
11298 return this.list.isVisible();
11302 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11303 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11304 * @param {String} value The data value of the item to select
11305 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11306 * selected item if it is not currently in view (defaults to true)
11307 * @return {Boolean} True if the value matched an item in the list, else false
11309 selectByValue : function(v, scrollIntoView){
11310 if(v !== undefined && v !== null){
11311 var r = this.findRecord(this.valueField || this.displayField, v);
11313 this.select(this.store.indexOf(r), scrollIntoView);
11321 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11322 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11323 * @param {Number} index The zero-based index of the list item to select
11324 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11325 * selected item if it is not currently in view (defaults to true)
11327 select : function(index, scrollIntoView){
11328 this.selectedIndex = index;
11329 this.view.select(index);
11330 if(scrollIntoView !== false){
11331 var el = this.view.getNode(index);
11332 if(el && !this.multiple && !this.tickable){
11333 this.list.scrollChildIntoView(el, false);
11339 selectNext : function(){
11340 var ct = this.store.getCount();
11342 if(this.selectedIndex == -1){
11344 }else if(this.selectedIndex < ct-1){
11345 this.select(this.selectedIndex+1);
11351 selectPrev : function(){
11352 var ct = this.store.getCount();
11354 if(this.selectedIndex == -1){
11356 }else if(this.selectedIndex != 0){
11357 this.select(this.selectedIndex-1);
11363 onKeyUp : function(e){
11364 if(this.editable !== false && !e.isSpecialKey()){
11365 this.lastKey = e.getKey();
11366 this.dqTask.delay(this.queryDelay);
11371 validateBlur : function(){
11372 return !this.list || !this.list.isVisible();
11376 initQuery : function(){
11377 this.doQuery(this.getRawValue());
11381 doForce : function(){
11382 if(this.inputEl().dom.value.length > 0){
11383 this.inputEl().dom.value =
11384 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11390 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11391 * query allowing the query action to be canceled if needed.
11392 * @param {String} query The SQL query to execute
11393 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11394 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11395 * saved in the current store (defaults to false)
11397 doQuery : function(q, forceAll){
11399 if(q === undefined || q === null){
11404 forceAll: forceAll,
11408 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11413 forceAll = qe.forceAll;
11414 if(forceAll === true || (q.length >= this.minChars)){
11416 this.hasQuery = true;
11418 if(this.lastQuery != q || this.alwaysQuery){
11419 this.lastQuery = q;
11420 if(this.mode == 'local'){
11421 this.selectedIndex = -1;
11423 this.store.clearFilter();
11425 this.store.filter(this.displayField, q);
11429 this.store.baseParams[this.queryParam] = q;
11431 var options = {params : this.getParams(q)};
11434 options.add = true;
11435 options.params.start = this.page * this.pageSize;
11438 this.store.load(options);
11440 * this code will make the page width larger, at the beginning, the list not align correctly,
11441 * we should expand the list on onLoad
11442 * so command out it
11447 this.selectedIndex = -1;
11452 this.loadNext = false;
11456 getParams : function(q){
11458 //p[this.queryParam] = q;
11462 p.limit = this.pageSize;
11468 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11470 collapse : function(){
11471 if(!this.isExpanded()){
11475 this.hasFocus = false;
11481 this.cancelBtn.hide();
11482 this.trigger.show();
11485 Roo.get(document).un('mousedown', this.collapseIf, this);
11486 Roo.get(document).un('mousewheel', this.collapseIf, this);
11487 if (!this.editable) {
11488 Roo.get(document).un('keydown', this.listKeyPress, this);
11490 this.fireEvent('collapse', this);
11494 collapseIf : function(e){
11495 var in_combo = e.within(this.el);
11496 var in_list = e.within(this.list);
11497 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11499 if (in_combo || in_list || is_list) {
11500 //e.stopPropagation();
11505 this.onTickableFooterButtonClick(e, false, false);
11513 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11515 expand : function(){
11517 if(this.isExpanded() || !this.hasFocus){
11524 this.restrictHeight();
11528 this.tickItems = Roo.apply([], this.item);
11531 this.cancelBtn.show();
11532 this.trigger.hide();
11536 Roo.get(document).on('mousedown', this.collapseIf, this);
11537 Roo.get(document).on('mousewheel', this.collapseIf, this);
11538 if (!this.editable) {
11539 Roo.get(document).on('keydown', this.listKeyPress, this);
11542 this.fireEvent('expand', this);
11546 // Implements the default empty TriggerField.onTriggerClick function
11547 onTriggerClick : function(e)
11549 Roo.log('trigger click');
11551 if(this.disabled || !this.triggerList){
11556 this.loadNext = false;
11558 if(this.isExpanded()){
11560 if (!this.blockFocus) {
11561 this.inputEl().focus();
11565 this.hasFocus = true;
11566 if(this.triggerAction == 'all') {
11567 this.doQuery(this.allQuery, true);
11569 this.doQuery(this.getRawValue());
11571 if (!this.blockFocus) {
11572 this.inputEl().focus();
11577 onTickableTriggerClick : function(e)
11584 this.loadNext = false;
11585 this.hasFocus = true;
11587 if(this.triggerAction == 'all') {
11588 this.doQuery(this.allQuery, true);
11590 this.doQuery(this.getRawValue());
11594 onSearchFieldClick : function(e)
11596 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11601 this.loadNext = false;
11602 this.hasFocus = true;
11604 if(this.triggerAction == 'all') {
11605 this.doQuery(this.allQuery, true);
11607 this.doQuery(this.getRawValue());
11611 listKeyPress : function(e)
11613 //Roo.log('listkeypress');
11614 // scroll to first matching element based on key pres..
11615 if (e.isSpecialKey()) {
11618 var k = String.fromCharCode(e.getKey()).toUpperCase();
11621 var csel = this.view.getSelectedNodes();
11622 var cselitem = false;
11624 var ix = this.view.indexOf(csel[0]);
11625 cselitem = this.store.getAt(ix);
11626 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11632 this.store.each(function(v) {
11634 // start at existing selection.
11635 if (cselitem.id == v.id) {
11641 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11642 match = this.store.indexOf(v);
11648 if (match === false) {
11649 return true; // no more action?
11652 this.view.select(match);
11653 var sn = Roo.get(this.view.getSelectedNodes()[0])
11654 //sn.scrollIntoView(sn.dom.parentNode, false);
11657 onViewScroll : function(e, t){
11659 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11663 this.hasQuery = true;
11665 this.loading = this.list.select('.loading', true).first();
11667 if(this.loading === null){
11668 this.list.createChild({
11670 cls: 'loading select2-more-results select2-active',
11671 html: 'Loading more results...'
11674 this.loading = this.list.select('.loading', true).first();
11676 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11678 this.loading.hide();
11681 this.loading.show();
11686 this.loadNext = true;
11688 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11693 addItem : function(o)
11695 var dv = ''; // display value
11697 if (this.displayField) {
11698 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11700 // this is an error condition!!!
11701 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11708 var choice = this.choices.createChild({
11710 cls: 'select2-search-choice',
11719 cls: 'select2-search-choice-close',
11724 }, this.searchField);
11726 var close = choice.select('a.select2-search-choice-close', true).first()
11728 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11736 this.inputEl().dom.value = '';
11740 onRemoveItem : function(e, _self, o)
11742 e.preventDefault();
11743 var index = this.item.indexOf(o.data) * 1;
11746 Roo.log('not this item?!');
11750 this.item.splice(index, 1);
11755 this.fireEvent('remove', this, e);
11759 syncValue : function()
11761 if(!this.item.length){
11768 Roo.each(this.item, function(i){
11769 if(_this.valueField){
11770 value.push(i[_this.valueField]);
11777 this.value = value.join(',');
11779 if(this.hiddenField){
11780 this.hiddenField.dom.value = this.value;
11784 clearItem : function()
11786 if(!this.multiple){
11792 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11799 inputEl: function ()
11802 return this.searchField;
11804 return this.el.select('input.form-control',true).first();
11808 onTickableFooterButtonClick : function(e, btn, el)
11810 e.preventDefault();
11812 if(btn && btn.name == 'cancel'){
11813 this.tickItems = Roo.apply([], this.item);
11822 Roo.each(this.tickItems, function(o){
11833 * @cfg {Boolean} grow
11837 * @cfg {Number} growMin
11841 * @cfg {Number} growMax
11851 * Ext JS Library 1.1.1
11852 * Copyright(c) 2006-2007, Ext JS, LLC.
11854 * Originally Released Under LGPL - original licence link has changed is not relivant.
11857 * <script type="text/javascript">
11862 * @extends Roo.util.Observable
11863 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11864 * This class also supports single and multi selection modes. <br>
11865 * Create a data model bound view:
11867 var store = new Roo.data.Store(...);
11869 var view = new Roo.View({
11871 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11873 singleSelect: true,
11874 selectedClass: "ydataview-selected",
11878 // listen for node click?
11879 view.on("click", function(vw, index, node, e){
11880 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11884 dataModel.load("foobar.xml");
11886 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11888 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11889 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11891 * Note: old style constructor is still suported (container, template, config)
11894 * Create a new View
11895 * @param {Object} config The config object
11898 Roo.View = function(config, depreciated_tpl, depreciated_config){
11900 this.parent = false;
11902 if (typeof(depreciated_tpl) == 'undefined') {
11903 // new way.. - universal constructor.
11904 Roo.apply(this, config);
11905 this.el = Roo.get(this.el);
11908 this.el = Roo.get(config);
11909 this.tpl = depreciated_tpl;
11910 Roo.apply(this, depreciated_config);
11912 this.wrapEl = this.el.wrap().wrap();
11913 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11916 if(typeof(this.tpl) == "string"){
11917 this.tpl = new Roo.Template(this.tpl);
11919 // support xtype ctors..
11920 this.tpl = new Roo.factory(this.tpl, Roo);
11924 this.tpl.compile();
11929 * @event beforeclick
11930 * Fires before a click is processed. Returns false to cancel the default action.
11931 * @param {Roo.View} this
11932 * @param {Number} index The index of the target node
11933 * @param {HTMLElement} node The target node
11934 * @param {Roo.EventObject} e The raw event object
11936 "beforeclick" : true,
11939 * Fires when a template node is clicked.
11940 * @param {Roo.View} this
11941 * @param {Number} index The index of the target node
11942 * @param {HTMLElement} node The target node
11943 * @param {Roo.EventObject} e The raw event object
11948 * Fires when a template node is double clicked.
11949 * @param {Roo.View} this
11950 * @param {Number} index The index of the target node
11951 * @param {HTMLElement} node The target node
11952 * @param {Roo.EventObject} e The raw event object
11956 * @event contextmenu
11957 * Fires when a template node is right clicked.
11958 * @param {Roo.View} this
11959 * @param {Number} index The index of the target node
11960 * @param {HTMLElement} node The target node
11961 * @param {Roo.EventObject} e The raw event object
11963 "contextmenu" : true,
11965 * @event selectionchange
11966 * Fires when the selected nodes change.
11967 * @param {Roo.View} this
11968 * @param {Array} selections Array of the selected nodes
11970 "selectionchange" : true,
11973 * @event beforeselect
11974 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11975 * @param {Roo.View} this
11976 * @param {HTMLElement} node The node to be selected
11977 * @param {Array} selections Array of currently selected nodes
11979 "beforeselect" : true,
11981 * @event preparedata
11982 * Fires on every row to render, to allow you to change the data.
11983 * @param {Roo.View} this
11984 * @param {Object} data to be rendered (change this)
11986 "preparedata" : true
11994 "click": this.onClick,
11995 "dblclick": this.onDblClick,
11996 "contextmenu": this.onContextMenu,
12000 this.selections = [];
12002 this.cmp = new Roo.CompositeElementLite([]);
12004 this.store = Roo.factory(this.store, Roo.data);
12005 this.setStore(this.store, true);
12008 if ( this.footer && this.footer.xtype) {
12010 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12012 this.footer.dataSource = this.store
12013 this.footer.container = fctr;
12014 this.footer = Roo.factory(this.footer, Roo);
12015 fctr.insertFirst(this.el);
12017 // this is a bit insane - as the paging toolbar seems to detach the el..
12018 // dom.parentNode.parentNode.parentNode
12019 // they get detached?
12023 Roo.View.superclass.constructor.call(this);
12028 Roo.extend(Roo.View, Roo.util.Observable, {
12031 * @cfg {Roo.data.Store} store Data store to load data from.
12036 * @cfg {String|Roo.Element} el The container element.
12041 * @cfg {String|Roo.Template} tpl The template used by this View
12045 * @cfg {String} dataName the named area of the template to use as the data area
12046 * Works with domtemplates roo-name="name"
12050 * @cfg {String} selectedClass The css class to add to selected nodes
12052 selectedClass : "x-view-selected",
12054 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12059 * @cfg {String} text to display on mask (default Loading)
12063 * @cfg {Boolean} multiSelect Allow multiple selection
12065 multiSelect : false,
12067 * @cfg {Boolean} singleSelect Allow single selection
12069 singleSelect: false,
12072 * @cfg {Boolean} toggleSelect - selecting
12074 toggleSelect : false,
12077 * @cfg {Boolean} tickable - selecting
12082 * Returns the element this view is bound to.
12083 * @return {Roo.Element}
12085 getEl : function(){
12086 return this.wrapEl;
12092 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12094 refresh : function(){
12095 Roo.log('refresh');
12098 // if we are using something like 'domtemplate', then
12099 // the what gets used is:
12100 // t.applySubtemplate(NAME, data, wrapping data..)
12101 // the outer template then get' applied with
12102 // the store 'extra data'
12103 // and the body get's added to the
12104 // roo-name="data" node?
12105 // <span class='roo-tpl-{name}'></span> ?????
12109 this.clearSelections();
12110 this.el.update("");
12112 var records = this.store.getRange();
12113 if(records.length < 1) {
12115 // is this valid?? = should it render a template??
12117 this.el.update(this.emptyText);
12121 if (this.dataName) {
12122 this.el.update(t.apply(this.store.meta)); //????
12123 el = this.el.child('.roo-tpl-' + this.dataName);
12126 for(var i = 0, len = records.length; i < len; i++){
12127 var data = this.prepareData(records[i].data, i, records[i]);
12128 this.fireEvent("preparedata", this, data, i, records[i]);
12130 var d = Roo.apply({}, data);
12133 Roo.apply(d, {'roo-id' : Roo.id()});
12137 Roo.each(this.parent.item, function(item){
12138 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12141 Roo.apply(d, {'roo-data-checked' : 'checked'});
12145 html[html.length] = Roo.util.Format.trim(
12147 t.applySubtemplate(this.dataName, d, this.store.meta) :
12154 el.update(html.join(""));
12155 this.nodes = el.dom.childNodes;
12156 this.updateIndexes(0);
12161 * Function to override to reformat the data that is sent to
12162 * the template for each node.
12163 * DEPRICATED - use the preparedata event handler.
12164 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12165 * a JSON object for an UpdateManager bound view).
12167 prepareData : function(data, index, record)
12169 this.fireEvent("preparedata", this, data, index, record);
12173 onUpdate : function(ds, record){
12174 Roo.log('on update');
12175 this.clearSelections();
12176 var index = this.store.indexOf(record);
12177 var n = this.nodes[index];
12178 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12179 n.parentNode.removeChild(n);
12180 this.updateIndexes(index, index);
12186 onAdd : function(ds, records, index)
12188 Roo.log(['on Add', ds, records, index] );
12189 this.clearSelections();
12190 if(this.nodes.length == 0){
12194 var n = this.nodes[index];
12195 for(var i = 0, len = records.length; i < len; i++){
12196 var d = this.prepareData(records[i].data, i, records[i]);
12198 this.tpl.insertBefore(n, d);
12201 this.tpl.append(this.el, d);
12204 this.updateIndexes(index);
12207 onRemove : function(ds, record, index){
12208 Roo.log('onRemove');
12209 this.clearSelections();
12210 var el = this.dataName ?
12211 this.el.child('.roo-tpl-' + this.dataName) :
12214 el.dom.removeChild(this.nodes[index]);
12215 this.updateIndexes(index);
12219 * Refresh an individual node.
12220 * @param {Number} index
12222 refreshNode : function(index){
12223 this.onUpdate(this.store, this.store.getAt(index));
12226 updateIndexes : function(startIndex, endIndex){
12227 var ns = this.nodes;
12228 startIndex = startIndex || 0;
12229 endIndex = endIndex || ns.length - 1;
12230 for(var i = startIndex; i <= endIndex; i++){
12231 ns[i].nodeIndex = i;
12236 * Changes the data store this view uses and refresh the view.
12237 * @param {Store} store
12239 setStore : function(store, initial){
12240 if(!initial && this.store){
12241 this.store.un("datachanged", this.refresh);
12242 this.store.un("add", this.onAdd);
12243 this.store.un("remove", this.onRemove);
12244 this.store.un("update", this.onUpdate);
12245 this.store.un("clear", this.refresh);
12246 this.store.un("beforeload", this.onBeforeLoad);
12247 this.store.un("load", this.onLoad);
12248 this.store.un("loadexception", this.onLoad);
12252 store.on("datachanged", this.refresh, this);
12253 store.on("add", this.onAdd, this);
12254 store.on("remove", this.onRemove, this);
12255 store.on("update", this.onUpdate, this);
12256 store.on("clear", this.refresh, this);
12257 store.on("beforeload", this.onBeforeLoad, this);
12258 store.on("load", this.onLoad, this);
12259 store.on("loadexception", this.onLoad, this);
12267 * onbeforeLoad - masks the loading area.
12270 onBeforeLoad : function(store,opts)
12272 Roo.log('onBeforeLoad');
12274 this.el.update("");
12276 this.el.mask(this.mask ? this.mask : "Loading" );
12278 onLoad : function ()
12285 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12286 * @param {HTMLElement} node
12287 * @return {HTMLElement} The template node
12289 findItemFromChild : function(node){
12290 var el = this.dataName ?
12291 this.el.child('.roo-tpl-' + this.dataName,true) :
12294 if(!node || node.parentNode == el){
12297 var p = node.parentNode;
12298 while(p && p != el){
12299 if(p.parentNode == el){
12308 onClick : function(e){
12309 var item = this.findItemFromChild(e.getTarget());
12311 var index = this.indexOf(item);
12312 if(this.onItemClick(item, index, e) !== false){
12313 this.fireEvent("click", this, index, item, e);
12316 this.clearSelections();
12321 onContextMenu : function(e){
12322 var item = this.findItemFromChild(e.getTarget());
12324 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12329 onDblClick : function(e){
12330 var item = this.findItemFromChild(e.getTarget());
12332 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12336 onItemClick : function(item, index, e)
12338 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12341 if (this.toggleSelect) {
12342 var m = this.isSelected(item) ? 'unselect' : 'select';
12345 _t[m](item, true, false);
12348 if(this.multiSelect || this.singleSelect){
12349 if(this.multiSelect && e.shiftKey && this.lastSelection){
12350 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12352 this.select(item, this.multiSelect && e.ctrlKey);
12353 this.lastSelection = item;
12356 if(!this.tickable){
12357 e.preventDefault();
12365 * Get the number of selected nodes.
12368 getSelectionCount : function(){
12369 return this.selections.length;
12373 * Get the currently selected nodes.
12374 * @return {Array} An array of HTMLElements
12376 getSelectedNodes : function(){
12377 return this.selections;
12381 * Get the indexes of the selected nodes.
12384 getSelectedIndexes : function(){
12385 var indexes = [], s = this.selections;
12386 for(var i = 0, len = s.length; i < len; i++){
12387 indexes.push(s[i].nodeIndex);
12393 * Clear all selections
12394 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12396 clearSelections : function(suppressEvent){
12397 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12398 this.cmp.elements = this.selections;
12399 this.cmp.removeClass(this.selectedClass);
12400 this.selections = [];
12401 if(!suppressEvent){
12402 this.fireEvent("selectionchange", this, this.selections);
12408 * Returns true if the passed node is selected
12409 * @param {HTMLElement/Number} node The node or node index
12410 * @return {Boolean}
12412 isSelected : function(node){
12413 var s = this.selections;
12417 node = this.getNode(node);
12418 return s.indexOf(node) !== -1;
12423 * @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
12424 * @param {Boolean} keepExisting (optional) true to keep existing selections
12425 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12427 select : function(nodeInfo, keepExisting, suppressEvent){
12428 if(nodeInfo instanceof Array){
12430 this.clearSelections(true);
12432 for(var i = 0, len = nodeInfo.length; i < len; i++){
12433 this.select(nodeInfo[i], true, true);
12437 var node = this.getNode(nodeInfo);
12438 if(!node || this.isSelected(node)){
12439 return; // already selected.
12442 this.clearSelections(true);
12444 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12445 Roo.fly(node).addClass(this.selectedClass);
12446 this.selections.push(node);
12447 if(!suppressEvent){
12448 this.fireEvent("selectionchange", this, this.selections);
12456 * @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
12457 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12458 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12460 unselect : function(nodeInfo, keepExisting, suppressEvent)
12462 if(nodeInfo instanceof Array){
12463 Roo.each(this.selections, function(s) {
12464 this.unselect(s, nodeInfo);
12468 var node = this.getNode(nodeInfo);
12469 if(!node || !this.isSelected(node)){
12470 Roo.log("not selected");
12471 return; // not selected.
12475 Roo.each(this.selections, function(s) {
12477 Roo.fly(node).removeClass(this.selectedClass);
12484 this.selections= ns;
12485 this.fireEvent("selectionchange", this, this.selections);
12489 * Gets a template node.
12490 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12491 * @return {HTMLElement} The node or null if it wasn't found
12493 getNode : function(nodeInfo){
12494 if(typeof nodeInfo == "string"){
12495 return document.getElementById(nodeInfo);
12496 }else if(typeof nodeInfo == "number"){
12497 return this.nodes[nodeInfo];
12503 * Gets a range template nodes.
12504 * @param {Number} startIndex
12505 * @param {Number} endIndex
12506 * @return {Array} An array of nodes
12508 getNodes : function(start, end){
12509 var ns = this.nodes;
12510 start = start || 0;
12511 end = typeof end == "undefined" ? ns.length - 1 : end;
12514 for(var i = start; i <= end; i++){
12518 for(var i = start; i >= end; i--){
12526 * Finds the index of the passed node
12527 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12528 * @return {Number} The index of the node or -1
12530 indexOf : function(node){
12531 node = this.getNode(node);
12532 if(typeof node.nodeIndex == "number"){
12533 return node.nodeIndex;
12535 var ns = this.nodes;
12536 for(var i = 0, len = ns.length; i < len; i++){
12547 * based on jquery fullcalendar
12551 Roo.bootstrap = Roo.bootstrap || {};
12553 * @class Roo.bootstrap.Calendar
12554 * @extends Roo.bootstrap.Component
12555 * Bootstrap Calendar class
12556 * @cfg {Boolean} loadMask (true|false) default false
12557 * @cfg {Object} header generate the user specific header of the calendar, default false
12560 * Create a new Container
12561 * @param {Object} config The config object
12566 Roo.bootstrap.Calendar = function(config){
12567 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12571 * Fires when a date is selected
12572 * @param {DatePicker} this
12573 * @param {Date} date The selected date
12577 * @event monthchange
12578 * Fires when the displayed month changes
12579 * @param {DatePicker} this
12580 * @param {Date} date The selected month
12582 'monthchange': true,
12584 * @event evententer
12585 * Fires when mouse over an event
12586 * @param {Calendar} this
12587 * @param {event} Event
12589 'evententer': true,
12591 * @event eventleave
12592 * Fires when the mouse leaves an
12593 * @param {Calendar} this
12596 'eventleave': true,
12598 * @event eventclick
12599 * Fires when the mouse click an
12600 * @param {Calendar} this
12609 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12612 * @cfg {Number} startDay
12613 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12621 getAutoCreate : function(){
12624 var fc_button = function(name, corner, style, content ) {
12625 return Roo.apply({},{
12627 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12629 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12632 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12643 style : 'width:100%',
12650 cls : 'fc-header-left',
12652 fc_button('prev', 'left', 'arrow', '‹' ),
12653 fc_button('next', 'right', 'arrow', '›' ),
12654 { tag: 'span', cls: 'fc-header-space' },
12655 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12663 cls : 'fc-header-center',
12667 cls: 'fc-header-title',
12670 html : 'month / year'
12678 cls : 'fc-header-right',
12680 /* fc_button('month', 'left', '', 'month' ),
12681 fc_button('week', '', '', 'week' ),
12682 fc_button('day', 'right', '', 'day' )
12694 header = this.header;
12697 var cal_heads = function() {
12699 // fixme - handle this.
12701 for (var i =0; i < Date.dayNames.length; i++) {
12702 var d = Date.dayNames[i];
12705 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12706 html : d.substring(0,3)
12710 ret[0].cls += ' fc-first';
12711 ret[6].cls += ' fc-last';
12714 var cal_cell = function(n) {
12717 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12722 cls: 'fc-day-number',
12726 cls: 'fc-day-content',
12730 style: 'position: relative;' // height: 17px;
12742 var cal_rows = function() {
12745 for (var r = 0; r < 6; r++) {
12752 for (var i =0; i < Date.dayNames.length; i++) {
12753 var d = Date.dayNames[i];
12754 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12757 row.cn[0].cls+=' fc-first';
12758 row.cn[0].cn[0].style = 'min-height:90px';
12759 row.cn[6].cls+=' fc-last';
12763 ret[0].cls += ' fc-first';
12764 ret[4].cls += ' fc-prev-last';
12765 ret[5].cls += ' fc-last';
12772 cls: 'fc-border-separate',
12773 style : 'width:100%',
12781 cls : 'fc-first fc-last',
12799 cls : 'fc-content',
12800 style : "position: relative;",
12803 cls : 'fc-view fc-view-month fc-grid',
12804 style : 'position: relative',
12805 unselectable : 'on',
12808 cls : 'fc-event-container',
12809 style : 'position:absolute;z-index:8;top:0;left:0;'
12827 initEvents : function()
12830 throw "can not find store for calendar";
12836 style: "text-align:center",
12840 style: "background-color:white;width:50%;margin:250 auto",
12844 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12855 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12857 var size = this.el.select('.fc-content', true).first().getSize();
12858 this.maskEl.setSize(size.width, size.height);
12859 this.maskEl.enableDisplayMode("block");
12860 if(!this.loadMask){
12861 this.maskEl.hide();
12864 this.store = Roo.factory(this.store, Roo.data);
12865 this.store.on('load', this.onLoad, this);
12866 this.store.on('beforeload', this.onBeforeLoad, this);
12870 this.cells = this.el.select('.fc-day',true);
12871 //Roo.log(this.cells);
12872 this.textNodes = this.el.query('.fc-day-number');
12873 this.cells.addClassOnOver('fc-state-hover');
12875 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12876 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12877 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12878 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12880 this.on('monthchange', this.onMonthChange, this);
12882 this.update(new Date().clearTime());
12885 resize : function() {
12886 var sz = this.el.getSize();
12888 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12889 this.el.select('.fc-day-content div',true).setHeight(34);
12894 showPrevMonth : function(e){
12895 this.update(this.activeDate.add("mo", -1));
12897 showToday : function(e){
12898 this.update(new Date().clearTime());
12901 showNextMonth : function(e){
12902 this.update(this.activeDate.add("mo", 1));
12906 showPrevYear : function(){
12907 this.update(this.activeDate.add("y", -1));
12911 showNextYear : function(){
12912 this.update(this.activeDate.add("y", 1));
12917 update : function(date)
12919 var vd = this.activeDate;
12920 this.activeDate = date;
12921 // if(vd && this.el){
12922 // var t = date.getTime();
12923 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12924 // Roo.log('using add remove');
12926 // this.fireEvent('monthchange', this, date);
12928 // this.cells.removeClass("fc-state-highlight");
12929 // this.cells.each(function(c){
12930 // if(c.dateValue == t){
12931 // c.addClass("fc-state-highlight");
12932 // setTimeout(function(){
12933 // try{c.dom.firstChild.focus();}catch(e){}
12943 var days = date.getDaysInMonth();
12945 var firstOfMonth = date.getFirstDateOfMonth();
12946 var startingPos = firstOfMonth.getDay()-this.startDay;
12948 if(startingPos < this.startDay){
12952 var pm = date.add(Date.MONTH, -1);
12953 var prevStart = pm.getDaysInMonth()-startingPos;
12955 this.cells = this.el.select('.fc-day',true);
12956 this.textNodes = this.el.query('.fc-day-number');
12957 this.cells.addClassOnOver('fc-state-hover');
12959 var cells = this.cells.elements;
12960 var textEls = this.textNodes;
12962 Roo.each(cells, function(cell){
12963 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12966 days += startingPos;
12968 // convert everything to numbers so it's fast
12969 var day = 86400000;
12970 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12973 //Roo.log(prevStart);
12975 var today = new Date().clearTime().getTime();
12976 var sel = date.clearTime().getTime();
12977 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12978 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12979 var ddMatch = this.disabledDatesRE;
12980 var ddText = this.disabledDatesText;
12981 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12982 var ddaysText = this.disabledDaysText;
12983 var format = this.format;
12985 var setCellClass = function(cal, cell){
12989 //Roo.log('set Cell Class');
12991 var t = d.getTime();
12995 cell.dateValue = t;
12997 cell.className += " fc-today";
12998 cell.className += " fc-state-highlight";
12999 cell.title = cal.todayText;
13002 // disable highlight in other month..
13003 //cell.className += " fc-state-highlight";
13008 cell.className = " fc-state-disabled";
13009 cell.title = cal.minText;
13013 cell.className = " fc-state-disabled";
13014 cell.title = cal.maxText;
13018 if(ddays.indexOf(d.getDay()) != -1){
13019 cell.title = ddaysText;
13020 cell.className = " fc-state-disabled";
13023 if(ddMatch && format){
13024 var fvalue = d.dateFormat(format);
13025 if(ddMatch.test(fvalue)){
13026 cell.title = ddText.replace("%0", fvalue);
13027 cell.className = " fc-state-disabled";
13031 if (!cell.initialClassName) {
13032 cell.initialClassName = cell.dom.className;
13035 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13040 for(; i < startingPos; i++) {
13041 textEls[i].innerHTML = (++prevStart);
13042 d.setDate(d.getDate()+1);
13044 cells[i].className = "fc-past fc-other-month";
13045 setCellClass(this, cells[i]);
13050 for(; i < days; i++){
13051 intDay = i - startingPos + 1;
13052 textEls[i].innerHTML = (intDay);
13053 d.setDate(d.getDate()+1);
13055 cells[i].className = ''; // "x-date-active";
13056 setCellClass(this, cells[i]);
13060 for(; i < 42; i++) {
13061 textEls[i].innerHTML = (++extraDays);
13062 d.setDate(d.getDate()+1);
13064 cells[i].className = "fc-future fc-other-month";
13065 setCellClass(this, cells[i]);
13068 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13070 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13072 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13073 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13075 if(totalRows != 6){
13076 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13077 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13080 this.fireEvent('monthchange', this, date);
13084 if(!this.internalRender){
13085 var main = this.el.dom.firstChild;
13086 var w = main.offsetWidth;
13087 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13088 Roo.fly(main).setWidth(w);
13089 this.internalRender = true;
13090 // opera does not respect the auto grow header center column
13091 // then, after it gets a width opera refuses to recalculate
13092 // without a second pass
13093 if(Roo.isOpera && !this.secondPass){
13094 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13095 this.secondPass = true;
13096 this.update.defer(10, this, [date]);
13103 findCell : function(dt) {
13104 dt = dt.clearTime().getTime();
13106 this.cells.each(function(c){
13107 //Roo.log("check " +c.dateValue + '?=' + dt);
13108 if(c.dateValue == dt){
13118 findCells : function(ev) {
13119 var s = ev.start.clone().clearTime().getTime();
13121 var e= ev.end.clone().clearTime().getTime();
13124 this.cells.each(function(c){
13125 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13127 if(c.dateValue > e){
13130 if(c.dateValue < s){
13139 // findBestRow: function(cells)
13143 // for (var i =0 ; i < cells.length;i++) {
13144 // ret = Math.max(cells[i].rows || 0,ret);
13151 addItem : function(ev)
13153 // look for vertical location slot in
13154 var cells = this.findCells(ev);
13156 // ev.row = this.findBestRow(cells);
13158 // work out the location.
13162 for(var i =0; i < cells.length; i++) {
13164 cells[i].row = cells[0].row;
13167 cells[i].row = cells[i].row + 1;
13177 if (crow.start.getY() == cells[i].getY()) {
13179 crow.end = cells[i];
13196 cells[0].events.push(ev);
13198 this.calevents.push(ev);
13201 clearEvents: function() {
13203 if(!this.calevents){
13207 Roo.each(this.cells.elements, function(c){
13213 Roo.each(this.calevents, function(e) {
13214 Roo.each(e.els, function(el) {
13215 el.un('mouseenter' ,this.onEventEnter, this);
13216 el.un('mouseleave' ,this.onEventLeave, this);
13221 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13227 renderEvents: function()
13231 this.cells.each(function(c) {
13240 if(c.row != c.events.length){
13241 r = 4 - (4 - (c.row - c.events.length));
13244 c.events = ev.slice(0, r);
13245 c.more = ev.slice(r);
13247 if(c.more.length && c.more.length == 1){
13248 c.events.push(c.more.pop());
13251 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13255 this.cells.each(function(c) {
13257 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13260 for (var e = 0; e < c.events.length; e++){
13261 var ev = c.events[e];
13262 var rows = ev.rows;
13264 for(var i = 0; i < rows.length; i++) {
13266 // how many rows should it span..
13269 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13270 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13272 unselectable : "on",
13275 cls: 'fc-event-inner',
13279 // cls: 'fc-event-time',
13280 // html : cells.length > 1 ? '' : ev.time
13284 cls: 'fc-event-title',
13285 html : String.format('{0}', ev.title)
13292 cls: 'ui-resizable-handle ui-resizable-e',
13293 html : '  '
13300 cfg.cls += ' fc-event-start';
13302 if ((i+1) == rows.length) {
13303 cfg.cls += ' fc-event-end';
13306 var ctr = _this.el.select('.fc-event-container',true).first();
13307 var cg = ctr.createChild(cfg);
13309 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13310 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13312 var r = (c.more.length) ? 1 : 0;
13313 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13314 cg.setWidth(ebox.right - sbox.x -2);
13316 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13317 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13318 cg.on('click', _this.onEventClick, _this, ev);
13329 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13330 style : 'position: absolute',
13331 unselectable : "on",
13334 cls: 'fc-event-inner',
13338 cls: 'fc-event-title',
13346 cls: 'ui-resizable-handle ui-resizable-e',
13347 html : '  '
13353 var ctr = _this.el.select('.fc-event-container',true).first();
13354 var cg = ctr.createChild(cfg);
13356 var sbox = c.select('.fc-day-content',true).first().getBox();
13357 var ebox = c.select('.fc-day-content',true).first().getBox();
13359 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13360 cg.setWidth(ebox.right - sbox.x -2);
13362 cg.on('click', _this.onMoreEventClick, _this, c.more);
13372 onEventEnter: function (e, el,event,d) {
13373 this.fireEvent('evententer', this, el, event);
13376 onEventLeave: function (e, el,event,d) {
13377 this.fireEvent('eventleave', this, el, event);
13380 onEventClick: function (e, el,event,d) {
13381 this.fireEvent('eventclick', this, el, event);
13384 onMonthChange: function () {
13388 onMoreEventClick: function(e, el, more)
13392 this.calpopover.placement = 'right';
13393 this.calpopover.setTitle('More');
13395 this.calpopover.setContent('');
13397 var ctr = this.calpopover.el.select('.popover-content', true).first();
13399 Roo.each(more, function(m){
13401 cls : 'fc-event-hori fc-event-draggable',
13404 var cg = ctr.createChild(cfg);
13406 cg.on('click', _this.onEventClick, _this, m);
13409 this.calpopover.show(el);
13414 onLoad: function ()
13416 this.calevents = [];
13419 if(this.store.getCount() > 0){
13420 this.store.data.each(function(d){
13423 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13424 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13425 time : d.data.start_time,
13426 title : d.data.title,
13427 description : d.data.description,
13428 venue : d.data.venue
13433 this.renderEvents();
13435 if(this.calevents.length && this.loadMask){
13436 this.maskEl.hide();
13440 onBeforeLoad: function()
13442 this.clearEvents();
13444 this.maskEl.show();
13458 * @class Roo.bootstrap.Popover
13459 * @extends Roo.bootstrap.Component
13460 * Bootstrap Popover class
13461 * @cfg {String} html contents of the popover (or false to use children..)
13462 * @cfg {String} title of popover (or false to hide)
13463 * @cfg {String} placement how it is placed
13464 * @cfg {String} trigger click || hover (or false to trigger manually)
13465 * @cfg {String} over what (parent or false to trigger manually.)
13468 * Create a new Popover
13469 * @param {Object} config The config object
13472 Roo.bootstrap.Popover = function(config){
13473 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13476 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13478 title: 'Fill in a title',
13481 placement : 'right',
13482 trigger : 'hover', // hover
13486 can_build_overlaid : false,
13488 getChildContainer : function()
13490 return this.el.select('.popover-content',true).first();
13493 getAutoCreate : function(){
13494 Roo.log('make popover?');
13496 cls : 'popover roo-dynamic',
13497 style: 'display:block',
13503 cls : 'popover-inner',
13507 cls: 'popover-title',
13511 cls : 'popover-content',
13522 setTitle: function(str)
13524 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13526 setContent: function(str)
13528 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13530 // as it get's added to the bottom of the page.
13531 onRender : function(ct, position)
13533 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13535 var cfg = Roo.apply({}, this.getAutoCreate());
13539 cfg.cls += ' ' + this.cls;
13542 cfg.style = this.style;
13544 Roo.log("adding to ")
13545 this.el = Roo.get(document.body).createChild(cfg, position);
13551 initEvents : function()
13553 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13554 this.el.enableDisplayMode('block');
13556 if (this.over === false) {
13559 if (this.triggers === false) {
13562 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13563 var triggers = this.trigger ? this.trigger.split(' ') : [];
13564 Roo.each(triggers, function(trigger) {
13566 if (trigger == 'click') {
13567 on_el.on('click', this.toggle, this);
13568 } else if (trigger != 'manual') {
13569 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13570 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13572 on_el.on(eventIn ,this.enter, this);
13573 on_el.on(eventOut, this.leave, this);
13584 toggle : function () {
13585 this.hoverState == 'in' ? this.leave() : this.enter();
13588 enter : function () {
13591 clearTimeout(this.timeout);
13593 this.hoverState = 'in'
13595 if (!this.delay || !this.delay.show) {
13600 this.timeout = setTimeout(function () {
13601 if (_t.hoverState == 'in') {
13604 }, this.delay.show)
13606 leave : function() {
13607 clearTimeout(this.timeout);
13609 this.hoverState = 'out'
13611 if (!this.delay || !this.delay.hide) {
13616 this.timeout = setTimeout(function () {
13617 if (_t.hoverState == 'out') {
13620 }, this.delay.hide)
13623 show : function (on_el)
13626 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13629 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13630 if (this.html !== false) {
13631 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13633 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13634 if (!this.title.length) {
13635 this.el.select('.popover-title',true).hide();
13638 var placement = typeof this.placement == 'function' ?
13639 this.placement.call(this, this.el, on_el) :
13642 var autoToken = /\s?auto?\s?/i;
13643 var autoPlace = autoToken.test(placement);
13645 placement = placement.replace(autoToken, '') || 'top';
13649 //this.el.setXY([0,0]);
13651 this.el.dom.style.display='block';
13652 this.el.addClass(placement);
13654 //this.el.appendTo(on_el);
13656 var p = this.getPosition();
13657 var box = this.el.getBox();
13662 var align = Roo.bootstrap.Popover.alignment[placement]
13663 this.el.alignTo(on_el, align[0],align[1]);
13664 //var arrow = this.el.select('.arrow',true).first();
13665 //arrow.set(align[2],
13667 this.el.addClass('in');
13668 this.hoverState = null;
13670 if (this.el.hasClass('fade')) {
13677 this.el.setXY([0,0]);
13678 this.el.removeClass('in');
13685 Roo.bootstrap.Popover.alignment = {
13686 'left' : ['r-l', [-10,0], 'right'],
13687 'right' : ['l-r', [10,0], 'left'],
13688 'bottom' : ['t-b', [0,10], 'top'],
13689 'top' : [ 'b-t', [0,-10], 'bottom']
13700 * @class Roo.bootstrap.Progress
13701 * @extends Roo.bootstrap.Component
13702 * Bootstrap Progress class
13703 * @cfg {Boolean} striped striped of the progress bar
13704 * @cfg {Boolean} active animated of the progress bar
13708 * Create a new Progress
13709 * @param {Object} config The config object
13712 Roo.bootstrap.Progress = function(config){
13713 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13716 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13721 getAutoCreate : function(){
13729 cfg.cls += ' progress-striped';
13733 cfg.cls += ' active';
13752 * @class Roo.bootstrap.ProgressBar
13753 * @extends Roo.bootstrap.Component
13754 * Bootstrap ProgressBar class
13755 * @cfg {Number} aria_valuenow aria-value now
13756 * @cfg {Number} aria_valuemin aria-value min
13757 * @cfg {Number} aria_valuemax aria-value max
13758 * @cfg {String} label label for the progress bar
13759 * @cfg {String} panel (success | info | warning | danger )
13760 * @cfg {String} role role of the progress bar
13761 * @cfg {String} sr_only text
13765 * Create a new ProgressBar
13766 * @param {Object} config The config object
13769 Roo.bootstrap.ProgressBar = function(config){
13770 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13773 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13777 aria_valuemax : 100,
13783 getAutoCreate : function()
13788 cls: 'progress-bar',
13789 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13801 cfg.role = this.role;
13804 if(this.aria_valuenow){
13805 cfg['aria-valuenow'] = this.aria_valuenow;
13808 if(this.aria_valuemin){
13809 cfg['aria-valuemin'] = this.aria_valuemin;
13812 if(this.aria_valuemax){
13813 cfg['aria-valuemax'] = this.aria_valuemax;
13816 if(this.label && !this.sr_only){
13817 cfg.html = this.label;
13821 cfg.cls += ' progress-bar-' + this.panel;
13827 update : function(aria_valuenow)
13829 this.aria_valuenow = aria_valuenow;
13831 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13846 * @class Roo.bootstrap.TabGroup
13847 * @extends Roo.bootstrap.Column
13848 * Bootstrap Column class
13849 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13850 * @cfg {Boolean} carousel true to make the group behave like a carousel
13853 * Create a new TabGroup
13854 * @param {Object} config The config object
13857 Roo.bootstrap.TabGroup = function(config){
13858 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13860 this.navId = Roo.id();
13863 Roo.bootstrap.TabGroup.register(this);
13867 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13870 transition : false,
13872 getAutoCreate : function()
13874 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13876 cfg.cls += ' tab-content';
13878 if (this.carousel) {
13879 cfg.cls += ' carousel slide';
13881 cls : 'carousel-inner'
13888 getChildContainer : function()
13890 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13894 * register a Navigation item
13895 * @param {Roo.bootstrap.NavItem} the navitem to add
13897 register : function(item)
13899 this.tabs.push( item);
13900 item.navId = this.navId; // not really needed..
13904 getActivePanel : function()
13907 Roo.each(this.tabs, function(t) {
13917 getPanelByName : function(n)
13920 Roo.each(this.tabs, function(t) {
13921 if (t.tabId == n) {
13929 indexOfPanel : function(p)
13932 Roo.each(this.tabs, function(t,i) {
13933 if (t.tabId == p.tabId) {
13942 * show a specific panel
13943 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13944 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13946 showPanel : function (pan)
13949 if (typeof(pan) == 'number') {
13950 pan = this.tabs[pan];
13952 if (typeof(pan) == 'string') {
13953 pan = this.getPanelByName(pan);
13955 if (pan.tabId == this.getActivePanel().tabId) {
13958 var cur = this.getActivePanel();
13960 if (false === cur.fireEvent('beforedeactivate')) {
13964 if (this.carousel) {
13965 this.transition = true;
13966 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13967 var lr = dir == 'next' ? 'left' : 'right';
13968 pan.el.addClass(dir); // or prev
13969 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13970 cur.el.addClass(lr); // or right
13971 pan.el.addClass(lr);
13974 cur.el.on('transitionend', function() {
13975 Roo.log("trans end?");
13977 pan.el.removeClass([lr,dir]);
13978 pan.setActive(true);
13980 cur.el.removeClass([lr]);
13981 cur.setActive(false);
13983 _this.transition = false;
13985 }, this, { single: true } );
13989 cur.setActive(false);
13990 pan.setActive(true);
13994 showPanelNext : function()
13996 var i = this.indexOfPanel(this.getActivePanel());
13997 if (i > this.tabs.length) {
14000 this.showPanel(this.tabs[i+1]);
14002 showPanelPrev : function()
14004 var i = this.indexOfPanel(this.getActivePanel());
14008 this.showPanel(this.tabs[i-1]);
14019 Roo.apply(Roo.bootstrap.TabGroup, {
14023 * register a Navigation Group
14024 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14026 register : function(navgrp)
14028 this.groups[navgrp.navId] = navgrp;
14032 * fetch a Navigation Group based on the navigation ID
14033 * if one does not exist , it will get created.
14034 * @param {string} the navgroup to add
14035 * @returns {Roo.bootstrap.NavGroup} the navgroup
14037 get: function(navId) {
14038 if (typeof(this.groups[navId]) == 'undefined') {
14039 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14041 return this.groups[navId] ;
14056 * @class Roo.bootstrap.TabPanel
14057 * @extends Roo.bootstrap.Component
14058 * Bootstrap TabPanel class
14059 * @cfg {Boolean} active panel active
14060 * @cfg {String} html panel content
14061 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14062 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14066 * Create a new TabPanel
14067 * @param {Object} config The config object
14070 Roo.bootstrap.TabPanel = function(config){
14071 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14075 * Fires when the active status changes
14076 * @param {Roo.bootstrap.TabPanel} this
14077 * @param {Boolean} state the new state
14082 * @event beforedeactivate
14083 * Fires before a tab is de-activated - can be used to do validation on a form.
14084 * @param {Roo.bootstrap.TabPanel} this
14085 * @return {Boolean} false if there is an error
14088 'beforedeactivate': true
14091 this.tabId = this.tabId || Roo.id();
14095 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14102 getAutoCreate : function(){
14105 // item is needed for carousel - not sure if it has any effect otherwise
14106 cls: 'tab-pane item',
14107 html: this.html || ''
14111 cfg.cls += ' active';
14115 cfg.tabId = this.tabId;
14122 initEvents: function()
14124 Roo.log('-------- init events on tab panel ---------');
14126 var p = this.parent();
14127 this.navId = this.navId || p.navId;
14129 if (typeof(this.navId) != 'undefined') {
14130 // not really needed.. but just in case.. parent should be a NavGroup.
14131 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14132 Roo.log(['register', tg, this]);
14138 onRender : function(ct, position)
14140 // Roo.log("Call onRender: " + this.xtype);
14142 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14150 setActive: function(state)
14152 Roo.log("panel - set active " + this.tabId + "=" + state);
14154 this.active = state;
14156 this.el.removeClass('active');
14158 } else if (!this.el.hasClass('active')) {
14159 this.el.addClass('active');
14161 this.fireEvent('changed', this, state);
14178 * @class Roo.bootstrap.DateField
14179 * @extends Roo.bootstrap.Input
14180 * Bootstrap DateField class
14181 * @cfg {Number} weekStart default 0
14182 * @cfg {Number} weekStart default 0
14183 * @cfg {Number} viewMode default empty, (months|years)
14184 * @cfg {Number} minViewMode default empty, (months|years)
14185 * @cfg {Number} startDate default -Infinity
14186 * @cfg {Number} endDate default Infinity
14187 * @cfg {Boolean} todayHighlight default false
14188 * @cfg {Boolean} todayBtn default false
14189 * @cfg {Boolean} calendarWeeks default false
14190 * @cfg {Object} daysOfWeekDisabled default empty
14192 * @cfg {Boolean} keyboardNavigation default true
14193 * @cfg {String} language default en
14196 * Create a new DateField
14197 * @param {Object} config The config object
14200 Roo.bootstrap.DateField = function(config){
14201 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14205 * Fires when this field show.
14206 * @param {Roo.bootstrap.DateField} this
14207 * @param {Mixed} date The date value
14212 * Fires when this field hide.
14213 * @param {Roo.bootstrap.DateField} this
14214 * @param {Mixed} date The date value
14219 * Fires when select a date.
14220 * @param {Roo.bootstrap.DateField} this
14221 * @param {Mixed} date The date value
14227 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14230 * @cfg {String} format
14231 * The default date format string which can be overriden for localization support. The format must be
14232 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14236 * @cfg {String} altFormats
14237 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14238 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14240 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14248 todayHighlight : false,
14254 keyboardNavigation: true,
14256 calendarWeeks: false,
14258 startDate: -Infinity,
14262 daysOfWeekDisabled: [],
14266 UTCDate: function()
14268 return new Date(Date.UTC.apply(Date, arguments));
14271 UTCToday: function()
14273 var today = new Date();
14274 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14277 getDate: function() {
14278 var d = this.getUTCDate();
14279 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14282 getUTCDate: function() {
14286 setDate: function(d) {
14287 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14290 setUTCDate: function(d) {
14292 this.setValue(this.formatDate(this.date));
14295 onRender: function(ct, position)
14298 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14300 this.language = this.language || 'en';
14301 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14302 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14304 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14305 this.format = this.format || 'm/d/y';
14306 this.isInline = false;
14307 this.isInput = true;
14308 this.component = this.el.select('.add-on', true).first() || false;
14309 this.component = (this.component && this.component.length === 0) ? false : this.component;
14310 this.hasInput = this.component && this.inputEL().length;
14312 if (typeof(this.minViewMode === 'string')) {
14313 switch (this.minViewMode) {
14315 this.minViewMode = 1;
14318 this.minViewMode = 2;
14321 this.minViewMode = 0;
14326 if (typeof(this.viewMode === 'string')) {
14327 switch (this.viewMode) {
14340 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14342 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14344 this.picker().on('mousedown', this.onMousedown, this);
14345 this.picker().on('click', this.onClick, this);
14347 this.picker().addClass('datepicker-dropdown');
14349 this.startViewMode = this.viewMode;
14352 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14353 if(!this.calendarWeeks){
14358 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14359 v.attr('colspan', function(i, val){
14360 return parseInt(val) + 1;
14365 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14367 this.setStartDate(this.startDate);
14368 this.setEndDate(this.endDate);
14370 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14377 if(this.isInline) {
14382 picker : function()
14384 return this.el.select('.datepicker', true).first();
14387 fillDow: function()
14389 var dowCnt = this.weekStart;
14398 if(this.calendarWeeks){
14406 while (dowCnt < this.weekStart + 7) {
14410 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14414 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14417 fillMonths: function()
14420 var months = this.picker().select('>.datepicker-months td', true).first();
14422 months.dom.innerHTML = '';
14428 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14431 months.createChild(month);
14439 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14441 if (this.date < this.startDate) {
14442 this.viewDate = new Date(this.startDate);
14443 } else if (this.date > this.endDate) {
14444 this.viewDate = new Date(this.endDate);
14446 this.viewDate = new Date(this.date);
14454 var d = new Date(this.viewDate),
14455 year = d.getUTCFullYear(),
14456 month = d.getUTCMonth(),
14457 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14458 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14459 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14460 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14461 currentDate = this.date && this.date.valueOf(),
14462 today = this.UTCToday();
14464 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14466 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14468 // this.picker.select('>tfoot th.today').
14469 // .text(dates[this.language].today)
14470 // .toggle(this.todayBtn !== false);
14472 this.updateNavArrows();
14475 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14477 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14479 prevMonth.setUTCDate(day);
14481 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14483 var nextMonth = new Date(prevMonth);
14485 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14487 nextMonth = nextMonth.valueOf();
14489 var fillMonths = false;
14491 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14493 while(prevMonth.valueOf() < nextMonth) {
14496 if (prevMonth.getUTCDay() === this.weekStart) {
14498 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14506 if(this.calendarWeeks){
14507 // ISO 8601: First week contains first thursday.
14508 // ISO also states week starts on Monday, but we can be more abstract here.
14510 // Start of current week: based on weekstart/current date
14511 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14512 // Thursday of this week
14513 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14514 // First Thursday of year, year from thursday
14515 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14516 // Calendar week: ms between thursdays, div ms per day, div 7 days
14517 calWeek = (th - yth) / 864e5 / 7 + 1;
14519 fillMonths.cn.push({
14527 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14529 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14532 if (this.todayHighlight &&
14533 prevMonth.getUTCFullYear() == today.getFullYear() &&
14534 prevMonth.getUTCMonth() == today.getMonth() &&
14535 prevMonth.getUTCDate() == today.getDate()) {
14536 clsName += ' today';
14539 if (currentDate && prevMonth.valueOf() === currentDate) {
14540 clsName += ' active';
14543 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14544 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14545 clsName += ' disabled';
14548 fillMonths.cn.push({
14550 cls: 'day ' + clsName,
14551 html: prevMonth.getDate()
14554 prevMonth.setDate(prevMonth.getDate()+1);
14557 var currentYear = this.date && this.date.getUTCFullYear();
14558 var currentMonth = this.date && this.date.getUTCMonth();
14560 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14562 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14563 v.removeClass('active');
14565 if(currentYear === year && k === currentMonth){
14566 v.addClass('active');
14569 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14570 v.addClass('disabled');
14576 year = parseInt(year/10, 10) * 10;
14578 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14580 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14583 for (var i = -1; i < 11; i++) {
14584 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14586 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14594 showMode: function(dir)
14597 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14599 Roo.each(this.picker().select('>div',true).elements, function(v){
14600 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14603 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14608 if(this.isInline) return;
14610 this.picker().removeClass(['bottom', 'top']);
14612 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14614 * place to the top of element!
14618 this.picker().addClass('top');
14619 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14624 this.picker().addClass('bottom');
14626 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14629 parseDate : function(value)
14631 if(!value || value instanceof Date){
14634 var v = Date.parseDate(value, this.format);
14635 if (!v && this.useIso) {
14636 v = Date.parseDate(value, 'Y-m-d');
14638 if(!v && this.altFormats){
14639 if(!this.altFormatsArray){
14640 this.altFormatsArray = this.altFormats.split("|");
14642 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14643 v = Date.parseDate(value, this.altFormatsArray[i]);
14649 formatDate : function(date, fmt)
14651 return (!date || !(date instanceof Date)) ?
14652 date : date.dateFormat(fmt || this.format);
14655 onFocus : function()
14657 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14661 onBlur : function()
14663 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14665 var d = this.inputEl().getValue();
14676 this.picker().show();
14680 this.fireEvent('show', this, this.date);
14685 if(this.isInline) return;
14686 this.picker().hide();
14687 this.viewMode = this.startViewMode;
14690 this.fireEvent('hide', this, this.date);
14694 onMousedown: function(e)
14696 e.stopPropagation();
14697 e.preventDefault();
14702 Roo.bootstrap.DateField.superclass.keyup.call(this);
14706 setValue: function(v)
14708 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14710 var d = new Date(v);
14712 if(isNaN(d.getTime())){
14716 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14720 this.fireEvent('select', this, this.date);
14724 getValue: function()
14726 return this.formatDate(this.date);
14729 fireKey: function(e)
14731 if (!this.picker().isVisible()){
14732 if (e.keyCode == 27) // allow escape to hide and re-show picker
14737 var dateChanged = false,
14739 newDate, newViewDate;
14744 e.preventDefault();
14748 if (!this.keyboardNavigation) break;
14749 dir = e.keyCode == 37 ? -1 : 1;
14752 newDate = this.moveYear(this.date, dir);
14753 newViewDate = this.moveYear(this.viewDate, dir);
14754 } else if (e.shiftKey){
14755 newDate = this.moveMonth(this.date, dir);
14756 newViewDate = this.moveMonth(this.viewDate, dir);
14758 newDate = new Date(this.date);
14759 newDate.setUTCDate(this.date.getUTCDate() + dir);
14760 newViewDate = new Date(this.viewDate);
14761 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14763 if (this.dateWithinRange(newDate)){
14764 this.date = newDate;
14765 this.viewDate = newViewDate;
14766 this.setValue(this.formatDate(this.date));
14768 e.preventDefault();
14769 dateChanged = true;
14774 if (!this.keyboardNavigation) break;
14775 dir = e.keyCode == 38 ? -1 : 1;
14777 newDate = this.moveYear(this.date, dir);
14778 newViewDate = this.moveYear(this.viewDate, dir);
14779 } else if (e.shiftKey){
14780 newDate = this.moveMonth(this.date, dir);
14781 newViewDate = this.moveMonth(this.viewDate, dir);
14783 newDate = new Date(this.date);
14784 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14785 newViewDate = new Date(this.viewDate);
14786 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14788 if (this.dateWithinRange(newDate)){
14789 this.date = newDate;
14790 this.viewDate = newViewDate;
14791 this.setValue(this.formatDate(this.date));
14793 e.preventDefault();
14794 dateChanged = true;
14798 this.setValue(this.formatDate(this.date));
14800 e.preventDefault();
14803 this.setValue(this.formatDate(this.date));
14817 onClick: function(e)
14819 e.stopPropagation();
14820 e.preventDefault();
14822 var target = e.getTarget();
14824 if(target.nodeName.toLowerCase() === 'i'){
14825 target = Roo.get(target).dom.parentNode;
14828 var nodeName = target.nodeName;
14829 var className = target.className;
14830 var html = target.innerHTML;
14832 switch(nodeName.toLowerCase()) {
14834 switch(className) {
14840 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14841 switch(this.viewMode){
14843 this.viewDate = this.moveMonth(this.viewDate, dir);
14847 this.viewDate = this.moveYear(this.viewDate, dir);
14853 var date = new Date();
14854 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14856 this.setValue(this.formatDate(this.date));
14863 if (className.indexOf('disabled') === -1) {
14864 this.viewDate.setUTCDate(1);
14865 if (className.indexOf('month') !== -1) {
14866 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14868 var year = parseInt(html, 10) || 0;
14869 this.viewDate.setUTCFullYear(year);
14878 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14879 var day = parseInt(html, 10) || 1;
14880 var year = this.viewDate.getUTCFullYear(),
14881 month = this.viewDate.getUTCMonth();
14883 if (className.indexOf('old') !== -1) {
14890 } else if (className.indexOf('new') !== -1) {
14898 this.date = this.UTCDate(year, month, day,0,0,0,0);
14899 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14901 this.setValue(this.formatDate(this.date));
14908 setStartDate: function(startDate)
14910 this.startDate = startDate || -Infinity;
14911 if (this.startDate !== -Infinity) {
14912 this.startDate = this.parseDate(this.startDate);
14915 this.updateNavArrows();
14918 setEndDate: function(endDate)
14920 this.endDate = endDate || Infinity;
14921 if (this.endDate !== Infinity) {
14922 this.endDate = this.parseDate(this.endDate);
14925 this.updateNavArrows();
14928 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14930 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14931 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14932 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14934 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14935 return parseInt(d, 10);
14938 this.updateNavArrows();
14941 updateNavArrows: function()
14943 var d = new Date(this.viewDate),
14944 year = d.getUTCFullYear(),
14945 month = d.getUTCMonth();
14947 Roo.each(this.picker().select('.prev', true).elements, function(v){
14949 switch (this.viewMode) {
14952 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14958 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14965 Roo.each(this.picker().select('.next', true).elements, function(v){
14967 switch (this.viewMode) {
14970 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14976 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14984 moveMonth: function(date, dir)
14986 if (!dir) return date;
14987 var new_date = new Date(date.valueOf()),
14988 day = new_date.getUTCDate(),
14989 month = new_date.getUTCMonth(),
14990 mag = Math.abs(dir),
14992 dir = dir > 0 ? 1 : -1;
14995 // If going back one month, make sure month is not current month
14996 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14998 return new_date.getUTCMonth() == month;
15000 // If going forward one month, make sure month is as expected
15001 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15003 return new_date.getUTCMonth() != new_month;
15005 new_month = month + dir;
15006 new_date.setUTCMonth(new_month);
15007 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15008 if (new_month < 0 || new_month > 11)
15009 new_month = (new_month + 12) % 12;
15011 // For magnitudes >1, move one month at a time...
15012 for (var i=0; i<mag; i++)
15013 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15014 new_date = this.moveMonth(new_date, dir);
15015 // ...then reset the day, keeping it in the new month
15016 new_month = new_date.getUTCMonth();
15017 new_date.setUTCDate(day);
15019 return new_month != new_date.getUTCMonth();
15022 // Common date-resetting loop -- if date is beyond end of month, make it
15025 new_date.setUTCDate(--day);
15026 new_date.setUTCMonth(new_month);
15031 moveYear: function(date, dir)
15033 return this.moveMonth(date, dir*12);
15036 dateWithinRange: function(date)
15038 return date >= this.startDate && date <= this.endDate;
15044 this.picker().remove();
15049 Roo.apply(Roo.bootstrap.DateField, {
15060 html: '<i class="fa fa-arrow-left"/>'
15070 html: '<i class="fa fa-arrow-right"/>'
15112 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15113 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15114 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15115 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15116 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15129 navFnc: 'FullYear',
15134 navFnc: 'FullYear',
15139 Roo.apply(Roo.bootstrap.DateField, {
15143 cls: 'datepicker dropdown-menu',
15147 cls: 'datepicker-days',
15151 cls: 'table-condensed',
15153 Roo.bootstrap.DateField.head,
15157 Roo.bootstrap.DateField.footer
15164 cls: 'datepicker-months',
15168 cls: 'table-condensed',
15170 Roo.bootstrap.DateField.head,
15171 Roo.bootstrap.DateField.content,
15172 Roo.bootstrap.DateField.footer
15179 cls: 'datepicker-years',
15183 cls: 'table-condensed',
15185 Roo.bootstrap.DateField.head,
15186 Roo.bootstrap.DateField.content,
15187 Roo.bootstrap.DateField.footer
15206 * @class Roo.bootstrap.TimeField
15207 * @extends Roo.bootstrap.Input
15208 * Bootstrap DateField class
15212 * Create a new TimeField
15213 * @param {Object} config The config object
15216 Roo.bootstrap.TimeField = function(config){
15217 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15221 * Fires when this field show.
15222 * @param {Roo.bootstrap.DateField} this
15223 * @param {Mixed} date The date value
15228 * Fires when this field hide.
15229 * @param {Roo.bootstrap.DateField} this
15230 * @param {Mixed} date The date value
15235 * Fires when select a date.
15236 * @param {Roo.bootstrap.DateField} this
15237 * @param {Mixed} date The date value
15243 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15246 * @cfg {String} format
15247 * The default time format string which can be overriden for localization support. The format must be
15248 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15252 onRender: function(ct, position)
15255 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15257 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15259 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15261 this.pop = this.picker().select('>.datepicker-time',true).first();
15262 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15264 this.picker().on('mousedown', this.onMousedown, this);
15265 this.picker().on('click', this.onClick, this);
15267 this.picker().addClass('datepicker-dropdown');
15272 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15273 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15274 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15275 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15276 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15277 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15281 fireKey: function(e){
15282 if (!this.picker().isVisible()){
15283 if (e.keyCode == 27) // allow escape to hide and re-show picker
15288 e.preventDefault();
15296 this.onTogglePeriod();
15299 this.onIncrementMinutes();
15302 this.onDecrementMinutes();
15311 onClick: function(e) {
15312 e.stopPropagation();
15313 e.preventDefault();
15316 picker : function()
15318 return this.el.select('.datepicker', true).first();
15321 fillTime: function()
15323 var time = this.pop.select('tbody', true).first();
15325 time.dom.innerHTML = '';
15340 cls: 'hours-up glyphicon glyphicon-chevron-up'
15360 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15381 cls: 'timepicker-hour',
15396 cls: 'timepicker-minute',
15411 cls: 'btn btn-primary period',
15433 cls: 'hours-down glyphicon glyphicon-chevron-down'
15453 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15471 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15478 var hours = this.time.getHours();
15479 var minutes = this.time.getMinutes();
15492 hours = hours - 12;
15496 hours = '0' + hours;
15500 minutes = '0' + minutes;
15503 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15504 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15505 this.pop.select('button', true).first().dom.innerHTML = period;
15511 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15513 var cls = ['bottom'];
15515 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15522 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15527 this.picker().addClass(cls.join('-'));
15531 Roo.each(cls, function(c){
15533 _this.picker().setTop(_this.inputEl().getHeight());
15537 _this.picker().setTop(0 - _this.picker().getHeight());
15542 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15546 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15553 onFocus : function()
15555 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15559 onBlur : function()
15561 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15567 this.picker().show();
15572 this.fireEvent('show', this, this.date);
15577 this.picker().hide();
15580 this.fireEvent('hide', this, this.date);
15583 setTime : function()
15586 this.setValue(this.time.format(this.format));
15588 this.fireEvent('select', this, this.date);
15593 onMousedown: function(e){
15594 e.stopPropagation();
15595 e.preventDefault();
15598 onIncrementHours: function()
15600 Roo.log('onIncrementHours');
15601 this.time = this.time.add(Date.HOUR, 1);
15606 onDecrementHours: function()
15608 Roo.log('onDecrementHours');
15609 this.time = this.time.add(Date.HOUR, -1);
15613 onIncrementMinutes: function()
15615 Roo.log('onIncrementMinutes');
15616 this.time = this.time.add(Date.MINUTE, 1);
15620 onDecrementMinutes: function()
15622 Roo.log('onDecrementMinutes');
15623 this.time = this.time.add(Date.MINUTE, -1);
15627 onTogglePeriod: function()
15629 Roo.log('onTogglePeriod');
15630 this.time = this.time.add(Date.HOUR, 12);
15637 Roo.apply(Roo.bootstrap.TimeField, {
15667 cls: 'btn btn-info ok',
15679 Roo.apply(Roo.bootstrap.TimeField, {
15683 cls: 'datepicker dropdown-menu',
15687 cls: 'datepicker-time',
15691 cls: 'table-condensed',
15693 Roo.bootstrap.TimeField.content,
15694 Roo.bootstrap.TimeField.footer
15713 * @class Roo.bootstrap.CheckBox
15714 * @extends Roo.bootstrap.Input
15715 * Bootstrap CheckBox class
15717 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15718 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15719 * @cfg {String} boxLabel The text that appears beside the checkbox
15720 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15721 * @cfg {Boolean} checked initnal the element
15725 * Create a new CheckBox
15726 * @param {Object} config The config object
15729 Roo.bootstrap.CheckBox = function(config){
15730 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15735 * Fires when the element is checked or unchecked.
15736 * @param {Roo.bootstrap.CheckBox} this This input
15737 * @param {Boolean} checked The new checked value
15743 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15745 inputType: 'checkbox',
15752 getAutoCreate : function()
15754 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15760 cfg.cls = 'form-group checkbox' //input-group
15768 type : this.inputType,
15769 value : (!this.checked) ? this.valueOff : this.inputValue,
15770 cls : 'roo-checkbox', //'form-box',
15771 placeholder : this.placeholder || ''
15775 if (this.weight) { // Validity check?
15776 cfg.cls += " checkbox-" + this.weight;
15779 if (this.disabled) {
15780 input.disabled=true;
15784 input.checked = this.checked;
15788 input.name = this.name;
15792 input.cls += ' input-' + this.size;
15796 ['xs','sm','md','lg'].map(function(size){
15797 if (settings[size]) {
15798 cfg.cls += ' col-' + size + '-' + settings[size];
15804 var inputblock = input;
15809 if (this.before || this.after) {
15812 cls : 'input-group',
15816 inputblock.cn.push({
15818 cls : 'input-group-addon',
15822 inputblock.cn.push(input);
15824 inputblock.cn.push({
15826 cls : 'input-group-addon',
15833 if (align ==='left' && this.fieldLabel.length) {
15834 Roo.log("left and has label");
15840 cls : 'control-label col-md-' + this.labelWidth,
15841 html : this.fieldLabel
15845 cls : "col-md-" + (12 - this.labelWidth),
15852 } else if ( this.fieldLabel.length) {
15857 tag: this.boxLabel ? 'span' : 'label',
15859 cls: 'control-label box-input-label',
15860 //cls : 'input-group-addon',
15861 html : this.fieldLabel
15871 Roo.log(" no label && no align");
15872 cfg.cn = [ inputblock ] ;
15881 html: this.boxLabel
15893 * return the real input element.
15895 inputEl: function ()
15897 return this.el.select('input.roo-checkbox',true).first();
15902 return this.el.select('label.control-label',true).first();
15905 initEvents : function()
15907 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15909 this.inputEl().on('click', this.onClick, this);
15913 onClick : function()
15915 this.setChecked(!this.checked);
15918 setChecked : function(state,suppressEvent)
15920 this.checked = state;
15922 this.inputEl().dom.checked = state;
15924 if(suppressEvent !== true){
15925 this.fireEvent('check', this, state);
15928 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15932 setValue : function(v,suppressEvent)
15934 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15948 * @class Roo.bootstrap.Radio
15949 * @extends Roo.bootstrap.CheckBox
15950 * Bootstrap Radio class
15953 * Create a new Radio
15954 * @param {Object} config The config object
15957 Roo.bootstrap.Radio = function(config){
15958 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15962 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15964 inputType: 'radio',
15968 getAutoCreate : function()
15970 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15976 cfg.cls = 'form-group radio' //input-group
15981 type : this.inputType,
15982 value : (!this.checked) ? this.valueOff : this.inputValue,
15984 placeholder : this.placeholder || ''
15987 if (this.weight) { // Validity check?
15988 cfg.cls += " radio-" + this.weight;
15990 if (this.disabled) {
15991 input.disabled=true;
15995 input.checked = this.checked;
15999 input.name = this.name;
16003 input.cls += ' input-' + this.size;
16007 ['xs','sm','md','lg'].map(function(size){
16008 if (settings[size]) {
16009 cfg.cls += ' col-' + size + '-' + settings[size];
16013 var inputblock = input;
16015 if (this.before || this.after) {
16018 cls : 'input-group',
16022 inputblock.cn.push({
16024 cls : 'input-group-addon',
16028 inputblock.cn.push(input);
16030 inputblock.cn.push({
16032 cls : 'input-group-addon',
16039 if (align ==='left' && this.fieldLabel.length) {
16040 Roo.log("left and has label");
16046 cls : 'control-label col-md-' + this.labelWidth,
16047 html : this.fieldLabel
16051 cls : "col-md-" + (12 - this.labelWidth),
16058 } else if ( this.fieldLabel.length) {
16065 cls: 'control-label box-input-label',
16066 //cls : 'input-group-addon',
16067 html : this.fieldLabel
16077 Roo.log(" no label && no align");
16092 html: this.boxLabel
16099 inputEl: function ()
16101 return this.el.select('input.roo-radio',true).first();
16103 onClick : function()
16105 this.setChecked(true);
16108 setChecked : function(state,suppressEvent)
16111 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16112 v.dom.checked = false;
16116 this.checked = state;
16117 this.inputEl().dom.checked = state;
16119 if(suppressEvent !== true){
16120 this.fireEvent('check', this, state);
16123 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16127 getGroupValue : function()
16130 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16131 if(v.dom.checked == true){
16132 value = v.dom.value;
16140 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16141 * @return {Mixed} value The field value
16143 getValue : function(){
16144 return this.getGroupValue();
16150 //<script type="text/javascript">
16153 * Based Ext JS Library 1.1.1
16154 * Copyright(c) 2006-2007, Ext JS, LLC.
16160 * @class Roo.HtmlEditorCore
16161 * @extends Roo.Component
16162 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16164 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16167 Roo.HtmlEditorCore = function(config){
16170 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16173 * @event initialize
16174 * Fires when the editor is fully initialized (including the iframe)
16175 * @param {Roo.HtmlEditorCore} this
16180 * Fires when the editor is first receives the focus. Any insertion must wait
16181 * until after this event.
16182 * @param {Roo.HtmlEditorCore} this
16186 * @event beforesync
16187 * Fires before the textarea is updated with content from the editor iframe. Return false
16188 * to cancel the sync.
16189 * @param {Roo.HtmlEditorCore} this
16190 * @param {String} html
16194 * @event beforepush
16195 * Fires before the iframe editor is updated with content from the textarea. Return false
16196 * to cancel the push.
16197 * @param {Roo.HtmlEditorCore} this
16198 * @param {String} html
16203 * Fires when the textarea is updated with content from the editor iframe.
16204 * @param {Roo.HtmlEditorCore} this
16205 * @param {String} html
16210 * Fires when the iframe editor is updated with content from the textarea.
16211 * @param {Roo.HtmlEditorCore} this
16212 * @param {String} html
16217 * @event editorevent
16218 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16219 * @param {Roo.HtmlEditorCore} this
16227 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16231 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16237 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16242 * @cfg {Number} height (in pixels)
16246 * @cfg {Number} width (in pixels)
16251 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16254 stylesheets: false,
16259 // private properties
16260 validationEvent : false,
16262 initialized : false,
16264 sourceEditMode : false,
16265 onFocus : Roo.emptyFn,
16267 hideMode:'offsets',
16275 * Protected method that will not generally be called directly. It
16276 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16277 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16279 getDocMarkup : function(){
16282 Roo.log(this.stylesheets);
16284 // inherit styels from page...??
16285 if (this.stylesheets === false) {
16287 Roo.get(document.head).select('style').each(function(node) {
16288 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16291 Roo.get(document.head).select('link').each(function(node) {
16292 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16295 } else if (!this.stylesheets.length) {
16297 st = '<style type="text/css">' +
16298 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16301 Roo.each(this.stylesheets, function(s) {
16302 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16307 st += '<style type="text/css">' +
16308 'IMG { cursor: pointer } ' +
16312 return '<html><head>' + st +
16313 //<style type="text/css">' +
16314 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16316 ' </head><body class="roo-htmleditor-body"></body></html>';
16320 onRender : function(ct, position)
16323 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16324 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16327 this.el.dom.style.border = '0 none';
16328 this.el.dom.setAttribute('tabIndex', -1);
16329 this.el.addClass('x-hidden hide');
16333 if(Roo.isIE){ // fix IE 1px bogus margin
16334 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16338 this.frameId = Roo.id();
16342 var iframe = this.owner.wrap.createChild({
16344 cls: 'form-control', // bootstrap..
16346 name: this.frameId,
16347 frameBorder : 'no',
16348 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16353 this.iframe = iframe.dom;
16355 this.assignDocWin();
16357 this.doc.designMode = 'on';
16360 this.doc.write(this.getDocMarkup());
16364 var task = { // must defer to wait for browser to be ready
16366 //console.log("run task?" + this.doc.readyState);
16367 this.assignDocWin();
16368 if(this.doc.body || this.doc.readyState == 'complete'){
16370 this.doc.designMode="on";
16374 Roo.TaskMgr.stop(task);
16375 this.initEditor.defer(10, this);
16382 Roo.TaskMgr.start(task);
16389 onResize : function(w, h)
16391 Roo.log('resize: ' +w + ',' + h );
16392 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16396 if(typeof w == 'number'){
16398 this.iframe.style.width = w + 'px';
16400 if(typeof h == 'number'){
16402 this.iframe.style.height = h + 'px';
16404 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16411 * Toggles the editor between standard and source edit mode.
16412 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16414 toggleSourceEdit : function(sourceEditMode){
16416 this.sourceEditMode = sourceEditMode === true;
16418 if(this.sourceEditMode){
16420 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16423 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16424 //this.iframe.className = '';
16427 //this.setSize(this.owner.wrap.getSize());
16428 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16435 * Protected method that will not generally be called directly. If you need/want
16436 * custom HTML cleanup, this is the method you should override.
16437 * @param {String} html The HTML to be cleaned
16438 * return {String} The cleaned HTML
16440 cleanHtml : function(html){
16441 html = String(html);
16442 if(html.length > 5){
16443 if(Roo.isSafari){ // strip safari nonsense
16444 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16447 if(html == ' '){
16454 * HTML Editor -> Textarea
16455 * Protected method that will not generally be called directly. Syncs the contents
16456 * of the editor iframe with the textarea.
16458 syncValue : function(){
16459 if(this.initialized){
16460 var bd = (this.doc.body || this.doc.documentElement);
16461 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16462 var html = bd.innerHTML;
16464 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16465 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16467 html = '<div style="'+m[0]+'">' + html + '</div>';
16470 html = this.cleanHtml(html);
16471 // fix up the special chars.. normaly like back quotes in word...
16472 // however we do not want to do this with chinese..
16473 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16474 var cc = b.charCodeAt();
16476 (cc >= 0x4E00 && cc < 0xA000 ) ||
16477 (cc >= 0x3400 && cc < 0x4E00 ) ||
16478 (cc >= 0xf900 && cc < 0xfb00 )
16484 if(this.owner.fireEvent('beforesync', this, html) !== false){
16485 this.el.dom.value = html;
16486 this.owner.fireEvent('sync', this, html);
16492 * Protected method that will not generally be called directly. Pushes the value of the textarea
16493 * into the iframe editor.
16495 pushValue : function(){
16496 if(this.initialized){
16497 var v = this.el.dom.value.trim();
16499 // if(v.length < 1){
16503 if(this.owner.fireEvent('beforepush', this, v) !== false){
16504 var d = (this.doc.body || this.doc.documentElement);
16506 this.cleanUpPaste();
16507 this.el.dom.value = d.innerHTML;
16508 this.owner.fireEvent('push', this, v);
16514 deferFocus : function(){
16515 this.focus.defer(10, this);
16519 focus : function(){
16520 if(this.win && !this.sourceEditMode){
16527 assignDocWin: function()
16529 var iframe = this.iframe;
16532 this.doc = iframe.contentWindow.document;
16533 this.win = iframe.contentWindow;
16535 // if (!Roo.get(this.frameId)) {
16538 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16539 // this.win = Roo.get(this.frameId).dom.contentWindow;
16541 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16545 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16546 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16551 initEditor : function(){
16552 //console.log("INIT EDITOR");
16553 this.assignDocWin();
16557 this.doc.designMode="on";
16559 this.doc.write(this.getDocMarkup());
16562 var dbody = (this.doc.body || this.doc.documentElement);
16563 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16564 // this copies styles from the containing element into thsi one..
16565 // not sure why we need all of this..
16566 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16568 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16569 //ss['background-attachment'] = 'fixed'; // w3c
16570 dbody.bgProperties = 'fixed'; // ie
16571 //Roo.DomHelper.applyStyles(dbody, ss);
16572 Roo.EventManager.on(this.doc, {
16573 //'mousedown': this.onEditorEvent,
16574 'mouseup': this.onEditorEvent,
16575 'dblclick': this.onEditorEvent,
16576 'click': this.onEditorEvent,
16577 'keyup': this.onEditorEvent,
16582 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16584 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16585 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16587 this.initialized = true;
16589 this.owner.fireEvent('initialize', this);
16594 onDestroy : function(){
16600 //for (var i =0; i < this.toolbars.length;i++) {
16601 // // fixme - ask toolbars for heights?
16602 // this.toolbars[i].onDestroy();
16605 //this.wrap.dom.innerHTML = '';
16606 //this.wrap.remove();
16611 onFirstFocus : function(){
16613 this.assignDocWin();
16616 this.activated = true;
16619 if(Roo.isGecko){ // prevent silly gecko errors
16621 var s = this.win.getSelection();
16622 if(!s.focusNode || s.focusNode.nodeType != 3){
16623 var r = s.getRangeAt(0);
16624 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16629 this.execCmd('useCSS', true);
16630 this.execCmd('styleWithCSS', false);
16633 this.owner.fireEvent('activate', this);
16637 adjustFont: function(btn){
16638 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16639 //if(Roo.isSafari){ // safari
16642 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16643 if(Roo.isSafari){ // safari
16644 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16645 v = (v < 10) ? 10 : v;
16646 v = (v > 48) ? 48 : v;
16647 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16652 v = Math.max(1, v+adjust);
16654 this.execCmd('FontSize', v );
16657 onEditorEvent : function(e){
16658 this.owner.fireEvent('editorevent', this, e);
16659 // this.updateToolbar();
16660 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16663 insertTag : function(tg)
16665 // could be a bit smarter... -> wrap the current selected tRoo..
16666 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16668 range = this.createRange(this.getSelection());
16669 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16670 wrappingNode.appendChild(range.extractContents());
16671 range.insertNode(wrappingNode);
16678 this.execCmd("formatblock", tg);
16682 insertText : function(txt)
16686 var range = this.createRange();
16687 range.deleteContents();
16688 //alert(Sender.getAttribute('label'));
16690 range.insertNode(this.doc.createTextNode(txt));
16696 * Executes a Midas editor command on the editor document and performs necessary focus and
16697 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16698 * @param {String} cmd The Midas command
16699 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16701 relayCmd : function(cmd, value){
16703 this.execCmd(cmd, value);
16704 this.owner.fireEvent('editorevent', this);
16705 //this.updateToolbar();
16706 this.owner.deferFocus();
16710 * Executes a Midas editor command directly on the editor document.
16711 * For visual commands, you should use {@link #relayCmd} instead.
16712 * <b>This should only be called after the editor is initialized.</b>
16713 * @param {String} cmd The Midas command
16714 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16716 execCmd : function(cmd, value){
16717 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16724 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16726 * @param {String} text | dom node..
16728 insertAtCursor : function(text)
16733 if(!this.activated){
16739 var r = this.doc.selection.createRange();
16750 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16754 // from jquery ui (MIT licenced)
16756 var win = this.win;
16758 if (win.getSelection && win.getSelection().getRangeAt) {
16759 range = win.getSelection().getRangeAt(0);
16760 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16761 range.insertNode(node);
16762 } else if (win.document.selection && win.document.selection.createRange) {
16763 // no firefox support
16764 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16765 win.document.selection.createRange().pasteHTML(txt);
16767 // no firefox support
16768 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16769 this.execCmd('InsertHTML', txt);
16778 mozKeyPress : function(e){
16780 var c = e.getCharCode(), cmd;
16783 c = String.fromCharCode(c).toLowerCase();
16797 this.cleanUpPaste.defer(100, this);
16805 e.preventDefault();
16813 fixKeys : function(){ // load time branching for fastest keydown performance
16815 return function(e){
16816 var k = e.getKey(), r;
16819 r = this.doc.selection.createRange();
16822 r.pasteHTML('    ');
16829 r = this.doc.selection.createRange();
16831 var target = r.parentElement();
16832 if(!target || target.tagName.toLowerCase() != 'li'){
16834 r.pasteHTML('<br />');
16840 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16841 this.cleanUpPaste.defer(100, this);
16847 }else if(Roo.isOpera){
16848 return function(e){
16849 var k = e.getKey();
16853 this.execCmd('InsertHTML','    ');
16856 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16857 this.cleanUpPaste.defer(100, this);
16862 }else if(Roo.isSafari){
16863 return function(e){
16864 var k = e.getKey();
16868 this.execCmd('InsertText','\t');
16872 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16873 this.cleanUpPaste.defer(100, this);
16881 getAllAncestors: function()
16883 var p = this.getSelectedNode();
16886 a.push(p); // push blank onto stack..
16887 p = this.getParentElement();
16891 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16895 a.push(this.doc.body);
16899 lastSelNode : false,
16902 getSelection : function()
16904 this.assignDocWin();
16905 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16908 getSelectedNode: function()
16910 // this may only work on Gecko!!!
16912 // should we cache this!!!!
16917 var range = this.createRange(this.getSelection()).cloneRange();
16920 var parent = range.parentElement();
16922 var testRange = range.duplicate();
16923 testRange.moveToElementText(parent);
16924 if (testRange.inRange(range)) {
16927 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16930 parent = parent.parentElement;
16935 // is ancestor a text element.
16936 var ac = range.commonAncestorContainer;
16937 if (ac.nodeType == 3) {
16938 ac = ac.parentNode;
16941 var ar = ac.childNodes;
16944 var other_nodes = [];
16945 var has_other_nodes = false;
16946 for (var i=0;i<ar.length;i++) {
16947 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16950 // fullly contained node.
16952 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16957 // probably selected..
16958 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16959 other_nodes.push(ar[i]);
16963 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16968 has_other_nodes = true;
16970 if (!nodes.length && other_nodes.length) {
16971 nodes= other_nodes;
16973 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16979 createRange: function(sel)
16981 // this has strange effects when using with
16982 // top toolbar - not sure if it's a great idea.
16983 //this.editor.contentWindow.focus();
16984 if (typeof sel != "undefined") {
16986 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16988 return this.doc.createRange();
16991 return this.doc.createRange();
16994 getParentElement: function()
16997 this.assignDocWin();
16998 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17000 var range = this.createRange(sel);
17003 var p = range.commonAncestorContainer;
17004 while (p.nodeType == 3) { // text node
17015 * Range intersection.. the hard stuff...
17019 * [ -- selected range --- ]
17023 * if end is before start or hits it. fail.
17024 * if start is after end or hits it fail.
17026 * if either hits (but other is outside. - then it's not
17032 // @see http://www.thismuchiknow.co.uk/?p=64.
17033 rangeIntersectsNode : function(range, node)
17035 var nodeRange = node.ownerDocument.createRange();
17037 nodeRange.selectNode(node);
17039 nodeRange.selectNodeContents(node);
17042 var rangeStartRange = range.cloneRange();
17043 rangeStartRange.collapse(true);
17045 var rangeEndRange = range.cloneRange();
17046 rangeEndRange.collapse(false);
17048 var nodeStartRange = nodeRange.cloneRange();
17049 nodeStartRange.collapse(true);
17051 var nodeEndRange = nodeRange.cloneRange();
17052 nodeEndRange.collapse(false);
17054 return rangeStartRange.compareBoundaryPoints(
17055 Range.START_TO_START, nodeEndRange) == -1 &&
17056 rangeEndRange.compareBoundaryPoints(
17057 Range.START_TO_START, nodeStartRange) == 1;
17061 rangeCompareNode : function(range, node)
17063 var nodeRange = node.ownerDocument.createRange();
17065 nodeRange.selectNode(node);
17067 nodeRange.selectNodeContents(node);
17071 range.collapse(true);
17073 nodeRange.collapse(true);
17075 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17076 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17078 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17080 var nodeIsBefore = ss == 1;
17081 var nodeIsAfter = ee == -1;
17083 if (nodeIsBefore && nodeIsAfter)
17085 if (!nodeIsBefore && nodeIsAfter)
17086 return 1; //right trailed.
17088 if (nodeIsBefore && !nodeIsAfter)
17089 return 2; // left trailed.
17094 // private? - in a new class?
17095 cleanUpPaste : function()
17097 // cleans up the whole document..
17098 Roo.log('cleanuppaste');
17100 this.cleanUpChildren(this.doc.body);
17101 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17102 if (clean != this.doc.body.innerHTML) {
17103 this.doc.body.innerHTML = clean;
17108 cleanWordChars : function(input) {// change the chars to hex code
17109 var he = Roo.HtmlEditorCore;
17111 var output = input;
17112 Roo.each(he.swapCodes, function(sw) {
17113 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17115 output = output.replace(swapper, sw[1]);
17122 cleanUpChildren : function (n)
17124 if (!n.childNodes.length) {
17127 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17128 this.cleanUpChild(n.childNodes[i]);
17135 cleanUpChild : function (node)
17138 //console.log(node);
17139 if (node.nodeName == "#text") {
17140 // clean up silly Windows -- stuff?
17143 if (node.nodeName == "#comment") {
17144 node.parentNode.removeChild(node);
17145 // clean up silly Windows -- stuff?
17149 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17151 node.parentNode.removeChild(node);
17156 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17158 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17159 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17161 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17162 // remove_keep_children = true;
17165 if (remove_keep_children) {
17166 this.cleanUpChildren(node);
17167 // inserts everything just before this node...
17168 while (node.childNodes.length) {
17169 var cn = node.childNodes[0];
17170 node.removeChild(cn);
17171 node.parentNode.insertBefore(cn, node);
17173 node.parentNode.removeChild(node);
17177 if (!node.attributes || !node.attributes.length) {
17178 this.cleanUpChildren(node);
17182 function cleanAttr(n,v)
17185 if (v.match(/^\./) || v.match(/^\//)) {
17188 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17191 if (v.match(/^#/)) {
17194 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17195 node.removeAttribute(n);
17199 function cleanStyle(n,v)
17201 if (v.match(/expression/)) { //XSS?? should we even bother..
17202 node.removeAttribute(n);
17205 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17206 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17209 var parts = v.split(/;/);
17212 Roo.each(parts, function(p) {
17213 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17217 var l = p.split(':').shift().replace(/\s+/g,'');
17218 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17220 if ( cblack.indexOf(l) > -1) {
17221 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17222 //node.removeAttribute(n);
17226 // only allow 'c whitelisted system attributes'
17227 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17228 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17229 //node.removeAttribute(n);
17239 if (clean.length) {
17240 node.setAttribute(n, clean.join(';'));
17242 node.removeAttribute(n);
17248 for (var i = node.attributes.length-1; i > -1 ; i--) {
17249 var a = node.attributes[i];
17252 if (a.name.toLowerCase().substr(0,2)=='on') {
17253 node.removeAttribute(a.name);
17256 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17257 node.removeAttribute(a.name);
17260 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17261 cleanAttr(a.name,a.value); // fixme..
17264 if (a.name == 'style') {
17265 cleanStyle(a.name,a.value);
17268 /// clean up MS crap..
17269 // tecnically this should be a list of valid class'es..
17272 if (a.name == 'class') {
17273 if (a.value.match(/^Mso/)) {
17274 node.className = '';
17277 if (a.value.match(/body/)) {
17278 node.className = '';
17289 this.cleanUpChildren(node);
17294 * Clean up MS wordisms...
17296 cleanWord : function(node)
17299 var cleanWordChildren = function()
17301 if (!node.childNodes.length) {
17304 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17305 _t.cleanWord(node.childNodes[i]);
17311 this.cleanWord(this.doc.body);
17314 if (node.nodeName == "#text") {
17315 // clean up silly Windows -- stuff?
17318 if (node.nodeName == "#comment") {
17319 node.parentNode.removeChild(node);
17320 // clean up silly Windows -- stuff?
17324 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17325 node.parentNode.removeChild(node);
17329 // remove - but keep children..
17330 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17331 while (node.childNodes.length) {
17332 var cn = node.childNodes[0];
17333 node.removeChild(cn);
17334 node.parentNode.insertBefore(cn, node);
17336 node.parentNode.removeChild(node);
17337 cleanWordChildren();
17341 if (node.className.length) {
17343 var cn = node.className.split(/\W+/);
17345 Roo.each(cn, function(cls) {
17346 if (cls.match(/Mso[a-zA-Z]+/)) {
17351 node.className = cna.length ? cna.join(' ') : '';
17353 node.removeAttribute("class");
17357 if (node.hasAttribute("lang")) {
17358 node.removeAttribute("lang");
17361 if (node.hasAttribute("style")) {
17363 var styles = node.getAttribute("style").split(";");
17365 Roo.each(styles, function(s) {
17366 if (!s.match(/:/)) {
17369 var kv = s.split(":");
17370 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17373 // what ever is left... we allow.
17376 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17377 if (!nstyle.length) {
17378 node.removeAttribute('style');
17382 cleanWordChildren();
17386 domToHTML : function(currentElement, depth, nopadtext) {
17388 depth = depth || 0;
17389 nopadtext = nopadtext || false;
17391 if (!currentElement) {
17392 return this.domToHTML(this.doc.body);
17395 //Roo.log(currentElement);
17397 var allText = false;
17398 var nodeName = currentElement.nodeName;
17399 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17401 if (nodeName == '#text') {
17402 return currentElement.nodeValue;
17407 if (nodeName != 'BODY') {
17410 // Prints the node tagName, such as <A>, <IMG>, etc
17413 for(i = 0; i < currentElement.attributes.length;i++) {
17415 var aname = currentElement.attributes.item(i).name;
17416 if (!currentElement.attributes.item(i).value.length) {
17419 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17422 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17431 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17434 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17439 // Traverse the tree
17441 var currentElementChild = currentElement.childNodes.item(i);
17442 var allText = true;
17443 var innerHTML = '';
17445 while (currentElementChild) {
17446 // Formatting code (indent the tree so it looks nice on the screen)
17447 var nopad = nopadtext;
17448 if (lastnode == 'SPAN') {
17452 if (currentElementChild.nodeName == '#text') {
17453 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17454 if (!nopad && toadd.length > 80) {
17455 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17457 innerHTML += toadd;
17460 currentElementChild = currentElement.childNodes.item(i);
17466 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17468 // Recursively traverse the tree structure of the child node
17469 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17470 lastnode = currentElementChild.nodeName;
17472 currentElementChild=currentElement.childNodes.item(i);
17478 // The remaining code is mostly for formatting the tree
17479 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17484 ret+= "</"+tagName+">";
17490 // hide stuff that is not compatible
17504 * @event specialkey
17508 * @cfg {String} fieldClass @hide
17511 * @cfg {String} focusClass @hide
17514 * @cfg {String} autoCreate @hide
17517 * @cfg {String} inputType @hide
17520 * @cfg {String} invalidClass @hide
17523 * @cfg {String} invalidText @hide
17526 * @cfg {String} msgFx @hide
17529 * @cfg {String} validateOnBlur @hide
17533 Roo.HtmlEditorCore.white = [
17534 'area', 'br', 'img', 'input', 'hr', 'wbr',
17536 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17537 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17538 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17539 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17540 'table', 'ul', 'xmp',
17542 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17545 'dir', 'menu', 'ol', 'ul', 'dl',
17551 Roo.HtmlEditorCore.black = [
17552 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17554 'base', 'basefont', 'bgsound', 'blink', 'body',
17555 'frame', 'frameset', 'head', 'html', 'ilayer',
17556 'iframe', 'layer', 'link', 'meta', 'object',
17557 'script', 'style' ,'title', 'xml' // clean later..
17559 Roo.HtmlEditorCore.clean = [
17560 'script', 'style', 'title', 'xml'
17562 Roo.HtmlEditorCore.remove = [
17567 Roo.HtmlEditorCore.ablack = [
17571 Roo.HtmlEditorCore.aclean = [
17572 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17576 Roo.HtmlEditorCore.pwhite= [
17577 'http', 'https', 'mailto'
17580 // white listed style attributes.
17581 Roo.HtmlEditorCore.cwhite= [
17582 // 'text-align', /// default is to allow most things..
17588 // black listed style attributes.
17589 Roo.HtmlEditorCore.cblack= [
17590 // 'font-size' -- this can be set by the project
17594 Roo.HtmlEditorCore.swapCodes =[
17613 * @class Roo.bootstrap.HtmlEditor
17614 * @extends Roo.bootstrap.TextArea
17615 * Bootstrap HtmlEditor class
17618 * Create a new HtmlEditor
17619 * @param {Object} config The config object
17622 Roo.bootstrap.HtmlEditor = function(config){
17623 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17624 if (!this.toolbars) {
17625 this.toolbars = [];
17627 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17630 * @event initialize
17631 * Fires when the editor is fully initialized (including the iframe)
17632 * @param {HtmlEditor} this
17637 * Fires when the editor is first receives the focus. Any insertion must wait
17638 * until after this event.
17639 * @param {HtmlEditor} this
17643 * @event beforesync
17644 * Fires before the textarea is updated with content from the editor iframe. Return false
17645 * to cancel the sync.
17646 * @param {HtmlEditor} this
17647 * @param {String} html
17651 * @event beforepush
17652 * Fires before the iframe editor is updated with content from the textarea. Return false
17653 * to cancel the push.
17654 * @param {HtmlEditor} this
17655 * @param {String} html
17660 * Fires when the textarea is updated with content from the editor iframe.
17661 * @param {HtmlEditor} this
17662 * @param {String} html
17667 * Fires when the iframe editor is updated with content from the textarea.
17668 * @param {HtmlEditor} this
17669 * @param {String} html
17673 * @event editmodechange
17674 * Fires when the editor switches edit modes
17675 * @param {HtmlEditor} this
17676 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17678 editmodechange: true,
17680 * @event editorevent
17681 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17682 * @param {HtmlEditor} this
17686 * @event firstfocus
17687 * Fires when on first focus - needed by toolbars..
17688 * @param {HtmlEditor} this
17693 * Auto save the htmlEditor value as a file into Events
17694 * @param {HtmlEditor} this
17698 * @event savedpreview
17699 * preview the saved version of htmlEditor
17700 * @param {HtmlEditor} this
17707 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17711 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17716 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17721 * @cfg {Number} height (in pixels)
17725 * @cfg {Number} width (in pixels)
17730 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17733 stylesheets: false,
17738 // private properties
17739 validationEvent : false,
17741 initialized : false,
17744 onFocus : Roo.emptyFn,
17746 hideMode:'offsets',
17749 tbContainer : false,
17751 toolbarContainer :function() {
17752 return this.wrap.select('.x-html-editor-tb',true).first();
17756 * Protected method that will not generally be called directly. It
17757 * is called when the editor creates its toolbar. Override this method if you need to
17758 * add custom toolbar buttons.
17759 * @param {HtmlEditor} editor
17761 createToolbar : function(){
17763 Roo.log("create toolbars");
17765 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17766 this.toolbars[0].render(this.toolbarContainer());
17770 // if (!editor.toolbars || !editor.toolbars.length) {
17771 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17774 // for (var i =0 ; i < editor.toolbars.length;i++) {
17775 // editor.toolbars[i] = Roo.factory(
17776 // typeof(editor.toolbars[i]) == 'string' ?
17777 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17778 // Roo.bootstrap.HtmlEditor);
17779 // editor.toolbars[i].init(editor);
17785 onRender : function(ct, position)
17787 // Roo.log("Call onRender: " + this.xtype);
17789 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17791 this.wrap = this.inputEl().wrap({
17792 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17795 this.editorcore.onRender(ct, position);
17797 if (this.resizable) {
17798 this.resizeEl = new Roo.Resizable(this.wrap, {
17802 minHeight : this.height,
17803 height: this.height,
17804 handles : this.resizable,
17807 resize : function(r, w, h) {
17808 _t.onResize(w,h); // -something
17814 this.createToolbar(this);
17817 if(!this.width && this.resizable){
17818 this.setSize(this.wrap.getSize());
17820 if (this.resizeEl) {
17821 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17822 // should trigger onReize..
17828 onResize : function(w, h)
17830 Roo.log('resize: ' +w + ',' + h );
17831 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17835 if(this.inputEl() ){
17836 if(typeof w == 'number'){
17837 var aw = w - this.wrap.getFrameWidth('lr');
17838 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17841 if(typeof h == 'number'){
17842 var tbh = -11; // fixme it needs to tool bar size!
17843 for (var i =0; i < this.toolbars.length;i++) {
17844 // fixme - ask toolbars for heights?
17845 tbh += this.toolbars[i].el.getHeight();
17846 //if (this.toolbars[i].footer) {
17847 // tbh += this.toolbars[i].footer.el.getHeight();
17855 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17856 ah -= 5; // knock a few pixes off for look..
17857 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17861 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17862 this.editorcore.onResize(ew,eh);
17867 * Toggles the editor between standard and source edit mode.
17868 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17870 toggleSourceEdit : function(sourceEditMode)
17872 this.editorcore.toggleSourceEdit(sourceEditMode);
17874 if(this.editorcore.sourceEditMode){
17875 Roo.log('editor - showing textarea');
17878 // Roo.log(this.syncValue());
17880 this.inputEl().removeClass(['hide', 'x-hidden']);
17881 this.inputEl().dom.removeAttribute('tabIndex');
17882 this.inputEl().focus();
17884 Roo.log('editor - hiding textarea');
17886 // Roo.log(this.pushValue());
17889 this.inputEl().addClass(['hide', 'x-hidden']);
17890 this.inputEl().dom.setAttribute('tabIndex', -1);
17891 //this.deferFocus();
17894 if(this.resizable){
17895 this.setSize(this.wrap.getSize());
17898 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17901 // private (for BoxComponent)
17902 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17904 // private (for BoxComponent)
17905 getResizeEl : function(){
17909 // private (for BoxComponent)
17910 getPositionEl : function(){
17915 initEvents : function(){
17916 this.originalValue = this.getValue();
17920 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17923 // markInvalid : Roo.emptyFn,
17925 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17928 // clearInvalid : Roo.emptyFn,
17930 setValue : function(v){
17931 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17932 this.editorcore.pushValue();
17937 deferFocus : function(){
17938 this.focus.defer(10, this);
17942 focus : function(){
17943 this.editorcore.focus();
17949 onDestroy : function(){
17955 for (var i =0; i < this.toolbars.length;i++) {
17956 // fixme - ask toolbars for heights?
17957 this.toolbars[i].onDestroy();
17960 this.wrap.dom.innerHTML = '';
17961 this.wrap.remove();
17966 onFirstFocus : function(){
17967 //Roo.log("onFirstFocus");
17968 this.editorcore.onFirstFocus();
17969 for (var i =0; i < this.toolbars.length;i++) {
17970 this.toolbars[i].onFirstFocus();
17976 syncValue : function()
17978 this.editorcore.syncValue();
17981 pushValue : function()
17983 this.editorcore.pushValue();
17987 // hide stuff that is not compatible
18001 * @event specialkey
18005 * @cfg {String} fieldClass @hide
18008 * @cfg {String} focusClass @hide
18011 * @cfg {String} autoCreate @hide
18014 * @cfg {String} inputType @hide
18017 * @cfg {String} invalidClass @hide
18020 * @cfg {String} invalidText @hide
18023 * @cfg {String} msgFx @hide
18026 * @cfg {String} validateOnBlur @hide
18035 Roo.namespace('Roo.bootstrap.htmleditor');
18037 * @class Roo.bootstrap.HtmlEditorToolbar1
18042 new Roo.bootstrap.HtmlEditor({
18045 new Roo.bootstrap.HtmlEditorToolbar1({
18046 disable : { fonts: 1 , format: 1, ..., ... , ...],
18052 * @cfg {Object} disable List of elements to disable..
18053 * @cfg {Array} btns List of additional buttons.
18057 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18060 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18063 Roo.apply(this, config);
18065 // default disabled, based on 'good practice'..
18066 this.disable = this.disable || {};
18067 Roo.applyIf(this.disable, {
18070 specialElements : true
18072 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18074 this.editor = config.editor;
18075 this.editorcore = config.editor.editorcore;
18077 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18079 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18080 // dont call parent... till later.
18082 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18087 editorcore : false,
18092 "h1","h2","h3","h4","h5","h6",
18094 "abbr", "acronym", "address", "cite", "samp", "var",
18098 onRender : function(ct, position)
18100 // Roo.log("Call onRender: " + this.xtype);
18102 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18104 this.el.dom.style.marginBottom = '0';
18106 var editorcore = this.editorcore;
18107 var editor= this.editor;
18110 var btn = function(id,cmd , toggle, handler){
18112 var event = toggle ? 'toggle' : 'click';
18117 xns: Roo.bootstrap,
18120 enableToggle:toggle !== false,
18122 pressed : toggle ? false : null,
18125 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18126 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18135 xns: Roo.bootstrap,
18136 glyphicon : 'font',
18140 xns: Roo.bootstrap,
18144 Roo.each(this.formats, function(f) {
18145 style.menu.items.push({
18147 xns: Roo.bootstrap,
18148 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18153 editorcore.insertTag(this.tagname);
18160 children.push(style);
18163 btn('bold',false,true);
18164 btn('italic',false,true);
18165 btn('align-left', 'justifyleft',true);
18166 btn('align-center', 'justifycenter',true);
18167 btn('align-right' , 'justifyright',true);
18168 btn('link', false, false, function(btn) {
18169 //Roo.log("create link?");
18170 var url = prompt(this.createLinkText, this.defaultLinkValue);
18171 if(url && url != 'http:/'+'/'){
18172 this.editorcore.relayCmd('createlink', url);
18175 btn('list','insertunorderedlist',true);
18176 btn('pencil', false,true, function(btn){
18179 this.toggleSourceEdit(btn.pressed);
18185 xns: Roo.bootstrap,
18190 xns: Roo.bootstrap,
18195 cog.menu.items.push({
18197 xns: Roo.bootstrap,
18198 html : Clean styles,
18203 editorcore.insertTag(this.tagname);
18212 this.xtype = 'NavSimplebar';
18214 for(var i=0;i< children.length;i++) {
18216 this.buttons.add(this.addxtypeChild(children[i]));
18220 editor.on('editorevent', this.updateToolbar, this);
18222 onBtnClick : function(id)
18224 this.editorcore.relayCmd(id);
18225 this.editorcore.focus();
18229 * Protected method that will not generally be called directly. It triggers
18230 * a toolbar update by reading the markup state of the current selection in the editor.
18232 updateToolbar: function(){
18234 if(!this.editorcore.activated){
18235 this.editor.onFirstFocus(); // is this neeed?
18239 var btns = this.buttons;
18240 var doc = this.editorcore.doc;
18241 btns.get('bold').setActive(doc.queryCommandState('bold'));
18242 btns.get('italic').setActive(doc.queryCommandState('italic'));
18243 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18245 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18246 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18247 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18249 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18250 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18253 var ans = this.editorcore.getAllAncestors();
18254 if (this.formatCombo) {
18257 var store = this.formatCombo.store;
18258 this.formatCombo.setValue("");
18259 for (var i =0; i < ans.length;i++) {
18260 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18262 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18270 // hides menus... - so this cant be on a menu...
18271 Roo.bootstrap.MenuMgr.hideAll();
18273 Roo.bootstrap.MenuMgr.hideAll();
18274 //this.editorsyncValue();
18276 onFirstFocus: function() {
18277 this.buttons.each(function(item){
18281 toggleSourceEdit : function(sourceEditMode){
18284 if(sourceEditMode){
18285 Roo.log("disabling buttons");
18286 this.buttons.each( function(item){
18287 if(item.cmd != 'pencil'){
18293 Roo.log("enabling buttons");
18294 if(this.editorcore.initialized){
18295 this.buttons.each( function(item){
18301 Roo.log("calling toggole on editor");
18302 // tell the editor that it's been pressed..
18303 this.editor.toggleSourceEdit(sourceEditMode);
18313 * @class Roo.bootstrap.Table.AbstractSelectionModel
18314 * @extends Roo.util.Observable
18315 * Abstract base class for grid SelectionModels. It provides the interface that should be
18316 * implemented by descendant classes. This class should not be directly instantiated.
18319 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18320 this.locked = false;
18321 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18325 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18326 /** @ignore Called by the grid automatically. Do not call directly. */
18327 init : function(grid){
18333 * Locks the selections.
18336 this.locked = true;
18340 * Unlocks the selections.
18342 unlock : function(){
18343 this.locked = false;
18347 * Returns true if the selections are locked.
18348 * @return {Boolean}
18350 isLocked : function(){
18351 return this.locked;
18355 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18356 * @class Roo.bootstrap.Table.RowSelectionModel
18357 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18358 * It supports multiple selections and keyboard selection/navigation.
18360 * @param {Object} config
18363 Roo.bootstrap.Table.RowSelectionModel = function(config){
18364 Roo.apply(this, config);
18365 this.selections = new Roo.util.MixedCollection(false, function(o){
18370 this.lastActive = false;
18374 * @event selectionchange
18375 * Fires when the selection changes
18376 * @param {SelectionModel} this
18378 "selectionchange" : true,
18380 * @event afterselectionchange
18381 * Fires after the selection changes (eg. by key press or clicking)
18382 * @param {SelectionModel} this
18384 "afterselectionchange" : true,
18386 * @event beforerowselect
18387 * Fires when a row is selected being selected, return false to cancel.
18388 * @param {SelectionModel} this
18389 * @param {Number} rowIndex The selected index
18390 * @param {Boolean} keepExisting False if other selections will be cleared
18392 "beforerowselect" : true,
18395 * Fires when a row is selected.
18396 * @param {SelectionModel} this
18397 * @param {Number} rowIndex The selected index
18398 * @param {Roo.data.Record} r The record
18400 "rowselect" : true,
18402 * @event rowdeselect
18403 * Fires when a row is deselected.
18404 * @param {SelectionModel} this
18405 * @param {Number} rowIndex The selected index
18407 "rowdeselect" : true
18409 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18410 this.locked = false;
18413 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18415 * @cfg {Boolean} singleSelect
18416 * True to allow selection of only one row at a time (defaults to false)
18418 singleSelect : false,
18421 initEvents : function(){
18423 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18424 this.grid.on("mousedown", this.handleMouseDown, this);
18425 }else{ // allow click to work like normal
18426 this.grid.on("rowclick", this.handleDragableRowClick, this);
18429 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18430 "up" : function(e){
18432 this.selectPrevious(e.shiftKey);
18433 }else if(this.last !== false && this.lastActive !== false){
18434 var last = this.last;
18435 this.selectRange(this.last, this.lastActive-1);
18436 this.grid.getView().focusRow(this.lastActive);
18437 if(last !== false){
18441 this.selectFirstRow();
18443 this.fireEvent("afterselectionchange", this);
18445 "down" : function(e){
18447 this.selectNext(e.shiftKey);
18448 }else if(this.last !== false && this.lastActive !== false){
18449 var last = this.last;
18450 this.selectRange(this.last, this.lastActive+1);
18451 this.grid.getView().focusRow(this.lastActive);
18452 if(last !== false){
18456 this.selectFirstRow();
18458 this.fireEvent("afterselectionchange", this);
18463 var view = this.grid.view;
18464 view.on("refresh", this.onRefresh, this);
18465 view.on("rowupdated", this.onRowUpdated, this);
18466 view.on("rowremoved", this.onRemove, this);
18470 onRefresh : function(){
18471 var ds = this.grid.dataSource, i, v = this.grid.view;
18472 var s = this.selections;
18473 s.each(function(r){
18474 if((i = ds.indexOfId(r.id)) != -1){
18483 onRemove : function(v, index, r){
18484 this.selections.remove(r);
18488 onRowUpdated : function(v, index, r){
18489 if(this.isSelected(r)){
18490 v.onRowSelect(index);
18496 * @param {Array} records The records to select
18497 * @param {Boolean} keepExisting (optional) True to keep existing selections
18499 selectRecords : function(records, keepExisting){
18501 this.clearSelections();
18503 var ds = this.grid.dataSource;
18504 for(var i = 0, len = records.length; i < len; i++){
18505 this.selectRow(ds.indexOf(records[i]), true);
18510 * Gets the number of selected rows.
18513 getCount : function(){
18514 return this.selections.length;
18518 * Selects the first row in the grid.
18520 selectFirstRow : function(){
18525 * Select the last row.
18526 * @param {Boolean} keepExisting (optional) True to keep existing selections
18528 selectLastRow : function(keepExisting){
18529 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18533 * Selects the row immediately following the last selected row.
18534 * @param {Boolean} keepExisting (optional) True to keep existing selections
18536 selectNext : function(keepExisting){
18537 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18538 this.selectRow(this.last+1, keepExisting);
18539 this.grid.getView().focusRow(this.last);
18544 * Selects the row that precedes the last selected row.
18545 * @param {Boolean} keepExisting (optional) True to keep existing selections
18547 selectPrevious : function(keepExisting){
18549 this.selectRow(this.last-1, keepExisting);
18550 this.grid.getView().focusRow(this.last);
18555 * Returns the selected records
18556 * @return {Array} Array of selected records
18558 getSelections : function(){
18559 return [].concat(this.selections.items);
18563 * Returns the first selected record.
18566 getSelected : function(){
18567 return this.selections.itemAt(0);
18572 * Clears all selections.
18574 clearSelections : function(fast){
18575 if(this.locked) return;
18577 var ds = this.grid.dataSource;
18578 var s = this.selections;
18579 s.each(function(r){
18580 this.deselectRow(ds.indexOfId(r.id));
18584 this.selections.clear();
18591 * Selects all rows.
18593 selectAll : function(){
18594 if(this.locked) return;
18595 this.selections.clear();
18596 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18597 this.selectRow(i, true);
18602 * Returns True if there is a selection.
18603 * @return {Boolean}
18605 hasSelection : function(){
18606 return this.selections.length > 0;
18610 * Returns True if the specified row is selected.
18611 * @param {Number/Record} record The record or index of the record to check
18612 * @return {Boolean}
18614 isSelected : function(index){
18615 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18616 return (r && this.selections.key(r.id) ? true : false);
18620 * Returns True if the specified record id is selected.
18621 * @param {String} id The id of record to check
18622 * @return {Boolean}
18624 isIdSelected : function(id){
18625 return (this.selections.key(id) ? true : false);
18629 handleMouseDown : function(e, t){
18630 var view = this.grid.getView(), rowIndex;
18631 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18634 if(e.shiftKey && this.last !== false){
18635 var last = this.last;
18636 this.selectRange(last, rowIndex, e.ctrlKey);
18637 this.last = last; // reset the last
18638 view.focusRow(rowIndex);
18640 var isSelected = this.isSelected(rowIndex);
18641 if(e.button !== 0 && isSelected){
18642 view.focusRow(rowIndex);
18643 }else if(e.ctrlKey && isSelected){
18644 this.deselectRow(rowIndex);
18645 }else if(!isSelected){
18646 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18647 view.focusRow(rowIndex);
18650 this.fireEvent("afterselectionchange", this);
18653 handleDragableRowClick : function(grid, rowIndex, e)
18655 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18656 this.selectRow(rowIndex, false);
18657 grid.view.focusRow(rowIndex);
18658 this.fireEvent("afterselectionchange", this);
18663 * Selects multiple rows.
18664 * @param {Array} rows Array of the indexes of the row to select
18665 * @param {Boolean} keepExisting (optional) True to keep existing selections
18667 selectRows : function(rows, keepExisting){
18669 this.clearSelections();
18671 for(var i = 0, len = rows.length; i < len; i++){
18672 this.selectRow(rows[i], true);
18677 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18678 * @param {Number} startRow The index of the first row in the range
18679 * @param {Number} endRow The index of the last row in the range
18680 * @param {Boolean} keepExisting (optional) True to retain existing selections
18682 selectRange : function(startRow, endRow, keepExisting){
18683 if(this.locked) return;
18685 this.clearSelections();
18687 if(startRow <= endRow){
18688 for(var i = startRow; i <= endRow; i++){
18689 this.selectRow(i, true);
18692 for(var i = startRow; i >= endRow; i--){
18693 this.selectRow(i, true);
18699 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18700 * @param {Number} startRow The index of the first row in the range
18701 * @param {Number} endRow The index of the last row in the range
18703 deselectRange : function(startRow, endRow, preventViewNotify){
18704 if(this.locked) return;
18705 for(var i = startRow; i <= endRow; i++){
18706 this.deselectRow(i, preventViewNotify);
18712 * @param {Number} row The index of the row to select
18713 * @param {Boolean} keepExisting (optional) True to keep existing selections
18715 selectRow : function(index, keepExisting, preventViewNotify){
18716 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18717 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18718 if(!keepExisting || this.singleSelect){
18719 this.clearSelections();
18721 var r = this.grid.dataSource.getAt(index);
18722 this.selections.add(r);
18723 this.last = this.lastActive = index;
18724 if(!preventViewNotify){
18725 this.grid.getView().onRowSelect(index);
18727 this.fireEvent("rowselect", this, index, r);
18728 this.fireEvent("selectionchange", this);
18734 * @param {Number} row The index of the row to deselect
18736 deselectRow : function(index, preventViewNotify){
18737 if(this.locked) return;
18738 if(this.last == index){
18741 if(this.lastActive == index){
18742 this.lastActive = false;
18744 var r = this.grid.dataSource.getAt(index);
18745 this.selections.remove(r);
18746 if(!preventViewNotify){
18747 this.grid.getView().onRowDeselect(index);
18749 this.fireEvent("rowdeselect", this, index);
18750 this.fireEvent("selectionchange", this);
18754 restoreLast : function(){
18756 this.last = this._last;
18761 acceptsNav : function(row, col, cm){
18762 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18766 onEditorKey : function(field, e){
18767 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18772 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18774 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18776 }else if(k == e.ENTER && !e.ctrlKey){
18780 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18782 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18784 }else if(k == e.ESC){
18788 g.startEditing(newCell[0], newCell[1]);
18793 * Ext JS Library 1.1.1
18794 * Copyright(c) 2006-2007, Ext JS, LLC.
18796 * Originally Released Under LGPL - original licence link has changed is not relivant.
18799 * <script type="text/javascript">
18803 * @class Roo.bootstrap.PagingToolbar
18805 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18807 * Create a new PagingToolbar
18808 * @param {Object} config The config object
18810 Roo.bootstrap.PagingToolbar = function(config)
18812 // old args format still supported... - xtype is prefered..
18813 // created from xtype...
18814 var ds = config.dataSource;
18815 this.toolbarItems = [];
18816 if (config.items) {
18817 this.toolbarItems = config.items;
18818 // config.items = [];
18821 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18828 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18832 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18834 * @cfg {Roo.data.Store} dataSource
18835 * The underlying data store providing the paged data
18838 * @cfg {String/HTMLElement/Element} container
18839 * container The id or element that will contain the toolbar
18842 * @cfg {Boolean} displayInfo
18843 * True to display the displayMsg (defaults to false)
18846 * @cfg {Number} pageSize
18847 * The number of records to display per page (defaults to 20)
18851 * @cfg {String} displayMsg
18852 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18854 displayMsg : 'Displaying {0} - {1} of {2}',
18856 * @cfg {String} emptyMsg
18857 * The message to display when no records are found (defaults to "No data to display")
18859 emptyMsg : 'No data to display',
18861 * Customizable piece of the default paging text (defaults to "Page")
18864 beforePageText : "Page",
18866 * Customizable piece of the default paging text (defaults to "of %0")
18869 afterPageText : "of {0}",
18871 * Customizable piece of the default paging text (defaults to "First Page")
18874 firstText : "First Page",
18876 * Customizable piece of the default paging text (defaults to "Previous Page")
18879 prevText : "Previous Page",
18881 * Customizable piece of the default paging text (defaults to "Next Page")
18884 nextText : "Next Page",
18886 * Customizable piece of the default paging text (defaults to "Last Page")
18889 lastText : "Last Page",
18891 * Customizable piece of the default paging text (defaults to "Refresh")
18894 refreshText : "Refresh",
18898 onRender : function(ct, position)
18900 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18901 this.navgroup.parentId = this.id;
18902 this.navgroup.onRender(this.el, null);
18903 // add the buttons to the navgroup
18905 if(this.displayInfo){
18906 Roo.log(this.el.select('ul.navbar-nav',true).first());
18907 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18908 this.displayEl = this.el.select('.x-paging-info', true).first();
18909 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18910 // this.displayEl = navel.el.select('span',true).first();
18916 Roo.each(_this.buttons, function(e){
18917 Roo.factory(e).onRender(_this.el, null);
18921 Roo.each(_this.toolbarItems, function(e) {
18922 _this.navgroup.addItem(e);
18925 this.first = this.navgroup.addItem({
18926 tooltip: this.firstText,
18928 icon : 'fa fa-backward',
18930 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18933 this.prev = this.navgroup.addItem({
18934 tooltip: this.prevText,
18936 icon : 'fa fa-step-backward',
18938 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18940 //this.addSeparator();
18943 var field = this.navgroup.addItem( {
18945 cls : 'x-paging-position',
18947 html : this.beforePageText +
18948 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18949 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18952 this.field = field.el.select('input', true).first();
18953 this.field.on("keydown", this.onPagingKeydown, this);
18954 this.field.on("focus", function(){this.dom.select();});
18957 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18958 //this.field.setHeight(18);
18959 //this.addSeparator();
18960 this.next = this.navgroup.addItem({
18961 tooltip: this.nextText,
18963 html : ' <i class="fa fa-step-forward">',
18965 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18967 this.last = this.navgroup.addItem({
18968 tooltip: this.lastText,
18969 icon : 'fa fa-forward',
18972 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18974 //this.addSeparator();
18975 this.loading = this.navgroup.addItem({
18976 tooltip: this.refreshText,
18977 icon: 'fa fa-refresh',
18979 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18985 updateInfo : function(){
18986 if(this.displayEl){
18987 var count = this.ds.getCount();
18988 var msg = count == 0 ?
18992 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18994 this.displayEl.update(msg);
18999 onLoad : function(ds, r, o){
19000 this.cursor = o.params ? o.params.start : 0;
19001 var d = this.getPageData(),
19005 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19006 this.field.dom.value = ap;
19007 this.first.setDisabled(ap == 1);
19008 this.prev.setDisabled(ap == 1);
19009 this.next.setDisabled(ap == ps);
19010 this.last.setDisabled(ap == ps);
19011 this.loading.enable();
19016 getPageData : function(){
19017 var total = this.ds.getTotalCount();
19020 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19021 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19026 onLoadError : function(){
19027 this.loading.enable();
19031 onPagingKeydown : function(e){
19032 var k = e.getKey();
19033 var d = this.getPageData();
19035 var v = this.field.dom.value, pageNum;
19036 if(!v || isNaN(pageNum = parseInt(v, 10))){
19037 this.field.dom.value = d.activePage;
19040 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19041 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19044 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))
19046 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19047 this.field.dom.value = pageNum;
19048 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19051 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19053 var v = this.field.dom.value, pageNum;
19054 var increment = (e.shiftKey) ? 10 : 1;
19055 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19057 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19058 this.field.dom.value = d.activePage;
19061 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19063 this.field.dom.value = parseInt(v, 10) + increment;
19064 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19065 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19072 beforeLoad : function(){
19074 this.loading.disable();
19079 onClick : function(which){
19086 ds.load({params:{start: 0, limit: this.pageSize}});
19089 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19092 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19095 var total = ds.getTotalCount();
19096 var extra = total % this.pageSize;
19097 var lastStart = extra ? (total - extra) : total-this.pageSize;
19098 ds.load({params:{start: lastStart, limit: this.pageSize}});
19101 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19107 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19108 * @param {Roo.data.Store} store The data store to unbind
19110 unbind : function(ds){
19111 ds.un("beforeload", this.beforeLoad, this);
19112 ds.un("load", this.onLoad, this);
19113 ds.un("loadexception", this.onLoadError, this);
19114 ds.un("remove", this.updateInfo, this);
19115 ds.un("add", this.updateInfo, this);
19116 this.ds = undefined;
19120 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19121 * @param {Roo.data.Store} store The data store to bind
19123 bind : function(ds){
19124 ds.on("beforeload", this.beforeLoad, this);
19125 ds.on("load", this.onLoad, this);
19126 ds.on("loadexception", this.onLoadError, this);
19127 ds.on("remove", this.updateInfo, this);
19128 ds.on("add", this.updateInfo, this);
19139 * @class Roo.bootstrap.MessageBar
19140 * @extends Roo.bootstrap.Component
19141 * Bootstrap MessageBar class
19142 * @cfg {String} html contents of the MessageBar
19143 * @cfg {String} weight (info | success | warning | danger) default info
19144 * @cfg {String} beforeClass insert the bar before the given class
19145 * @cfg {Boolean} closable (true | false) default false
19146 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19149 * Create a new Element
19150 * @param {Object} config The config object
19153 Roo.bootstrap.MessageBar = function(config){
19154 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19157 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19163 beforeClass: 'bootstrap-sticky-wrap',
19165 getAutoCreate : function(){
19169 cls: 'alert alert-dismissable alert-' + this.weight,
19174 html: this.html || ''
19180 cfg.cls += ' alert-messages-fixed';
19194 onRender : function(ct, position)
19196 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19199 var cfg = Roo.apply({}, this.getAutoCreate());
19203 cfg.cls += ' ' + this.cls;
19206 cfg.style = this.style;
19208 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19210 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19213 this.el.select('>button.close').on('click', this.hide, this);
19219 if (!this.rendered) {
19225 this.fireEvent('show', this);
19231 if (!this.rendered) {
19237 this.fireEvent('hide', this);
19240 update : function()
19242 // var e = this.el.dom.firstChild;
19244 // if(this.closable){
19245 // e = e.nextSibling;
19248 // e.data = this.html || '';
19250 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19266 * @class Roo.bootstrap.Graph
19267 * @extends Roo.bootstrap.Component
19268 * Bootstrap Graph class
19272 @cfg {String} graphtype bar | vbar | pie
19273 @cfg {number} g_x coodinator | centre x (pie)
19274 @cfg {number} g_y coodinator | centre y (pie)
19275 @cfg {number} g_r radius (pie)
19276 @cfg {number} g_height height of the chart (respected by all elements in the set)
19277 @cfg {number} g_width width of the chart (respected by all elements in the set)
19278 @cfg {Object} title The title of the chart
19281 -opts (object) options for the chart
19283 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19284 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19286 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.
19287 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19289 o stretch (boolean)
19291 -opts (object) options for the pie
19294 o startAngle (number)
19295 o endAngle (number)
19299 * Create a new Input
19300 * @param {Object} config The config object
19303 Roo.bootstrap.Graph = function(config){
19304 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19310 * The img click event for the img.
19311 * @param {Roo.EventObject} e
19317 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19328 //g_colors: this.colors,
19335 getAutoCreate : function(){
19346 onRender : function(ct,position){
19347 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19348 this.raphael = Raphael(this.el.dom);
19350 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19351 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19352 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19353 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19355 r.text(160, 10, "Single Series Chart").attr(txtattr);
19356 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19357 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19358 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19360 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19361 r.barchart(330, 10, 300, 220, data1);
19362 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19363 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19366 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19367 // r.barchart(30, 30, 560, 250, xdata, {
19368 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19369 // axis : "0 0 1 1",
19370 // axisxlabels : xdata
19371 // //yvalues : cols,
19374 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19376 // this.load(null,xdata,{
19377 // axis : "0 0 1 1",
19378 // axisxlabels : xdata
19383 load : function(graphtype,xdata,opts){
19384 this.raphael.clear();
19386 graphtype = this.graphtype;
19391 var r = this.raphael,
19392 fin = function () {
19393 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19395 fout = function () {
19396 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19398 pfin = function() {
19399 this.sector.stop();
19400 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19403 this.label[0].stop();
19404 this.label[0].attr({ r: 7.5 });
19405 this.label[1].attr({ "font-weight": 800 });
19408 pfout = function() {
19409 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19412 this.label[0].animate({ r: 5 }, 500, "bounce");
19413 this.label[1].attr({ "font-weight": 400 });
19419 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19422 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19425 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19426 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19428 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19435 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19440 setTitle: function(o)
19445 initEvents: function() {
19448 this.el.on('click', this.onClick, this);
19452 onClick : function(e)
19454 Roo.log('img onclick');
19455 this.fireEvent('click', this, e);
19467 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19470 * @class Roo.bootstrap.dash.NumberBox
19471 * @extends Roo.bootstrap.Component
19472 * Bootstrap NumberBox class
19473 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19474 * @cfg {String} headline Box headline
19475 * @cfg {String} content Box content
19476 * @cfg {String} icon Box icon
19477 * @cfg {String} footer Footer text
19478 * @cfg {String} fhref Footer href
19481 * Create a new NumberBox
19482 * @param {Object} config The config object
19486 Roo.bootstrap.dash.NumberBox = function(config){
19487 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19491 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19501 getAutoCreate : function(){
19505 cls : 'small-box bg-' + this.bgcolor,
19513 cls : 'roo-headline',
19514 html : this.headline
19518 cls : 'roo-content',
19519 html : this.content
19533 cls : 'ion ' + this.icon
19542 cls : 'small-box-footer',
19543 href : this.fhref || '#',
19547 cfg.cn.push(footer);
19554 onRender : function(ct,position){
19555 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19562 setHeadline: function (value)
19564 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19567 setFooter: function (value, href)
19569 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19572 this.el.select('a.small-box-footer',true).first().attr('href', href);
19577 setContent: function (value)
19579 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19582 initEvents: function()
19596 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19599 * @class Roo.bootstrap.dash.TabBox
19600 * @extends Roo.bootstrap.Component
19601 * Bootstrap TabBox class
19602 * @cfg {String} title Title of the TabBox
19603 * @cfg {String} icon Icon of the TabBox
19604 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19607 * Create a new TabBox
19608 * @param {Object} config The config object
19612 Roo.bootstrap.dash.TabBox = function(config){
19613 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19618 * When a pane is added
19619 * @param {Roo.bootstrap.dash.TabPane} pane
19626 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19632 getChildContainer : function()
19634 return this.el.select('.tab-content', true).first();
19637 getAutoCreate : function(){
19641 cls: 'pull-left header',
19649 cls: 'fa ' + this.icon
19656 cls: 'nav-tabs-custom',
19660 cls: 'nav nav-tabs pull-right',
19667 cls: 'tab-content no-padding',
19675 initEvents : function()
19677 //Roo.log('add add pane handler');
19678 this.on('addpane', this.onAddPane, this);
19681 * Updates the box title
19682 * @param {String} html to set the title to.
19684 setTitle : function(value)
19686 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19688 onAddPane : function(pane)
19690 //Roo.log('addpane');
19692 // tabs are rendere left to right..
19693 if(!this.showtabs){
19697 var ctr = this.el.select('.nav-tabs', true).first();
19700 var existing = ctr.select('.nav-tab',true);
19701 var qty = existing.getCount();;
19704 var tab = ctr.createChild({
19706 cls : 'nav-tab' + (qty ? '' : ' active'),
19714 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19717 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19719 pane.el.addClass('active');
19724 onTabClick : function(ev,un,ob,pane)
19726 //Roo.log('tab - prev default');
19727 ev.preventDefault();
19730 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19731 pane.tab.addClass('active');
19732 //Roo.log(pane.title);
19733 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19734 // technically we should have a deactivate event.. but maybe add later.
19735 // and it should not de-activate the selected tab...
19737 pane.el.addClass('active');
19738 pane.fireEvent('activate');
19753 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19755 * @class Roo.bootstrap.TabPane
19756 * @extends Roo.bootstrap.Component
19757 * Bootstrap TabPane class
19758 * @cfg {Boolean} active (false | true) Default false
19759 * @cfg {String} title title of panel
19763 * Create a new TabPane
19764 * @param {Object} config The config object
19767 Roo.bootstrap.dash.TabPane = function(config){
19768 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19772 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19777 // the tabBox that this is attached to.
19780 getAutoCreate : function()
19788 cfg.cls += ' active';
19793 initEvents : function()
19795 //Roo.log('trigger add pane handler');
19796 this.parent().fireEvent('addpane', this)
19800 * Updates the tab title
19801 * @param {String} html to set the title to.
19803 setTitle: function(str)
19809 this.tab.select('a', true).first().dom.innerHTML = str;
19826 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19829 * @class Roo.bootstrap.menu.Menu
19830 * @extends Roo.bootstrap.Component
19831 * Bootstrap Menu class - container for Menu
19832 * @cfg {String} html Text of the menu
19833 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19834 * @cfg {String} icon Font awesome icon
19835 * @cfg {String} pos Menu align to (top | bottom) default bottom
19839 * Create a new Menu
19840 * @param {Object} config The config object
19844 Roo.bootstrap.menu.Menu = function(config){
19845 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19849 * @event beforeshow
19850 * Fires before this menu is displayed
19851 * @param {Roo.bootstrap.menu.Menu} this
19855 * @event beforehide
19856 * Fires before this menu is hidden
19857 * @param {Roo.bootstrap.menu.Menu} this
19862 * Fires after this menu is displayed
19863 * @param {Roo.bootstrap.menu.Menu} this
19868 * Fires after this menu is hidden
19869 * @param {Roo.bootstrap.menu.Menu} this
19874 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19875 * @param {Roo.bootstrap.menu.Menu} this
19876 * @param {Roo.EventObject} e
19883 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19887 weight : 'default',
19892 getChildContainer : function() {
19893 if(this.isSubMenu){
19897 return this.el.select('ul.dropdown-menu', true).first();
19900 getAutoCreate : function()
19905 cls : 'roo-menu-text',
19913 cls : 'fa ' + this.icon
19924 cls : 'dropdown-button btn btn-' + this.weight,
19929 cls : 'dropdown-toggle btn btn-' + this.weight,
19939 cls : 'dropdown-menu'
19945 if(this.pos == 'top'){
19946 cfg.cls += ' dropup';
19949 if(this.isSubMenu){
19952 cls : 'dropdown-menu'
19959 onRender : function(ct, position)
19961 this.isSubMenu = ct.hasClass('dropdown-submenu');
19963 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19966 initEvents : function()
19968 if(this.isSubMenu){
19972 this.hidden = true;
19974 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19975 this.triggerEl.on('click', this.onTriggerPress, this);
19977 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19978 this.buttonEl.on('click', this.onClick, this);
19984 if(this.isSubMenu){
19988 return this.el.select('ul.dropdown-menu', true).first();
19991 onClick : function(e)
19993 this.fireEvent("click", this, e);
19996 onTriggerPress : function(e)
19998 if (this.isVisible()) {
20005 isVisible : function(){
20006 return !this.hidden;
20011 this.fireEvent("beforeshow", this);
20013 this.hidden = false;
20014 this.el.addClass('open');
20016 Roo.get(document).on("mouseup", this.onMouseUp, this);
20018 this.fireEvent("show", this);
20025 this.fireEvent("beforehide", this);
20027 this.hidden = true;
20028 this.el.removeClass('open');
20030 Roo.get(document).un("mouseup", this.onMouseUp);
20032 this.fireEvent("hide", this);
20035 onMouseUp : function()
20049 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20052 * @class Roo.bootstrap.menu.Item
20053 * @extends Roo.bootstrap.Component
20054 * Bootstrap MenuItem class
20055 * @cfg {Boolean} submenu (true | false) default false
20056 * @cfg {String} html text of the item
20057 * @cfg {String} href the link
20058 * @cfg {Boolean} disable (true | false) default false
20059 * @cfg {Boolean} preventDefault (true | false) default true
20060 * @cfg {String} icon Font awesome icon
20061 * @cfg {String} pos Submenu align to (left | right) default right
20065 * Create a new Item
20066 * @param {Object} config The config object
20070 Roo.bootstrap.menu.Item = function(config){
20071 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20075 * Fires when the mouse is hovering over this menu
20076 * @param {Roo.bootstrap.menu.Item} this
20077 * @param {Roo.EventObject} e
20082 * Fires when the mouse exits this menu
20083 * @param {Roo.bootstrap.menu.Item} this
20084 * @param {Roo.EventObject} e
20090 * The raw click event for the entire grid.
20091 * @param {Roo.EventObject} e
20097 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20102 preventDefault: true,
20107 getAutoCreate : function()
20112 cls : 'roo-menu-item-text',
20120 cls : 'fa ' + this.icon
20129 href : this.href || '#',
20136 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20140 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20142 if(this.pos == 'left'){
20143 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20150 initEvents : function()
20152 this.el.on('mouseover', this.onMouseOver, this);
20153 this.el.on('mouseout', this.onMouseOut, this);
20155 this.el.select('a', true).first().on('click', this.onClick, this);
20159 onClick : function(e)
20161 if(this.preventDefault){
20162 e.preventDefault();
20165 this.fireEvent("click", this, e);
20168 onMouseOver : function(e)
20170 if(this.submenu && this.pos == 'left'){
20171 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20174 this.fireEvent("mouseover", this, e);
20177 onMouseOut : function(e)
20179 this.fireEvent("mouseout", this, e);
20191 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20194 * @class Roo.bootstrap.menu.Separator
20195 * @extends Roo.bootstrap.Component
20196 * Bootstrap Separator class
20199 * Create a new Separator
20200 * @param {Object} config The config object
20204 Roo.bootstrap.menu.Separator = function(config){
20205 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20208 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20210 getAutoCreate : function(){