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){
11521 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11522 this.list.setWidth(lw);
11529 this.restrictHeight();
11533 this.tickItems = Roo.apply([], this.item);
11536 this.cancelBtn.show();
11537 this.trigger.hide();
11541 Roo.get(document).on('mousedown', this.collapseIf, this);
11542 Roo.get(document).on('mousewheel', this.collapseIf, this);
11543 if (!this.editable) {
11544 Roo.get(document).on('keydown', this.listKeyPress, this);
11547 this.fireEvent('expand', this);
11551 // Implements the default empty TriggerField.onTriggerClick function
11552 onTriggerClick : function(e)
11554 Roo.log('trigger click');
11556 if(this.disabled || !this.triggerList){
11561 this.loadNext = false;
11563 if(this.isExpanded()){
11565 if (!this.blockFocus) {
11566 this.inputEl().focus();
11570 this.hasFocus = true;
11571 if(this.triggerAction == 'all') {
11572 this.doQuery(this.allQuery, true);
11574 this.doQuery(this.getRawValue());
11576 if (!this.blockFocus) {
11577 this.inputEl().focus();
11582 onTickableTriggerClick : function(e)
11589 this.loadNext = false;
11590 this.hasFocus = true;
11592 if(this.triggerAction == 'all') {
11593 this.doQuery(this.allQuery, true);
11595 this.doQuery(this.getRawValue());
11599 onSearchFieldClick : function(e)
11601 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11606 this.loadNext = false;
11607 this.hasFocus = true;
11609 if(this.triggerAction == 'all') {
11610 this.doQuery(this.allQuery, true);
11612 this.doQuery(this.getRawValue());
11616 listKeyPress : function(e)
11618 //Roo.log('listkeypress');
11619 // scroll to first matching element based on key pres..
11620 if (e.isSpecialKey()) {
11623 var k = String.fromCharCode(e.getKey()).toUpperCase();
11626 var csel = this.view.getSelectedNodes();
11627 var cselitem = false;
11629 var ix = this.view.indexOf(csel[0]);
11630 cselitem = this.store.getAt(ix);
11631 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11637 this.store.each(function(v) {
11639 // start at existing selection.
11640 if (cselitem.id == v.id) {
11646 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11647 match = this.store.indexOf(v);
11653 if (match === false) {
11654 return true; // no more action?
11657 this.view.select(match);
11658 var sn = Roo.get(this.view.getSelectedNodes()[0])
11659 //sn.scrollIntoView(sn.dom.parentNode, false);
11662 onViewScroll : function(e, t){
11664 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11668 this.hasQuery = true;
11670 this.loading = this.list.select('.loading', true).first();
11672 if(this.loading === null){
11673 this.list.createChild({
11675 cls: 'loading select2-more-results select2-active',
11676 html: 'Loading more results...'
11679 this.loading = this.list.select('.loading', true).first();
11681 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11683 this.loading.hide();
11686 this.loading.show();
11691 this.loadNext = true;
11693 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11698 addItem : function(o)
11700 var dv = ''; // display value
11702 if (this.displayField) {
11703 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11705 // this is an error condition!!!
11706 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11713 var choice = this.choices.createChild({
11715 cls: 'select2-search-choice',
11724 cls: 'select2-search-choice-close',
11729 }, this.searchField);
11731 var close = choice.select('a.select2-search-choice-close', true).first()
11733 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11741 this.inputEl().dom.value = '';
11745 onRemoveItem : function(e, _self, o)
11747 e.preventDefault();
11748 var index = this.item.indexOf(o.data) * 1;
11751 Roo.log('not this item?!');
11755 this.item.splice(index, 1);
11760 this.fireEvent('remove', this, e);
11764 syncValue : function()
11766 if(!this.item.length){
11773 Roo.each(this.item, function(i){
11774 if(_this.valueField){
11775 value.push(i[_this.valueField]);
11782 this.value = value.join(',');
11784 if(this.hiddenField){
11785 this.hiddenField.dom.value = this.value;
11789 clearItem : function()
11791 if(!this.multiple){
11797 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11804 inputEl: function ()
11807 return this.searchField;
11809 return this.el.select('input.form-control',true).first();
11813 onTickableFooterButtonClick : function(e, btn, el)
11815 e.preventDefault();
11817 if(btn && btn.name == 'cancel'){
11818 this.tickItems = Roo.apply([], this.item);
11827 Roo.each(this.tickItems, function(o){
11838 * @cfg {Boolean} grow
11842 * @cfg {Number} growMin
11846 * @cfg {Number} growMax
11856 * Ext JS Library 1.1.1
11857 * Copyright(c) 2006-2007, Ext JS, LLC.
11859 * Originally Released Under LGPL - original licence link has changed is not relivant.
11862 * <script type="text/javascript">
11867 * @extends Roo.util.Observable
11868 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11869 * This class also supports single and multi selection modes. <br>
11870 * Create a data model bound view:
11872 var store = new Roo.data.Store(...);
11874 var view = new Roo.View({
11876 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11878 singleSelect: true,
11879 selectedClass: "ydataview-selected",
11883 // listen for node click?
11884 view.on("click", function(vw, index, node, e){
11885 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11889 dataModel.load("foobar.xml");
11891 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11893 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11894 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11896 * Note: old style constructor is still suported (container, template, config)
11899 * Create a new View
11900 * @param {Object} config The config object
11903 Roo.View = function(config, depreciated_tpl, depreciated_config){
11905 this.parent = false;
11907 if (typeof(depreciated_tpl) == 'undefined') {
11908 // new way.. - universal constructor.
11909 Roo.apply(this, config);
11910 this.el = Roo.get(this.el);
11913 this.el = Roo.get(config);
11914 this.tpl = depreciated_tpl;
11915 Roo.apply(this, depreciated_config);
11917 this.wrapEl = this.el.wrap().wrap();
11918 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11921 if(typeof(this.tpl) == "string"){
11922 this.tpl = new Roo.Template(this.tpl);
11924 // support xtype ctors..
11925 this.tpl = new Roo.factory(this.tpl, Roo);
11929 this.tpl.compile();
11934 * @event beforeclick
11935 * Fires before a click is processed. Returns false to cancel the default action.
11936 * @param {Roo.View} this
11937 * @param {Number} index The index of the target node
11938 * @param {HTMLElement} node The target node
11939 * @param {Roo.EventObject} e The raw event object
11941 "beforeclick" : true,
11944 * Fires when a template node is clicked.
11945 * @param {Roo.View} this
11946 * @param {Number} index The index of the target node
11947 * @param {HTMLElement} node The target node
11948 * @param {Roo.EventObject} e The raw event object
11953 * Fires when a template node is double clicked.
11954 * @param {Roo.View} this
11955 * @param {Number} index The index of the target node
11956 * @param {HTMLElement} node The target node
11957 * @param {Roo.EventObject} e The raw event object
11961 * @event contextmenu
11962 * Fires when a template node is right clicked.
11963 * @param {Roo.View} this
11964 * @param {Number} index The index of the target node
11965 * @param {HTMLElement} node The target node
11966 * @param {Roo.EventObject} e The raw event object
11968 "contextmenu" : true,
11970 * @event selectionchange
11971 * Fires when the selected nodes change.
11972 * @param {Roo.View} this
11973 * @param {Array} selections Array of the selected nodes
11975 "selectionchange" : true,
11978 * @event beforeselect
11979 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11980 * @param {Roo.View} this
11981 * @param {HTMLElement} node The node to be selected
11982 * @param {Array} selections Array of currently selected nodes
11984 "beforeselect" : true,
11986 * @event preparedata
11987 * Fires on every row to render, to allow you to change the data.
11988 * @param {Roo.View} this
11989 * @param {Object} data to be rendered (change this)
11991 "preparedata" : true
11999 "click": this.onClick,
12000 "dblclick": this.onDblClick,
12001 "contextmenu": this.onContextMenu,
12005 this.selections = [];
12007 this.cmp = new Roo.CompositeElementLite([]);
12009 this.store = Roo.factory(this.store, Roo.data);
12010 this.setStore(this.store, true);
12013 if ( this.footer && this.footer.xtype) {
12015 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12017 this.footer.dataSource = this.store
12018 this.footer.container = fctr;
12019 this.footer = Roo.factory(this.footer, Roo);
12020 fctr.insertFirst(this.el);
12022 // this is a bit insane - as the paging toolbar seems to detach the el..
12023 // dom.parentNode.parentNode.parentNode
12024 // they get detached?
12028 Roo.View.superclass.constructor.call(this);
12033 Roo.extend(Roo.View, Roo.util.Observable, {
12036 * @cfg {Roo.data.Store} store Data store to load data from.
12041 * @cfg {String|Roo.Element} el The container element.
12046 * @cfg {String|Roo.Template} tpl The template used by this View
12050 * @cfg {String} dataName the named area of the template to use as the data area
12051 * Works with domtemplates roo-name="name"
12055 * @cfg {String} selectedClass The css class to add to selected nodes
12057 selectedClass : "x-view-selected",
12059 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12064 * @cfg {String} text to display on mask (default Loading)
12068 * @cfg {Boolean} multiSelect Allow multiple selection
12070 multiSelect : false,
12072 * @cfg {Boolean} singleSelect Allow single selection
12074 singleSelect: false,
12077 * @cfg {Boolean} toggleSelect - selecting
12079 toggleSelect : false,
12082 * @cfg {Boolean} tickable - selecting
12087 * Returns the element this view is bound to.
12088 * @return {Roo.Element}
12090 getEl : function(){
12091 return this.wrapEl;
12097 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12099 refresh : function(){
12100 Roo.log('refresh');
12103 // if we are using something like 'domtemplate', then
12104 // the what gets used is:
12105 // t.applySubtemplate(NAME, data, wrapping data..)
12106 // the outer template then get' applied with
12107 // the store 'extra data'
12108 // and the body get's added to the
12109 // roo-name="data" node?
12110 // <span class='roo-tpl-{name}'></span> ?????
12114 this.clearSelections();
12115 this.el.update("");
12117 var records = this.store.getRange();
12118 if(records.length < 1) {
12120 // is this valid?? = should it render a template??
12122 this.el.update(this.emptyText);
12126 if (this.dataName) {
12127 this.el.update(t.apply(this.store.meta)); //????
12128 el = this.el.child('.roo-tpl-' + this.dataName);
12131 for(var i = 0, len = records.length; i < len; i++){
12132 var data = this.prepareData(records[i].data, i, records[i]);
12133 this.fireEvent("preparedata", this, data, i, records[i]);
12135 var d = Roo.apply({}, data);
12138 Roo.apply(d, {'roo-id' : Roo.id()});
12142 Roo.each(this.parent.item, function(item){
12143 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12146 Roo.apply(d, {'roo-data-checked' : 'checked'});
12150 html[html.length] = Roo.util.Format.trim(
12152 t.applySubtemplate(this.dataName, d, this.store.meta) :
12159 el.update(html.join(""));
12160 this.nodes = el.dom.childNodes;
12161 this.updateIndexes(0);
12166 * Function to override to reformat the data that is sent to
12167 * the template for each node.
12168 * DEPRICATED - use the preparedata event handler.
12169 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12170 * a JSON object for an UpdateManager bound view).
12172 prepareData : function(data, index, record)
12174 this.fireEvent("preparedata", this, data, index, record);
12178 onUpdate : function(ds, record){
12179 Roo.log('on update');
12180 this.clearSelections();
12181 var index = this.store.indexOf(record);
12182 var n = this.nodes[index];
12183 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12184 n.parentNode.removeChild(n);
12185 this.updateIndexes(index, index);
12191 onAdd : function(ds, records, index)
12193 Roo.log(['on Add', ds, records, index] );
12194 this.clearSelections();
12195 if(this.nodes.length == 0){
12199 var n = this.nodes[index];
12200 for(var i = 0, len = records.length; i < len; i++){
12201 var d = this.prepareData(records[i].data, i, records[i]);
12203 this.tpl.insertBefore(n, d);
12206 this.tpl.append(this.el, d);
12209 this.updateIndexes(index);
12212 onRemove : function(ds, record, index){
12213 Roo.log('onRemove');
12214 this.clearSelections();
12215 var el = this.dataName ?
12216 this.el.child('.roo-tpl-' + this.dataName) :
12219 el.dom.removeChild(this.nodes[index]);
12220 this.updateIndexes(index);
12224 * Refresh an individual node.
12225 * @param {Number} index
12227 refreshNode : function(index){
12228 this.onUpdate(this.store, this.store.getAt(index));
12231 updateIndexes : function(startIndex, endIndex){
12232 var ns = this.nodes;
12233 startIndex = startIndex || 0;
12234 endIndex = endIndex || ns.length - 1;
12235 for(var i = startIndex; i <= endIndex; i++){
12236 ns[i].nodeIndex = i;
12241 * Changes the data store this view uses and refresh the view.
12242 * @param {Store} store
12244 setStore : function(store, initial){
12245 if(!initial && this.store){
12246 this.store.un("datachanged", this.refresh);
12247 this.store.un("add", this.onAdd);
12248 this.store.un("remove", this.onRemove);
12249 this.store.un("update", this.onUpdate);
12250 this.store.un("clear", this.refresh);
12251 this.store.un("beforeload", this.onBeforeLoad);
12252 this.store.un("load", this.onLoad);
12253 this.store.un("loadexception", this.onLoad);
12257 store.on("datachanged", this.refresh, this);
12258 store.on("add", this.onAdd, this);
12259 store.on("remove", this.onRemove, this);
12260 store.on("update", this.onUpdate, this);
12261 store.on("clear", this.refresh, this);
12262 store.on("beforeload", this.onBeforeLoad, this);
12263 store.on("load", this.onLoad, this);
12264 store.on("loadexception", this.onLoad, this);
12272 * onbeforeLoad - masks the loading area.
12275 onBeforeLoad : function(store,opts)
12277 Roo.log('onBeforeLoad');
12279 this.el.update("");
12281 this.el.mask(this.mask ? this.mask : "Loading" );
12283 onLoad : function ()
12290 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12291 * @param {HTMLElement} node
12292 * @return {HTMLElement} The template node
12294 findItemFromChild : function(node){
12295 var el = this.dataName ?
12296 this.el.child('.roo-tpl-' + this.dataName,true) :
12299 if(!node || node.parentNode == el){
12302 var p = node.parentNode;
12303 while(p && p != el){
12304 if(p.parentNode == el){
12313 onClick : function(e){
12314 var item = this.findItemFromChild(e.getTarget());
12316 var index = this.indexOf(item);
12317 if(this.onItemClick(item, index, e) !== false){
12318 this.fireEvent("click", this, index, item, e);
12321 this.clearSelections();
12326 onContextMenu : function(e){
12327 var item = this.findItemFromChild(e.getTarget());
12329 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12334 onDblClick : function(e){
12335 var item = this.findItemFromChild(e.getTarget());
12337 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12341 onItemClick : function(item, index, e)
12343 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12346 if (this.toggleSelect) {
12347 var m = this.isSelected(item) ? 'unselect' : 'select';
12350 _t[m](item, true, false);
12353 if(this.multiSelect || this.singleSelect){
12354 if(this.multiSelect && e.shiftKey && this.lastSelection){
12355 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12357 this.select(item, this.multiSelect && e.ctrlKey);
12358 this.lastSelection = item;
12361 if(!this.tickable){
12362 e.preventDefault();
12370 * Get the number of selected nodes.
12373 getSelectionCount : function(){
12374 return this.selections.length;
12378 * Get the currently selected nodes.
12379 * @return {Array} An array of HTMLElements
12381 getSelectedNodes : function(){
12382 return this.selections;
12386 * Get the indexes of the selected nodes.
12389 getSelectedIndexes : function(){
12390 var indexes = [], s = this.selections;
12391 for(var i = 0, len = s.length; i < len; i++){
12392 indexes.push(s[i].nodeIndex);
12398 * Clear all selections
12399 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12401 clearSelections : function(suppressEvent){
12402 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12403 this.cmp.elements = this.selections;
12404 this.cmp.removeClass(this.selectedClass);
12405 this.selections = [];
12406 if(!suppressEvent){
12407 this.fireEvent("selectionchange", this, this.selections);
12413 * Returns true if the passed node is selected
12414 * @param {HTMLElement/Number} node The node or node index
12415 * @return {Boolean}
12417 isSelected : function(node){
12418 var s = this.selections;
12422 node = this.getNode(node);
12423 return s.indexOf(node) !== -1;
12428 * @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
12429 * @param {Boolean} keepExisting (optional) true to keep existing selections
12430 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12432 select : function(nodeInfo, keepExisting, suppressEvent){
12433 if(nodeInfo instanceof Array){
12435 this.clearSelections(true);
12437 for(var i = 0, len = nodeInfo.length; i < len; i++){
12438 this.select(nodeInfo[i], true, true);
12442 var node = this.getNode(nodeInfo);
12443 if(!node || this.isSelected(node)){
12444 return; // already selected.
12447 this.clearSelections(true);
12449 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12450 Roo.fly(node).addClass(this.selectedClass);
12451 this.selections.push(node);
12452 if(!suppressEvent){
12453 this.fireEvent("selectionchange", this, this.selections);
12461 * @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
12462 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12463 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12465 unselect : function(nodeInfo, keepExisting, suppressEvent)
12467 if(nodeInfo instanceof Array){
12468 Roo.each(this.selections, function(s) {
12469 this.unselect(s, nodeInfo);
12473 var node = this.getNode(nodeInfo);
12474 if(!node || !this.isSelected(node)){
12475 Roo.log("not selected");
12476 return; // not selected.
12480 Roo.each(this.selections, function(s) {
12482 Roo.fly(node).removeClass(this.selectedClass);
12489 this.selections= ns;
12490 this.fireEvent("selectionchange", this, this.selections);
12494 * Gets a template node.
12495 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12496 * @return {HTMLElement} The node or null if it wasn't found
12498 getNode : function(nodeInfo){
12499 if(typeof nodeInfo == "string"){
12500 return document.getElementById(nodeInfo);
12501 }else if(typeof nodeInfo == "number"){
12502 return this.nodes[nodeInfo];
12508 * Gets a range template nodes.
12509 * @param {Number} startIndex
12510 * @param {Number} endIndex
12511 * @return {Array} An array of nodes
12513 getNodes : function(start, end){
12514 var ns = this.nodes;
12515 start = start || 0;
12516 end = typeof end == "undefined" ? ns.length - 1 : end;
12519 for(var i = start; i <= end; i++){
12523 for(var i = start; i >= end; i--){
12531 * Finds the index of the passed node
12532 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12533 * @return {Number} The index of the node or -1
12535 indexOf : function(node){
12536 node = this.getNode(node);
12537 if(typeof node.nodeIndex == "number"){
12538 return node.nodeIndex;
12540 var ns = this.nodes;
12541 for(var i = 0, len = ns.length; i < len; i++){
12552 * based on jquery fullcalendar
12556 Roo.bootstrap = Roo.bootstrap || {};
12558 * @class Roo.bootstrap.Calendar
12559 * @extends Roo.bootstrap.Component
12560 * Bootstrap Calendar class
12561 * @cfg {Boolean} loadMask (true|false) default false
12562 * @cfg {Object} header generate the user specific header of the calendar, default false
12565 * Create a new Container
12566 * @param {Object} config The config object
12571 Roo.bootstrap.Calendar = function(config){
12572 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12576 * Fires when a date is selected
12577 * @param {DatePicker} this
12578 * @param {Date} date The selected date
12582 * @event monthchange
12583 * Fires when the displayed month changes
12584 * @param {DatePicker} this
12585 * @param {Date} date The selected month
12587 'monthchange': true,
12589 * @event evententer
12590 * Fires when mouse over an event
12591 * @param {Calendar} this
12592 * @param {event} Event
12594 'evententer': true,
12596 * @event eventleave
12597 * Fires when the mouse leaves an
12598 * @param {Calendar} this
12601 'eventleave': true,
12603 * @event eventclick
12604 * Fires when the mouse click an
12605 * @param {Calendar} this
12614 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12617 * @cfg {Number} startDay
12618 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12626 getAutoCreate : function(){
12629 var fc_button = function(name, corner, style, content ) {
12630 return Roo.apply({},{
12632 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12634 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12637 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12648 style : 'width:100%',
12655 cls : 'fc-header-left',
12657 fc_button('prev', 'left', 'arrow', '‹' ),
12658 fc_button('next', 'right', 'arrow', '›' ),
12659 { tag: 'span', cls: 'fc-header-space' },
12660 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12668 cls : 'fc-header-center',
12672 cls: 'fc-header-title',
12675 html : 'month / year'
12683 cls : 'fc-header-right',
12685 /* fc_button('month', 'left', '', 'month' ),
12686 fc_button('week', '', '', 'week' ),
12687 fc_button('day', 'right', '', 'day' )
12699 header = this.header;
12702 var cal_heads = function() {
12704 // fixme - handle this.
12706 for (var i =0; i < Date.dayNames.length; i++) {
12707 var d = Date.dayNames[i];
12710 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12711 html : d.substring(0,3)
12715 ret[0].cls += ' fc-first';
12716 ret[6].cls += ' fc-last';
12719 var cal_cell = function(n) {
12722 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12727 cls: 'fc-day-number',
12731 cls: 'fc-day-content',
12735 style: 'position: relative;' // height: 17px;
12747 var cal_rows = function() {
12750 for (var r = 0; r < 6; r++) {
12757 for (var i =0; i < Date.dayNames.length; i++) {
12758 var d = Date.dayNames[i];
12759 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12762 row.cn[0].cls+=' fc-first';
12763 row.cn[0].cn[0].style = 'min-height:90px';
12764 row.cn[6].cls+=' fc-last';
12768 ret[0].cls += ' fc-first';
12769 ret[4].cls += ' fc-prev-last';
12770 ret[5].cls += ' fc-last';
12777 cls: 'fc-border-separate',
12778 style : 'width:100%',
12786 cls : 'fc-first fc-last',
12804 cls : 'fc-content',
12805 style : "position: relative;",
12808 cls : 'fc-view fc-view-month fc-grid',
12809 style : 'position: relative',
12810 unselectable : 'on',
12813 cls : 'fc-event-container',
12814 style : 'position:absolute;z-index:8;top:0;left:0;'
12832 initEvents : function()
12835 throw "can not find store for calendar";
12841 style: "text-align:center",
12845 style: "background-color:white;width:50%;margin:250 auto",
12849 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12860 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12862 var size = this.el.select('.fc-content', true).first().getSize();
12863 this.maskEl.setSize(size.width, size.height);
12864 this.maskEl.enableDisplayMode("block");
12865 if(!this.loadMask){
12866 this.maskEl.hide();
12869 this.store = Roo.factory(this.store, Roo.data);
12870 this.store.on('load', this.onLoad, this);
12871 this.store.on('beforeload', this.onBeforeLoad, this);
12875 this.cells = this.el.select('.fc-day',true);
12876 //Roo.log(this.cells);
12877 this.textNodes = this.el.query('.fc-day-number');
12878 this.cells.addClassOnOver('fc-state-hover');
12880 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12881 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12882 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12883 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12885 this.on('monthchange', this.onMonthChange, this);
12887 this.update(new Date().clearTime());
12890 resize : function() {
12891 var sz = this.el.getSize();
12893 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12894 this.el.select('.fc-day-content div',true).setHeight(34);
12899 showPrevMonth : function(e){
12900 this.update(this.activeDate.add("mo", -1));
12902 showToday : function(e){
12903 this.update(new Date().clearTime());
12906 showNextMonth : function(e){
12907 this.update(this.activeDate.add("mo", 1));
12911 showPrevYear : function(){
12912 this.update(this.activeDate.add("y", -1));
12916 showNextYear : function(){
12917 this.update(this.activeDate.add("y", 1));
12922 update : function(date)
12924 var vd = this.activeDate;
12925 this.activeDate = date;
12926 // if(vd && this.el){
12927 // var t = date.getTime();
12928 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12929 // Roo.log('using add remove');
12931 // this.fireEvent('monthchange', this, date);
12933 // this.cells.removeClass("fc-state-highlight");
12934 // this.cells.each(function(c){
12935 // if(c.dateValue == t){
12936 // c.addClass("fc-state-highlight");
12937 // setTimeout(function(){
12938 // try{c.dom.firstChild.focus();}catch(e){}
12948 var days = date.getDaysInMonth();
12950 var firstOfMonth = date.getFirstDateOfMonth();
12951 var startingPos = firstOfMonth.getDay()-this.startDay;
12953 if(startingPos < this.startDay){
12957 var pm = date.add(Date.MONTH, -1);
12958 var prevStart = pm.getDaysInMonth()-startingPos;
12960 this.cells = this.el.select('.fc-day',true);
12961 this.textNodes = this.el.query('.fc-day-number');
12962 this.cells.addClassOnOver('fc-state-hover');
12964 var cells = this.cells.elements;
12965 var textEls = this.textNodes;
12967 Roo.each(cells, function(cell){
12968 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12971 days += startingPos;
12973 // convert everything to numbers so it's fast
12974 var day = 86400000;
12975 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12978 //Roo.log(prevStart);
12980 var today = new Date().clearTime().getTime();
12981 var sel = date.clearTime().getTime();
12982 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12983 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12984 var ddMatch = this.disabledDatesRE;
12985 var ddText = this.disabledDatesText;
12986 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12987 var ddaysText = this.disabledDaysText;
12988 var format = this.format;
12990 var setCellClass = function(cal, cell){
12994 //Roo.log('set Cell Class');
12996 var t = d.getTime();
13000 cell.dateValue = t;
13002 cell.className += " fc-today";
13003 cell.className += " fc-state-highlight";
13004 cell.title = cal.todayText;
13007 // disable highlight in other month..
13008 //cell.className += " fc-state-highlight";
13013 cell.className = " fc-state-disabled";
13014 cell.title = cal.minText;
13018 cell.className = " fc-state-disabled";
13019 cell.title = cal.maxText;
13023 if(ddays.indexOf(d.getDay()) != -1){
13024 cell.title = ddaysText;
13025 cell.className = " fc-state-disabled";
13028 if(ddMatch && format){
13029 var fvalue = d.dateFormat(format);
13030 if(ddMatch.test(fvalue)){
13031 cell.title = ddText.replace("%0", fvalue);
13032 cell.className = " fc-state-disabled";
13036 if (!cell.initialClassName) {
13037 cell.initialClassName = cell.dom.className;
13040 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13045 for(; i < startingPos; i++) {
13046 textEls[i].innerHTML = (++prevStart);
13047 d.setDate(d.getDate()+1);
13049 cells[i].className = "fc-past fc-other-month";
13050 setCellClass(this, cells[i]);
13055 for(; i < days; i++){
13056 intDay = i - startingPos + 1;
13057 textEls[i].innerHTML = (intDay);
13058 d.setDate(d.getDate()+1);
13060 cells[i].className = ''; // "x-date-active";
13061 setCellClass(this, cells[i]);
13065 for(; i < 42; i++) {
13066 textEls[i].innerHTML = (++extraDays);
13067 d.setDate(d.getDate()+1);
13069 cells[i].className = "fc-future fc-other-month";
13070 setCellClass(this, cells[i]);
13073 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13075 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13077 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13078 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13080 if(totalRows != 6){
13081 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13082 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13085 this.fireEvent('monthchange', this, date);
13089 if(!this.internalRender){
13090 var main = this.el.dom.firstChild;
13091 var w = main.offsetWidth;
13092 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13093 Roo.fly(main).setWidth(w);
13094 this.internalRender = true;
13095 // opera does not respect the auto grow header center column
13096 // then, after it gets a width opera refuses to recalculate
13097 // without a second pass
13098 if(Roo.isOpera && !this.secondPass){
13099 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13100 this.secondPass = true;
13101 this.update.defer(10, this, [date]);
13108 findCell : function(dt) {
13109 dt = dt.clearTime().getTime();
13111 this.cells.each(function(c){
13112 //Roo.log("check " +c.dateValue + '?=' + dt);
13113 if(c.dateValue == dt){
13123 findCells : function(ev) {
13124 var s = ev.start.clone().clearTime().getTime();
13126 var e= ev.end.clone().clearTime().getTime();
13129 this.cells.each(function(c){
13130 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13132 if(c.dateValue > e){
13135 if(c.dateValue < s){
13144 // findBestRow: function(cells)
13148 // for (var i =0 ; i < cells.length;i++) {
13149 // ret = Math.max(cells[i].rows || 0,ret);
13156 addItem : function(ev)
13158 // look for vertical location slot in
13159 var cells = this.findCells(ev);
13161 // ev.row = this.findBestRow(cells);
13163 // work out the location.
13167 for(var i =0; i < cells.length; i++) {
13169 cells[i].row = cells[0].row;
13172 cells[i].row = cells[i].row + 1;
13182 if (crow.start.getY() == cells[i].getY()) {
13184 crow.end = cells[i];
13201 cells[0].events.push(ev);
13203 this.calevents.push(ev);
13206 clearEvents: function() {
13208 if(!this.calevents){
13212 Roo.each(this.cells.elements, function(c){
13218 Roo.each(this.calevents, function(e) {
13219 Roo.each(e.els, function(el) {
13220 el.un('mouseenter' ,this.onEventEnter, this);
13221 el.un('mouseleave' ,this.onEventLeave, this);
13226 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13232 renderEvents: function()
13236 this.cells.each(function(c) {
13245 if(c.row != c.events.length){
13246 r = 4 - (4 - (c.row - c.events.length));
13249 c.events = ev.slice(0, r);
13250 c.more = ev.slice(r);
13252 if(c.more.length && c.more.length == 1){
13253 c.events.push(c.more.pop());
13256 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13260 this.cells.each(function(c) {
13262 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13265 for (var e = 0; e < c.events.length; e++){
13266 var ev = c.events[e];
13267 var rows = ev.rows;
13269 for(var i = 0; i < rows.length; i++) {
13271 // how many rows should it span..
13274 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13275 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13277 unselectable : "on",
13280 cls: 'fc-event-inner',
13284 // cls: 'fc-event-time',
13285 // html : cells.length > 1 ? '' : ev.time
13289 cls: 'fc-event-title',
13290 html : String.format('{0}', ev.title)
13297 cls: 'ui-resizable-handle ui-resizable-e',
13298 html : '  '
13305 cfg.cls += ' fc-event-start';
13307 if ((i+1) == rows.length) {
13308 cfg.cls += ' fc-event-end';
13311 var ctr = _this.el.select('.fc-event-container',true).first();
13312 var cg = ctr.createChild(cfg);
13314 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13315 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13317 var r = (c.more.length) ? 1 : 0;
13318 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13319 cg.setWidth(ebox.right - sbox.x -2);
13321 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13322 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13323 cg.on('click', _this.onEventClick, _this, ev);
13334 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13335 style : 'position: absolute',
13336 unselectable : "on",
13339 cls: 'fc-event-inner',
13343 cls: 'fc-event-title',
13351 cls: 'ui-resizable-handle ui-resizable-e',
13352 html : '  '
13358 var ctr = _this.el.select('.fc-event-container',true).first();
13359 var cg = ctr.createChild(cfg);
13361 var sbox = c.select('.fc-day-content',true).first().getBox();
13362 var ebox = c.select('.fc-day-content',true).first().getBox();
13364 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13365 cg.setWidth(ebox.right - sbox.x -2);
13367 cg.on('click', _this.onMoreEventClick, _this, c.more);
13377 onEventEnter: function (e, el,event,d) {
13378 this.fireEvent('evententer', this, el, event);
13381 onEventLeave: function (e, el,event,d) {
13382 this.fireEvent('eventleave', this, el, event);
13385 onEventClick: function (e, el,event,d) {
13386 this.fireEvent('eventclick', this, el, event);
13389 onMonthChange: function () {
13393 onMoreEventClick: function(e, el, more)
13397 this.calpopover.placement = 'right';
13398 this.calpopover.setTitle('More');
13400 this.calpopover.setContent('');
13402 var ctr = this.calpopover.el.select('.popover-content', true).first();
13404 Roo.each(more, function(m){
13406 cls : 'fc-event-hori fc-event-draggable',
13409 var cg = ctr.createChild(cfg);
13411 cg.on('click', _this.onEventClick, _this, m);
13414 this.calpopover.show(el);
13419 onLoad: function ()
13421 this.calevents = [];
13424 if(this.store.getCount() > 0){
13425 this.store.data.each(function(d){
13428 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13429 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13430 time : d.data.start_time,
13431 title : d.data.title,
13432 description : d.data.description,
13433 venue : d.data.venue
13438 this.renderEvents();
13440 if(this.calevents.length && this.loadMask){
13441 this.maskEl.hide();
13445 onBeforeLoad: function()
13447 this.clearEvents();
13449 this.maskEl.show();
13463 * @class Roo.bootstrap.Popover
13464 * @extends Roo.bootstrap.Component
13465 * Bootstrap Popover class
13466 * @cfg {String} html contents of the popover (or false to use children..)
13467 * @cfg {String} title of popover (or false to hide)
13468 * @cfg {String} placement how it is placed
13469 * @cfg {String} trigger click || hover (or false to trigger manually)
13470 * @cfg {String} over what (parent or false to trigger manually.)
13473 * Create a new Popover
13474 * @param {Object} config The config object
13477 Roo.bootstrap.Popover = function(config){
13478 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13481 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13483 title: 'Fill in a title',
13486 placement : 'right',
13487 trigger : 'hover', // hover
13491 can_build_overlaid : false,
13493 getChildContainer : function()
13495 return this.el.select('.popover-content',true).first();
13498 getAutoCreate : function(){
13499 Roo.log('make popover?');
13501 cls : 'popover roo-dynamic',
13502 style: 'display:block',
13508 cls : 'popover-inner',
13512 cls: 'popover-title',
13516 cls : 'popover-content',
13527 setTitle: function(str)
13529 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13531 setContent: function(str)
13533 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13535 // as it get's added to the bottom of the page.
13536 onRender : function(ct, position)
13538 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13540 var cfg = Roo.apply({}, this.getAutoCreate());
13544 cfg.cls += ' ' + this.cls;
13547 cfg.style = this.style;
13549 Roo.log("adding to ")
13550 this.el = Roo.get(document.body).createChild(cfg, position);
13556 initEvents : function()
13558 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13559 this.el.enableDisplayMode('block');
13561 if (this.over === false) {
13564 if (this.triggers === false) {
13567 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13568 var triggers = this.trigger ? this.trigger.split(' ') : [];
13569 Roo.each(triggers, function(trigger) {
13571 if (trigger == 'click') {
13572 on_el.on('click', this.toggle, this);
13573 } else if (trigger != 'manual') {
13574 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13575 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13577 on_el.on(eventIn ,this.enter, this);
13578 on_el.on(eventOut, this.leave, this);
13589 toggle : function () {
13590 this.hoverState == 'in' ? this.leave() : this.enter();
13593 enter : function () {
13596 clearTimeout(this.timeout);
13598 this.hoverState = 'in'
13600 if (!this.delay || !this.delay.show) {
13605 this.timeout = setTimeout(function () {
13606 if (_t.hoverState == 'in') {
13609 }, this.delay.show)
13611 leave : function() {
13612 clearTimeout(this.timeout);
13614 this.hoverState = 'out'
13616 if (!this.delay || !this.delay.hide) {
13621 this.timeout = setTimeout(function () {
13622 if (_t.hoverState == 'out') {
13625 }, this.delay.hide)
13628 show : function (on_el)
13631 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13634 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13635 if (this.html !== false) {
13636 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13638 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13639 if (!this.title.length) {
13640 this.el.select('.popover-title',true).hide();
13643 var placement = typeof this.placement == 'function' ?
13644 this.placement.call(this, this.el, on_el) :
13647 var autoToken = /\s?auto?\s?/i;
13648 var autoPlace = autoToken.test(placement);
13650 placement = placement.replace(autoToken, '') || 'top';
13654 //this.el.setXY([0,0]);
13656 this.el.dom.style.display='block';
13657 this.el.addClass(placement);
13659 //this.el.appendTo(on_el);
13661 var p = this.getPosition();
13662 var box = this.el.getBox();
13667 var align = Roo.bootstrap.Popover.alignment[placement]
13668 this.el.alignTo(on_el, align[0],align[1]);
13669 //var arrow = this.el.select('.arrow',true).first();
13670 //arrow.set(align[2],
13672 this.el.addClass('in');
13673 this.hoverState = null;
13675 if (this.el.hasClass('fade')) {
13682 this.el.setXY([0,0]);
13683 this.el.removeClass('in');
13690 Roo.bootstrap.Popover.alignment = {
13691 'left' : ['r-l', [-10,0], 'right'],
13692 'right' : ['l-r', [10,0], 'left'],
13693 'bottom' : ['t-b', [0,10], 'top'],
13694 'top' : [ 'b-t', [0,-10], 'bottom']
13705 * @class Roo.bootstrap.Progress
13706 * @extends Roo.bootstrap.Component
13707 * Bootstrap Progress class
13708 * @cfg {Boolean} striped striped of the progress bar
13709 * @cfg {Boolean} active animated of the progress bar
13713 * Create a new Progress
13714 * @param {Object} config The config object
13717 Roo.bootstrap.Progress = function(config){
13718 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13721 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13726 getAutoCreate : function(){
13734 cfg.cls += ' progress-striped';
13738 cfg.cls += ' active';
13757 * @class Roo.bootstrap.ProgressBar
13758 * @extends Roo.bootstrap.Component
13759 * Bootstrap ProgressBar class
13760 * @cfg {Number} aria_valuenow aria-value now
13761 * @cfg {Number} aria_valuemin aria-value min
13762 * @cfg {Number} aria_valuemax aria-value max
13763 * @cfg {String} label label for the progress bar
13764 * @cfg {String} panel (success | info | warning | danger )
13765 * @cfg {String} role role of the progress bar
13766 * @cfg {String} sr_only text
13770 * Create a new ProgressBar
13771 * @param {Object} config The config object
13774 Roo.bootstrap.ProgressBar = function(config){
13775 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13778 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13782 aria_valuemax : 100,
13788 getAutoCreate : function()
13793 cls: 'progress-bar',
13794 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13806 cfg.role = this.role;
13809 if(this.aria_valuenow){
13810 cfg['aria-valuenow'] = this.aria_valuenow;
13813 if(this.aria_valuemin){
13814 cfg['aria-valuemin'] = this.aria_valuemin;
13817 if(this.aria_valuemax){
13818 cfg['aria-valuemax'] = this.aria_valuemax;
13821 if(this.label && !this.sr_only){
13822 cfg.html = this.label;
13826 cfg.cls += ' progress-bar-' + this.panel;
13832 update : function(aria_valuenow)
13834 this.aria_valuenow = aria_valuenow;
13836 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13851 * @class Roo.bootstrap.TabGroup
13852 * @extends Roo.bootstrap.Column
13853 * Bootstrap Column class
13854 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13855 * @cfg {Boolean} carousel true to make the group behave like a carousel
13858 * Create a new TabGroup
13859 * @param {Object} config The config object
13862 Roo.bootstrap.TabGroup = function(config){
13863 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13865 this.navId = Roo.id();
13868 Roo.bootstrap.TabGroup.register(this);
13872 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13875 transition : false,
13877 getAutoCreate : function()
13879 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13881 cfg.cls += ' tab-content';
13883 if (this.carousel) {
13884 cfg.cls += ' carousel slide';
13886 cls : 'carousel-inner'
13893 getChildContainer : function()
13895 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13899 * register a Navigation item
13900 * @param {Roo.bootstrap.NavItem} the navitem to add
13902 register : function(item)
13904 this.tabs.push( item);
13905 item.navId = this.navId; // not really needed..
13909 getActivePanel : function()
13912 Roo.each(this.tabs, function(t) {
13922 getPanelByName : function(n)
13925 Roo.each(this.tabs, function(t) {
13926 if (t.tabId == n) {
13934 indexOfPanel : function(p)
13937 Roo.each(this.tabs, function(t,i) {
13938 if (t.tabId == p.tabId) {
13947 * show a specific panel
13948 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13949 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13951 showPanel : function (pan)
13954 if (typeof(pan) == 'number') {
13955 pan = this.tabs[pan];
13957 if (typeof(pan) == 'string') {
13958 pan = this.getPanelByName(pan);
13960 if (pan.tabId == this.getActivePanel().tabId) {
13963 var cur = this.getActivePanel();
13965 if (false === cur.fireEvent('beforedeactivate')) {
13969 if (this.carousel) {
13970 this.transition = true;
13971 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13972 var lr = dir == 'next' ? 'left' : 'right';
13973 pan.el.addClass(dir); // or prev
13974 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13975 cur.el.addClass(lr); // or right
13976 pan.el.addClass(lr);
13979 cur.el.on('transitionend', function() {
13980 Roo.log("trans end?");
13982 pan.el.removeClass([lr,dir]);
13983 pan.setActive(true);
13985 cur.el.removeClass([lr]);
13986 cur.setActive(false);
13988 _this.transition = false;
13990 }, this, { single: true } );
13994 cur.setActive(false);
13995 pan.setActive(true);
13999 showPanelNext : function()
14001 var i = this.indexOfPanel(this.getActivePanel());
14002 if (i > this.tabs.length) {
14005 this.showPanel(this.tabs[i+1]);
14007 showPanelPrev : function()
14009 var i = this.indexOfPanel(this.getActivePanel());
14013 this.showPanel(this.tabs[i-1]);
14024 Roo.apply(Roo.bootstrap.TabGroup, {
14028 * register a Navigation Group
14029 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14031 register : function(navgrp)
14033 this.groups[navgrp.navId] = navgrp;
14037 * fetch a Navigation Group based on the navigation ID
14038 * if one does not exist , it will get created.
14039 * @param {string} the navgroup to add
14040 * @returns {Roo.bootstrap.NavGroup} the navgroup
14042 get: function(navId) {
14043 if (typeof(this.groups[navId]) == 'undefined') {
14044 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14046 return this.groups[navId] ;
14061 * @class Roo.bootstrap.TabPanel
14062 * @extends Roo.bootstrap.Component
14063 * Bootstrap TabPanel class
14064 * @cfg {Boolean} active panel active
14065 * @cfg {String} html panel content
14066 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14067 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14071 * Create a new TabPanel
14072 * @param {Object} config The config object
14075 Roo.bootstrap.TabPanel = function(config){
14076 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14080 * Fires when the active status changes
14081 * @param {Roo.bootstrap.TabPanel} this
14082 * @param {Boolean} state the new state
14087 * @event beforedeactivate
14088 * Fires before a tab is de-activated - can be used to do validation on a form.
14089 * @param {Roo.bootstrap.TabPanel} this
14090 * @return {Boolean} false if there is an error
14093 'beforedeactivate': true
14096 this.tabId = this.tabId || Roo.id();
14100 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14107 getAutoCreate : function(){
14110 // item is needed for carousel - not sure if it has any effect otherwise
14111 cls: 'tab-pane item',
14112 html: this.html || ''
14116 cfg.cls += ' active';
14120 cfg.tabId = this.tabId;
14127 initEvents: function()
14129 Roo.log('-------- init events on tab panel ---------');
14131 var p = this.parent();
14132 this.navId = this.navId || p.navId;
14134 if (typeof(this.navId) != 'undefined') {
14135 // not really needed.. but just in case.. parent should be a NavGroup.
14136 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14137 Roo.log(['register', tg, this]);
14143 onRender : function(ct, position)
14145 // Roo.log("Call onRender: " + this.xtype);
14147 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14155 setActive: function(state)
14157 Roo.log("panel - set active " + this.tabId + "=" + state);
14159 this.active = state;
14161 this.el.removeClass('active');
14163 } else if (!this.el.hasClass('active')) {
14164 this.el.addClass('active');
14166 this.fireEvent('changed', this, state);
14183 * @class Roo.bootstrap.DateField
14184 * @extends Roo.bootstrap.Input
14185 * Bootstrap DateField class
14186 * @cfg {Number} weekStart default 0
14187 * @cfg {Number} weekStart default 0
14188 * @cfg {Number} viewMode default empty, (months|years)
14189 * @cfg {Number} minViewMode default empty, (months|years)
14190 * @cfg {Number} startDate default -Infinity
14191 * @cfg {Number} endDate default Infinity
14192 * @cfg {Boolean} todayHighlight default false
14193 * @cfg {Boolean} todayBtn default false
14194 * @cfg {Boolean} calendarWeeks default false
14195 * @cfg {Object} daysOfWeekDisabled default empty
14197 * @cfg {Boolean} keyboardNavigation default true
14198 * @cfg {String} language default en
14201 * Create a new DateField
14202 * @param {Object} config The config object
14205 Roo.bootstrap.DateField = function(config){
14206 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14210 * Fires when this field show.
14211 * @param {Roo.bootstrap.DateField} this
14212 * @param {Mixed} date The date value
14217 * Fires when this field hide.
14218 * @param {Roo.bootstrap.DateField} this
14219 * @param {Mixed} date The date value
14224 * Fires when select a date.
14225 * @param {Roo.bootstrap.DateField} this
14226 * @param {Mixed} date The date value
14232 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14235 * @cfg {String} format
14236 * The default date format string which can be overriden for localization support. The format must be
14237 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14241 * @cfg {String} altFormats
14242 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14243 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14245 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14253 todayHighlight : false,
14259 keyboardNavigation: true,
14261 calendarWeeks: false,
14263 startDate: -Infinity,
14267 daysOfWeekDisabled: [],
14271 UTCDate: function()
14273 return new Date(Date.UTC.apply(Date, arguments));
14276 UTCToday: function()
14278 var today = new Date();
14279 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14282 getDate: function() {
14283 var d = this.getUTCDate();
14284 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14287 getUTCDate: function() {
14291 setDate: function(d) {
14292 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14295 setUTCDate: function(d) {
14297 this.setValue(this.formatDate(this.date));
14300 onRender: function(ct, position)
14303 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14305 this.language = this.language || 'en';
14306 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14307 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14309 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14310 this.format = this.format || 'm/d/y';
14311 this.isInline = false;
14312 this.isInput = true;
14313 this.component = this.el.select('.add-on', true).first() || false;
14314 this.component = (this.component && this.component.length === 0) ? false : this.component;
14315 this.hasInput = this.component && this.inputEL().length;
14317 if (typeof(this.minViewMode === 'string')) {
14318 switch (this.minViewMode) {
14320 this.minViewMode = 1;
14323 this.minViewMode = 2;
14326 this.minViewMode = 0;
14331 if (typeof(this.viewMode === 'string')) {
14332 switch (this.viewMode) {
14345 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14347 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14349 this.picker().on('mousedown', this.onMousedown, this);
14350 this.picker().on('click', this.onClick, this);
14352 this.picker().addClass('datepicker-dropdown');
14354 this.startViewMode = this.viewMode;
14357 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14358 if(!this.calendarWeeks){
14363 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14364 v.attr('colspan', function(i, val){
14365 return parseInt(val) + 1;
14370 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14372 this.setStartDate(this.startDate);
14373 this.setEndDate(this.endDate);
14375 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14382 if(this.isInline) {
14387 picker : function()
14389 return this.el.select('.datepicker', true).first();
14392 fillDow: function()
14394 var dowCnt = this.weekStart;
14403 if(this.calendarWeeks){
14411 while (dowCnt < this.weekStart + 7) {
14415 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14419 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14422 fillMonths: function()
14425 var months = this.picker().select('>.datepicker-months td', true).first();
14427 months.dom.innerHTML = '';
14433 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14436 months.createChild(month);
14444 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14446 if (this.date < this.startDate) {
14447 this.viewDate = new Date(this.startDate);
14448 } else if (this.date > this.endDate) {
14449 this.viewDate = new Date(this.endDate);
14451 this.viewDate = new Date(this.date);
14459 var d = new Date(this.viewDate),
14460 year = d.getUTCFullYear(),
14461 month = d.getUTCMonth(),
14462 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14463 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14464 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14465 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14466 currentDate = this.date && this.date.valueOf(),
14467 today = this.UTCToday();
14469 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14471 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14473 // this.picker.select('>tfoot th.today').
14474 // .text(dates[this.language].today)
14475 // .toggle(this.todayBtn !== false);
14477 this.updateNavArrows();
14480 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14482 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14484 prevMonth.setUTCDate(day);
14486 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14488 var nextMonth = new Date(prevMonth);
14490 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14492 nextMonth = nextMonth.valueOf();
14494 var fillMonths = false;
14496 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14498 while(prevMonth.valueOf() < nextMonth) {
14501 if (prevMonth.getUTCDay() === this.weekStart) {
14503 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14511 if(this.calendarWeeks){
14512 // ISO 8601: First week contains first thursday.
14513 // ISO also states week starts on Monday, but we can be more abstract here.
14515 // Start of current week: based on weekstart/current date
14516 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14517 // Thursday of this week
14518 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14519 // First Thursday of year, year from thursday
14520 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14521 // Calendar week: ms between thursdays, div ms per day, div 7 days
14522 calWeek = (th - yth) / 864e5 / 7 + 1;
14524 fillMonths.cn.push({
14532 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14534 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14537 if (this.todayHighlight &&
14538 prevMonth.getUTCFullYear() == today.getFullYear() &&
14539 prevMonth.getUTCMonth() == today.getMonth() &&
14540 prevMonth.getUTCDate() == today.getDate()) {
14541 clsName += ' today';
14544 if (currentDate && prevMonth.valueOf() === currentDate) {
14545 clsName += ' active';
14548 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14549 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14550 clsName += ' disabled';
14553 fillMonths.cn.push({
14555 cls: 'day ' + clsName,
14556 html: prevMonth.getDate()
14559 prevMonth.setDate(prevMonth.getDate()+1);
14562 var currentYear = this.date && this.date.getUTCFullYear();
14563 var currentMonth = this.date && this.date.getUTCMonth();
14565 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14567 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14568 v.removeClass('active');
14570 if(currentYear === year && k === currentMonth){
14571 v.addClass('active');
14574 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14575 v.addClass('disabled');
14581 year = parseInt(year/10, 10) * 10;
14583 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14585 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14588 for (var i = -1; i < 11; i++) {
14589 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14591 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14599 showMode: function(dir)
14602 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14604 Roo.each(this.picker().select('>div',true).elements, function(v){
14605 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14608 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14613 if(this.isInline) return;
14615 this.picker().removeClass(['bottom', 'top']);
14617 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14619 * place to the top of element!
14623 this.picker().addClass('top');
14624 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14629 this.picker().addClass('bottom');
14631 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14634 parseDate : function(value)
14636 if(!value || value instanceof Date){
14639 var v = Date.parseDate(value, this.format);
14640 if (!v && this.useIso) {
14641 v = Date.parseDate(value, 'Y-m-d');
14643 if(!v && this.altFormats){
14644 if(!this.altFormatsArray){
14645 this.altFormatsArray = this.altFormats.split("|");
14647 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14648 v = Date.parseDate(value, this.altFormatsArray[i]);
14654 formatDate : function(date, fmt)
14656 return (!date || !(date instanceof Date)) ?
14657 date : date.dateFormat(fmt || this.format);
14660 onFocus : function()
14662 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14666 onBlur : function()
14668 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14670 var d = this.inputEl().getValue();
14681 this.picker().show();
14685 this.fireEvent('show', this, this.date);
14690 if(this.isInline) return;
14691 this.picker().hide();
14692 this.viewMode = this.startViewMode;
14695 this.fireEvent('hide', this, this.date);
14699 onMousedown: function(e)
14701 e.stopPropagation();
14702 e.preventDefault();
14707 Roo.bootstrap.DateField.superclass.keyup.call(this);
14711 setValue: function(v)
14713 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14715 var d = new Date(v);
14717 if(isNaN(d.getTime())){
14721 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14725 this.fireEvent('select', this, this.date);
14729 getValue: function()
14731 return this.formatDate(this.date);
14734 fireKey: function(e)
14736 if (!this.picker().isVisible()){
14737 if (e.keyCode == 27) // allow escape to hide and re-show picker
14742 var dateChanged = false,
14744 newDate, newViewDate;
14749 e.preventDefault();
14753 if (!this.keyboardNavigation) break;
14754 dir = e.keyCode == 37 ? -1 : 1;
14757 newDate = this.moveYear(this.date, dir);
14758 newViewDate = this.moveYear(this.viewDate, dir);
14759 } else if (e.shiftKey){
14760 newDate = this.moveMonth(this.date, dir);
14761 newViewDate = this.moveMonth(this.viewDate, dir);
14763 newDate = new Date(this.date);
14764 newDate.setUTCDate(this.date.getUTCDate() + dir);
14765 newViewDate = new Date(this.viewDate);
14766 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14768 if (this.dateWithinRange(newDate)){
14769 this.date = newDate;
14770 this.viewDate = newViewDate;
14771 this.setValue(this.formatDate(this.date));
14773 e.preventDefault();
14774 dateChanged = true;
14779 if (!this.keyboardNavigation) break;
14780 dir = e.keyCode == 38 ? -1 : 1;
14782 newDate = this.moveYear(this.date, dir);
14783 newViewDate = this.moveYear(this.viewDate, dir);
14784 } else if (e.shiftKey){
14785 newDate = this.moveMonth(this.date, dir);
14786 newViewDate = this.moveMonth(this.viewDate, dir);
14788 newDate = new Date(this.date);
14789 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14790 newViewDate = new Date(this.viewDate);
14791 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14793 if (this.dateWithinRange(newDate)){
14794 this.date = newDate;
14795 this.viewDate = newViewDate;
14796 this.setValue(this.formatDate(this.date));
14798 e.preventDefault();
14799 dateChanged = true;
14803 this.setValue(this.formatDate(this.date));
14805 e.preventDefault();
14808 this.setValue(this.formatDate(this.date));
14822 onClick: function(e)
14824 e.stopPropagation();
14825 e.preventDefault();
14827 var target = e.getTarget();
14829 if(target.nodeName.toLowerCase() === 'i'){
14830 target = Roo.get(target).dom.parentNode;
14833 var nodeName = target.nodeName;
14834 var className = target.className;
14835 var html = target.innerHTML;
14837 switch(nodeName.toLowerCase()) {
14839 switch(className) {
14845 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14846 switch(this.viewMode){
14848 this.viewDate = this.moveMonth(this.viewDate, dir);
14852 this.viewDate = this.moveYear(this.viewDate, dir);
14858 var date = new Date();
14859 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14861 this.setValue(this.formatDate(this.date));
14868 if (className.indexOf('disabled') === -1) {
14869 this.viewDate.setUTCDate(1);
14870 if (className.indexOf('month') !== -1) {
14871 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14873 var year = parseInt(html, 10) || 0;
14874 this.viewDate.setUTCFullYear(year);
14883 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14884 var day = parseInt(html, 10) || 1;
14885 var year = this.viewDate.getUTCFullYear(),
14886 month = this.viewDate.getUTCMonth();
14888 if (className.indexOf('old') !== -1) {
14895 } else if (className.indexOf('new') !== -1) {
14903 this.date = this.UTCDate(year, month, day,0,0,0,0);
14904 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14906 this.setValue(this.formatDate(this.date));
14913 setStartDate: function(startDate)
14915 this.startDate = startDate || -Infinity;
14916 if (this.startDate !== -Infinity) {
14917 this.startDate = this.parseDate(this.startDate);
14920 this.updateNavArrows();
14923 setEndDate: function(endDate)
14925 this.endDate = endDate || Infinity;
14926 if (this.endDate !== Infinity) {
14927 this.endDate = this.parseDate(this.endDate);
14930 this.updateNavArrows();
14933 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14935 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14936 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14937 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14939 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14940 return parseInt(d, 10);
14943 this.updateNavArrows();
14946 updateNavArrows: function()
14948 var d = new Date(this.viewDate),
14949 year = d.getUTCFullYear(),
14950 month = d.getUTCMonth();
14952 Roo.each(this.picker().select('.prev', true).elements, function(v){
14954 switch (this.viewMode) {
14957 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14963 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14970 Roo.each(this.picker().select('.next', true).elements, function(v){
14972 switch (this.viewMode) {
14975 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14981 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14989 moveMonth: function(date, dir)
14991 if (!dir) return date;
14992 var new_date = new Date(date.valueOf()),
14993 day = new_date.getUTCDate(),
14994 month = new_date.getUTCMonth(),
14995 mag = Math.abs(dir),
14997 dir = dir > 0 ? 1 : -1;
15000 // If going back one month, make sure month is not current month
15001 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15003 return new_date.getUTCMonth() == month;
15005 // If going forward one month, make sure month is as expected
15006 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15008 return new_date.getUTCMonth() != new_month;
15010 new_month = month + dir;
15011 new_date.setUTCMonth(new_month);
15012 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15013 if (new_month < 0 || new_month > 11)
15014 new_month = (new_month + 12) % 12;
15016 // For magnitudes >1, move one month at a time...
15017 for (var i=0; i<mag; i++)
15018 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15019 new_date = this.moveMonth(new_date, dir);
15020 // ...then reset the day, keeping it in the new month
15021 new_month = new_date.getUTCMonth();
15022 new_date.setUTCDate(day);
15024 return new_month != new_date.getUTCMonth();
15027 // Common date-resetting loop -- if date is beyond end of month, make it
15030 new_date.setUTCDate(--day);
15031 new_date.setUTCMonth(new_month);
15036 moveYear: function(date, dir)
15038 return this.moveMonth(date, dir*12);
15041 dateWithinRange: function(date)
15043 return date >= this.startDate && date <= this.endDate;
15049 this.picker().remove();
15054 Roo.apply(Roo.bootstrap.DateField, {
15065 html: '<i class="fa fa-arrow-left"/>'
15075 html: '<i class="fa fa-arrow-right"/>'
15117 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15118 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15119 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15120 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15121 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15134 navFnc: 'FullYear',
15139 navFnc: 'FullYear',
15144 Roo.apply(Roo.bootstrap.DateField, {
15148 cls: 'datepicker dropdown-menu',
15152 cls: 'datepicker-days',
15156 cls: 'table-condensed',
15158 Roo.bootstrap.DateField.head,
15162 Roo.bootstrap.DateField.footer
15169 cls: 'datepicker-months',
15173 cls: 'table-condensed',
15175 Roo.bootstrap.DateField.head,
15176 Roo.bootstrap.DateField.content,
15177 Roo.bootstrap.DateField.footer
15184 cls: 'datepicker-years',
15188 cls: 'table-condensed',
15190 Roo.bootstrap.DateField.head,
15191 Roo.bootstrap.DateField.content,
15192 Roo.bootstrap.DateField.footer
15211 * @class Roo.bootstrap.TimeField
15212 * @extends Roo.bootstrap.Input
15213 * Bootstrap DateField class
15217 * Create a new TimeField
15218 * @param {Object} config The config object
15221 Roo.bootstrap.TimeField = function(config){
15222 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15226 * Fires when this field show.
15227 * @param {Roo.bootstrap.DateField} this
15228 * @param {Mixed} date The date value
15233 * Fires when this field hide.
15234 * @param {Roo.bootstrap.DateField} this
15235 * @param {Mixed} date The date value
15240 * Fires when select a date.
15241 * @param {Roo.bootstrap.DateField} this
15242 * @param {Mixed} date The date value
15248 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15251 * @cfg {String} format
15252 * The default time format string which can be overriden for localization support. The format must be
15253 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15257 onRender: function(ct, position)
15260 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15262 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15264 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15266 this.pop = this.picker().select('>.datepicker-time',true).first();
15267 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15269 this.picker().on('mousedown', this.onMousedown, this);
15270 this.picker().on('click', this.onClick, this);
15272 this.picker().addClass('datepicker-dropdown');
15277 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15278 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15279 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15280 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15281 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15282 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15286 fireKey: function(e){
15287 if (!this.picker().isVisible()){
15288 if (e.keyCode == 27) // allow escape to hide and re-show picker
15293 e.preventDefault();
15301 this.onTogglePeriod();
15304 this.onIncrementMinutes();
15307 this.onDecrementMinutes();
15316 onClick: function(e) {
15317 e.stopPropagation();
15318 e.preventDefault();
15321 picker : function()
15323 return this.el.select('.datepicker', true).first();
15326 fillTime: function()
15328 var time = this.pop.select('tbody', true).first();
15330 time.dom.innerHTML = '';
15345 cls: 'hours-up glyphicon glyphicon-chevron-up'
15365 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15386 cls: 'timepicker-hour',
15401 cls: 'timepicker-minute',
15416 cls: 'btn btn-primary period',
15438 cls: 'hours-down glyphicon glyphicon-chevron-down'
15458 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15476 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15483 var hours = this.time.getHours();
15484 var minutes = this.time.getMinutes();
15497 hours = hours - 12;
15501 hours = '0' + hours;
15505 minutes = '0' + minutes;
15508 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15509 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15510 this.pop.select('button', true).first().dom.innerHTML = period;
15516 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15518 var cls = ['bottom'];
15520 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15527 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15532 this.picker().addClass(cls.join('-'));
15536 Roo.each(cls, function(c){
15538 _this.picker().setTop(_this.inputEl().getHeight());
15542 _this.picker().setTop(0 - _this.picker().getHeight());
15547 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15551 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15558 onFocus : function()
15560 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15564 onBlur : function()
15566 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15572 this.picker().show();
15577 this.fireEvent('show', this, this.date);
15582 this.picker().hide();
15585 this.fireEvent('hide', this, this.date);
15588 setTime : function()
15591 this.setValue(this.time.format(this.format));
15593 this.fireEvent('select', this, this.date);
15598 onMousedown: function(e){
15599 e.stopPropagation();
15600 e.preventDefault();
15603 onIncrementHours: function()
15605 Roo.log('onIncrementHours');
15606 this.time = this.time.add(Date.HOUR, 1);
15611 onDecrementHours: function()
15613 Roo.log('onDecrementHours');
15614 this.time = this.time.add(Date.HOUR, -1);
15618 onIncrementMinutes: function()
15620 Roo.log('onIncrementMinutes');
15621 this.time = this.time.add(Date.MINUTE, 1);
15625 onDecrementMinutes: function()
15627 Roo.log('onDecrementMinutes');
15628 this.time = this.time.add(Date.MINUTE, -1);
15632 onTogglePeriod: function()
15634 Roo.log('onTogglePeriod');
15635 this.time = this.time.add(Date.HOUR, 12);
15642 Roo.apply(Roo.bootstrap.TimeField, {
15672 cls: 'btn btn-info ok',
15684 Roo.apply(Roo.bootstrap.TimeField, {
15688 cls: 'datepicker dropdown-menu',
15692 cls: 'datepicker-time',
15696 cls: 'table-condensed',
15698 Roo.bootstrap.TimeField.content,
15699 Roo.bootstrap.TimeField.footer
15718 * @class Roo.bootstrap.CheckBox
15719 * @extends Roo.bootstrap.Input
15720 * Bootstrap CheckBox class
15722 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15723 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15724 * @cfg {String} boxLabel The text that appears beside the checkbox
15725 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15726 * @cfg {Boolean} checked initnal the element
15730 * Create a new CheckBox
15731 * @param {Object} config The config object
15734 Roo.bootstrap.CheckBox = function(config){
15735 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15740 * Fires when the element is checked or unchecked.
15741 * @param {Roo.bootstrap.CheckBox} this This input
15742 * @param {Boolean} checked The new checked value
15748 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15750 inputType: 'checkbox',
15757 getAutoCreate : function()
15759 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15765 cfg.cls = 'form-group checkbox' //input-group
15773 type : this.inputType,
15774 value : (!this.checked) ? this.valueOff : this.inputValue,
15775 cls : 'roo-checkbox', //'form-box',
15776 placeholder : this.placeholder || ''
15780 if (this.weight) { // Validity check?
15781 cfg.cls += " checkbox-" + this.weight;
15784 if (this.disabled) {
15785 input.disabled=true;
15789 input.checked = this.checked;
15793 input.name = this.name;
15797 input.cls += ' input-' + this.size;
15801 ['xs','sm','md','lg'].map(function(size){
15802 if (settings[size]) {
15803 cfg.cls += ' col-' + size + '-' + settings[size];
15809 var inputblock = input;
15814 if (this.before || this.after) {
15817 cls : 'input-group',
15821 inputblock.cn.push({
15823 cls : 'input-group-addon',
15827 inputblock.cn.push(input);
15829 inputblock.cn.push({
15831 cls : 'input-group-addon',
15838 if (align ==='left' && this.fieldLabel.length) {
15839 Roo.log("left and has label");
15845 cls : 'control-label col-md-' + this.labelWidth,
15846 html : this.fieldLabel
15850 cls : "col-md-" + (12 - this.labelWidth),
15857 } else if ( this.fieldLabel.length) {
15862 tag: this.boxLabel ? 'span' : 'label',
15864 cls: 'control-label box-input-label',
15865 //cls : 'input-group-addon',
15866 html : this.fieldLabel
15876 Roo.log(" no label && no align");
15877 cfg.cn = [ inputblock ] ;
15886 html: this.boxLabel
15898 * return the real input element.
15900 inputEl: function ()
15902 return this.el.select('input.roo-checkbox',true).first();
15907 return this.el.select('label.control-label',true).first();
15910 initEvents : function()
15912 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15914 this.inputEl().on('click', this.onClick, this);
15918 onClick : function()
15920 this.setChecked(!this.checked);
15923 setChecked : function(state,suppressEvent)
15925 this.checked = state;
15927 this.inputEl().dom.checked = state;
15929 if(suppressEvent !== true){
15930 this.fireEvent('check', this, state);
15933 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15937 setValue : function(v,suppressEvent)
15939 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15953 * @class Roo.bootstrap.Radio
15954 * @extends Roo.bootstrap.CheckBox
15955 * Bootstrap Radio class
15958 * Create a new Radio
15959 * @param {Object} config The config object
15962 Roo.bootstrap.Radio = function(config){
15963 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15967 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15969 inputType: 'radio',
15973 getAutoCreate : function()
15975 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15981 cfg.cls = 'form-group radio' //input-group
15986 type : this.inputType,
15987 value : (!this.checked) ? this.valueOff : this.inputValue,
15989 placeholder : this.placeholder || ''
15992 if (this.weight) { // Validity check?
15993 cfg.cls += " radio-" + this.weight;
15995 if (this.disabled) {
15996 input.disabled=true;
16000 input.checked = this.checked;
16004 input.name = this.name;
16008 input.cls += ' input-' + this.size;
16012 ['xs','sm','md','lg'].map(function(size){
16013 if (settings[size]) {
16014 cfg.cls += ' col-' + size + '-' + settings[size];
16018 var inputblock = input;
16020 if (this.before || this.after) {
16023 cls : 'input-group',
16027 inputblock.cn.push({
16029 cls : 'input-group-addon',
16033 inputblock.cn.push(input);
16035 inputblock.cn.push({
16037 cls : 'input-group-addon',
16044 if (align ==='left' && this.fieldLabel.length) {
16045 Roo.log("left and has label");
16051 cls : 'control-label col-md-' + this.labelWidth,
16052 html : this.fieldLabel
16056 cls : "col-md-" + (12 - this.labelWidth),
16063 } else if ( this.fieldLabel.length) {
16070 cls: 'control-label box-input-label',
16071 //cls : 'input-group-addon',
16072 html : this.fieldLabel
16082 Roo.log(" no label && no align");
16097 html: this.boxLabel
16104 inputEl: function ()
16106 return this.el.select('input.roo-radio',true).first();
16108 onClick : function()
16110 this.setChecked(true);
16113 setChecked : function(state,suppressEvent)
16116 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16117 v.dom.checked = false;
16121 this.checked = state;
16122 this.inputEl().dom.checked = state;
16124 if(suppressEvent !== true){
16125 this.fireEvent('check', this, state);
16128 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16132 getGroupValue : function()
16135 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16136 if(v.dom.checked == true){
16137 value = v.dom.value;
16145 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16146 * @return {Mixed} value The field value
16148 getValue : function(){
16149 return this.getGroupValue();
16155 //<script type="text/javascript">
16158 * Based Ext JS Library 1.1.1
16159 * Copyright(c) 2006-2007, Ext JS, LLC.
16165 * @class Roo.HtmlEditorCore
16166 * @extends Roo.Component
16167 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16169 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16172 Roo.HtmlEditorCore = function(config){
16175 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16178 * @event initialize
16179 * Fires when the editor is fully initialized (including the iframe)
16180 * @param {Roo.HtmlEditorCore} this
16185 * Fires when the editor is first receives the focus. Any insertion must wait
16186 * until after this event.
16187 * @param {Roo.HtmlEditorCore} this
16191 * @event beforesync
16192 * Fires before the textarea is updated with content from the editor iframe. Return false
16193 * to cancel the sync.
16194 * @param {Roo.HtmlEditorCore} this
16195 * @param {String} html
16199 * @event beforepush
16200 * Fires before the iframe editor is updated with content from the textarea. Return false
16201 * to cancel the push.
16202 * @param {Roo.HtmlEditorCore} this
16203 * @param {String} html
16208 * Fires when the textarea is updated with content from the editor iframe.
16209 * @param {Roo.HtmlEditorCore} this
16210 * @param {String} html
16215 * Fires when the iframe editor is updated with content from the textarea.
16216 * @param {Roo.HtmlEditorCore} this
16217 * @param {String} html
16222 * @event editorevent
16223 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16224 * @param {Roo.HtmlEditorCore} this
16232 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16236 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16242 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16247 * @cfg {Number} height (in pixels)
16251 * @cfg {Number} width (in pixels)
16256 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16259 stylesheets: false,
16264 // private properties
16265 validationEvent : false,
16267 initialized : false,
16269 sourceEditMode : false,
16270 onFocus : Roo.emptyFn,
16272 hideMode:'offsets',
16280 * Protected method that will not generally be called directly. It
16281 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16282 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16284 getDocMarkup : function(){
16287 Roo.log(this.stylesheets);
16289 // inherit styels from page...??
16290 if (this.stylesheets === false) {
16292 Roo.get(document.head).select('style').each(function(node) {
16293 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16296 Roo.get(document.head).select('link').each(function(node) {
16297 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16300 } else if (!this.stylesheets.length) {
16302 st = '<style type="text/css">' +
16303 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16306 Roo.each(this.stylesheets, function(s) {
16307 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16312 st += '<style type="text/css">' +
16313 'IMG { cursor: pointer } ' +
16317 return '<html><head>' + st +
16318 //<style type="text/css">' +
16319 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16321 ' </head><body class="roo-htmleditor-body"></body></html>';
16325 onRender : function(ct, position)
16328 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16329 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16332 this.el.dom.style.border = '0 none';
16333 this.el.dom.setAttribute('tabIndex', -1);
16334 this.el.addClass('x-hidden hide');
16338 if(Roo.isIE){ // fix IE 1px bogus margin
16339 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16343 this.frameId = Roo.id();
16347 var iframe = this.owner.wrap.createChild({
16349 cls: 'form-control', // bootstrap..
16351 name: this.frameId,
16352 frameBorder : 'no',
16353 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16358 this.iframe = iframe.dom;
16360 this.assignDocWin();
16362 this.doc.designMode = 'on';
16365 this.doc.write(this.getDocMarkup());
16369 var task = { // must defer to wait for browser to be ready
16371 //console.log("run task?" + this.doc.readyState);
16372 this.assignDocWin();
16373 if(this.doc.body || this.doc.readyState == 'complete'){
16375 this.doc.designMode="on";
16379 Roo.TaskMgr.stop(task);
16380 this.initEditor.defer(10, this);
16387 Roo.TaskMgr.start(task);
16394 onResize : function(w, h)
16396 Roo.log('resize: ' +w + ',' + h );
16397 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16401 if(typeof w == 'number'){
16403 this.iframe.style.width = w + 'px';
16405 if(typeof h == 'number'){
16407 this.iframe.style.height = h + 'px';
16409 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16416 * Toggles the editor between standard and source edit mode.
16417 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16419 toggleSourceEdit : function(sourceEditMode){
16421 this.sourceEditMode = sourceEditMode === true;
16423 if(this.sourceEditMode){
16425 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16428 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16429 //this.iframe.className = '';
16432 //this.setSize(this.owner.wrap.getSize());
16433 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16440 * Protected method that will not generally be called directly. If you need/want
16441 * custom HTML cleanup, this is the method you should override.
16442 * @param {String} html The HTML to be cleaned
16443 * return {String} The cleaned HTML
16445 cleanHtml : function(html){
16446 html = String(html);
16447 if(html.length > 5){
16448 if(Roo.isSafari){ // strip safari nonsense
16449 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16452 if(html == ' '){
16459 * HTML Editor -> Textarea
16460 * Protected method that will not generally be called directly. Syncs the contents
16461 * of the editor iframe with the textarea.
16463 syncValue : function(){
16464 if(this.initialized){
16465 var bd = (this.doc.body || this.doc.documentElement);
16466 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16467 var html = bd.innerHTML;
16469 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16470 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16472 html = '<div style="'+m[0]+'">' + html + '</div>';
16475 html = this.cleanHtml(html);
16476 // fix up the special chars.. normaly like back quotes in word...
16477 // however we do not want to do this with chinese..
16478 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16479 var cc = b.charCodeAt();
16481 (cc >= 0x4E00 && cc < 0xA000 ) ||
16482 (cc >= 0x3400 && cc < 0x4E00 ) ||
16483 (cc >= 0xf900 && cc < 0xfb00 )
16489 if(this.owner.fireEvent('beforesync', this, html) !== false){
16490 this.el.dom.value = html;
16491 this.owner.fireEvent('sync', this, html);
16497 * Protected method that will not generally be called directly. Pushes the value of the textarea
16498 * into the iframe editor.
16500 pushValue : function(){
16501 if(this.initialized){
16502 var v = this.el.dom.value.trim();
16504 // if(v.length < 1){
16508 if(this.owner.fireEvent('beforepush', this, v) !== false){
16509 var d = (this.doc.body || this.doc.documentElement);
16511 this.cleanUpPaste();
16512 this.el.dom.value = d.innerHTML;
16513 this.owner.fireEvent('push', this, v);
16519 deferFocus : function(){
16520 this.focus.defer(10, this);
16524 focus : function(){
16525 if(this.win && !this.sourceEditMode){
16532 assignDocWin: function()
16534 var iframe = this.iframe;
16537 this.doc = iframe.contentWindow.document;
16538 this.win = iframe.contentWindow;
16540 // if (!Roo.get(this.frameId)) {
16543 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16544 // this.win = Roo.get(this.frameId).dom.contentWindow;
16546 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16550 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16551 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16556 initEditor : function(){
16557 //console.log("INIT EDITOR");
16558 this.assignDocWin();
16562 this.doc.designMode="on";
16564 this.doc.write(this.getDocMarkup());
16567 var dbody = (this.doc.body || this.doc.documentElement);
16568 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16569 // this copies styles from the containing element into thsi one..
16570 // not sure why we need all of this..
16571 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16573 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16574 //ss['background-attachment'] = 'fixed'; // w3c
16575 dbody.bgProperties = 'fixed'; // ie
16576 //Roo.DomHelper.applyStyles(dbody, ss);
16577 Roo.EventManager.on(this.doc, {
16578 //'mousedown': this.onEditorEvent,
16579 'mouseup': this.onEditorEvent,
16580 'dblclick': this.onEditorEvent,
16581 'click': this.onEditorEvent,
16582 'keyup': this.onEditorEvent,
16587 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16589 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16590 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16592 this.initialized = true;
16594 this.owner.fireEvent('initialize', this);
16599 onDestroy : function(){
16605 //for (var i =0; i < this.toolbars.length;i++) {
16606 // // fixme - ask toolbars for heights?
16607 // this.toolbars[i].onDestroy();
16610 //this.wrap.dom.innerHTML = '';
16611 //this.wrap.remove();
16616 onFirstFocus : function(){
16618 this.assignDocWin();
16621 this.activated = true;
16624 if(Roo.isGecko){ // prevent silly gecko errors
16626 var s = this.win.getSelection();
16627 if(!s.focusNode || s.focusNode.nodeType != 3){
16628 var r = s.getRangeAt(0);
16629 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16634 this.execCmd('useCSS', true);
16635 this.execCmd('styleWithCSS', false);
16638 this.owner.fireEvent('activate', this);
16642 adjustFont: function(btn){
16643 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16644 //if(Roo.isSafari){ // safari
16647 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16648 if(Roo.isSafari){ // safari
16649 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16650 v = (v < 10) ? 10 : v;
16651 v = (v > 48) ? 48 : v;
16652 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16657 v = Math.max(1, v+adjust);
16659 this.execCmd('FontSize', v );
16662 onEditorEvent : function(e){
16663 this.owner.fireEvent('editorevent', this, e);
16664 // this.updateToolbar();
16665 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16668 insertTag : function(tg)
16670 // could be a bit smarter... -> wrap the current selected tRoo..
16671 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16673 range = this.createRange(this.getSelection());
16674 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16675 wrappingNode.appendChild(range.extractContents());
16676 range.insertNode(wrappingNode);
16683 this.execCmd("formatblock", tg);
16687 insertText : function(txt)
16691 var range = this.createRange();
16692 range.deleteContents();
16693 //alert(Sender.getAttribute('label'));
16695 range.insertNode(this.doc.createTextNode(txt));
16701 * Executes a Midas editor command on the editor document and performs necessary focus and
16702 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16703 * @param {String} cmd The Midas command
16704 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16706 relayCmd : function(cmd, value){
16708 this.execCmd(cmd, value);
16709 this.owner.fireEvent('editorevent', this);
16710 //this.updateToolbar();
16711 this.owner.deferFocus();
16715 * Executes a Midas editor command directly on the editor document.
16716 * For visual commands, you should use {@link #relayCmd} instead.
16717 * <b>This should only be called after the editor is initialized.</b>
16718 * @param {String} cmd The Midas command
16719 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16721 execCmd : function(cmd, value){
16722 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16729 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16731 * @param {String} text | dom node..
16733 insertAtCursor : function(text)
16738 if(!this.activated){
16744 var r = this.doc.selection.createRange();
16755 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16759 // from jquery ui (MIT licenced)
16761 var win = this.win;
16763 if (win.getSelection && win.getSelection().getRangeAt) {
16764 range = win.getSelection().getRangeAt(0);
16765 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16766 range.insertNode(node);
16767 } else if (win.document.selection && win.document.selection.createRange) {
16768 // no firefox support
16769 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16770 win.document.selection.createRange().pasteHTML(txt);
16772 // no firefox support
16773 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16774 this.execCmd('InsertHTML', txt);
16783 mozKeyPress : function(e){
16785 var c = e.getCharCode(), cmd;
16788 c = String.fromCharCode(c).toLowerCase();
16802 this.cleanUpPaste.defer(100, this);
16810 e.preventDefault();
16818 fixKeys : function(){ // load time branching for fastest keydown performance
16820 return function(e){
16821 var k = e.getKey(), r;
16824 r = this.doc.selection.createRange();
16827 r.pasteHTML('    ');
16834 r = this.doc.selection.createRange();
16836 var target = r.parentElement();
16837 if(!target || target.tagName.toLowerCase() != 'li'){
16839 r.pasteHTML('<br />');
16845 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16846 this.cleanUpPaste.defer(100, this);
16852 }else if(Roo.isOpera){
16853 return function(e){
16854 var k = e.getKey();
16858 this.execCmd('InsertHTML','    ');
16861 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16862 this.cleanUpPaste.defer(100, this);
16867 }else if(Roo.isSafari){
16868 return function(e){
16869 var k = e.getKey();
16873 this.execCmd('InsertText','\t');
16877 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16878 this.cleanUpPaste.defer(100, this);
16886 getAllAncestors: function()
16888 var p = this.getSelectedNode();
16891 a.push(p); // push blank onto stack..
16892 p = this.getParentElement();
16896 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16900 a.push(this.doc.body);
16904 lastSelNode : false,
16907 getSelection : function()
16909 this.assignDocWin();
16910 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16913 getSelectedNode: function()
16915 // this may only work on Gecko!!!
16917 // should we cache this!!!!
16922 var range = this.createRange(this.getSelection()).cloneRange();
16925 var parent = range.parentElement();
16927 var testRange = range.duplicate();
16928 testRange.moveToElementText(parent);
16929 if (testRange.inRange(range)) {
16932 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16935 parent = parent.parentElement;
16940 // is ancestor a text element.
16941 var ac = range.commonAncestorContainer;
16942 if (ac.nodeType == 3) {
16943 ac = ac.parentNode;
16946 var ar = ac.childNodes;
16949 var other_nodes = [];
16950 var has_other_nodes = false;
16951 for (var i=0;i<ar.length;i++) {
16952 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16955 // fullly contained node.
16957 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16962 // probably selected..
16963 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16964 other_nodes.push(ar[i]);
16968 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16973 has_other_nodes = true;
16975 if (!nodes.length && other_nodes.length) {
16976 nodes= other_nodes;
16978 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16984 createRange: function(sel)
16986 // this has strange effects when using with
16987 // top toolbar - not sure if it's a great idea.
16988 //this.editor.contentWindow.focus();
16989 if (typeof sel != "undefined") {
16991 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16993 return this.doc.createRange();
16996 return this.doc.createRange();
16999 getParentElement: function()
17002 this.assignDocWin();
17003 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17005 var range = this.createRange(sel);
17008 var p = range.commonAncestorContainer;
17009 while (p.nodeType == 3) { // text node
17020 * Range intersection.. the hard stuff...
17024 * [ -- selected range --- ]
17028 * if end is before start or hits it. fail.
17029 * if start is after end or hits it fail.
17031 * if either hits (but other is outside. - then it's not
17037 // @see http://www.thismuchiknow.co.uk/?p=64.
17038 rangeIntersectsNode : function(range, node)
17040 var nodeRange = node.ownerDocument.createRange();
17042 nodeRange.selectNode(node);
17044 nodeRange.selectNodeContents(node);
17047 var rangeStartRange = range.cloneRange();
17048 rangeStartRange.collapse(true);
17050 var rangeEndRange = range.cloneRange();
17051 rangeEndRange.collapse(false);
17053 var nodeStartRange = nodeRange.cloneRange();
17054 nodeStartRange.collapse(true);
17056 var nodeEndRange = nodeRange.cloneRange();
17057 nodeEndRange.collapse(false);
17059 return rangeStartRange.compareBoundaryPoints(
17060 Range.START_TO_START, nodeEndRange) == -1 &&
17061 rangeEndRange.compareBoundaryPoints(
17062 Range.START_TO_START, nodeStartRange) == 1;
17066 rangeCompareNode : function(range, node)
17068 var nodeRange = node.ownerDocument.createRange();
17070 nodeRange.selectNode(node);
17072 nodeRange.selectNodeContents(node);
17076 range.collapse(true);
17078 nodeRange.collapse(true);
17080 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17081 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17083 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17085 var nodeIsBefore = ss == 1;
17086 var nodeIsAfter = ee == -1;
17088 if (nodeIsBefore && nodeIsAfter)
17090 if (!nodeIsBefore && nodeIsAfter)
17091 return 1; //right trailed.
17093 if (nodeIsBefore && !nodeIsAfter)
17094 return 2; // left trailed.
17099 // private? - in a new class?
17100 cleanUpPaste : function()
17102 // cleans up the whole document..
17103 Roo.log('cleanuppaste');
17105 this.cleanUpChildren(this.doc.body);
17106 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17107 if (clean != this.doc.body.innerHTML) {
17108 this.doc.body.innerHTML = clean;
17113 cleanWordChars : function(input) {// change the chars to hex code
17114 var he = Roo.HtmlEditorCore;
17116 var output = input;
17117 Roo.each(he.swapCodes, function(sw) {
17118 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17120 output = output.replace(swapper, sw[1]);
17127 cleanUpChildren : function (n)
17129 if (!n.childNodes.length) {
17132 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17133 this.cleanUpChild(n.childNodes[i]);
17140 cleanUpChild : function (node)
17143 //console.log(node);
17144 if (node.nodeName == "#text") {
17145 // clean up silly Windows -- stuff?
17148 if (node.nodeName == "#comment") {
17149 node.parentNode.removeChild(node);
17150 // clean up silly Windows -- stuff?
17154 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17156 node.parentNode.removeChild(node);
17161 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17163 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17164 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17166 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17167 // remove_keep_children = true;
17170 if (remove_keep_children) {
17171 this.cleanUpChildren(node);
17172 // inserts everything just before this node...
17173 while (node.childNodes.length) {
17174 var cn = node.childNodes[0];
17175 node.removeChild(cn);
17176 node.parentNode.insertBefore(cn, node);
17178 node.parentNode.removeChild(node);
17182 if (!node.attributes || !node.attributes.length) {
17183 this.cleanUpChildren(node);
17187 function cleanAttr(n,v)
17190 if (v.match(/^\./) || v.match(/^\//)) {
17193 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17196 if (v.match(/^#/)) {
17199 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17200 node.removeAttribute(n);
17204 function cleanStyle(n,v)
17206 if (v.match(/expression/)) { //XSS?? should we even bother..
17207 node.removeAttribute(n);
17210 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17211 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17214 var parts = v.split(/;/);
17217 Roo.each(parts, function(p) {
17218 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17222 var l = p.split(':').shift().replace(/\s+/g,'');
17223 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17225 if ( cblack.indexOf(l) > -1) {
17226 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17227 //node.removeAttribute(n);
17231 // only allow 'c whitelisted system attributes'
17232 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17233 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17234 //node.removeAttribute(n);
17244 if (clean.length) {
17245 node.setAttribute(n, clean.join(';'));
17247 node.removeAttribute(n);
17253 for (var i = node.attributes.length-1; i > -1 ; i--) {
17254 var a = node.attributes[i];
17257 if (a.name.toLowerCase().substr(0,2)=='on') {
17258 node.removeAttribute(a.name);
17261 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17262 node.removeAttribute(a.name);
17265 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17266 cleanAttr(a.name,a.value); // fixme..
17269 if (a.name == 'style') {
17270 cleanStyle(a.name,a.value);
17273 /// clean up MS crap..
17274 // tecnically this should be a list of valid class'es..
17277 if (a.name == 'class') {
17278 if (a.value.match(/^Mso/)) {
17279 node.className = '';
17282 if (a.value.match(/body/)) {
17283 node.className = '';
17294 this.cleanUpChildren(node);
17299 * Clean up MS wordisms...
17301 cleanWord : function(node)
17304 var cleanWordChildren = function()
17306 if (!node.childNodes.length) {
17309 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17310 _t.cleanWord(node.childNodes[i]);
17316 this.cleanWord(this.doc.body);
17319 if (node.nodeName == "#text") {
17320 // clean up silly Windows -- stuff?
17323 if (node.nodeName == "#comment") {
17324 node.parentNode.removeChild(node);
17325 // clean up silly Windows -- stuff?
17329 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17330 node.parentNode.removeChild(node);
17334 // remove - but keep children..
17335 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17336 while (node.childNodes.length) {
17337 var cn = node.childNodes[0];
17338 node.removeChild(cn);
17339 node.parentNode.insertBefore(cn, node);
17341 node.parentNode.removeChild(node);
17342 cleanWordChildren();
17346 if (node.className.length) {
17348 var cn = node.className.split(/\W+/);
17350 Roo.each(cn, function(cls) {
17351 if (cls.match(/Mso[a-zA-Z]+/)) {
17356 node.className = cna.length ? cna.join(' ') : '';
17358 node.removeAttribute("class");
17362 if (node.hasAttribute("lang")) {
17363 node.removeAttribute("lang");
17366 if (node.hasAttribute("style")) {
17368 var styles = node.getAttribute("style").split(";");
17370 Roo.each(styles, function(s) {
17371 if (!s.match(/:/)) {
17374 var kv = s.split(":");
17375 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17378 // what ever is left... we allow.
17381 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17382 if (!nstyle.length) {
17383 node.removeAttribute('style');
17387 cleanWordChildren();
17391 domToHTML : function(currentElement, depth, nopadtext) {
17393 depth = depth || 0;
17394 nopadtext = nopadtext || false;
17396 if (!currentElement) {
17397 return this.domToHTML(this.doc.body);
17400 //Roo.log(currentElement);
17402 var allText = false;
17403 var nodeName = currentElement.nodeName;
17404 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17406 if (nodeName == '#text') {
17407 return currentElement.nodeValue;
17412 if (nodeName != 'BODY') {
17415 // Prints the node tagName, such as <A>, <IMG>, etc
17418 for(i = 0; i < currentElement.attributes.length;i++) {
17420 var aname = currentElement.attributes.item(i).name;
17421 if (!currentElement.attributes.item(i).value.length) {
17424 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17427 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17436 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17439 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17444 // Traverse the tree
17446 var currentElementChild = currentElement.childNodes.item(i);
17447 var allText = true;
17448 var innerHTML = '';
17450 while (currentElementChild) {
17451 // Formatting code (indent the tree so it looks nice on the screen)
17452 var nopad = nopadtext;
17453 if (lastnode == 'SPAN') {
17457 if (currentElementChild.nodeName == '#text') {
17458 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17459 if (!nopad && toadd.length > 80) {
17460 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17462 innerHTML += toadd;
17465 currentElementChild = currentElement.childNodes.item(i);
17471 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17473 // Recursively traverse the tree structure of the child node
17474 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17475 lastnode = currentElementChild.nodeName;
17477 currentElementChild=currentElement.childNodes.item(i);
17483 // The remaining code is mostly for formatting the tree
17484 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17489 ret+= "</"+tagName+">";
17495 // hide stuff that is not compatible
17509 * @event specialkey
17513 * @cfg {String} fieldClass @hide
17516 * @cfg {String} focusClass @hide
17519 * @cfg {String} autoCreate @hide
17522 * @cfg {String} inputType @hide
17525 * @cfg {String} invalidClass @hide
17528 * @cfg {String} invalidText @hide
17531 * @cfg {String} msgFx @hide
17534 * @cfg {String} validateOnBlur @hide
17538 Roo.HtmlEditorCore.white = [
17539 'area', 'br', 'img', 'input', 'hr', 'wbr',
17541 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17542 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17543 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17544 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17545 'table', 'ul', 'xmp',
17547 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17550 'dir', 'menu', 'ol', 'ul', 'dl',
17556 Roo.HtmlEditorCore.black = [
17557 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17559 'base', 'basefont', 'bgsound', 'blink', 'body',
17560 'frame', 'frameset', 'head', 'html', 'ilayer',
17561 'iframe', 'layer', 'link', 'meta', 'object',
17562 'script', 'style' ,'title', 'xml' // clean later..
17564 Roo.HtmlEditorCore.clean = [
17565 'script', 'style', 'title', 'xml'
17567 Roo.HtmlEditorCore.remove = [
17572 Roo.HtmlEditorCore.ablack = [
17576 Roo.HtmlEditorCore.aclean = [
17577 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17581 Roo.HtmlEditorCore.pwhite= [
17582 'http', 'https', 'mailto'
17585 // white listed style attributes.
17586 Roo.HtmlEditorCore.cwhite= [
17587 // 'text-align', /// default is to allow most things..
17593 // black listed style attributes.
17594 Roo.HtmlEditorCore.cblack= [
17595 // 'font-size' -- this can be set by the project
17599 Roo.HtmlEditorCore.swapCodes =[
17618 * @class Roo.bootstrap.HtmlEditor
17619 * @extends Roo.bootstrap.TextArea
17620 * Bootstrap HtmlEditor class
17623 * Create a new HtmlEditor
17624 * @param {Object} config The config object
17627 Roo.bootstrap.HtmlEditor = function(config){
17628 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17629 if (!this.toolbars) {
17630 this.toolbars = [];
17632 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17635 * @event initialize
17636 * Fires when the editor is fully initialized (including the iframe)
17637 * @param {HtmlEditor} this
17642 * Fires when the editor is first receives the focus. Any insertion must wait
17643 * until after this event.
17644 * @param {HtmlEditor} this
17648 * @event beforesync
17649 * Fires before the textarea is updated with content from the editor iframe. Return false
17650 * to cancel the sync.
17651 * @param {HtmlEditor} this
17652 * @param {String} html
17656 * @event beforepush
17657 * Fires before the iframe editor is updated with content from the textarea. Return false
17658 * to cancel the push.
17659 * @param {HtmlEditor} this
17660 * @param {String} html
17665 * Fires when the textarea is updated with content from the editor iframe.
17666 * @param {HtmlEditor} this
17667 * @param {String} html
17672 * Fires when the iframe editor is updated with content from the textarea.
17673 * @param {HtmlEditor} this
17674 * @param {String} html
17678 * @event editmodechange
17679 * Fires when the editor switches edit modes
17680 * @param {HtmlEditor} this
17681 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17683 editmodechange: true,
17685 * @event editorevent
17686 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17687 * @param {HtmlEditor} this
17691 * @event firstfocus
17692 * Fires when on first focus - needed by toolbars..
17693 * @param {HtmlEditor} this
17698 * Auto save the htmlEditor value as a file into Events
17699 * @param {HtmlEditor} this
17703 * @event savedpreview
17704 * preview the saved version of htmlEditor
17705 * @param {HtmlEditor} this
17712 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17716 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17721 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17726 * @cfg {Number} height (in pixels)
17730 * @cfg {Number} width (in pixels)
17735 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17738 stylesheets: false,
17743 // private properties
17744 validationEvent : false,
17746 initialized : false,
17749 onFocus : Roo.emptyFn,
17751 hideMode:'offsets',
17754 tbContainer : false,
17756 toolbarContainer :function() {
17757 return this.wrap.select('.x-html-editor-tb',true).first();
17761 * Protected method that will not generally be called directly. It
17762 * is called when the editor creates its toolbar. Override this method if you need to
17763 * add custom toolbar buttons.
17764 * @param {HtmlEditor} editor
17766 createToolbar : function(){
17768 Roo.log("create toolbars");
17770 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17771 this.toolbars[0].render(this.toolbarContainer());
17775 // if (!editor.toolbars || !editor.toolbars.length) {
17776 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17779 // for (var i =0 ; i < editor.toolbars.length;i++) {
17780 // editor.toolbars[i] = Roo.factory(
17781 // typeof(editor.toolbars[i]) == 'string' ?
17782 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17783 // Roo.bootstrap.HtmlEditor);
17784 // editor.toolbars[i].init(editor);
17790 onRender : function(ct, position)
17792 // Roo.log("Call onRender: " + this.xtype);
17794 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17796 this.wrap = this.inputEl().wrap({
17797 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17800 this.editorcore.onRender(ct, position);
17802 if (this.resizable) {
17803 this.resizeEl = new Roo.Resizable(this.wrap, {
17807 minHeight : this.height,
17808 height: this.height,
17809 handles : this.resizable,
17812 resize : function(r, w, h) {
17813 _t.onResize(w,h); // -something
17819 this.createToolbar(this);
17822 if(!this.width && this.resizable){
17823 this.setSize(this.wrap.getSize());
17825 if (this.resizeEl) {
17826 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17827 // should trigger onReize..
17833 onResize : function(w, h)
17835 Roo.log('resize: ' +w + ',' + h );
17836 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17840 if(this.inputEl() ){
17841 if(typeof w == 'number'){
17842 var aw = w - this.wrap.getFrameWidth('lr');
17843 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17846 if(typeof h == 'number'){
17847 var tbh = -11; // fixme it needs to tool bar size!
17848 for (var i =0; i < this.toolbars.length;i++) {
17849 // fixme - ask toolbars for heights?
17850 tbh += this.toolbars[i].el.getHeight();
17851 //if (this.toolbars[i].footer) {
17852 // tbh += this.toolbars[i].footer.el.getHeight();
17860 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17861 ah -= 5; // knock a few pixes off for look..
17862 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17866 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17867 this.editorcore.onResize(ew,eh);
17872 * Toggles the editor between standard and source edit mode.
17873 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17875 toggleSourceEdit : function(sourceEditMode)
17877 this.editorcore.toggleSourceEdit(sourceEditMode);
17879 if(this.editorcore.sourceEditMode){
17880 Roo.log('editor - showing textarea');
17883 // Roo.log(this.syncValue());
17885 this.inputEl().removeClass(['hide', 'x-hidden']);
17886 this.inputEl().dom.removeAttribute('tabIndex');
17887 this.inputEl().focus();
17889 Roo.log('editor - hiding textarea');
17891 // Roo.log(this.pushValue());
17894 this.inputEl().addClass(['hide', 'x-hidden']);
17895 this.inputEl().dom.setAttribute('tabIndex', -1);
17896 //this.deferFocus();
17899 if(this.resizable){
17900 this.setSize(this.wrap.getSize());
17903 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17906 // private (for BoxComponent)
17907 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17909 // private (for BoxComponent)
17910 getResizeEl : function(){
17914 // private (for BoxComponent)
17915 getPositionEl : function(){
17920 initEvents : function(){
17921 this.originalValue = this.getValue();
17925 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17928 // markInvalid : Roo.emptyFn,
17930 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17933 // clearInvalid : Roo.emptyFn,
17935 setValue : function(v){
17936 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17937 this.editorcore.pushValue();
17942 deferFocus : function(){
17943 this.focus.defer(10, this);
17947 focus : function(){
17948 this.editorcore.focus();
17954 onDestroy : function(){
17960 for (var i =0; i < this.toolbars.length;i++) {
17961 // fixme - ask toolbars for heights?
17962 this.toolbars[i].onDestroy();
17965 this.wrap.dom.innerHTML = '';
17966 this.wrap.remove();
17971 onFirstFocus : function(){
17972 //Roo.log("onFirstFocus");
17973 this.editorcore.onFirstFocus();
17974 for (var i =0; i < this.toolbars.length;i++) {
17975 this.toolbars[i].onFirstFocus();
17981 syncValue : function()
17983 this.editorcore.syncValue();
17986 pushValue : function()
17988 this.editorcore.pushValue();
17992 // hide stuff that is not compatible
18006 * @event specialkey
18010 * @cfg {String} fieldClass @hide
18013 * @cfg {String} focusClass @hide
18016 * @cfg {String} autoCreate @hide
18019 * @cfg {String} inputType @hide
18022 * @cfg {String} invalidClass @hide
18025 * @cfg {String} invalidText @hide
18028 * @cfg {String} msgFx @hide
18031 * @cfg {String} validateOnBlur @hide
18040 Roo.namespace('Roo.bootstrap.htmleditor');
18042 * @class Roo.bootstrap.HtmlEditorToolbar1
18047 new Roo.bootstrap.HtmlEditor({
18050 new Roo.bootstrap.HtmlEditorToolbar1({
18051 disable : { fonts: 1 , format: 1, ..., ... , ...],
18057 * @cfg {Object} disable List of elements to disable..
18058 * @cfg {Array} btns List of additional buttons.
18062 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18065 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18068 Roo.apply(this, config);
18070 // default disabled, based on 'good practice'..
18071 this.disable = this.disable || {};
18072 Roo.applyIf(this.disable, {
18075 specialElements : true
18077 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18079 this.editor = config.editor;
18080 this.editorcore = config.editor.editorcore;
18082 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18084 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18085 // dont call parent... till later.
18087 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18092 editorcore : false,
18097 "h1","h2","h3","h4","h5","h6",
18099 "abbr", "acronym", "address", "cite", "samp", "var",
18103 onRender : function(ct, position)
18105 // Roo.log("Call onRender: " + this.xtype);
18107 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18109 this.el.dom.style.marginBottom = '0';
18111 var editorcore = this.editorcore;
18112 var editor= this.editor;
18115 var btn = function(id,cmd , toggle, handler){
18117 var event = toggle ? 'toggle' : 'click';
18122 xns: Roo.bootstrap,
18125 enableToggle:toggle !== false,
18127 pressed : toggle ? false : null,
18130 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18131 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18140 xns: Roo.bootstrap,
18141 glyphicon : 'font',
18145 xns: Roo.bootstrap,
18149 Roo.each(this.formats, function(f) {
18150 style.menu.items.push({
18152 xns: Roo.bootstrap,
18153 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18158 editorcore.insertTag(this.tagname);
18165 children.push(style);
18168 btn('bold',false,true);
18169 btn('italic',false,true);
18170 btn('align-left', 'justifyleft',true);
18171 btn('align-center', 'justifycenter',true);
18172 btn('align-right' , 'justifyright',true);
18173 btn('link', false, false, function(btn) {
18174 //Roo.log("create link?");
18175 var url = prompt(this.createLinkText, this.defaultLinkValue);
18176 if(url && url != 'http:/'+'/'){
18177 this.editorcore.relayCmd('createlink', url);
18180 btn('list','insertunorderedlist',true);
18181 btn('pencil', false,true, function(btn){
18184 this.toggleSourceEdit(btn.pressed);
18190 xns: Roo.bootstrap,
18195 xns: Roo.bootstrap,
18200 cog.menu.items.push({
18202 xns: Roo.bootstrap,
18203 html : Clean styles,
18208 editorcore.insertTag(this.tagname);
18217 this.xtype = 'NavSimplebar';
18219 for(var i=0;i< children.length;i++) {
18221 this.buttons.add(this.addxtypeChild(children[i]));
18225 editor.on('editorevent', this.updateToolbar, this);
18227 onBtnClick : function(id)
18229 this.editorcore.relayCmd(id);
18230 this.editorcore.focus();
18234 * Protected method that will not generally be called directly. It triggers
18235 * a toolbar update by reading the markup state of the current selection in the editor.
18237 updateToolbar: function(){
18239 if(!this.editorcore.activated){
18240 this.editor.onFirstFocus(); // is this neeed?
18244 var btns = this.buttons;
18245 var doc = this.editorcore.doc;
18246 btns.get('bold').setActive(doc.queryCommandState('bold'));
18247 btns.get('italic').setActive(doc.queryCommandState('italic'));
18248 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18250 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18251 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18252 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18254 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18255 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18258 var ans = this.editorcore.getAllAncestors();
18259 if (this.formatCombo) {
18262 var store = this.formatCombo.store;
18263 this.formatCombo.setValue("");
18264 for (var i =0; i < ans.length;i++) {
18265 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18267 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18275 // hides menus... - so this cant be on a menu...
18276 Roo.bootstrap.MenuMgr.hideAll();
18278 Roo.bootstrap.MenuMgr.hideAll();
18279 //this.editorsyncValue();
18281 onFirstFocus: function() {
18282 this.buttons.each(function(item){
18286 toggleSourceEdit : function(sourceEditMode){
18289 if(sourceEditMode){
18290 Roo.log("disabling buttons");
18291 this.buttons.each( function(item){
18292 if(item.cmd != 'pencil'){
18298 Roo.log("enabling buttons");
18299 if(this.editorcore.initialized){
18300 this.buttons.each( function(item){
18306 Roo.log("calling toggole on editor");
18307 // tell the editor that it's been pressed..
18308 this.editor.toggleSourceEdit(sourceEditMode);
18318 * @class Roo.bootstrap.Table.AbstractSelectionModel
18319 * @extends Roo.util.Observable
18320 * Abstract base class for grid SelectionModels. It provides the interface that should be
18321 * implemented by descendant classes. This class should not be directly instantiated.
18324 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18325 this.locked = false;
18326 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18330 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18331 /** @ignore Called by the grid automatically. Do not call directly. */
18332 init : function(grid){
18338 * Locks the selections.
18341 this.locked = true;
18345 * Unlocks the selections.
18347 unlock : function(){
18348 this.locked = false;
18352 * Returns true if the selections are locked.
18353 * @return {Boolean}
18355 isLocked : function(){
18356 return this.locked;
18360 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18361 * @class Roo.bootstrap.Table.RowSelectionModel
18362 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18363 * It supports multiple selections and keyboard selection/navigation.
18365 * @param {Object} config
18368 Roo.bootstrap.Table.RowSelectionModel = function(config){
18369 Roo.apply(this, config);
18370 this.selections = new Roo.util.MixedCollection(false, function(o){
18375 this.lastActive = false;
18379 * @event selectionchange
18380 * Fires when the selection changes
18381 * @param {SelectionModel} this
18383 "selectionchange" : true,
18385 * @event afterselectionchange
18386 * Fires after the selection changes (eg. by key press or clicking)
18387 * @param {SelectionModel} this
18389 "afterselectionchange" : true,
18391 * @event beforerowselect
18392 * Fires when a row is selected being selected, return false to cancel.
18393 * @param {SelectionModel} this
18394 * @param {Number} rowIndex The selected index
18395 * @param {Boolean} keepExisting False if other selections will be cleared
18397 "beforerowselect" : true,
18400 * Fires when a row is selected.
18401 * @param {SelectionModel} this
18402 * @param {Number} rowIndex The selected index
18403 * @param {Roo.data.Record} r The record
18405 "rowselect" : true,
18407 * @event rowdeselect
18408 * Fires when a row is deselected.
18409 * @param {SelectionModel} this
18410 * @param {Number} rowIndex The selected index
18412 "rowdeselect" : true
18414 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18415 this.locked = false;
18418 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18420 * @cfg {Boolean} singleSelect
18421 * True to allow selection of only one row at a time (defaults to false)
18423 singleSelect : false,
18426 initEvents : function(){
18428 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18429 this.grid.on("mousedown", this.handleMouseDown, this);
18430 }else{ // allow click to work like normal
18431 this.grid.on("rowclick", this.handleDragableRowClick, this);
18434 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18435 "up" : function(e){
18437 this.selectPrevious(e.shiftKey);
18438 }else if(this.last !== false && this.lastActive !== false){
18439 var last = this.last;
18440 this.selectRange(this.last, this.lastActive-1);
18441 this.grid.getView().focusRow(this.lastActive);
18442 if(last !== false){
18446 this.selectFirstRow();
18448 this.fireEvent("afterselectionchange", this);
18450 "down" : function(e){
18452 this.selectNext(e.shiftKey);
18453 }else if(this.last !== false && this.lastActive !== false){
18454 var last = this.last;
18455 this.selectRange(this.last, this.lastActive+1);
18456 this.grid.getView().focusRow(this.lastActive);
18457 if(last !== false){
18461 this.selectFirstRow();
18463 this.fireEvent("afterselectionchange", this);
18468 var view = this.grid.view;
18469 view.on("refresh", this.onRefresh, this);
18470 view.on("rowupdated", this.onRowUpdated, this);
18471 view.on("rowremoved", this.onRemove, this);
18475 onRefresh : function(){
18476 var ds = this.grid.dataSource, i, v = this.grid.view;
18477 var s = this.selections;
18478 s.each(function(r){
18479 if((i = ds.indexOfId(r.id)) != -1){
18488 onRemove : function(v, index, r){
18489 this.selections.remove(r);
18493 onRowUpdated : function(v, index, r){
18494 if(this.isSelected(r)){
18495 v.onRowSelect(index);
18501 * @param {Array} records The records to select
18502 * @param {Boolean} keepExisting (optional) True to keep existing selections
18504 selectRecords : function(records, keepExisting){
18506 this.clearSelections();
18508 var ds = this.grid.dataSource;
18509 for(var i = 0, len = records.length; i < len; i++){
18510 this.selectRow(ds.indexOf(records[i]), true);
18515 * Gets the number of selected rows.
18518 getCount : function(){
18519 return this.selections.length;
18523 * Selects the first row in the grid.
18525 selectFirstRow : function(){
18530 * Select the last row.
18531 * @param {Boolean} keepExisting (optional) True to keep existing selections
18533 selectLastRow : function(keepExisting){
18534 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18538 * Selects the row immediately following the last selected row.
18539 * @param {Boolean} keepExisting (optional) True to keep existing selections
18541 selectNext : function(keepExisting){
18542 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18543 this.selectRow(this.last+1, keepExisting);
18544 this.grid.getView().focusRow(this.last);
18549 * Selects the row that precedes the last selected row.
18550 * @param {Boolean} keepExisting (optional) True to keep existing selections
18552 selectPrevious : function(keepExisting){
18554 this.selectRow(this.last-1, keepExisting);
18555 this.grid.getView().focusRow(this.last);
18560 * Returns the selected records
18561 * @return {Array} Array of selected records
18563 getSelections : function(){
18564 return [].concat(this.selections.items);
18568 * Returns the first selected record.
18571 getSelected : function(){
18572 return this.selections.itemAt(0);
18577 * Clears all selections.
18579 clearSelections : function(fast){
18580 if(this.locked) return;
18582 var ds = this.grid.dataSource;
18583 var s = this.selections;
18584 s.each(function(r){
18585 this.deselectRow(ds.indexOfId(r.id));
18589 this.selections.clear();
18596 * Selects all rows.
18598 selectAll : function(){
18599 if(this.locked) return;
18600 this.selections.clear();
18601 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18602 this.selectRow(i, true);
18607 * Returns True if there is a selection.
18608 * @return {Boolean}
18610 hasSelection : function(){
18611 return this.selections.length > 0;
18615 * Returns True if the specified row is selected.
18616 * @param {Number/Record} record The record or index of the record to check
18617 * @return {Boolean}
18619 isSelected : function(index){
18620 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18621 return (r && this.selections.key(r.id) ? true : false);
18625 * Returns True if the specified record id is selected.
18626 * @param {String} id The id of record to check
18627 * @return {Boolean}
18629 isIdSelected : function(id){
18630 return (this.selections.key(id) ? true : false);
18634 handleMouseDown : function(e, t){
18635 var view = this.grid.getView(), rowIndex;
18636 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18639 if(e.shiftKey && this.last !== false){
18640 var last = this.last;
18641 this.selectRange(last, rowIndex, e.ctrlKey);
18642 this.last = last; // reset the last
18643 view.focusRow(rowIndex);
18645 var isSelected = this.isSelected(rowIndex);
18646 if(e.button !== 0 && isSelected){
18647 view.focusRow(rowIndex);
18648 }else if(e.ctrlKey && isSelected){
18649 this.deselectRow(rowIndex);
18650 }else if(!isSelected){
18651 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18652 view.focusRow(rowIndex);
18655 this.fireEvent("afterselectionchange", this);
18658 handleDragableRowClick : function(grid, rowIndex, e)
18660 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18661 this.selectRow(rowIndex, false);
18662 grid.view.focusRow(rowIndex);
18663 this.fireEvent("afterselectionchange", this);
18668 * Selects multiple rows.
18669 * @param {Array} rows Array of the indexes of the row to select
18670 * @param {Boolean} keepExisting (optional) True to keep existing selections
18672 selectRows : function(rows, keepExisting){
18674 this.clearSelections();
18676 for(var i = 0, len = rows.length; i < len; i++){
18677 this.selectRow(rows[i], true);
18682 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18683 * @param {Number} startRow The index of the first row in the range
18684 * @param {Number} endRow The index of the last row in the range
18685 * @param {Boolean} keepExisting (optional) True to retain existing selections
18687 selectRange : function(startRow, endRow, keepExisting){
18688 if(this.locked) return;
18690 this.clearSelections();
18692 if(startRow <= endRow){
18693 for(var i = startRow; i <= endRow; i++){
18694 this.selectRow(i, true);
18697 for(var i = startRow; i >= endRow; i--){
18698 this.selectRow(i, true);
18704 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18705 * @param {Number} startRow The index of the first row in the range
18706 * @param {Number} endRow The index of the last row in the range
18708 deselectRange : function(startRow, endRow, preventViewNotify){
18709 if(this.locked) return;
18710 for(var i = startRow; i <= endRow; i++){
18711 this.deselectRow(i, preventViewNotify);
18717 * @param {Number} row The index of the row to select
18718 * @param {Boolean} keepExisting (optional) True to keep existing selections
18720 selectRow : function(index, keepExisting, preventViewNotify){
18721 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18722 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18723 if(!keepExisting || this.singleSelect){
18724 this.clearSelections();
18726 var r = this.grid.dataSource.getAt(index);
18727 this.selections.add(r);
18728 this.last = this.lastActive = index;
18729 if(!preventViewNotify){
18730 this.grid.getView().onRowSelect(index);
18732 this.fireEvent("rowselect", this, index, r);
18733 this.fireEvent("selectionchange", this);
18739 * @param {Number} row The index of the row to deselect
18741 deselectRow : function(index, preventViewNotify){
18742 if(this.locked) return;
18743 if(this.last == index){
18746 if(this.lastActive == index){
18747 this.lastActive = false;
18749 var r = this.grid.dataSource.getAt(index);
18750 this.selections.remove(r);
18751 if(!preventViewNotify){
18752 this.grid.getView().onRowDeselect(index);
18754 this.fireEvent("rowdeselect", this, index);
18755 this.fireEvent("selectionchange", this);
18759 restoreLast : function(){
18761 this.last = this._last;
18766 acceptsNav : function(row, col, cm){
18767 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18771 onEditorKey : function(field, e){
18772 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18777 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18779 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18781 }else if(k == e.ENTER && !e.ctrlKey){
18785 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18787 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18789 }else if(k == e.ESC){
18793 g.startEditing(newCell[0], newCell[1]);
18798 * Ext JS Library 1.1.1
18799 * Copyright(c) 2006-2007, Ext JS, LLC.
18801 * Originally Released Under LGPL - original licence link has changed is not relivant.
18804 * <script type="text/javascript">
18808 * @class Roo.bootstrap.PagingToolbar
18810 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18812 * Create a new PagingToolbar
18813 * @param {Object} config The config object
18815 Roo.bootstrap.PagingToolbar = function(config)
18817 // old args format still supported... - xtype is prefered..
18818 // created from xtype...
18819 var ds = config.dataSource;
18820 this.toolbarItems = [];
18821 if (config.items) {
18822 this.toolbarItems = config.items;
18823 // config.items = [];
18826 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18833 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18837 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18839 * @cfg {Roo.data.Store} dataSource
18840 * The underlying data store providing the paged data
18843 * @cfg {String/HTMLElement/Element} container
18844 * container The id or element that will contain the toolbar
18847 * @cfg {Boolean} displayInfo
18848 * True to display the displayMsg (defaults to false)
18851 * @cfg {Number} pageSize
18852 * The number of records to display per page (defaults to 20)
18856 * @cfg {String} displayMsg
18857 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18859 displayMsg : 'Displaying {0} - {1} of {2}',
18861 * @cfg {String} emptyMsg
18862 * The message to display when no records are found (defaults to "No data to display")
18864 emptyMsg : 'No data to display',
18866 * Customizable piece of the default paging text (defaults to "Page")
18869 beforePageText : "Page",
18871 * Customizable piece of the default paging text (defaults to "of %0")
18874 afterPageText : "of {0}",
18876 * Customizable piece of the default paging text (defaults to "First Page")
18879 firstText : "First Page",
18881 * Customizable piece of the default paging text (defaults to "Previous Page")
18884 prevText : "Previous Page",
18886 * Customizable piece of the default paging text (defaults to "Next Page")
18889 nextText : "Next Page",
18891 * Customizable piece of the default paging text (defaults to "Last Page")
18894 lastText : "Last Page",
18896 * Customizable piece of the default paging text (defaults to "Refresh")
18899 refreshText : "Refresh",
18903 onRender : function(ct, position)
18905 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18906 this.navgroup.parentId = this.id;
18907 this.navgroup.onRender(this.el, null);
18908 // add the buttons to the navgroup
18910 if(this.displayInfo){
18911 Roo.log(this.el.select('ul.navbar-nav',true).first());
18912 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18913 this.displayEl = this.el.select('.x-paging-info', true).first();
18914 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18915 // this.displayEl = navel.el.select('span',true).first();
18921 Roo.each(_this.buttons, function(e){
18922 Roo.factory(e).onRender(_this.el, null);
18926 Roo.each(_this.toolbarItems, function(e) {
18927 _this.navgroup.addItem(e);
18930 this.first = this.navgroup.addItem({
18931 tooltip: this.firstText,
18933 icon : 'fa fa-backward',
18935 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18938 this.prev = this.navgroup.addItem({
18939 tooltip: this.prevText,
18941 icon : 'fa fa-step-backward',
18943 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18945 //this.addSeparator();
18948 var field = this.navgroup.addItem( {
18950 cls : 'x-paging-position',
18952 html : this.beforePageText +
18953 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18954 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18957 this.field = field.el.select('input', true).first();
18958 this.field.on("keydown", this.onPagingKeydown, this);
18959 this.field.on("focus", function(){this.dom.select();});
18962 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18963 //this.field.setHeight(18);
18964 //this.addSeparator();
18965 this.next = this.navgroup.addItem({
18966 tooltip: this.nextText,
18968 html : ' <i class="fa fa-step-forward">',
18970 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18972 this.last = this.navgroup.addItem({
18973 tooltip: this.lastText,
18974 icon : 'fa fa-forward',
18977 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18979 //this.addSeparator();
18980 this.loading = this.navgroup.addItem({
18981 tooltip: this.refreshText,
18982 icon: 'fa fa-refresh',
18984 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18990 updateInfo : function(){
18991 if(this.displayEl){
18992 var count = this.ds.getCount();
18993 var msg = count == 0 ?
18997 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18999 this.displayEl.update(msg);
19004 onLoad : function(ds, r, o){
19005 this.cursor = o.params ? o.params.start : 0;
19006 var d = this.getPageData(),
19010 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19011 this.field.dom.value = ap;
19012 this.first.setDisabled(ap == 1);
19013 this.prev.setDisabled(ap == 1);
19014 this.next.setDisabled(ap == ps);
19015 this.last.setDisabled(ap == ps);
19016 this.loading.enable();
19021 getPageData : function(){
19022 var total = this.ds.getTotalCount();
19025 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19026 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19031 onLoadError : function(){
19032 this.loading.enable();
19036 onPagingKeydown : function(e){
19037 var k = e.getKey();
19038 var d = this.getPageData();
19040 var v = this.field.dom.value, pageNum;
19041 if(!v || isNaN(pageNum = parseInt(v, 10))){
19042 this.field.dom.value = d.activePage;
19045 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19046 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19049 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))
19051 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19052 this.field.dom.value = pageNum;
19053 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19056 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19058 var v = this.field.dom.value, pageNum;
19059 var increment = (e.shiftKey) ? 10 : 1;
19060 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19062 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19063 this.field.dom.value = d.activePage;
19066 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19068 this.field.dom.value = parseInt(v, 10) + increment;
19069 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19070 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19077 beforeLoad : function(){
19079 this.loading.disable();
19084 onClick : function(which){
19091 ds.load({params:{start: 0, limit: this.pageSize}});
19094 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19097 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19100 var total = ds.getTotalCount();
19101 var extra = total % this.pageSize;
19102 var lastStart = extra ? (total - extra) : total-this.pageSize;
19103 ds.load({params:{start: lastStart, limit: this.pageSize}});
19106 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19112 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19113 * @param {Roo.data.Store} store The data store to unbind
19115 unbind : function(ds){
19116 ds.un("beforeload", this.beforeLoad, this);
19117 ds.un("load", this.onLoad, this);
19118 ds.un("loadexception", this.onLoadError, this);
19119 ds.un("remove", this.updateInfo, this);
19120 ds.un("add", this.updateInfo, this);
19121 this.ds = undefined;
19125 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19126 * @param {Roo.data.Store} store The data store to bind
19128 bind : function(ds){
19129 ds.on("beforeload", this.beforeLoad, this);
19130 ds.on("load", this.onLoad, this);
19131 ds.on("loadexception", this.onLoadError, this);
19132 ds.on("remove", this.updateInfo, this);
19133 ds.on("add", this.updateInfo, this);
19144 * @class Roo.bootstrap.MessageBar
19145 * @extends Roo.bootstrap.Component
19146 * Bootstrap MessageBar class
19147 * @cfg {String} html contents of the MessageBar
19148 * @cfg {String} weight (info | success | warning | danger) default info
19149 * @cfg {String} beforeClass insert the bar before the given class
19150 * @cfg {Boolean} closable (true | false) default false
19151 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19154 * Create a new Element
19155 * @param {Object} config The config object
19158 Roo.bootstrap.MessageBar = function(config){
19159 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19162 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19168 beforeClass: 'bootstrap-sticky-wrap',
19170 getAutoCreate : function(){
19174 cls: 'alert alert-dismissable alert-' + this.weight,
19179 html: this.html || ''
19185 cfg.cls += ' alert-messages-fixed';
19199 onRender : function(ct, position)
19201 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19204 var cfg = Roo.apply({}, this.getAutoCreate());
19208 cfg.cls += ' ' + this.cls;
19211 cfg.style = this.style;
19213 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19215 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19218 this.el.select('>button.close').on('click', this.hide, this);
19224 if (!this.rendered) {
19230 this.fireEvent('show', this);
19236 if (!this.rendered) {
19242 this.fireEvent('hide', this);
19245 update : function()
19247 // var e = this.el.dom.firstChild;
19249 // if(this.closable){
19250 // e = e.nextSibling;
19253 // e.data = this.html || '';
19255 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19271 * @class Roo.bootstrap.Graph
19272 * @extends Roo.bootstrap.Component
19273 * Bootstrap Graph class
19277 @cfg {String} graphtype bar | vbar | pie
19278 @cfg {number} g_x coodinator | centre x (pie)
19279 @cfg {number} g_y coodinator | centre y (pie)
19280 @cfg {number} g_r radius (pie)
19281 @cfg {number} g_height height of the chart (respected by all elements in the set)
19282 @cfg {number} g_width width of the chart (respected by all elements in the set)
19283 @cfg {Object} title The title of the chart
19286 -opts (object) options for the chart
19288 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19289 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19291 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.
19292 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19294 o stretch (boolean)
19296 -opts (object) options for the pie
19299 o startAngle (number)
19300 o endAngle (number)
19304 * Create a new Input
19305 * @param {Object} config The config object
19308 Roo.bootstrap.Graph = function(config){
19309 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19315 * The img click event for the img.
19316 * @param {Roo.EventObject} e
19322 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19333 //g_colors: this.colors,
19340 getAutoCreate : function(){
19351 onRender : function(ct,position){
19352 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19353 this.raphael = Raphael(this.el.dom);
19355 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19356 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19357 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19358 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19360 r.text(160, 10, "Single Series Chart").attr(txtattr);
19361 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19362 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19363 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19365 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19366 r.barchart(330, 10, 300, 220, data1);
19367 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19368 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19371 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19372 // r.barchart(30, 30, 560, 250, xdata, {
19373 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19374 // axis : "0 0 1 1",
19375 // axisxlabels : xdata
19376 // //yvalues : cols,
19379 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19381 // this.load(null,xdata,{
19382 // axis : "0 0 1 1",
19383 // axisxlabels : xdata
19388 load : function(graphtype,xdata,opts){
19389 this.raphael.clear();
19391 graphtype = this.graphtype;
19396 var r = this.raphael,
19397 fin = function () {
19398 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19400 fout = function () {
19401 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19403 pfin = function() {
19404 this.sector.stop();
19405 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19408 this.label[0].stop();
19409 this.label[0].attr({ r: 7.5 });
19410 this.label[1].attr({ "font-weight": 800 });
19413 pfout = function() {
19414 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19417 this.label[0].animate({ r: 5 }, 500, "bounce");
19418 this.label[1].attr({ "font-weight": 400 });
19424 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19427 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19430 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19431 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19433 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19440 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19445 setTitle: function(o)
19450 initEvents: function() {
19453 this.el.on('click', this.onClick, this);
19457 onClick : function(e)
19459 Roo.log('img onclick');
19460 this.fireEvent('click', this, e);
19472 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19475 * @class Roo.bootstrap.dash.NumberBox
19476 * @extends Roo.bootstrap.Component
19477 * Bootstrap NumberBox class
19478 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19479 * @cfg {String} headline Box headline
19480 * @cfg {String} content Box content
19481 * @cfg {String} icon Box icon
19482 * @cfg {String} footer Footer text
19483 * @cfg {String} fhref Footer href
19486 * Create a new NumberBox
19487 * @param {Object} config The config object
19491 Roo.bootstrap.dash.NumberBox = function(config){
19492 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19496 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19506 getAutoCreate : function(){
19510 cls : 'small-box bg-' + this.bgcolor,
19518 cls : 'roo-headline',
19519 html : this.headline
19523 cls : 'roo-content',
19524 html : this.content
19538 cls : 'ion ' + this.icon
19547 cls : 'small-box-footer',
19548 href : this.fhref || '#',
19552 cfg.cn.push(footer);
19559 onRender : function(ct,position){
19560 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19567 setHeadline: function (value)
19569 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19572 setFooter: function (value, href)
19574 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19577 this.el.select('a.small-box-footer',true).first().attr('href', href);
19582 setContent: function (value)
19584 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19587 initEvents: function()
19601 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19604 * @class Roo.bootstrap.dash.TabBox
19605 * @extends Roo.bootstrap.Component
19606 * Bootstrap TabBox class
19607 * @cfg {String} title Title of the TabBox
19608 * @cfg {String} icon Icon of the TabBox
19609 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19612 * Create a new TabBox
19613 * @param {Object} config The config object
19617 Roo.bootstrap.dash.TabBox = function(config){
19618 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19623 * When a pane is added
19624 * @param {Roo.bootstrap.dash.TabPane} pane
19631 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19637 getChildContainer : function()
19639 return this.el.select('.tab-content', true).first();
19642 getAutoCreate : function(){
19646 cls: 'pull-left header',
19654 cls: 'fa ' + this.icon
19661 cls: 'nav-tabs-custom',
19665 cls: 'nav nav-tabs pull-right',
19672 cls: 'tab-content no-padding',
19680 initEvents : function()
19682 //Roo.log('add add pane handler');
19683 this.on('addpane', this.onAddPane, this);
19686 * Updates the box title
19687 * @param {String} html to set the title to.
19689 setTitle : function(value)
19691 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19693 onAddPane : function(pane)
19695 //Roo.log('addpane');
19697 // tabs are rendere left to right..
19698 if(!this.showtabs){
19702 var ctr = this.el.select('.nav-tabs', true).first();
19705 var existing = ctr.select('.nav-tab',true);
19706 var qty = existing.getCount();;
19709 var tab = ctr.createChild({
19711 cls : 'nav-tab' + (qty ? '' : ' active'),
19719 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19722 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19724 pane.el.addClass('active');
19729 onTabClick : function(ev,un,ob,pane)
19731 //Roo.log('tab - prev default');
19732 ev.preventDefault();
19735 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19736 pane.tab.addClass('active');
19737 //Roo.log(pane.title);
19738 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19739 // technically we should have a deactivate event.. but maybe add later.
19740 // and it should not de-activate the selected tab...
19742 pane.el.addClass('active');
19743 pane.fireEvent('activate');
19758 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19760 * @class Roo.bootstrap.TabPane
19761 * @extends Roo.bootstrap.Component
19762 * Bootstrap TabPane class
19763 * @cfg {Boolean} active (false | true) Default false
19764 * @cfg {String} title title of panel
19768 * Create a new TabPane
19769 * @param {Object} config The config object
19772 Roo.bootstrap.dash.TabPane = function(config){
19773 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19777 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19782 // the tabBox that this is attached to.
19785 getAutoCreate : function()
19793 cfg.cls += ' active';
19798 initEvents : function()
19800 //Roo.log('trigger add pane handler');
19801 this.parent().fireEvent('addpane', this)
19805 * Updates the tab title
19806 * @param {String} html to set the title to.
19808 setTitle: function(str)
19814 this.tab.select('a', true).first().dom.innerHTML = str;
19831 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19834 * @class Roo.bootstrap.menu.Menu
19835 * @extends Roo.bootstrap.Component
19836 * Bootstrap Menu class - container for Menu
19837 * @cfg {String} html Text of the menu
19838 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19839 * @cfg {String} icon Font awesome icon
19840 * @cfg {String} pos Menu align to (top | bottom) default bottom
19844 * Create a new Menu
19845 * @param {Object} config The config object
19849 Roo.bootstrap.menu.Menu = function(config){
19850 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19854 * @event beforeshow
19855 * Fires before this menu is displayed
19856 * @param {Roo.bootstrap.menu.Menu} this
19860 * @event beforehide
19861 * Fires before this menu is hidden
19862 * @param {Roo.bootstrap.menu.Menu} this
19867 * Fires after this menu is displayed
19868 * @param {Roo.bootstrap.menu.Menu} this
19873 * Fires after this menu is hidden
19874 * @param {Roo.bootstrap.menu.Menu} this
19879 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19880 * @param {Roo.bootstrap.menu.Menu} this
19881 * @param {Roo.EventObject} e
19888 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19892 weight : 'default',
19897 getChildContainer : function() {
19898 if(this.isSubMenu){
19902 return this.el.select('ul.dropdown-menu', true).first();
19905 getAutoCreate : function()
19910 cls : 'roo-menu-text',
19918 cls : 'fa ' + this.icon
19929 cls : 'dropdown-button btn btn-' + this.weight,
19934 cls : 'dropdown-toggle btn btn-' + this.weight,
19944 cls : 'dropdown-menu'
19950 if(this.pos == 'top'){
19951 cfg.cls += ' dropup';
19954 if(this.isSubMenu){
19957 cls : 'dropdown-menu'
19964 onRender : function(ct, position)
19966 this.isSubMenu = ct.hasClass('dropdown-submenu');
19968 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19971 initEvents : function()
19973 if(this.isSubMenu){
19977 this.hidden = true;
19979 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19980 this.triggerEl.on('click', this.onTriggerPress, this);
19982 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19983 this.buttonEl.on('click', this.onClick, this);
19989 if(this.isSubMenu){
19993 return this.el.select('ul.dropdown-menu', true).first();
19996 onClick : function(e)
19998 this.fireEvent("click", this, e);
20001 onTriggerPress : function(e)
20003 if (this.isVisible()) {
20010 isVisible : function(){
20011 return !this.hidden;
20016 this.fireEvent("beforeshow", this);
20018 this.hidden = false;
20019 this.el.addClass('open');
20021 Roo.get(document).on("mouseup", this.onMouseUp, this);
20023 this.fireEvent("show", this);
20030 this.fireEvent("beforehide", this);
20032 this.hidden = true;
20033 this.el.removeClass('open');
20035 Roo.get(document).un("mouseup", this.onMouseUp);
20037 this.fireEvent("hide", this);
20040 onMouseUp : function()
20054 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20057 * @class Roo.bootstrap.menu.Item
20058 * @extends Roo.bootstrap.Component
20059 * Bootstrap MenuItem class
20060 * @cfg {Boolean} submenu (true | false) default false
20061 * @cfg {String} html text of the item
20062 * @cfg {String} href the link
20063 * @cfg {Boolean} disable (true | false) default false
20064 * @cfg {Boolean} preventDefault (true | false) default true
20065 * @cfg {String} icon Font awesome icon
20066 * @cfg {String} pos Submenu align to (left | right) default right
20070 * Create a new Item
20071 * @param {Object} config The config object
20075 Roo.bootstrap.menu.Item = function(config){
20076 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20080 * Fires when the mouse is hovering over this menu
20081 * @param {Roo.bootstrap.menu.Item} this
20082 * @param {Roo.EventObject} e
20087 * Fires when the mouse exits this menu
20088 * @param {Roo.bootstrap.menu.Item} this
20089 * @param {Roo.EventObject} e
20095 * The raw click event for the entire grid.
20096 * @param {Roo.EventObject} e
20102 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20107 preventDefault: true,
20112 getAutoCreate : function()
20117 cls : 'roo-menu-item-text',
20125 cls : 'fa ' + this.icon
20134 href : this.href || '#',
20141 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20145 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20147 if(this.pos == 'left'){
20148 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20155 initEvents : function()
20157 this.el.on('mouseover', this.onMouseOver, this);
20158 this.el.on('mouseout', this.onMouseOut, this);
20160 this.el.select('a', true).first().on('click', this.onClick, this);
20164 onClick : function(e)
20166 if(this.preventDefault){
20167 e.preventDefault();
20170 this.fireEvent("click", this, e);
20173 onMouseOver : function(e)
20175 if(this.submenu && this.pos == 'left'){
20176 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20179 this.fireEvent("mouseover", this, e);
20182 onMouseOut : function(e)
20184 this.fireEvent("mouseout", this, e);
20196 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20199 * @class Roo.bootstrap.menu.Separator
20200 * @extends Roo.bootstrap.Component
20201 * Bootstrap Separator class
20204 * Create a new Separator
20205 * @param {Object} config The config object
20209 Roo.bootstrap.menu.Separator = function(config){
20210 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20213 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20215 getAutoCreate : function(){